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.
The npm.community site is dealing with a frequent failure mode whereby
sudo npm install -g ...results in anEISDIRerror 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
cacacheinvokes thechownrfunction to fix up the ownership of the directory it just created. I believe that npm 6.9.0 useschownr1.1.1, which would indicate that this code somehow ends up returningEISDIRvia 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
chownrinvokes theopen(2)system call on the directory it is given on some execution path. The only path I could see that (on MacOS, whereO_SYMLINKis defined) would be vialchownwhich has this implementation in node v8.x:I do not understand why this function calls
fs.open()unconditionally. If the file in question is not a symlink, wouldn't this guarantee anEISDIR? According to the OpenGroup,lchownshould behave likechownunless 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:
chownrprior to v1.1.1 usedchown, which does not perform thisopencall. I believe that the use oflchownwas introduced by commit a631d84 which is included in v1.1.1 which ships in npm 6.9.0 as per package.jsonI'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.