From 779e07246275c81e5a95cecdf410f6c32163f3cf Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Thu, 9 Aug 2018 16:52:41 -0700 Subject: [PATCH] fs: implement mkdir recursive (mkdirp) Implements mkdirp functionality in node_file.cc. The Benefit of implementing in C++ layer is that the logic is more easily shared between the Promise and callback implementation and there are notable performance improvements. This commit is part of the Tooling Group Initiative. Refs: https://github.com/nodejs/user-feedback/pull/70 PR-URL: https://github.com/nodejs/node/pull/21875 Reviewed-By: Anna Henningsen Reviewed-By: Matteo Collina Reviewed-By: Jon Moss Reviewed-By: Ron Korving Reviewed-By: James M Snell Reviewed-By: Michael Dawson Reviewed-By: Anatoli Papirovski Reviewed-By: Sam Ruby Reviewed-By: Joyee Cheung --- benchmark/fs/bench-mkdirp.js | 23 +++++ doc/api/fs.md | 35 +++++-- lib/fs.js | 45 ++++++--- lib/internal/fs/promises.js | 18 +++- src/node_file.cc | 158 ++++++++++++++++++++++++++++-- src/node_file.h | 42 ++++++++ test/parallel/test-fs-mkdir.js | 107 +++++++++++++++++++- test/parallel/test-fs-promises.js | 49 ++++++++- 8 files changed, 441 insertions(+), 36 deletions(-) create mode 100644 benchmark/fs/bench-mkdirp.js diff --git a/benchmark/fs/bench-mkdirp.js b/benchmark/fs/bench-mkdirp.js new file mode 100644 index 00000000000000..96a792c35a48e4 --- /dev/null +++ b/benchmark/fs/bench-mkdirp.js @@ -0,0 +1,23 @@ +'use strict'; + +const common = require('../common'); +const fs = require('fs'); +const tmpdir = require('../../test/common/tmpdir'); +tmpdir.refresh(); +let dirc = 0; + +const bench = common.createBenchmark(main, { + n: [1e4], +}); + +function main({ n }) { + bench.start(); + (function r(cntr) { + if (cntr-- <= 0) + return bench.end(n); + const pathname = `${tmpdir.path}/${++dirc}/${++dirc}/${++dirc}/${++dirc}`; + fs.mkdir(pathname, { createParents: true }, (err) => { + r(cntr); + }); + }(n)); +} diff --git a/doc/api/fs.md b/doc/api/fs.md index 25cb3fc7f87ee2..d7cfcf46347af7 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -2139,7 +2139,7 @@ changes: Synchronous lstat(2). -## fs.mkdir(path[, mode], callback) +## fs.mkdir(path[, options], callback) * `path` {string|Buffer|URL} -* `mode` {integer} Not supported on Windows. **Default:** `0o777`. +* `options` {Object|integer} + * `recursive` {boolean} **Default:** `false` + * `mode` {integer} Not supported on Windows. **Default:** `0o777`. * `callback` {Function} * `err` {Error} Asynchronously creates a directory. No arguments other than a possible exception are given to the completion callback. +The optional `options` argument can be an integer specifying mode (permission +and sticky bits), or an object with a `mode` property and a `recursive` +property indicating whether parent folders should be created. + +```js +// Creates /tmp/a/apple, regardless of whether `/tmp` and /tmp/a exist. +fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => { + if (err) throw err; +}); +``` + See also: mkdir(2). -## fs.mkdirSync(path[, mode]) +## fs.mkdirSync(path[, options]) * `path` {string|Buffer|URL} -* `mode` {integer} Not supported on Windows. **Default:** `0o777`. +* `options` {Object|integer} + * `recursive` {boolean} **Default:** `false` + * `mode` {integer} Not supported on Windows. **Default:** `0o777`. Synchronously creates a directory. Returns `undefined`. This is the synchronous version of [`fs.mkdir()`][]. @@ -4100,18 +4115,24 @@ changes: Asynchronous lstat(2). The `Promise` is resolved with the [`fs.Stats`][] object for the given symbolic link `path`. -### fsPromises.mkdir(path[, mode]) +### fsPromises.mkdir(path[, options]) * `path` {string|Buffer|URL} -* `mode` {integer} **Default:** `0o777` +* `options` {Object|integer} + * `recursive` {boolean} **Default:** `false` + * `mode` {integer} Not supported on Windows. **Default:** `0o777`. * Returns: {Promise} Asynchronously creates a directory then resolves the `Promise` with no arguments upon success. +The optional `options` argument can be an integer specifying mode (permission +and sticky bits), or an object with a `mode` property and a `recursive` +property indicating whether parent folders should be created. + ### fsPromises.mkdtemp(prefix[, options])