Skip to content

Commit 4ca2f90

Browse files
author
bcoe
committed
fs: recursion should bail on permission error
When creating directories recursively, the logic should bail immediately on UV_EACCES and bubble the error to the user. Fixes: #31481
1 parent 67e067e commit 4ca2f90

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

src/node_file.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,9 @@ int MKDirpSync(uv_loop_t* loop,
12461246
case UV_EPERM: {
12471247
return err;
12481248
}
1249+
case UV_EACCES: {
1250+
return err;
1251+
}
12491252
default:
12501253
uv_fs_req_cleanup(req);
12511254
int orig_err = err;
@@ -1322,6 +1325,10 @@ int MKDirpAsync(uv_loop_t* loop,
13221325
req_wrap->continuation_data()->Done(err);
13231326
break;
13241327
}
1328+
case UV_EACCES: {
1329+
req_wrap->continuation_data()->Done(err);
1330+
break;
1331+
}
13251332
default:
13261333
uv_fs_req_cleanup(req);
13271334
// Stash err for use in the callback.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
'use strict';
2+
3+
// Test that mkdir with recursive option returns appropriate error
4+
// when executed on folder it does not have permission to access.
5+
// Ref: https://github.com/nodejs/node/issues/31481
6+
7+
const common = require('../common');
8+
9+
if (!common.isWindows && process.getuid() === 0)
10+
common.skip('as this test should not be run as `root`');
11+
12+
if (common.isIBMi)
13+
common.skip('IBMi has a different access permission mechanism');
14+
15+
const tmpdir = require('../common/tmpdir');
16+
tmpdir.refresh();
17+
18+
const assert = require('assert');
19+
const fs = require('fs');
20+
const path = require('path');
21+
22+
let n = 0;
23+
24+
// Synchronous API should return an EACCESS error with path populated.
25+
{
26+
const dir = path.join(tmpdir.path, `mkdirp_${n++}`);
27+
fs.mkdirSync(dir);
28+
fs.chmodSync(dir, '444');
29+
let err = null;
30+
try {
31+
fs.mkdirSync(path.join(dir, '/foo'), { recursive: true });
32+
} catch (_err) {
33+
err = _err;
34+
}
35+
assert(err);
36+
assert.strictEqual(err.code, 'EACCES');
37+
assert(err.path);
38+
}
39+
40+
// Asynchronous API should return an EACCESS error with path populated.
41+
{
42+
const dir = path.join(tmpdir.path, `mkdirp_${n++}`);
43+
fs.mkdirSync(dir);
44+
fs.chmodSync(dir, '444');
45+
fs.mkdir(path.join(dir, '/bar'), { recursive: true }, (err) => {
46+
assert(err);
47+
assert.strictEqual(err.code, 'EACCES');
48+
assert(err.path);
49+
});
50+
}

0 commit comments

Comments
 (0)