mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
Add fs.mkstemp(), fs.mkstempSync() and fsPromises.mkstemp(), which create and open a unique temporary file in one operation. They expose uv_fs_mkstemp(), the file counterpart of the function behind fs.mkdtemp(). The callback and sync versions return the path and a file descriptor, the promise version returns the path and a FileHandle. libuv clears the path of the request when mkstemp() fails, so the template is saved in the request and used for the path of the error. The functions are also supported on mounted virtual file systems. Refs: https://github.com/nodejs/node/pull/33549 Refs: https://github.com/nodejs/node/issues/33890 Refs: https://github.com/nodejs/node/issues/5332 Signed-off-by: marcopiraccini <marco.piraccini@gmail.com> PR-URL: https://github.com/nodejs/node/pull/66484 Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
111 lines
3.5 KiB
JavaScript
111 lines
3.5 KiB
JavaScript
'use strict';
|
|
|
|
const common = require('../common');
|
|
const assert = require('assert');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { pathToFileURL } = require('url');
|
|
const tmpdir = require('../common/tmpdir');
|
|
|
|
tmpdir.refresh();
|
|
|
|
function checkPath(file, prefix) {
|
|
const name = path.basename(file);
|
|
assert.strictEqual(path.dirname(file), tmpdir.path);
|
|
assert.strictEqual(name.length, prefix.length + 6);
|
|
assert.ok(name.startsWith(prefix));
|
|
}
|
|
|
|
function checkFile({ path: file, fd }, prefix) {
|
|
checkPath(file, prefix);
|
|
assert.strictEqual(fs.writeSync(fd, 'hello'), 5);
|
|
if (!common.isWindows) {
|
|
assert.strictEqual(fs.fstatSync(fd).mode & 0o777, 0o600);
|
|
}
|
|
fs.closeSync(fd);
|
|
assert.strictEqual(fs.readFileSync(file, 'utf8'), 'hello');
|
|
}
|
|
|
|
// Sync
|
|
{
|
|
const first = fs.mkstempSync(tmpdir.resolve('sync-'));
|
|
const second = fs.mkstempSync(tmpdir.resolve('sync-'));
|
|
assert.notStrictEqual(first.path, second.path);
|
|
checkFile(first, 'sync-');
|
|
checkFile(second, 'sync-');
|
|
|
|
checkFile(fs.mkstempSync(pathToFileURL(tmpdir.resolve('url-'))), 'url-');
|
|
|
|
for (const result of [
|
|
fs.mkstempSync(tmpdir.resolve('buffer-'), 'buffer'),
|
|
fs.mkstempSync(tmpdir.resolve('buffer-'), { encoding: 'buffer' }),
|
|
fs.mkstempSync(Buffer.from(tmpdir.resolve('buffer-'))),
|
|
]) {
|
|
assert.ok(Buffer.isBuffer(result.path));
|
|
checkFile({ path: result.path.toString(), fd: result.fd }, 'buffer-');
|
|
}
|
|
}
|
|
|
|
// Callback
|
|
{
|
|
fs.mkstemp(tmpdir.resolve('callback-'), common.mustSucceed((file) => {
|
|
checkFile(file, 'callback-');
|
|
}));
|
|
|
|
fs.mkstemp(tmpdir.resolve('callback-'), 'buffer', common.mustSucceed((file) => {
|
|
assert.ok(Buffer.isBuffer(file.path));
|
|
checkFile({ path: file.path.toString(), fd: file.fd }, 'callback-');
|
|
}));
|
|
}
|
|
|
|
// Promises
|
|
(async () => {
|
|
const { path: file, handle } = await fs.promises.mkstemp(tmpdir.resolve('promise-'));
|
|
checkPath(file, 'promise-');
|
|
await handle.writeFile('hello');
|
|
await handle.close();
|
|
assert.strictEqual(fs.readFileSync(file, 'utf8'), 'hello');
|
|
|
|
const result = await fs.promises.mkstemp(Buffer.from(tmpdir.resolve('promise-')));
|
|
assert.ok(Buffer.isBuffer(result.path));
|
|
await result.handle.close();
|
|
})().then(common.mustCall());
|
|
|
|
// Errors report the template.
|
|
{
|
|
const prefix = tmpdir.resolve('missing', 'error-');
|
|
const expected = {
|
|
code: 'ENOENT',
|
|
syscall: 'mkstemp',
|
|
path: `${prefix}XXXXXX`,
|
|
message: `ENOENT: no such file or directory, mkstemp '${prefix}XXXXXX'`,
|
|
};
|
|
|
|
assert.throws(() => fs.mkstempSync(prefix), expected);
|
|
fs.mkstemp(prefix, common.mustCall((err, file) => {
|
|
assert.throws(() => { throw err; }, expected);
|
|
assert.strictEqual(file, undefined);
|
|
}));
|
|
assert.rejects(fs.promises.mkstemp(prefix), expected).then(common.mustCall());
|
|
}
|
|
|
|
// Invalid arguments
|
|
{
|
|
for (const prefix of [undefined, null, 1, {}, true]) {
|
|
const expected = { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' };
|
|
assert.throws(() => fs.mkstempSync(prefix), expected);
|
|
assert.throws(() => fs.mkstemp(prefix, common.mustNotCall()), expected);
|
|
assert.rejects(fs.promises.mkstemp(prefix), expected).then(common.mustCall());
|
|
}
|
|
|
|
assert.throws(() => fs.mkstemp(tmpdir.resolve('no-callback-')), {
|
|
code: 'ERR_INVALID_ARG_TYPE',
|
|
name: 'TypeError',
|
|
});
|
|
|
|
const withNull = { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError' };
|
|
assert.throws(() => fs.mkstempSync('fhqwhgads\u0000'), withNull);
|
|
assert.throws(() => fs.mkstemp('fhqwhgads\u0000', common.mustNotCall()), withNull);
|
|
assert.rejects(fs.promises.mkstemp('fhqwhgads\u0000'), withNull).then(common.mustCall());
|
|
}
|