Skip to content

Commit 9aca762

Browse files
committed
fs: throw copyFileSync errors in JS
1 parent 2bd889b commit 9aca762

File tree

4 files changed

+112
-30
lines changed

4 files changed

+112
-30
lines changed

lib/fs.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1913,7 +1913,7 @@ fs.copyFile = function(src, dest, flags, callback) {
19131913
callback = flags;
19141914
flags = 0;
19151915
} else if (typeof callback !== 'function') {
1916-
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'callback', 'Function');
1916+
throw new errors.TypeError('ERR_INVALID_CALLBACK');
19171917
}
19181918

19191919
src = getPathFromURL(src);
@@ -1936,10 +1936,13 @@ fs.copyFileSync = function(src, dest, flags) {
19361936
validatePath(src, 'src');
19371937
validatePath(dest, 'dest');
19381938

1939+
const ctx = { path: src, dest }; // non-prefixed
1940+
19391941
src = pathModule._makeLong(src);
19401942
dest = pathModule._makeLong(dest);
19411943
flags = flags | 0;
1942-
binding.copyFile(src, dest, flags);
1944+
binding.copyFile(src, dest, flags, undefined, ctx);
1945+
handleErrorFromBinding(ctx);
19431946
};
19441947

19451948

src/node_file.cc

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,21 +1233,28 @@ static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
12331233
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
12341234
Environment* env = Environment::GetCurrent(args);
12351235

1236-
CHECK_GE(args.Length(), 3);
1237-
CHECK(args[2]->IsInt32());
1236+
const int argc = args.Length();
1237+
CHECK_GE(argc, 3);
12381238

12391239
BufferValue src(env->isolate(), args[0]);
12401240
CHECK_NE(*src, nullptr);
1241+
12411242
BufferValue dest(env->isolate(), args[1]);
12421243
CHECK_NE(*dest, nullptr);
1243-
int flags = args[2]->Int32Value();
1244+
1245+
CHECK(args[2]->IsInt32());
1246+
const int flags = args[2].As<Int32>()->Value();
12441247

12451248
FSReqBase* req_wrap = GetReqWrap(env, args[3]);
1246-
if (req_wrap != nullptr) {
1247-
AsyncCall(env, req_wrap, args, "copyfile", UTF8, AfterNoArgs,
1248-
uv_fs_copyfile, *src, *dest, flags);
1249-
} else {
1250-
SYNC_DEST_CALL(copyfile, *src, *dest, *src, *dest, flags)
1249+
if (req_wrap != nullptr) { // copyFile(src, dest, flags, req)
1250+
AsyncDestCall(env, req_wrap, args, "copyfile",
1251+
*dest, dest.length(), UTF8, AfterNoArgs,
1252+
uv_fs_copyfile, *src, *dest, flags);
1253+
} else { // copyFile(src, dest, flags, undefined, ctx)
1254+
CHECK_EQ(argc, 5);
1255+
fs_req_wrap req_wrap;
1256+
SyncCall(env, args[4], &req_wrap, "copyfile",
1257+
uv_fs_copyfile, *src, *dest, flags);
12511258
}
12521259
}
12531260

test/parallel/test-fs-copyfile.js

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const fixtures = require('../common/fixtures');
44
const tmpdir = require('../common/tmpdir');
55
const assert = require('assert');
66
const fs = require('fs');
7+
const uv = process.binding('uv');
78
const path = require('path');
89
const src = fixtures.path('a.js');
910
const dest = path.join(tmpdir.path, 'copyfile.out');
@@ -37,15 +38,6 @@ verify(src, dest);
3738
fs.copyFileSync(src, dest, 0);
3839
verify(src, dest);
3940

40-
// Throws if destination exists and the COPYFILE_EXCL flag is provided.
41-
assert.throws(() => {
42-
fs.copyFileSync(src, dest, COPYFILE_EXCL);
43-
}, /^Error: EEXIST|ENOENT:.+, copyfile/);
44-
45-
// Throws if the source does not exist.
46-
assert.throws(() => {
47-
fs.copyFileSync(`${src}__does_not_exist`, dest, COPYFILE_EXCL);
48-
}, /^Error: ENOENT: no such file or directory, copyfile/);
4941

5042
// Copies asynchronously.
5143
fs.unlinkSync(dest);
@@ -55,19 +47,30 @@ fs.copyFile(src, dest, common.mustCall((err) => {
5547

5648
// Copy asynchronously with flags.
5749
fs.copyFile(src, dest, COPYFILE_EXCL, common.mustCall((err) => {
58-
assert(
59-
/^Error: EEXIST: file already exists, copyfile/.test(err.toString())
60-
);
50+
if (err.code === 'ENOENT') { // Could be ENOENT or EEXIST
51+
assert.strictEqual(err.message,
52+
'ENOENT: no such file or directory, copyfile ' +
53+
`'${src}' -> '${dest}'`);
54+
assert.strictEqual(err.errno, uv.UV_ENOENT);
55+
assert.strictEqual(err.code, 'ENOENT');
56+
assert.strictEqual(err.syscall, 'copyfile');
57+
} else {
58+
assert.strictEqual(err.message,
59+
'EEXIST: file already exists, copyfile ' +
60+
`'${src}' -> '${dest}'`);
61+
assert.strictEqual(err.errno, uv.UV_EEXIST);
62+
assert.strictEqual(err.code, 'EEXIST');
63+
assert.strictEqual(err.syscall, 'copyfile');
64+
}
6165
}));
6266
}));
6367

6468
// Throws if callback is not a function.
6569
common.expectsError(() => {
6670
fs.copyFile(src, dest, 0, 0);
6771
}, {
68-
code: 'ERR_INVALID_ARG_TYPE',
69-
type: TypeError,
70-
message: 'The "callback" argument must be of type Function'
72+
code: 'ERR_INVALID_CALLBACK',
73+
type: TypeError
7174
});
7275

7376
// Throws if the source path is not a string.
@@ -101,8 +104,3 @@ common.expectsError(() => {
101104
}
102105
);
103106
});
104-
105-
// Errors if invalid flags are provided.
106-
assert.throws(() => {
107-
fs.copyFileSync(src, dest, -1);
108-
}, /^Error: EINVAL: invalid argument, copyfile/);

test/parallel/test-fs-error-messages.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const existingFile = fixtures.path('exit.js');
3030
const existingFile2 = fixtures.path('create-file.js');
3131
const existingDir = fixtures.path('empty');
3232
const existingDir2 = fixtures.path('keys');
33+
const { COPYFILE_EXCL } = fs.constants;
3334
const uv = process.binding('uv');
3435

3536
// Template tag function for escaping special characters in strings so that:
@@ -617,3 +618,76 @@ if (!common.isAIX) {
617618
validateError
618619
);
619620
}
621+
622+
// copyFile with invalid flags
623+
{
624+
const validateError = (err) => {
625+
assert.strictEqual(err.message,
626+
'EINVAL: invalid argument, copyfile ' +
627+
`'${existingFile}' -> '${nonexistentFile}'`);
628+
assert.strictEqual(err.errno, uv.UV_EINVAL);
629+
assert.strictEqual(err.code, 'EINVAL');
630+
assert.strictEqual(err.syscall, 'copyfile');
631+
return true;
632+
};
633+
634+
// TODO(joyeecheung): test fs.copyFile() when uv_fs_copyfile does not
635+
// keep the loop open when the flags are invalid.
636+
// See https://github.com/libuv/libuv/pull/1747
637+
638+
assert.throws(
639+
() => fs.copyFileSync(existingFile, nonexistentFile, -1),
640+
validateError
641+
);
642+
}
643+
644+
// copyFile: destination exists but the COPYFILE_EXCL flag is provided.
645+
{
646+
const validateError = (err) => {
647+
if (err.code === 'ENOENT') { // Could be ENOENT or EEXIST
648+
assert.strictEqual(err.message,
649+
'ENOENT: no such file or directory, copyfile ' +
650+
`'${existingFile}' -> '${existingFile2}'`);
651+
assert.strictEqual(err.errno, uv.UV_ENOENT);
652+
assert.strictEqual(err.code, 'ENOENT');
653+
assert.strictEqual(err.syscall, 'copyfile');
654+
} else {
655+
assert.strictEqual(err.message,
656+
'EEXIST: file already exists, copyfile ' +
657+
`'${existingFile}' -> '${existingFile2}'`);
658+
assert.strictEqual(err.errno, uv.UV_EEXIST);
659+
assert.strictEqual(err.code, 'EEXIST');
660+
assert.strictEqual(err.syscall, 'copyfile');
661+
}
662+
return true;
663+
};
664+
665+
fs.copyFile(existingFile, existingFile2, COPYFILE_EXCL,
666+
common.mustCall(validateError));
667+
668+
assert.throws(
669+
() => fs.copyFileSync(existingFile, existingFile2, COPYFILE_EXCL),
670+
validateError
671+
);
672+
}
673+
674+
// copyFile: the source does not exist.
675+
{
676+
const validateError = (err) => {
677+
assert.strictEqual(err.message,
678+
'ENOENT: no such file or directory, copyfile ' +
679+
`'${nonexistentFile}' -> '${existingFile2}'`);
680+
assert.strictEqual(err.errno, uv.UV_ENOENT);
681+
assert.strictEqual(err.code, 'ENOENT');
682+
assert.strictEqual(err.syscall, 'copyfile');
683+
return true;
684+
};
685+
686+
fs.copyFile(nonexistentFile, existingFile2, COPYFILE_EXCL,
687+
common.mustCall(validateError));
688+
689+
assert.throws(
690+
() => fs.copyFileSync(nonexistentFile, existingFile2, COPYFILE_EXCL),
691+
validateError
692+
);
693+
}

0 commit comments

Comments
 (0)