• 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 modes.
667{
668  const validateError = {
669    message: /"mode".+must be an integer >= 0 && <= 7\. Received -1/,
670    code: 'ERR_OUT_OF_RANGE'
671  };
672
673  assert.throws(
674    () => fs.copyFile(existingFile, nonexistentFile, -1, () => {}),
675    validateError
676  );
677  assert.throws(
678    () => fs.copyFileSync(existingFile, nonexistentFile, -1),
679    validateError
680  );
681}
682
683// copyFile: destination exists but the COPYFILE_EXCL flag is provided.
684{
685  const validateError = (err) => {
686    if (err.code === 'ENOENT') {  // Could be ENOENT or EEXIST
687      assert.strictEqual(err.message,
688                         'ENOENT: no such file or directory, copyfile ' +
689                         `'${existingFile}' -> '${existingFile2}'`);
690      assert.strictEqual(err.errno, UV_ENOENT);
691      assert.strictEqual(err.code, 'ENOENT');
692      assert.strictEqual(err.syscall, 'copyfile');
693    } else {
694      assert.strictEqual(err.message,
695                         'EEXIST: file already exists, copyfile ' +
696                         `'${existingFile}' -> '${existingFile2}'`);
697      assert.strictEqual(err.errno, UV_EEXIST);
698      assert.strictEqual(err.code, 'EEXIST');
699      assert.strictEqual(err.syscall, 'copyfile');
700    }
701    return true;
702  };
703
704  fs.copyFile(existingFile, existingFile2, COPYFILE_EXCL,
705              common.mustCall(validateError));
706
707  assert.throws(
708    () => fs.copyFileSync(existingFile, existingFile2, COPYFILE_EXCL),
709    validateError
710  );
711}
712
713// copyFile: the source does not exist.
714{
715  const validateError = (err) => {
716    assert.strictEqual(err.message,
717                       'ENOENT: no such file or directory, copyfile ' +
718                       `'${nonexistentFile}' -> '${existingFile2}'`);
719    assert.strictEqual(err.errno, UV_ENOENT);
720    assert.strictEqual(err.code, 'ENOENT');
721    assert.strictEqual(err.syscall, 'copyfile');
722    return true;
723  };
724
725  fs.copyFile(nonexistentFile, existingFile2, COPYFILE_EXCL,
726              common.mustCall(validateError));
727
728  assert.throws(
729    () => fs.copyFileSync(nonexistentFile, existingFile2, COPYFILE_EXCL),
730    validateError
731  );
732}
733
734// read
735{
736  const validateError = (err) => {
737    assert.strictEqual(err.message, 'EBADF: bad file descriptor, read');
738    assert.strictEqual(err.errno, UV_EBADF);
739    assert.strictEqual(err.code, 'EBADF');
740    assert.strictEqual(err.syscall, 'read');
741    return true;
742  };
743
744  common.runWithInvalidFD((fd) => {
745    const buf = Buffer.alloc(5);
746    fs.read(fd, buf, 0, 1, 1, common.mustCall(validateError));
747
748    assert.throws(
749      () => fs.readSync(fd, buf, 0, 1, 1),
750      validateError
751    );
752  });
753}
754
755// fchmod
756{
757  const validateError = (err) => {
758    assert.strictEqual(err.message, 'EBADF: bad file descriptor, fchmod');
759    assert.strictEqual(err.errno, UV_EBADF);
760    assert.strictEqual(err.code, 'EBADF');
761    assert.strictEqual(err.syscall, 'fchmod');
762    return true;
763  };
764
765  common.runWithInvalidFD((fd) => {
766    fs.fchmod(fd, 0o666, common.mustCall(validateError));
767
768    assert.throws(
769      () => fs.fchmodSync(fd, 0o666),
770      validateError
771    );
772  });
773}
774
775// fchown
776if (!common.isWindows) {
777  const validateError = (err) => {
778    assert.strictEqual(err.message, 'EBADF: bad file descriptor, fchown');
779    assert.strictEqual(err.errno, UV_EBADF);
780    assert.strictEqual(err.code, 'EBADF');
781    assert.strictEqual(err.syscall, 'fchown');
782    return true;
783  };
784
785  common.runWithInvalidFD((fd) => {
786    fs.fchown(fd, process.getuid(), process.getgid(),
787              common.mustCall(validateError));
788
789    assert.throws(
790      () => fs.fchownSync(fd, process.getuid(), process.getgid()),
791      validateError
792    );
793  });
794}
795
796// write buffer
797{
798  const validateError = (err) => {
799    assert.strictEqual(err.message, 'EBADF: bad file descriptor, write');
800    assert.strictEqual(err.errno, UV_EBADF);
801    assert.strictEqual(err.code, 'EBADF');
802    assert.strictEqual(err.syscall, 'write');
803    return true;
804  };
805
806  common.runWithInvalidFD((fd) => {
807    const buf = Buffer.alloc(5);
808    fs.write(fd, buf, 0, 1, 1, common.mustCall(validateError));
809
810    assert.throws(
811      () => fs.writeSync(fd, buf, 0, 1, 1),
812      validateError
813    );
814  });
815}
816
817// write string
818{
819  const validateError = (err) => {
820    assert.strictEqual(err.message, 'EBADF: bad file descriptor, write');
821    assert.strictEqual(err.errno, UV_EBADF);
822    assert.strictEqual(err.code, 'EBADF');
823    assert.strictEqual(err.syscall, 'write');
824    return true;
825  };
826
827  common.runWithInvalidFD((fd) => {
828    fs.write(fd, 'test', 1, common.mustCall(validateError));
829
830    assert.throws(
831      () => fs.writeSync(fd, 'test', 1),
832      validateError
833    );
834  });
835}
836
837
838// futimes
839if (!common.isAIX) {
840  const validateError = (err) => {
841    assert.strictEqual(err.message, 'EBADF: bad file descriptor, futime');
842    assert.strictEqual(err.errno, UV_EBADF);
843    assert.strictEqual(err.code, 'EBADF');
844    assert.strictEqual(err.syscall, 'futime');
845    return true;
846  };
847
848  common.runWithInvalidFD((fd) => {
849    fs.futimes(fd, new Date(), new Date(), common.mustCall(validateError));
850
851    assert.throws(
852      () => fs.futimesSync(fd, new Date(), new Date()),
853      validateError
854    );
855  });
856}
857