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.match(err.message, regexp);
203    assert.strictEqual(err.errno, UV_ENOENT);
204    assert.strictEqual(err.code, 'ENOENT');
205    assert.strictEqual(err.syscall, 'link');
206    return true;
207  };
208
209  fs.link(nonexistentFile, 'foo', common.mustCall(validateError));
210
211  assert.throws(
212    () => fs.linkSync(nonexistentFile, 'foo'),
213    validateError
214  );
215}
216
217// link existing file
218{
219  const validateError = (err) => {
220    assert.strictEqual(existingFile, err.path);
221    assert.strictEqual(existingFile2, err.dest);
222    assert.strictEqual(
223      err.message,
224      `EEXIST: file already exists, link '${existingFile}' -> ` +
225      `'${existingFile2}'`);
226    assert.strictEqual(err.errno, UV_EEXIST);
227    assert.strictEqual(err.code, 'EEXIST');
228    assert.strictEqual(err.syscall, 'link');
229    return true;
230  };
231
232  fs.link(existingFile, existingFile2, common.mustCall(validateError));
233
234  assert.throws(
235    () => fs.linkSync(existingFile, existingFile2),
236    validateError
237  );
238}
239
240// symlink
241{
242  const validateError = (err) => {
243    assert.strictEqual(existingFile, err.path);
244    assert.strictEqual(existingFile2, err.dest);
245    assert.strictEqual(
246      err.message,
247      `EEXIST: file already exists, symlink '${existingFile}' -> ` +
248      `'${existingFile2}'`);
249    assert.strictEqual(err.errno, UV_EEXIST);
250    assert.strictEqual(err.code, 'EEXIST');
251    assert.strictEqual(err.syscall, 'symlink');
252    return true;
253  };
254
255  fs.symlink(existingFile, existingFile2, common.mustCall(validateError));
256
257  assert.throws(
258    () => fs.symlinkSync(existingFile, existingFile2),
259    validateError
260  );
261}
262
263// unlink
264{
265  const validateError = (err) => {
266    assert.strictEqual(nonexistentFile, err.path);
267    assert.strictEqual(
268      err.message,
269      `ENOENT: no such file or directory, unlink '${nonexistentFile}'`);
270    assert.strictEqual(err.errno, UV_ENOENT);
271    assert.strictEqual(err.code, 'ENOENT');
272    assert.strictEqual(err.syscall, 'unlink');
273    return true;
274  };
275
276  fs.unlink(nonexistentFile, common.mustCall(validateError));
277
278  assert.throws(
279    () => fs.unlinkSync(nonexistentFile),
280    validateError
281  );
282}
283
284// rename
285{
286  const validateError = (err) => {
287    assert.strictEqual(nonexistentFile, err.path);
288    // Could be resolved to an absolute path
289    assert.ok(err.dest.endsWith('foo'),
290              `expect ${err.dest} to end with 'foo'`);
291    const regexp = new RegExp('ENOENT: no such file or directory, rename ' +
292                              re`'${nonexistentFile}' -> ` + '\'.*foo\'');
293    assert.match(err.message, regexp);
294    assert.strictEqual(err.errno, UV_ENOENT);
295    assert.strictEqual(err.code, 'ENOENT');
296    assert.strictEqual(err.syscall, 'rename');
297    return true;
298  };
299
300  const destFile = path.join(tmpdir.path, 'foo');
301  fs.rename(nonexistentFile, destFile, common.mustCall(validateError));
302
303  assert.throws(
304    () => fs.renameSync(nonexistentFile, destFile),
305    validateError
306  );
307}
308
309// Rename non-empty directory
310{
311  const validateError = (err) => {
312    assert.strictEqual(existingDir, err.path);
313    assert.strictEqual(existingDir2, err.dest);
314    assert.strictEqual(err.syscall, 'rename');
315    // Could be ENOTEMPTY, EEXIST, or EPERM, depending on the platform
316    if (err.code === 'ENOTEMPTY') {
317      assert.strictEqual(
318        err.message,
319        `ENOTEMPTY: directory not empty, rename '${existingDir}' -> ` +
320        `'${existingDir2}'`);
321      assert.strictEqual(err.errno, UV_ENOTEMPTY);
322    } else if (err.code === 'EXDEV') {  // Not on the same mounted filesystem
323      assert.strictEqual(
324        err.message,
325        `EXDEV: cross-device link not permitted, rename '${existingDir}' -> ` +
326            `'${existingDir2}'`);
327    } else if (err.code === 'EEXIST') {  // smartos and aix
328      assert.strictEqual(
329        err.message,
330        `EEXIST: file already exists, rename '${existingDir}' -> ` +
331        `'${existingDir2}'`);
332      assert.strictEqual(err.errno, UV_EEXIST);
333    } else {  // windows
334      assert.strictEqual(
335        err.message,
336        `EPERM: operation not permitted, rename '${existingDir}' -> ` +
337        `'${existingDir2}'`);
338      assert.strictEqual(err.errno, UV_EPERM);
339      assert.strictEqual(err.code, 'EPERM');
340    }
341    return true;
342  };
343
344  fs.rename(existingDir, existingDir2, common.mustCall(validateError));
345
346  assert.throws(
347    () => fs.renameSync(existingDir, existingDir2),
348    validateError
349  );
350}
351
352// rmdir
353{
354  const validateError = (err) => {
355    assert.strictEqual(nonexistentFile, err.path);
356    assert.strictEqual(
357      err.message,
358      `ENOENT: no such file or directory, rmdir '${nonexistentFile}'`);
359    assert.strictEqual(err.errno, UV_ENOENT);
360    assert.strictEqual(err.code, 'ENOENT');
361    assert.strictEqual(err.syscall, 'rmdir');
362    return true;
363  };
364
365  fs.rmdir(nonexistentFile, common.mustCall(validateError));
366
367  assert.throws(
368    () => fs.rmdirSync(nonexistentFile),
369    validateError
370  );
371}
372
373// rmdir a file
374{
375  const validateError = (err) => {
376    assert.strictEqual(existingFile, err.path);
377    assert.strictEqual(err.syscall, 'rmdir');
378    if (err.code === 'ENOTDIR') {
379      assert.strictEqual(
380        err.message,
381        `ENOTDIR: not a directory, rmdir '${existingFile}'`);
382      assert.strictEqual(err.errno, UV_ENOTDIR);
383    } else {  // windows
384      assert.strictEqual(
385        err.message,
386        `ENOENT: no such file or directory, rmdir '${existingFile}'`);
387      assert.strictEqual(err.errno, UV_ENOENT);
388      assert.strictEqual(err.code, 'ENOENT');
389    }
390    return true;
391  };
392
393  fs.rmdir(existingFile, common.mustCall(validateError));
394
395  assert.throws(
396    () => fs.rmdirSync(existingFile),
397    validateError
398  );
399}
400
401// mkdir
402{
403  const validateError = (err) => {
404    assert.strictEqual(existingFile, err.path);
405    assert.strictEqual(
406      err.message,
407      `EEXIST: file already exists, mkdir '${existingFile}'`);
408    assert.strictEqual(err.errno, UV_EEXIST);
409    assert.strictEqual(err.code, 'EEXIST');
410    assert.strictEqual(err.syscall, 'mkdir');
411    return true;
412  };
413
414  fs.mkdir(existingFile, 0o666, common.mustCall(validateError));
415
416  assert.throws(
417    () => fs.mkdirSync(existingFile, 0o666),
418    validateError
419  );
420}
421
422// chmod
423{
424  const validateError = (err) => {
425    assert.strictEqual(nonexistentFile, err.path);
426    assert.strictEqual(
427      err.message,
428      `ENOENT: no such file or directory, chmod '${nonexistentFile}'`);
429    assert.strictEqual(err.errno, UV_ENOENT);
430    assert.strictEqual(err.code, 'ENOENT');
431    assert.strictEqual(err.syscall, 'chmod');
432    return true;
433  };
434
435  fs.chmod(nonexistentFile, 0o666, common.mustCall(validateError));
436
437  assert.throws(
438    () => fs.chmodSync(nonexistentFile, 0o666),
439    validateError
440  );
441}
442
443// open
444{
445  const validateError = (err) => {
446    assert.strictEqual(nonexistentFile, err.path);
447    assert.strictEqual(
448      err.message,
449      `ENOENT: no such file or directory, open '${nonexistentFile}'`);
450    assert.strictEqual(err.errno, UV_ENOENT);
451    assert.strictEqual(err.code, 'ENOENT');
452    assert.strictEqual(err.syscall, 'open');
453    return true;
454  };
455
456  fs.open(nonexistentFile, 'r', 0o666, common.mustCall(validateError));
457
458  assert.throws(
459    () => fs.openSync(nonexistentFile, 'r', 0o666),
460    validateError
461  );
462}
463
464
465// close
466{
467  const validateError = (err) => {
468    assert.strictEqual(err.message, 'EBADF: bad file descriptor, close');
469    assert.strictEqual(err.errno, UV_EBADF);
470    assert.strictEqual(err.code, 'EBADF');
471    assert.strictEqual(err.syscall, 'close');
472    return true;
473  };
474
475  common.runWithInvalidFD((fd) => {
476    fs.close(fd, common.mustCall(validateError));
477
478    assert.throws(
479      () => fs.closeSync(fd),
480      validateError
481    );
482  });
483}
484
485// readFile
486{
487  const validateError = (err) => {
488    assert.strictEqual(nonexistentFile, err.path);
489    assert.strictEqual(
490      err.message,
491      `ENOENT: no such file or directory, open '${nonexistentFile}'`);
492    assert.strictEqual(err.errno, UV_ENOENT);
493    assert.strictEqual(err.code, 'ENOENT');
494    assert.strictEqual(err.syscall, 'open');
495    return true;
496  };
497
498  fs.readFile(nonexistentFile, common.mustCall(validateError));
499
500  assert.throws(
501    () => fs.readFileSync(nonexistentFile),
502    validateError
503  );
504}
505
506// readdir
507{
508  const validateError = (err) => {
509    assert.strictEqual(nonexistentFile, err.path);
510    assert.strictEqual(
511      err.message,
512      `ENOENT: no such file or directory, scandir '${nonexistentFile}'`);
513    assert.strictEqual(err.errno, UV_ENOENT);
514    assert.strictEqual(err.code, 'ENOENT');
515    assert.strictEqual(err.syscall, 'scandir');
516    return true;
517  };
518
519  fs.readdir(nonexistentFile, common.mustCall(validateError));
520
521  assert.throws(
522    () => fs.readdirSync(nonexistentFile),
523    validateError
524  );
525}
526
527// ftruncate
528{
529  const validateError = (err) => {
530    assert.strictEqual(err.syscall, 'ftruncate');
531    // Could be EBADF or EINVAL, depending on the platform
532    if (err.code === 'EBADF') {
533      assert.strictEqual(err.message, 'EBADF: bad file descriptor, ftruncate');
534      assert.strictEqual(err.errno, UV_EBADF);
535    } else {
536      assert.strictEqual(err.message, 'EINVAL: invalid argument, ftruncate');
537      assert.strictEqual(err.errno, UV_EINVAL);
538      assert.strictEqual(err.code, 'EINVAL');
539    }
540    return true;
541  };
542
543  common.runWithInvalidFD((fd) => {
544    fs.ftruncate(fd, 4, common.mustCall(validateError));
545
546    assert.throws(
547      () => fs.ftruncateSync(fd, 4),
548      validateError
549    );
550  });
551}
552
553// fdatasync
554{
555  const validateError = (err) => {
556    assert.strictEqual(err.message, 'EBADF: bad file descriptor, fdatasync');
557    assert.strictEqual(err.errno, UV_EBADF);
558    assert.strictEqual(err.code, 'EBADF');
559    assert.strictEqual(err.syscall, 'fdatasync');
560    return true;
561  };
562
563  common.runWithInvalidFD((fd) => {
564    fs.fdatasync(fd, common.mustCall(validateError));
565
566    assert.throws(
567      () => fs.fdatasyncSync(fd),
568      validateError
569    );
570  });
571}
572
573// fsync
574{
575  const validateError = (err) => {
576    assert.strictEqual(err.message, 'EBADF: bad file descriptor, fsync');
577    assert.strictEqual(err.errno, UV_EBADF);
578    assert.strictEqual(err.code, 'EBADF');
579    assert.strictEqual(err.syscall, 'fsync');
580    return true;
581  };
582
583  common.runWithInvalidFD((fd) => {
584    fs.fsync(fd, common.mustCall(validateError));
585
586    assert.throws(
587      () => fs.fsyncSync(fd),
588      validateError
589    );
590  });
591}
592
593// chown
594if (!common.isWindows) {
595  const validateError = (err) => {
596    assert.strictEqual(nonexistentFile, err.path);
597    assert.strictEqual(
598      err.message,
599      `ENOENT: no such file or directory, chown '${nonexistentFile}'`);
600    assert.strictEqual(err.errno, UV_ENOENT);
601    assert.strictEqual(err.code, 'ENOENT');
602    assert.strictEqual(err.syscall, 'chown');
603    return true;
604  };
605
606  fs.chown(nonexistentFile, process.getuid(), process.getgid(),
607           common.mustCall(validateError));
608
609  assert.throws(
610    () => fs.chownSync(nonexistentFile,
611                       process.getuid(), process.getgid()),
612    validateError
613  );
614}
615
616// utimes
617if (!common.isAIX) {
618  const validateError = (err) => {
619    assert.strictEqual(nonexistentFile, err.path);
620    assert.strictEqual(
621      err.message,
622      `ENOENT: no such file or directory, utime '${nonexistentFile}'`);
623    assert.strictEqual(err.errno, UV_ENOENT);
624    assert.strictEqual(err.code, 'ENOENT');
625    assert.strictEqual(err.syscall, 'utime');
626    return true;
627  };
628
629  fs.utimes(nonexistentFile, new Date(), new Date(),
630            common.mustCall(validateError));
631
632  assert.throws(
633    () => fs.utimesSync(nonexistentFile, new Date(), new Date()),
634    validateError
635  );
636}
637
638// mkdtemp
639{
640  const validateError = (err) => {
641    const pathPrefix = new RegExp('^' + re`${nonexistentDir}`);
642    assert.match(err.path, pathPrefix);
643
644    const prefix = new RegExp('^ENOENT: no such file or directory, mkdtemp ' +
645                              re`'${nonexistentDir}`);
646    assert.match(err.message, prefix);
647
648    assert.strictEqual(err.errno, UV_ENOENT);
649    assert.strictEqual(err.code, 'ENOENT');
650    assert.strictEqual(err.syscall, 'mkdtemp');
651    return true;
652  };
653
654  fs.mkdtemp(nonexistentDir, common.mustCall(validateError));
655
656  assert.throws(
657    () => fs.mkdtempSync(nonexistentDir),
658    validateError
659  );
660}
661
662// Check copyFile with invalid modes.
663{
664  const validateError = {
665    code: 'ERR_OUT_OF_RANGE',
666  };
667
668  assert.throws(
669    () => fs.copyFile(existingFile, nonexistentFile, -1, () => {}),
670    validateError
671  );
672  assert.throws(
673    () => fs.copyFileSync(existingFile, nonexistentFile, -1),
674    validateError
675  );
676}
677
678// copyFile: destination exists but the COPYFILE_EXCL flag is provided.
679{
680  const validateError = (err) => {
681    if (err.code === 'ENOENT') {  // Could be ENOENT or EEXIST
682      assert.strictEqual(err.message,
683                         'ENOENT: no such file or directory, copyfile ' +
684                         `'${existingFile}' -> '${existingFile2}'`);
685      assert.strictEqual(err.errno, UV_ENOENT);
686      assert.strictEqual(err.code, 'ENOENT');
687      assert.strictEqual(err.syscall, 'copyfile');
688    } else {
689      assert.strictEqual(err.message,
690                         'EEXIST: file already exists, copyfile ' +
691                         `'${existingFile}' -> '${existingFile2}'`);
692      assert.strictEqual(err.errno, UV_EEXIST);
693      assert.strictEqual(err.code, 'EEXIST');
694      assert.strictEqual(err.syscall, 'copyfile');
695    }
696    return true;
697  };
698
699  fs.copyFile(existingFile, existingFile2, COPYFILE_EXCL,
700              common.mustCall(validateError));
701
702  assert.throws(
703    () => fs.copyFileSync(existingFile, existingFile2, COPYFILE_EXCL),
704    validateError
705  );
706}
707
708// copyFile: the source does not exist.
709{
710  const validateError = (err) => {
711    assert.strictEqual(err.message,
712                       'ENOENT: no such file or directory, copyfile ' +
713                       `'${nonexistentFile}' -> '${existingFile2}'`);
714    assert.strictEqual(err.errno, UV_ENOENT);
715    assert.strictEqual(err.code, 'ENOENT');
716    assert.strictEqual(err.syscall, 'copyfile');
717    return true;
718  };
719
720  fs.copyFile(nonexistentFile, existingFile2, COPYFILE_EXCL,
721              common.mustCall(validateError));
722
723  assert.throws(
724    () => fs.copyFileSync(nonexistentFile, existingFile2, COPYFILE_EXCL),
725    validateError
726  );
727}
728
729// read
730{
731  const validateError = (err) => {
732    assert.strictEqual(err.message, 'EBADF: bad file descriptor, read');
733    assert.strictEqual(err.errno, UV_EBADF);
734    assert.strictEqual(err.code, 'EBADF');
735    assert.strictEqual(err.syscall, 'read');
736    return true;
737  };
738
739  common.runWithInvalidFD((fd) => {
740    const buf = Buffer.alloc(5);
741    fs.read(fd, buf, 0, 1, 1, common.mustCall(validateError));
742
743    assert.throws(
744      () => fs.readSync(fd, buf, 0, 1, 1),
745      validateError
746    );
747  });
748}
749
750// fchmod
751{
752  const validateError = (err) => {
753    assert.strictEqual(err.message, 'EBADF: bad file descriptor, fchmod');
754    assert.strictEqual(err.errno, UV_EBADF);
755    assert.strictEqual(err.code, 'EBADF');
756    assert.strictEqual(err.syscall, 'fchmod');
757    return true;
758  };
759
760  common.runWithInvalidFD((fd) => {
761    fs.fchmod(fd, 0o666, common.mustCall(validateError));
762
763    assert.throws(
764      () => fs.fchmodSync(fd, 0o666),
765      validateError
766    );
767  });
768}
769
770// fchown
771if (!common.isWindows) {
772  const validateError = (err) => {
773    assert.strictEqual(err.message, 'EBADF: bad file descriptor, fchown');
774    assert.strictEqual(err.errno, UV_EBADF);
775    assert.strictEqual(err.code, 'EBADF');
776    assert.strictEqual(err.syscall, 'fchown');
777    return true;
778  };
779
780  common.runWithInvalidFD((fd) => {
781    fs.fchown(fd, process.getuid(), process.getgid(),
782              common.mustCall(validateError));
783
784    assert.throws(
785      () => fs.fchownSync(fd, process.getuid(), process.getgid()),
786      validateError
787    );
788  });
789}
790
791// write buffer
792{
793  const validateError = (err) => {
794    assert.strictEqual(err.message, 'EBADF: bad file descriptor, write');
795    assert.strictEqual(err.errno, UV_EBADF);
796    assert.strictEqual(err.code, 'EBADF');
797    assert.strictEqual(err.syscall, 'write');
798    return true;
799  };
800
801  common.runWithInvalidFD((fd) => {
802    const buf = Buffer.alloc(5);
803    fs.write(fd, buf, 0, 1, 1, common.mustCall(validateError));
804
805    assert.throws(
806      () => fs.writeSync(fd, buf, 0, 1, 1),
807      validateError
808    );
809  });
810}
811
812// write string
813{
814  const validateError = (err) => {
815    assert.strictEqual(err.message, 'EBADF: bad file descriptor, write');
816    assert.strictEqual(err.errno, UV_EBADF);
817    assert.strictEqual(err.code, 'EBADF');
818    assert.strictEqual(err.syscall, 'write');
819    return true;
820  };
821
822  common.runWithInvalidFD((fd) => {
823    fs.write(fd, 'test', 1, common.mustCall(validateError));
824
825    assert.throws(
826      () => fs.writeSync(fd, 'test', 1),
827      validateError
828    );
829  });
830}
831
832
833// futimes
834if (!common.isAIX) {
835  const validateError = (err) => {
836    assert.strictEqual(err.message, 'EBADF: bad file descriptor, futime');
837    assert.strictEqual(err.errno, UV_EBADF);
838    assert.strictEqual(err.code, 'EBADF');
839    assert.strictEqual(err.syscall, 'futime');
840    return true;
841  };
842
843  common.runWithInvalidFD((fd) => {
844    fs.futimes(fd, new Date(), new Date(), common.mustCall(validateError));
845
846    assert.throws(
847      () => fs.futimesSync(fd, new Date(), new Date()),
848      validateError
849    );
850  });
851}
852