nodejs/node-v0.x-archive

fs.unlink() treats permissions differently on Windows vs. Unix

arturadib opened this issue · 11 comments

The following test creates a file with read-only permissions in a writeable directory, and attempts to unlink the file. It passes on Linux/Darwin, but on Windows it throws the EPERM exception:

var fs = require('fs'),
    path = require('path'),
    assert = require('assert'),
    dir = 'tmp_'+Date.now(),
    file = dir+'/file.txt';

var existsSync = fs.existsSync || path.existsSync;

console.log('working on dir:', dir);

fs.mkdirSync(dir);
fs.writeFileSync(file, 'asdf');
fs.chmodSync(file, '0444'); // -r--r--r--
fs.unlinkSync(file);

assert.equal(existsSync(file), false); // file should be erased since dir is writeable

Apparently on Windows fs.unlink() expects the file to be writeable in order to remove it, whereas on Unix it suffices for the parent directory to be writeable in order to remove/move files (see e.g. http://www.greenend.org.uk/rjk/tech/perms.html).

Should the unlink behavior be normalized across platforms, or is this behavior really supposed to be platform-dependent?

PS: The issue is true for both fs.unlink() and fs.unlinkSync()


Used: Node version 0.6.14
Tested on: Windows 7, Windows 2008, Mac OS X, and Ubuntu

Should the unlink behavior be normalized across platforms, or is this behavior really supposed to be platform-dependent?

If unlink(2) is platform-dependent, fs.unlink should be platform-dependent. This operation is supposed to be atomic, so any additional checks are undesirable.

You can do any normalization you want in the userspace.

If unlink(2) is platform-dependent, fs.unlink should be platform-dependent

I don't know how much normalization Node / libuv is willing to make for such POSIX vs. CRT differences. For example, libuv already normalizes part of fs.open on Windows to match Unix's behavior.

Part of me thinks that the primitive should remain platform-dependent (which avoids surprises for platform Ninjas), part of me would prefer that fs would be an abstract layer that normalizes what's under the hood (which avoids surprises for non-Ninjas).

For example, libuv already normalizes part of fs.open on Windows to match Unix's behavior.

That's not quite comparable because it doesn't change the atomicity of the open syscall, only the default flags.

I'll let @piscisaureus and @igorzi decide but my gut feeling is that it's a very bad idea indeed to try and patch up unlink()'s behavior, unless (and maybe not even then) it can be done atomically.

@bnoordhuis Windows' DeleteFile is not atomic, so we can just fix this without regressions.

Windows' DeleteFile is not atomic, so we can just fix this without regressions.

Good. Assigning to you. :-)

@piscisaureus any progress on this one? thanks

@piscisaureus any progress on this one? thanks

This prevents Meteorite from working on Windows :(

@Hades32 have you tried the windows-updates branch of Meteorite (oortcloud/meteorite#248) ? I think that we've resolved this (and many others) issues in it.

@yeputons no, thanks, I'll have a look. I just hacked to gather some alternative Meteor launcher just so I could test Meteorite, when I hit this... :)

Fixed in libuv in libuv/libuv@0db81a9, and in Node with 84f1ab6