Skip to content

Commit

Permalink
fs: add the fs.mkdtemp() function.
Browse files Browse the repository at this point in the history
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 <thechargingvolcano@gmail.com>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
ralt authored and evanlucas committed Mar 31, 2016
1 parent 731f7b8 commit 80155d3
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 0 deletions.
24 changes: 24 additions & 0 deletions doc/api/fs.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,30 @@ to the completion callback. `mode` defaults to `0o777`.

Synchronous mkdir(2). Returns `undefined`.

## fs.mkdtemp(prefix, callback)

Creates a unique temporary directory.

Generates six random characters to be appended behind a required
`prefix` to create a unique temporary directory.

The created folder path is passed as a string to the callback's second
parameter.

Example:

```js
fs.mkdtemp('/tmp/foo-', (err, folder) => {
console.log(folder);
// Prints: /tmp/foo-itXde2
});
```

## fs.mkdtempSync(template)

The synchronous version of [`fs.mkdtemp()`][]. Returns the created
folder path.

## fs.open(path, flags[, mode], callback)

Asynchronous file open. See open(2). `flags` can be:
Expand Down
21 changes: 21 additions & 0 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2078,3 +2078,24 @@ SyncWriteStream.prototype.destroy = function() {
};

SyncWriteStream.prototype.destroySoon = SyncWriteStream.prototype.destroy;

fs.mkdtemp = function(prefix, callback) {
if (typeof callback !== 'function') {
throw new TypeError('"callback" argument must be a function');
}

if (!nullCheck(prefix, callback)) {
return;
}

var req = new FSReqWrap();
req.oncomplete = callback;

binding.mkdtemp(prefix + 'XXXXXX', req);
};

fs.mkdtempSync = function(prefix) {
nullCheck(prefix);

return binding.mkdtemp(prefix + 'XXXXXX');
};
26 changes: 26 additions & 0 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ static void After(uv_fs_t *req) {
static_cast<const uv_stat_t*>(req->ptr));
break;

case UV_FS_MKDTEMP:
argv[1] = String::NewFromUtf8(env->isolate(),
static_cast<const char*>(req->path));
break;

case UV_FS_READLINK:
argv[1] = String::NewFromUtf8(env->isolate(),
static_cast<const char*>(req->ptr));
Expand Down Expand Up @@ -1291,6 +1296,25 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
}
}

static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

if (args.Length() < 1)
return TYPE_ERROR("template is required");
if (!args[0]->IsString())
return TYPE_ERROR("template must be a string");

node::Utf8Value tmpl(env->isolate(), args[0]);

if (args[1]->IsObject()) {
ASYNC_CALL(mkdtemp, args[1], *tmpl);
} else {
SYNC_CALL(mkdtemp, *tmpl, *tmpl);
args.GetReturnValue().Set(String::NewFromUtf8(env->isolate(),
SYNC_REQ.path));
}
}

void FSInitialize(const FunctionCallbackInfo<Value>& args) {
Local<Function> stats_constructor = args[0].As<Function>();
CHECK(stats_constructor->IsFunction());
Expand Down Expand Up @@ -1344,6 +1368,8 @@ void InitFs(Local<Object> target,
env->SetMethod(target, "utimes", UTimes);
env->SetMethod(target, "futimes", FUTimes);

env->SetMethod(target, "mkdtemp", Mkdtemp);

StatWatcher::Initialize(env, target);

// Create FunctionTemplate for FSReqWrap
Expand Down
27 changes: 27 additions & 0 deletions test/parallel/test-fs-mkdtemp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict';

const common = require('../common');
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const Buffer = require('buffer').Buffer;

common.refreshTmpDir();

const tmpFolder = fs.mkdtempSync(path.join(common.tmpDir, 'foo.'));

assert(path.basename(tmpFolder).length === 'foo.XXXXXX'.length);
assert(common.fileExists(tmpFolder));

const utf8 = fs.mkdtempSync(path.join(common.tmpDir, '\u0222abc.'));
assert.equal(Buffer.byteLength(path.basename(utf8)),
Buffer.byteLength('\u0222abc.XXXXXX'));
assert(common.fileExists(utf8));

fs.mkdtemp(
path.join(common.tmpDir, 'bar.'),
common.mustCall(function(err, folder) {
assert.ifError(err);
assert(common.fileExists(folder));
})
);

0 comments on commit 80155d3

Please sign in to comment.