• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Flags: --expose-internals
2// Copyright Joyent, Inc. and other Node contributors.
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the
6// "Software"), to deal in the Software without restriction, including
7// without limitation the rights to use, copy, modify, merge, publish,
8// distribute, sublicense, and/or sell copies of the Software, and to permit
9// persons to whom the Software is furnished to do so, subject to the
10// following conditions:
11//
12// The above copyright notice and this permission notice shall be included
13// in all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21// USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23'use strict';
24const common = require('../common');
25const fixtures = require('../common/fixtures');
26const tmpdir = require('../common/tmpdir');
27const assert = require('assert');
28const fs = require('fs');
29const path = require('path');
30
31tmpdir.refresh();
32
33
34const nonexistentFile = path.join(tmpdir.path, 'non-existent');
35const nonexistentDir = path.join(tmpdir.path, 'non-existent', 'foo', 'bar');
36const existingFile = path.join(tmpdir.path, 'existingFile.js');
37const existingFile2 = path.join(tmpdir.path, 'existingFile2.js');
38const existingDir = path.join(tmpdir.path, 'dir');
39const existingDir2 = fixtures.path('keys');
40fs.mkdirSync(existingDir);
41fs.writeFileSync(existingFile, 'test', 'utf-8');
42fs.writeFileSync(existingFile2, 'test', 'utf-8');
43
44
45const { COPYFILE_EXCL } = fs.constants;
46const { internalBinding } = require('internal/test/binding');
47const {
48  UV_EBADF,
49  UV_EEXIST,
50  UV_EINVAL,
51  UV_ENOENT,
52  UV_ENOTDIR,
53  UV_ENOTEMPTY,
54  UV_EPERM
55} = internalBinding('uv');
56
57// Template tag function for escaping special characters in strings so that:
58// new RegExp(re`${str}`).test(str) === true
59function re(literals, ...values) {
60  const escapeRE = /[\\^$.*+?()[\]{}|=!<>:-]/g;
61  let result = literals[0].replace(escapeRE, '\\$&');
62  for (const [i, value] of values.entries()) {
63    result += value.replace(escapeRE, '\\$&');
64    result += literals[i + 1].replace(escapeRE, '\\$&');
65  }
66  return result;
67}
68
69// stat
70{
71  const validateError = (err) => {
72    assert.strictEqual(nonexistentFile, err.path);
73    assert.strictEqual(
74      err.message,
75      `ENOENT: no such file or directory, stat '${nonexistentFile}'`);
76    assert.strictEqual(err.errno, UV_ENOENT);
77    assert.strictEqual(err.code, 'ENOENT');
78    assert.strictEqual(err.syscall, 'stat');
79    return true;
80  };
81
82  fs.stat(nonexistentFile, common.mustCall(validateError));
83
84  assert.throws(
85    () => fs.statSync(nonexistentFile),
86    validateError
87  );
88}
89
90// lstat
91{
92  const validateError = (err) => {
93    assert.strictEqual(nonexistentFile, err.path);
94    assert.strictEqual(
95      err.message,
96      `ENOENT: no such file or directory, lstat '${nonexistentFile}'`);
97    assert.strictEqual(err.errno, UV_ENOENT);
98    assert.strictEqual(err.code, 'ENOENT');
99    assert.strictEqual(err.syscall, 'lstat');
100    return true;
101  };
102
103  fs.lstat(nonexistentFile, common.mustCall(validateError));
104  assert.throws(
105    () => fs.lstatSync(nonexistentFile),
106    validateError
107  );
108}
109
110// fstat
111{
112  const validateError = (err) => {
113    assert.strictEqual(err.message, 'EBADF: bad file descriptor, fstat');
114    assert.strictEqual(err.errno, UV_EBADF);
115    assert.strictEqual(err.code, 'EBADF');
116    assert.strictEqual(err.syscall, 'fstat');
117    return true;
118  };
119
120  common.runWithInvalidFD((fd) => {
121    fs.fstat(fd, common.mustCall(validateError));
122
123    assert.throws(
124      () => fs.fstatSync(fd),
125      validateError
126    );
127  });
128}
129
130// realpath
131{
132  const validateError = (err) => {
133    assert.strictEqual(nonexistentFile, err.path);
134    assert.strictEqual(
135      err.message,
136      `ENOENT: no such file or directory, lstat '${nonexistentFile}'`);
137    assert.strictEqual(err.errno, UV_ENOENT);
138    assert.strictEqual(err.code, 'ENOENT');
139    assert.strictEqual(err.syscall, 'lstat');
140    return true;
141  };
142
143  fs.realpath(nonexistentFile, common.mustCall(validateError));
144
145  assert.throws(
146    () => fs.realpathSync(nonexistentFile),
147    validateError
148  );
149}
150
151// native realpath
152{
153  const validateError = (err) => {
154    assert.strictEqual(nonexistentFile, err.path);
155    assert.strictEqual(
156      err.message,
157      `ENOENT: no such file or directory, realpath '${nonexistentFile}'`);
158    assert.strictEqual(err.errno, UV_ENOENT);
159    assert.strictEqual(err.code, 'ENOENT');
160    assert.strictEqual(err.syscall, 'realpath');
161    return true;
162  };
163
164  fs.realpath.native(nonexistentFile, common.mustCall(validateError));
165
166  assert.throws(
167    () => fs.realpathSync.native(nonexistentFile),
168    validateError
169  );
170}
171
172// readlink
173{
174  const validateError = (err) => {
175    assert.strictEqual(nonexistentFile, err.path);
176    assert.strictEqual(
177      err.message,
178      `ENOENT: no such file or directory, readlink '${nonexistentFile}'`);
179    assert.strictEqual(err.errno, UV_ENOENT);
180    assert.strictEqual(err.code, 'ENOENT');
181    assert.strictEqual(err.syscall, 'readlink');
182    return true;
183  };
184
185  fs.readlink(nonexistentFile, common.mustCall(validateError));
186
187  assert.throws(
188    () => fs.readlinkSync(nonexistentFile),
189    validateError
190  );
191}
192
193// Link nonexistent file
194{
195  const validateError = (err) => {
196    assert.strictEqual(nonexistentFile, err.path);
197    // Could be resolved to an absolute path
198    assert.ok(err.dest.endsWith('foo'),
199              `expect ${err.dest} to end with 'foo'`);
200    const regexp = new RegExp('^ENOENT: no such file or directory, link ' +
201                              re`'${nonexistentFile}' -> ` + '\'.*foo\'');
202    assert.ok(regexp.test(err.message),
203              `Expect ${err.message} to match ${regexp}`);
204    assert.strictEqual(err.errno, UV_ENOENT);
205    assert.strictEqual(err.code, 'ENOENT');
206    assert.strictEqual(err.syscall, 'link');
207    return true;
208  };
209
210  fs.link(nonexistentFile, 'foo', common.mustCall(validateError));
211
212  assert.throws(
213    () => fs.linkSync(nonexistentFile, 'foo'),
214    validateError
215  );
216}
217
218// link existing file
219{
220  const validateError = (err) => {
221    assert.strictEqual(existingFile, err.path);
222    assert.strictEqual(existingFile2, err.dest);
223    assert.strictEqual(
224      err.message,
225      `EEXIST: file already exists, link '${existingFile}' -> ` +
226      `'${existingFile2}'`);
227    assert.strictEqual(err.errno, UV_EEXIST);
228    assert.strictEqual(err.code, 'EEXIST');
229    assert.strictEqual(err.syscall, 'link');
230    return true;
231  };
232
233  fs.link(existingFile, existingFile2, common.mustCall(validateError));
234
235  assert.throws(
236    () => fs.linkSync(existingFile, existingFile2),
237    validateError
238  );
239}
240
241// symlink
242{
243  const validateError = (err) => {
244    assert.strictEqual(existingFile, err.path);
245    assert.strictEqual(existingFile2, err.dest);
246    assert.strictEqual(
247      err.message,
248      `EEXIST: file already exists, symlink '${existingFile}' -> ` +
249      `'${existingFile2}'`);
250    assert.strictEqual(err.errno, UV_EEXIST);
251    assert.strictEqual(err.code, 'EEXIST');
252    assert.strictEqual(err.syscall, 'symlink');
253    return true;
254  };
255
256  fs.symlink(existingFile, existingFile2, common.mustCall(validateError));
257
258  assert.throws(
259    () => fs.symlinkSync(existingFile, existingFile2),
260    validateError
261  );
262}
263
264// unlink
265{
266  const validateError = (err) => {
267    assert.strictEqual(nonexistentFile, err.path);
268    assert.strictEqual(
269      err.message,
270      `ENOENT: no such file or directory, unlink '${nonexistentFile}'`);
271    assert.strictEqual(err.errno, UV_ENOENT);
272    assert.strictEqual(err.code, 'ENOENT');
273    assert.strictEqual(err.syscall, 'unlink');
274    return true;
275  };
276
277  fs.unlink(nonexistentFile, common.mustCall(validateError));
278
279  assert.throws(
280    () => fs.unlinkSync(nonexistentFile),
281    validateError
282  );
283}
284
285// rename
286{
287  const validateError = (err) => {
288    assert.strictEqual(nonexistentFile, err.path);
289    // Could be resolved to an absolute path
290    assert.ok(err.dest.endsWith('foo'),
291              `expect ${err.dest} to end with 'foo'`);
292    const regexp = new RegExp('ENOENT: no such file or directory, rename ' +
293                              re`'${nonexistentFile}' -> ` + '\'.*foo\'');
294    assert.ok(regexp.test(err.message),
295              `Expect ${err.message} to match ${regexp}`);
296    assert.strictEqual(err.errno, UV_ENOENT);
297    assert.strictEqual(err.code, 'ENOENT');
298    assert.strictEqual(err.syscall, 'rename');
299    return true;
300  };
301
302  const destFile = path.join(tmpdir.path, 'foo');
303  fs.rename(nonexistentFile, destFile, common.mustCall(validateError));
304
305  assert.throws(
306    () => fs.renameSync(nonexistentFile, destFile),
307    validateError
308  );
309}
310
311// Rename non-empty directory
312{
313  const validateError = (err) => {
314    assert.strictEqual(existingDir, err.path);
315    assert.strictEqual(existingDir2, err.dest);
316    assert.strictEqual(err.syscall, 'rename');
317    // Could be ENOTEMPTY, EEXIST, or EPERM, depending on the platform
318    if (err.code === 'ENOTEMPTY') {
319      assert.strictEqual(
320        err.message,
321        `ENOTEMPTY: directory not empty, rename '${existingDir}' -> ` +
322        `'${existingDir2}'`);
323      assert.strictEqual(err.errno, UV_ENOTEMPTY);
324    } else if (err.code === 'EXDEV') {  // Not on the same mounted filesystem
325      assert.strictEqual(
326        err.message,
327        `EXDEV: cross-device link not permitted, rename '${existingDir}' -> ` +
328            `'${existingDir2}'`);
329    } else if (err.code === 'EEXIST') {  // smartos and aix
330      assert.strictEqual(
331        err.message,
332        `EEXIST: file already exists, rename '${existingDir}' -> ` +
333        `'${existingDir2}'`);
334      assert.strictEqual(err.errno, UV_EEXIST);
335    } else {  // windows
336      assert.strictEqual(
337        err.message,
338        `EPERM: operation not permitted, rename '${existingDir}' -> ` +
339        `'${existingDir2}'`);
340      assert.strictEqual(err.errno, UV_EPERM);
341      assert.strictEqual(err.code, 'EPERM');
342    }
343    return true;
344  };
345
346  fs.rename(existingDir, existingDir2, common.mustCall(validateError));
347
348  assert.throws(
349    () => fs.renameSync(existingDir, existingDir2),
350    validateError
351  );
352}
353
354// rmdir
355{
356  const validateError = (err) => {
357    assert.strictEqual(nonexistentFile, err.path);
358    assert.strictEqual(
359      err.message,
360      `ENOENT: no such file or directory, rmdir '${nonexistentFile}'`);
361    assert.strictEqual(err.errno, UV_ENOENT);
362    assert.strictEqual(err.code, 'ENOENT');
363    assert.strictEqual(err.syscall, 'rmdir');
364    return true;
365  };
366
367  fs.rmdir(nonexistentFile, common.mustCall(validateError));
368
369  assert.throws(
370    () => fs.rmdirSync(nonexistentFile),
371    validateError
372  );
373}
374
375// rmdir a file
376{
377  const validateError = (err) => {
378    assert.strictEqual(existingFile, err.path);
379    assert.strictEqual(err.syscall, 'rmdir');
380    if (err.code === 'ENOTDIR') {
381      assert.strictEqual(
382        err.message,
383        `ENOTDIR: not a directory, rmdir '${existingFile}'`);
384      assert.strictEqual(err.errno, UV_ENOTDIR);
385    } else {  // windows
386      assert.strictEqual(
387        err.message,
388        `ENOENT: no such file or directory, rmdir '${existingFile}'`);
389      assert.strictEqual(err.errno, UV_ENOENT);
390      assert.strictEqual(err.code, 'ENOENT');
391    }
392    return true;
393  };
394
395  fs.rmdir(existingFile, common.mustCall(validateError));
396
397  assert.throws(
398    () => fs.rmdirSync(existingFile),
399    validateError
400  );
401}
402
403// mkdir
404{
405  const validateError = (err) => {
406    assert.strictEqual(existingFile, err.path);
407    assert.strictEqual(
408      err.message,
409      `EEXIST: file already exists, mkdir '${existingFile}'`);
410    assert.strictEqual(err.errno, UV_EEXIST);
411    assert.strictEqual(err.code, 'EEXIST');
412    assert.strictEqual(err.syscall, 'mkdir');
413    return true;
414  };
415
416  fs.mkdir(existingFile, 0o666, common.mustCall(validateError));
417
418  assert.throws(
419    () => fs.mkdirSync(existingFile, 0o666),
420    validateError
421  );
422}
423
424// chmod
425{
426  const validateError = (err) => {
427    assert.strictEqual(nonexistentFile, err.path);
428    assert.strictEqual(
429      err.message,
430      `ENOENT: no such file or directory, chmod '${nonexistentFile}'`);
431    assert.strictEqual(err.errno, UV_ENOENT);
432    assert.strictEqual(err.code, 'ENOENT');
433    assert.strictEqual(err.syscall, 'chmod');
434    return true;
435  };
436
437  fs.chmod(nonexistentFile, 0o666, common.mustCall(validateError));
438
439  assert.throws(
440    () => fs.chmodSync(nonexistentFile, 0o666),
441    validateError
442  );
443}
444
445// open
446{
447  const validateError = (err) => {
448    assert.strictEqual(nonexistentFile, err.path);
449    assert.strictEqual(
450      err.message,
451      `ENOENT: no such file or directory, open '${nonexistentFile}'`);
452    assert.strictEqual(err.errno, UV_ENOENT);
453    assert.strictEqual(err.code, 'ENOENT');
454    assert.strictEqual(err.syscall, 'open');
455    return true;
456  };
457
458  fs.open(nonexistentFile, 'r', 0o666, common.mustCall(validateError));
459
460  assert.throws(
461    () => fs.openSync(nonexistentFile, 'r', 0o666),
462    validateError
463  );
464}
465
466
467// close
468{
469  const validateError = (err) => {
470    assert.strictEqual(err.message, 'EBADF: bad file descriptor, close');
471    assert.strictEqual(err.errno, UV_EBADF);
472    assert.strictEqual(err.code, 'EBADF');
473    assert.strictEqual(err.syscall, 'close');
474    return true;
475  };
476
477  common.runWithInvalidFD((fd) => {
478    fs.close(fd, common.mustCall(validateError));
479
480    assert.throws(
481      () => fs.closeSync(fd),
482      validateError
483    );
484  });
485}
486
487// readFile
488{
489  const validateError = (err) => {
490    assert.strictEqual(nonexistentFile, err.path);
491    assert.strictEqual(
492      err.message,
493      `ENOENT: no such file or directory, open '${nonexistentFile}'`);
494    assert.strictEqual(err.errno, UV_ENOENT);
495    assert.strictEqual(err.code, 'ENOENT');
496    assert.strictEqual(err.syscall, 'open');
497    return true;
498  };
499
500  fs.readFile(nonexistentFile, common.mustCall(validateError));
501
502  assert.throws(
503    () => fs.readFileSync(nonexistentFile),
504    validateError
505  );
506}
507
508// readdir
509{
510  const validateError = (err) => {
511    assert.strictEqual(nonexistentFile, err.path);
512    assert.strictEqual(
513      err.message,
514      `ENOENT: no such file or directory, scandir '${nonexistentFile}'`);
515    assert.strictEqual(err.errno, UV_ENOENT);
516    assert.strictEqual(err.code, 'ENOENT');
517    assert.strictEqual(err.syscall, 'scandir');
518    return true;
519  };
520
521  fs.readdir(nonexistentFile, common.mustCall(validateError));
522
523  assert.throws(
524    () => fs.readdirSync(nonexistentFile),
525    validateError
526  );
527}
528
529// ftruncate
530{
531  const validateError = (err) => {
532    assert.strictEqual(err.syscall, 'ftruncate');
533    // Could be EBADF or EINVAL, depending on the platform
534    if (err.code === 'EBADF') {
535      assert.strictEqual(err.message, 'EBADF: bad file descriptor, ftruncate');
536      assert.strictEqual(err.errno, UV_EBADF);
537    } else {
538      assert.strictEqual(err.message, 'EINVAL: invalid argument, ftruncate');
539      assert.strictEqual(err.errno, UV_EINVAL);
540      assert.strictEqual(err.code, 'EINVAL');
541    }
542    return true;
543  };
544
545  common.runWithInvalidFD((fd) => {
546    fs.ftruncate(fd, 4, common.mustCall(validateError));
547
548    assert.throws(
549      () => fs.ftruncateSync(fd, 4),
550      validateError
551    );
552  });
553}
554
555// fdatasync
556{
557  const validateError = (err) => {
558    assert.strictEqual(err.message, 'EBADF: bad file descriptor, fdatasync');
559    assert.strictEqual(err.errno, UV_EBADF);
560    assert.strictEqual(err.code, 'EBADF');
561    assert.strictEqual(err.syscall, 'fdatasync');
562    return true;
563  };
564
565  common.runWithInvalidFD((fd) => {
566    fs.fdatasync(fd, common.mustCall(validateError));
567
568    assert.throws(
569      () => fs.fdatasyncSync(fd),
570      validateError
571    );
572  });
573}
574
575// fsync
576{
577  const validateError = (err) => {
578    assert.strictEqual(err.message, 'EBADF: bad file descriptor, fsync');
579    assert.strictEqual(err.errno, UV_EBADF);
580    assert.strictEqual(err.code, 'EBADF');
581    assert.strictEqual(err.syscall, 'fsync');
582    return true;
583  };
584
585  common.runWithInvalidFD((fd) => {
586    fs.fsync(fd, common.mustCall(validateError));
587
588    assert.throws(
589      () => fs.fsyncSync(fd),
590      validateError
591    );
592  });
593}
594
595// chown
596if (!common.isWindows) {
597  const validateError = (err) => {
598    assert.strictEqual(nonexistentFile, err.path);
599    assert.strictEqual(
600      err.message,
601      `ENOENT: no such file or directory, chown '${nonexistentFile}'`);
602    assert.strictEqual(err.errno, UV_ENOENT);
603    assert.strictEqual(err.code, 'ENOENT');
604    assert.strictEqual(err.syscall, 'chown');
605    return true;
606  };
607
608  fs.chown(nonexistentFile, process.getuid(), process.getgid(),
609           common.mustCall(validateError));
610
611  assert.throws(
612    () => fs.chownSync(nonexistentFile,
613                       process.getuid(), process.getgid()),
614    validateError
615  );
616}
617
618// utimes
619if (!common.isAIX) {
620  const validateError = (err) => {
621    assert.strictEqual(nonexistentFile, err.path);
622    assert.strictEqual(
623      err.message,
624      `ENOENT: no such file or directory, utime '${nonexistentFile}'`);
625    assert.strictEqual(err.errno, UV_ENOENT);
626    assert.strictEqual(err.code, 'ENOENT');
627    assert.strictEqual(err.syscall, 'utime');
628    return true;
629  };
630
631  fs.utimes(nonexistentFile, new Date(), new Date(),
632            common.mustCall(validateError));
633
634  assert.throws(
635    () => fs.utimesSync(nonexistentFile, new Date(), new Date()),
636    validateError
637  );
638}
639
640// mkdtemp
641{
642  const validateError = (err) => {
643    const pathPrefix = new RegExp('^' + re`${nonexistentDir}`);
644    assert(pathPrefix.test(err.path),
645           `Expect ${err.path} to match ${pathPrefix}`);
646
647    const prefix = new RegExp('^ENOENT: no such file or directory, mkdtemp ' +
648                              re`'${nonexistentDir}`);
649    assert(prefix.test(err.message),
650           `Expect ${err.message} to match ${prefix}`);
651
652    assert.strictEqual(err.errno, UV_ENOENT);
653    assert.strictEqual(err.code, 'ENOENT');
654    assert.strictEqual(err.syscall, 'mkdtemp');
655    return true;
656  };
657
658  fs.mkdtemp(nonexistentDir, common.mustCall(validateError));
659
660  assert.throws(
661    () => fs.mkdtempSync(nonexistentDir),
662    validateError
663  );
664}
665
666// Check copyFile with invalid flags.
667{
668  const validateError = {
669    // TODO: Make sure the error message always also contains the src.
670    message: `EINVAL: invalid argument, copyfile -> '${nonexistentFile}'`,
671    errno: UV_EINVAL,
672    code: 'EINVAL',
673    syscall: 'copyfile'
674  };
675
676  fs.copyFile(existingFile, nonexistentFile, -1,
677              common.expectsError(validateError));
678
679  validateError.message = 'EINVAL: invalid argument, copyfile ' +
680                          `'${existingFile}' -> '${nonexistentFile}'`;
681  assert.throws(
682    () => fs.copyFileSync(existingFile, nonexistentFile, -1),
683    validateError
684  );
685}
686
687// copyFile: destination exists but the COPYFILE_EXCL flag is provided.
688{
689  const validateError = (err) => {
690    if (err.code === 'ENOENT') {  // Could be ENOENT or EEXIST
691      assert.strictEqual(err.message,
692                         'ENOENT: no such file or directory, copyfile ' +
693                         `'${existingFile}' -> '${existingFile2}'`);
694      assert.strictEqual(err.errno, UV_ENOENT);
695      assert.strictEqual(err.code, 'ENOENT');
696      assert.strictEqual(err.syscall, 'copyfile');
697    } else {
698      assert.strictEqual(err.message,
699                         'EEXIST: file already exists, copyfile ' +
700                         `'${existingFile}' -> '${existingFile2}'`);
701      assert.strictEqual(err.errno, UV_EEXIST);
702      assert.strictEqual(err.code, 'EEXIST');
703      assert.strictEqual(err.syscall, 'copyfile');
704    }
705    return true;
706  };
707
708  fs.copyFile(existingFile, existingFile2, COPYFILE_EXCL,
709              common.mustCall(validateError));
710
711  assert.throws(
712    () => fs.copyFileSync(existingFile, existingFile2, COPYFILE_EXCL),
713    validateError
714  );
715}
716
717// copyFile: the source does not exist.
718{
719  const validateError = (err) => {
720    assert.strictEqual(err.message,
721                       'ENOENT: no such file or directory, copyfile ' +
722                       `'${nonexistentFile}' -> '${existingFile2}'`);
723    assert.strictEqual(err.errno, UV_ENOENT);
724    assert.strictEqual(err.code, 'ENOENT');
725    assert.strictEqual(err.syscall, 'copyfile');
726    return true;
727  };
728
729  fs.copyFile(nonexistentFile, existingFile2, COPYFILE_EXCL,
730              common.mustCall(validateError));
731
732  assert.throws(
733    () => fs.copyFileSync(nonexistentFile, existingFile2, COPYFILE_EXCL),
734    validateError
735  );
736}
737
738// read
739{
740  const validateError = (err) => {
741    assert.strictEqual(err.message, 'EBADF: bad file descriptor, read');
742    assert.strictEqual(err.errno, UV_EBADF);
743    assert.strictEqual(err.code, 'EBADF');
744    assert.strictEqual(err.syscall, 'read');
745    return true;
746  };
747
748  common.runWithInvalidFD((fd) => {
749    const buf = Buffer.alloc(5);
750    fs.read(fd, buf, 0, 1, 1, common.mustCall(validateError));
751
752    assert.throws(
753      () => fs.readSync(fd, buf, 0, 1, 1),
754      validateError
755    );
756  });
757}
758
759// fchmod
760{
761  const validateError = (err) => {
762    assert.strictEqual(err.message, 'EBADF: bad file descriptor, fchmod');
763    assert.strictEqual(err.errno, UV_EBADF);
764    assert.strictEqual(err.code, 'EBADF');
765    assert.strictEqual(err.syscall, 'fchmod');
766    return true;
767  };
768
769  common.runWithInvalidFD((fd) => {
770    fs.fchmod(fd, 0o666, common.mustCall(validateError));
771
772    assert.throws(
773      () => fs.fchmodSync(fd, 0o666),
774      validateError
775    );
776  });
777}
778
779// fchown
780if (!common.isWindows) {
781  const validateError = (err) => {
782    assert.strictEqual(err.message, 'EBADF: bad file descriptor, fchown');
783    assert.strictEqual(err.errno, UV_EBADF);
784    assert.strictEqual(err.code, 'EBADF');
785    assert.strictEqual(err.syscall, 'fchown');
786    return true;
787  };
788
789  common.runWithInvalidFD((fd) => {
790    fs.fchown(fd, process.getuid(), process.getgid(),
791              common.mustCall(validateError));
792
793    assert.throws(
794      () => fs.fchownSync(fd, process.getuid(), process.getgid()),
795      validateError
796    );
797  });
798}
799
800// write buffer
801{
802  const validateError = (err) => {
803    assert.strictEqual(err.message, 'EBADF: bad file descriptor, write');
804    assert.strictEqual(err.errno, UV_EBADF);
805    assert.strictEqual(err.code, 'EBADF');
806    assert.strictEqual(err.syscall, 'write');
807    return true;
808  };
809
810  common.runWithInvalidFD((fd) => {
811    const buf = Buffer.alloc(5);
812    fs.write(fd, buf, 0, 1, 1, common.mustCall(validateError));
813
814    assert.throws(
815      () => fs.writeSync(fd, buf, 0, 1, 1),
816      validateError
817    );
818  });
819}
820
821// write string
822{
823  const validateError = (err) => {
824    assert.strictEqual(err.message, 'EBADF: bad file descriptor, write');
825    assert.strictEqual(err.errno, UV_EBADF);
826    assert.strictEqual(err.code, 'EBADF');
827    assert.strictEqual(err.syscall, 'write');
828    return true;
829  };
830
831  common.runWithInvalidFD((fd) => {
832    fs.write(fd, 'test', 1, common.mustCall(validateError));
833
834    assert.throws(
835      () => fs.writeSync(fd, 'test', 1),
836      validateError
837    );
838  });
839}
840
841
842// futimes
843if (!common.isAIX) {
844  const validateError = (err) => {
845    assert.strictEqual(err.message, 'EBADF: bad file descriptor, futime');
846    assert.strictEqual(err.errno, UV_EBADF);
847    assert.strictEqual(err.code, 'EBADF');
848    assert.strictEqual(err.syscall, 'futime');
849    return true;
850  };
851
852  common.runWithInvalidFD((fd) => {
853    fs.futimes(fd, new Date(), new Date(), common.mustCall(validateError));
854
855    assert.throws(
856      () => fs.futimesSync(fd, new Date(), new Date()),
857      validateError
858    );
859  });
860}
861