From bdef1b1eb45e2953e1ff68f0cc9a68ec83573e57 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 d0348d45c93f04..1f71a537e3eb46 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -2047,7 +2047,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()`][]. @@ -3979,18 +3994,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])