Skip to content

Commit

Permalink
fs: recursion should bail on permission error
Browse files Browse the repository at this point in the history
When creating directories recursively, the logic should bail
immediately on UV_EACCES and bubble the error to the user.

Fixes: #31481
  • Loading branch information
bcoe committed Jan 25, 2020
1 parent 67e067e commit 4ca2f90
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,9 @@ int MKDirpSync(uv_loop_t* loop,
case UV_EPERM: {
return err;
}
case UV_EACCES: {
return err;
}
default:
uv_fs_req_cleanup(req);
int orig_err = err;
Expand Down Expand Up @@ -1322,6 +1325,10 @@ int MKDirpAsync(uv_loop_t* loop,
req_wrap->continuation_data()->Done(err);
break;
}
case UV_EACCES: {
req_wrap->continuation_data()->Done(err);
break;
}
default:
uv_fs_req_cleanup(req);
// Stash err for use in the callback.
Expand Down
50 changes: 50 additions & 0 deletions test/parallel/test-fs-mkdir-recursive-eaccess.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use strict';

// Test that mkdir with recursive option returns appropriate error
// when executed on folder it does not have permission to access.
// Ref: https://github.com/nodejs/node/issues/31481

const common = require('../common');

if (!common.isWindows && process.getuid() === 0)
common.skip('as this test should not be run as `root`');

if (common.isIBMi)
common.skip('IBMi has a different access permission mechanism');

const tmpdir = require('../common/tmpdir');
tmpdir.refresh();

const assert = require('assert');
const fs = require('fs');
const path = require('path');

let n = 0;

// Synchronous API should return an EACCESS error with path populated.
{
const dir = path.join(tmpdir.path, `mkdirp_${n++}`);
fs.mkdirSync(dir);
fs.chmodSync(dir, '444');
let err = null;
try {
fs.mkdirSync(path.join(dir, '/foo'), { recursive: true });
} catch (_err) {
err = _err;
}
assert(err);
assert.strictEqual(err.code, 'EACCES');
assert(err.path);
}

// Asynchronous API should return an EACCESS error with path populated.
{
const dir = path.join(tmpdir.path, `mkdirp_${n++}`);
fs.mkdirSync(dir);
fs.chmodSync(dir, '444');
fs.mkdir(path.join(dir, '/bar'), { recursive: true }, (err) => {
assert(err);
assert.strictEqual(err.code, 'EACCES');
assert(err.path);
});
}

0 comments on commit 4ca2f90

Please sign in to comment.