Skip to content

Commit e5f8a6a

Browse files
raltbenjamingr
authored andcommitted
fs: add the fs.mkdtemp() function.
This uses libuv's mkdtemp function to provide a way to create a temporary folder, using a prefix as the path. The prefix is appended six random characters. The callback function will receive the name of the folder that was created. Usage example: fs.mkdtemp('/tmp/foo-', function(err, folder) { console.log(folder); // Prints: /tmp/foo-Tedi42 }); The fs.mkdtempSync version is also provided. Usage example: console.log(fs.mkdtemp('/tmp/foo-')); // Prints: tmp/foo-Tedi42 This pull request also includes the relevant documentation changes and tests. PR-URL: #5333 Reviewed-By: Sakthipriyan Vairamani <[email protected]> Reviewed-By: Trevor Norris <[email protected]> Reviewed-By: Saúl Ibarra Corretgé <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent e6bfe04 commit e5f8a6a

File tree

4 files changed

+98
-0
lines changed

4 files changed

+98
-0
lines changed

doc/api/fs.markdown

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,30 @@ to the completion callback. `mode` defaults to `0o777`.
532532

533533
Synchronous mkdir(2). Returns `undefined`.
534534

535+
## fs.mkdtemp(prefix, callback)
536+
537+
Creates a unique temporary directory.
538+
539+
Generates six random characters to be appended behind a required
540+
`prefix` to create a unique temporary directory.
541+
542+
The created folder path is passed as a string to the callback's second
543+
parameter.
544+
545+
Example:
546+
547+
```js
548+
fs.mkdtemp('/tmp/foo-', (err, folder) => {
549+
console.log(folder);
550+
// Prints: /tmp/foo-itXde2
551+
});
552+
```
553+
554+
## fs.mkdtempSync(template)
555+
556+
The synchronous version of [`fs.mkdtemp()`][]. Returns the created
557+
folder path.
558+
535559
## fs.open(path, flags[, mode], callback)
536560

537561
Asynchronous file open. See open(2). `flags` can be:

lib/fs.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2138,3 +2138,24 @@ SyncWriteStream.prototype.destroy = function() {
21382138
};
21392139

21402140
SyncWriteStream.prototype.destroySoon = SyncWriteStream.prototype.destroy;
2141+
2142+
fs.mkdtemp = function(prefix, callback) {
2143+
if (typeof callback !== 'function') {
2144+
throw new TypeError('"callback" argument must be a function');
2145+
}
2146+
2147+
if (!nullCheck(prefix, callback)) {
2148+
return;
2149+
}
2150+
2151+
var req = new FSReqWrap();
2152+
req.oncomplete = callback;
2153+
2154+
binding.mkdtemp(prefix + 'XXXXXX', req);
2155+
};
2156+
2157+
fs.mkdtempSync = function(prefix) {
2158+
nullCheck(prefix);
2159+
2160+
return binding.mkdtemp(prefix + 'XXXXXX');
2161+
};

src/node_file.cc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ static void After(uv_fs_t *req) {
200200
static_cast<const uv_stat_t*>(req->ptr));
201201
break;
202202

203+
case UV_FS_MKDTEMP:
204+
argv[1] = String::NewFromUtf8(env->isolate(),
205+
static_cast<const char*>(req->path));
206+
break;
207+
203208
case UV_FS_READLINK:
204209
argv[1] = String::NewFromUtf8(env->isolate(),
205210
static_cast<const char*>(req->ptr));
@@ -1294,6 +1299,25 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
12941299
}
12951300
}
12961301

1302+
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
1303+
Environment* env = Environment::GetCurrent(args);
1304+
1305+
if (args.Length() < 1)
1306+
return TYPE_ERROR("template is required");
1307+
if (!args[0]->IsString())
1308+
return TYPE_ERROR("template must be a string");
1309+
1310+
node::Utf8Value tmpl(env->isolate(), args[0]);
1311+
1312+
if (args[1]->IsObject()) {
1313+
ASYNC_CALL(mkdtemp, args[1], *tmpl);
1314+
} else {
1315+
SYNC_CALL(mkdtemp, *tmpl, *tmpl);
1316+
args.GetReturnValue().Set(String::NewFromUtf8(env->isolate(),
1317+
SYNC_REQ.path));
1318+
}
1319+
}
1320+
12971321
void FSInitialize(const FunctionCallbackInfo<Value>& args) {
12981322
Local<Function> stats_constructor = args[0].As<Function>();
12991323
CHECK(stats_constructor->IsFunction());
@@ -1347,6 +1371,8 @@ void InitFs(Local<Object> target,
13471371
env->SetMethod(target, "utimes", UTimes);
13481372
env->SetMethod(target, "futimes", FUTimes);
13491373

1374+
env->SetMethod(target, "mkdtemp", Mkdtemp);
1375+
13501376
StatWatcher::Initialize(env, target);
13511377

13521378
// Create FunctionTemplate for FSReqWrap

test/parallel/test-fs-mkdtemp.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const fs = require('fs');
6+
const path = require('path');
7+
const Buffer = require('buffer').Buffer;
8+
9+
common.refreshTmpDir();
10+
11+
const tmpFolder = fs.mkdtempSync(path.join(common.tmpDir, 'foo.'));
12+
13+
assert(path.basename(tmpFolder).length === 'foo.XXXXXX'.length);
14+
assert(common.fileExists(tmpFolder));
15+
16+
const utf8 = fs.mkdtempSync(path.join(common.tmpDir, '\u0222abc.'));
17+
assert.equal(Buffer.byteLength(path.basename(utf8)),
18+
Buffer.byteLength('\u0222abc.XXXXXX'));
19+
assert(common.fileExists(utf8));
20+
21+
fs.mkdtemp(
22+
path.join(common.tmpDir, 'bar.'),
23+
common.mustCall(function(err, folder) {
24+
assert.ifError(err);
25+
assert(common.fileExists(folder));
26+
})
27+
);

0 commit comments

Comments
 (0)