fs: expose copy-on-write flags for fs.copyFile()

This commit exposes the UV_FS_COPYFILE_FICLONE and
UV_FS_COPYFILE_FICLONE_FORCE flags added in libuv 1.20.0.

Fixes: https://github.com/nodejs/node/issues/19152
PR-URL: https://github.com/nodejs/node/pull/19759
Fixes: https://github.com/nodejs/node/issues/19152
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
cjihrig 2018-04-02 15:12:57 -04:00
parent 617946779c
commit a16d88d9e9
No known key found for this signature in database
GPG Key ID: 7434390BDBE9B9C5
4 changed files with 107 additions and 9 deletions

View File

@ -1175,8 +1175,18 @@ operation. If an error occurs after the destination file has been opened for
writing, Node.js will attempt to remove the destination. writing, Node.js will attempt to remove the destination.
`flags` is an optional integer that specifies the behavior `flags` is an optional integer that specifies the behavior
of the copy operation. The only supported flag is `fs.constants.COPYFILE_EXCL`, of the copy operation. It is possible to create a mask consisting of the bitwise
which causes the copy operation to fail if `dest` already exists. OR of two or more values (e.g.
`fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE`).
* `fs.constants.COPYFILE_EXCL` - The copy operation will fail if `dest` already
exists.
* `fs.constants.COPYFILE_FICLONE` - The copy operation will attempt to create a
copy-on-write reflink. If the platform does not support copy-on-write, then a
fallback copy mechanism is used.
* `fs.constants.COPYFILE_FICLONE_FORCE` - The copy operation will attempt to
create a copy-on-write reflink. If the platform does not support copy-on-write,
then the operation will fail.
Example: Example:
@ -1216,8 +1226,18 @@ atomicity of the copy operation. If an error occurs after the destination file
has been opened for writing, Node.js will attempt to remove the destination. has been opened for writing, Node.js will attempt to remove the destination.
`flags` is an optional integer that specifies the behavior `flags` is an optional integer that specifies the behavior
of the copy operation. The only supported flag is `fs.constants.COPYFILE_EXCL`, of the copy operation. It is possible to create a mask consisting of the bitwise
which causes the copy operation to fail if `dest` already exists. OR of two or more values (e.g.
`fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE`).
* `fs.constants.COPYFILE_EXCL` - The copy operation will fail if `dest` already
exists.
* `fs.constants.COPYFILE_FICLONE` - The copy operation will attempt to create a
copy-on-write reflink. If the platform does not support copy-on-write, then a
fallback copy mechanism is used.
* `fs.constants.COPYFILE_FICLONE_FORCE` - The copy operation will attempt to
create a copy-on-write reflink. If the platform does not support copy-on-write,
then the operation will fail.
Example: Example:
@ -3814,8 +3834,18 @@ error occurs after the destination file has been opened for writing, Node.js
will attempt to remove the destination. will attempt to remove the destination.
`flags` is an optional integer that specifies the behavior `flags` is an optional integer that specifies the behavior
of the copy operation. The only supported flag is `fs.constants.COPYFILE_EXCL`, of the copy operation. It is possible to create a mask consisting of the bitwise
which causes the copy operation to fail if `dest` already exists. OR of two or more values (e.g.
`fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE`).
* `fs.constants.COPYFILE_EXCL` - The copy operation will fail if `dest` already
exists.
* `fs.constants.COPYFILE_FICLONE` - The copy operation will attempt to create a
copy-on-write reflink. If the platform does not support copy-on-write, then a
fallback copy mechanism is used.
* `fs.constants.COPYFILE_FICLONE_FORCE` - The copy operation will attempt to
create a copy-on-write reflink. If the platform does not support copy-on-write,
then the operation will fail.
Example: Example:
@ -4449,6 +4479,34 @@ The following constants are meant for use with [`fs.access()`][].
</tr> </tr>
</table> </table>
### File Copy Constants
The following constants are meant for use with [`fs.copyFile()`][].
<table>
<tr>
<th>Constant</th>
<th>Description</th>
</tr>
<tr>
<td><code>COPYFILE_EXCL</code></td>
<td>If present, the copy operation will fail with an error if the
destination path already exists.</td>
</tr>
<tr>
<td><code>COPYFILE_FICLONE</code></td>
<td>If present, the copy operation will attempt to create a
copy-on-write reflink. If the underlying platform does not support
copy-on-write, then a fallback copy mechanism is used.</td>
</tr>
<tr>
<td><code>COPYFILE_FICLONE_FORCE</code></td>
<td>If present, the copy operation will attempt to create a
copy-on-write reflink. If the underlying platform does not support
copy-on-write, then the operation will fail with an error.</td>
</tr>
</table>
### File Open Constants ### File Open Constants
The following constants are meant for use with `fs.open()`. The following constants are meant for use with `fs.open()`.

View File

@ -1916,7 +1916,15 @@ fs.mkdtempSync = function(prefix, options) {
// Define copyFile() flags. // Define copyFile() flags.
Object.defineProperties(fs.constants, { Object.defineProperties(fs.constants, {
COPYFILE_EXCL: { enumerable: true, value: constants.UV_FS_COPYFILE_EXCL } COPYFILE_EXCL: { enumerable: true, value: constants.UV_FS_COPYFILE_EXCL },
COPYFILE_FICLONE: {
enumerable: true,
value: constants.UV_FS_COPYFILE_FICLONE
},
COPYFILE_FICLONE_FORCE: {
enumerable: true,
value: constants.UV_FS_COPYFILE_FICLONE_FORCE
}
}); });

View File

@ -1314,6 +1314,8 @@ void DefineConstants(v8::Isolate* isolate, Local<Object> target) {
// Define libuv constants. // Define libuv constants.
NODE_DEFINE_CONSTANT(os_constants, UV_UDP_REUSEADDR); NODE_DEFINE_CONSTANT(os_constants, UV_UDP_REUSEADDR);
NODE_DEFINE_CONSTANT(fs_constants, UV_FS_COPYFILE_EXCL); NODE_DEFINE_CONSTANT(fs_constants, UV_FS_COPYFILE_EXCL);
NODE_DEFINE_CONSTANT(fs_constants, UV_FS_COPYFILE_FICLONE);
NODE_DEFINE_CONSTANT(fs_constants, UV_FS_COPYFILE_FICLONE_FORCE);
os_constants->Set(OneByteString(isolate, "dlopen"), dlopen_constants); os_constants->Set(OneByteString(isolate, "dlopen"), dlopen_constants);
os_constants->Set(OneByteString(isolate, "errno"), err_constants); os_constants->Set(OneByteString(isolate, "errno"), err_constants);

View File

@ -8,7 +8,14 @@ const uv = process.binding('uv');
const path = require('path'); const path = require('path');
const src = fixtures.path('a.js'); const src = fixtures.path('a.js');
const dest = path.join(tmpdir.path, 'copyfile.out'); const dest = path.join(tmpdir.path, 'copyfile.out');
const { COPYFILE_EXCL, UV_FS_COPYFILE_EXCL } = fs.constants; const {
COPYFILE_EXCL,
COPYFILE_FICLONE,
COPYFILE_FICLONE_FORCE,
UV_FS_COPYFILE_EXCL,
UV_FS_COPYFILE_FICLONE,
UV_FS_COPYFILE_FICLONE_FORCE
} = fs.constants;
function verify(src, dest) { function verify(src, dest) {
const srcData = fs.readFileSync(src, 'utf8'); const srcData = fs.readFileSync(src, 'utf8');
@ -25,8 +32,14 @@ tmpdir.refresh();
// Verify that flags are defined. // Verify that flags are defined.
assert.strictEqual(typeof COPYFILE_EXCL, 'number'); assert.strictEqual(typeof COPYFILE_EXCL, 'number');
assert.strictEqual(typeof COPYFILE_FICLONE, 'number');
assert.strictEqual(typeof COPYFILE_FICLONE_FORCE, 'number');
assert.strictEqual(typeof UV_FS_COPYFILE_EXCL, 'number'); assert.strictEqual(typeof UV_FS_COPYFILE_EXCL, 'number');
assert.strictEqual(typeof UV_FS_COPYFILE_FICLONE, 'number');
assert.strictEqual(typeof UV_FS_COPYFILE_FICLONE_FORCE, 'number');
assert.strictEqual(COPYFILE_EXCL, UV_FS_COPYFILE_EXCL); assert.strictEqual(COPYFILE_EXCL, UV_FS_COPYFILE_EXCL);
assert.strictEqual(COPYFILE_FICLONE, UV_FS_COPYFILE_FICLONE);
assert.strictEqual(COPYFILE_FICLONE_FORCE, UV_FS_COPYFILE_FICLONE_FORCE);
// Verify that files are overwritten when no flags are provided. // Verify that files are overwritten when no flags are provided.
fs.writeFileSync(dest, '', 'utf8'); fs.writeFileSync(dest, '', 'utf8');
@ -38,9 +51,26 @@ verify(src, dest);
fs.copyFileSync(src, dest, 0); fs.copyFileSync(src, dest, 0);
verify(src, dest); verify(src, dest);
// Verify that UV_FS_COPYFILE_FICLONE can be used.
fs.unlinkSync(dest);
fs.copyFileSync(src, dest, UV_FS_COPYFILE_FICLONE);
verify(src, dest);
// Verify that COPYFILE_FICLONE_FORCE can be used.
try {
fs.unlinkSync(dest);
fs.copyFileSync(src, dest, COPYFILE_FICLONE_FORCE);
verify(src, dest);
} catch (err) {
assert.strictEqual(err.syscall, 'copyfile');
assert(err.code === 'ENOTSUP' || err.code === 'ENOTTY' ||
err.code === 'ENOSYS');
assert.strictEqual(err.path, src);
assert.strictEqual(err.dest, dest);
}
// Copies asynchronously. // Copies asynchronously.
fs.unlinkSync(dest); tmpdir.refresh(); // Don't use unlinkSync() since the last test may fail.
fs.copyFile(src, dest, common.mustCall((err) => { fs.copyFile(src, dest, common.mustCall((err) => {
assert.ifError(err); assert.ifError(err);
verify(src, dest); verify(src, dest);