Description
The npm.community site is dealing with a frequent failure mode whereby sudo npm install -g ...
results in an EISDIR
error on such paths as /Users/xxx/.npm/_cacache/index-v5/77/b2
. They call it the EISDIR conundrum.
Thanks to one of the users on that site we were able to pinpoint this error and tracked it to where cacache
invokes the chownr
function to fix up the ownership of the directory it just created. I believe that npm 6.9.0 uses chownr
1.1.1, which would indicate that this code somehow ends up returning EISDIR
via a callback to the caller (this is then turned via BB to the rejected promise visible in the error log.
Taken literally, the error would mean that chownr
invokes the open(2)
system call on the directory it is given on some execution path. The only path I could see that (on MacOS, where O_SYMLINK
is defined) would be via lchown
which has this implementation in node v8.x:
fs.lchown = function(path, uid, gid, callback) {
callback = maybeCallback(callback);
fs.open(path, constants.O_WRONLY | constants.O_SYMLINK, function(err, fd) {
if (err) {
callback(err);
return;
}
// Prefer to return the chown error, if one occurs,
// but still try to close, and report closing errors if they occur.
fs.fchown(fd, uid, gid, function(err) {
fs.close(fd, function(err2) {
callback(err || err2);
});
});
});
};
I do not understand why this function calls fs.open()
unconditionally. If the file in question is not a symlink, wouldn't this guarantee an EISDIR
? According to the OpenGroup, lchown
should behave like chown
unless the object in question is a symbolic link. The code in question appears to work if and only if the object in question is a symbolic link.
Side note: chownr
prior to v1.1.1 used chown
, which does not perform this open
call. I believe that the use of lchown
was introduced by commit a631d84 which is included in v1.1.1 which ships in npm 6.9.0 as per package.json
I'll stop here. I realize from what I've written so far that if my interpretation is correct, this is a node.js bug (MacOS specific) and not a chownr bug, but I'll leave this here for future reference anyway.