doc: improvements to console.markdown copy
[platform/upstream/nodejs.git] / lib / fs.js
1 // Maintainers, keep in mind that ES1-style octal literals (`0666`) are not
2 // allowed in strict mode. Use ES6-style octal literals instead (`0o666`).
3
4 'use strict';
5
6 const SlowBuffer = require('buffer').SlowBuffer;
7 const util = require('util');
8 const pathModule = require('path');
9
10 const binding = process.binding('fs');
11 const constants = require('constants');
12 const fs = exports;
13 const Buffer = require('buffer').Buffer;
14 const Stream = require('stream').Stream;
15 const EventEmitter = require('events');
16 const FSReqWrap = binding.FSReqWrap;
17 const FSEvent = process.binding('fs_event_wrap').FSEvent;
18
19 const Readable = Stream.Readable;
20 const Writable = Stream.Writable;
21
22 const kMinPoolSpace = 128;
23 const kMaxLength = require('buffer').kMaxLength;
24
25 const O_APPEND = constants.O_APPEND || 0;
26 const O_CREAT = constants.O_CREAT || 0;
27 const O_EXCL = constants.O_EXCL || 0;
28 const O_RDONLY = constants.O_RDONLY || 0;
29 const O_RDWR = constants.O_RDWR || 0;
30 const O_SYNC = constants.O_SYNC || 0;
31 const O_TRUNC = constants.O_TRUNC || 0;
32 const O_WRONLY = constants.O_WRONLY || 0;
33
34 const isWindows = process.platform === 'win32';
35
36 const DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG);
37 const errnoException = util._errnoException;
38
39 function throwOptionsError(options) {
40   throw new TypeError('Expected options to be either an object or a string, ' +
41     'but got ' + typeof options + ' instead');
42 }
43
44 function rethrow() {
45   // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and
46   // is fairly slow to generate.
47   if (DEBUG) {
48     var backtrace = new Error();
49     return function(err) {
50       if (err) {
51         backtrace.stack = err.name + ': ' + err.message +
52                           backtrace.stack.substr(backtrace.name.length);
53         throw backtrace;
54       }
55     };
56   }
57
58   return function(err) {
59     if (err) {
60       throw err;  // Forgot a callback but don't know where? Use NODE_DEBUG=fs
61     }
62   };
63 }
64
65 function maybeCallback(cb) {
66   return typeof cb === 'function' ? cb : rethrow();
67 }
68
69 // Ensure that callbacks run in the global context. Only use this function
70 // for callbacks that are passed to the binding layer, callbacks that are
71 // invoked from JS already run in the proper scope.
72 function makeCallback(cb) {
73   if (cb === undefined) {
74     return rethrow();
75   }
76
77   if (typeof cb !== 'function') {
78     throw new TypeError('callback must be a function');
79   }
80
81   return function() {
82     return cb.apply(null, arguments);
83   };
84 }
85
86 function assertEncoding(encoding) {
87   if (encoding && !Buffer.isEncoding(encoding)) {
88     throw new Error('Unknown encoding: ' + encoding);
89   }
90 }
91
92 function nullCheck(path, callback) {
93   if (('' + path).indexOf('\u0000') !== -1) {
94     var er = new Error('Path must be a string without null bytes.');
95     er.code = 'ENOENT';
96     if (typeof callback !== 'function')
97       throw er;
98     process.nextTick(callback, er);
99     return false;
100   }
101   return true;
102 }
103
104 // Static method to set the stats properties on a Stats object.
105 fs.Stats = function(
106     dev,
107     mode,
108     nlink,
109     uid,
110     gid,
111     rdev,
112     blksize,
113     ino,
114     size,
115     blocks,
116     atim_msec,
117     mtim_msec,
118     ctim_msec,
119     birthtim_msec) {
120   this.dev = dev;
121   this.mode = mode;
122   this.nlink = nlink;
123   this.uid = uid;
124   this.gid = gid;
125   this.rdev = rdev;
126   this.blksize = blksize;
127   this.ino = ino;
128   this.size = size;
129   this.blocks = blocks;
130   this.atime = new Date(atim_msec);
131   this.mtime = new Date(mtim_msec);
132   this.ctime = new Date(ctim_msec);
133   this.birthtime = new Date(birthtim_msec);
134 };
135
136 // Create a C++ binding to the function which creates a Stats object.
137 binding.FSInitialize(fs.Stats);
138
139 fs.Stats.prototype._checkModeProperty = function(property) {
140   return ((this.mode & constants.S_IFMT) === property);
141 };
142
143 fs.Stats.prototype.isDirectory = function() {
144   return this._checkModeProperty(constants.S_IFDIR);
145 };
146
147 fs.Stats.prototype.isFile = function() {
148   return this._checkModeProperty(constants.S_IFREG);
149 };
150
151 fs.Stats.prototype.isBlockDevice = function() {
152   return this._checkModeProperty(constants.S_IFBLK);
153 };
154
155 fs.Stats.prototype.isCharacterDevice = function() {
156   return this._checkModeProperty(constants.S_IFCHR);
157 };
158
159 fs.Stats.prototype.isSymbolicLink = function() {
160   return this._checkModeProperty(constants.S_IFLNK);
161 };
162
163 fs.Stats.prototype.isFIFO = function() {
164   return this._checkModeProperty(constants.S_IFIFO);
165 };
166
167 fs.Stats.prototype.isSocket = function() {
168   return this._checkModeProperty(constants.S_IFSOCK);
169 };
170
171 // Don't allow mode to accidentally be overwritten.
172 ['F_OK', 'R_OK', 'W_OK', 'X_OK'].forEach(function(key) {
173   Object.defineProperty(fs, key, {
174     enumerable: true, value: constants[key] || 0, writable: false
175   });
176 });
177
178 fs.access = function(path, mode, callback) {
179   if (typeof mode === 'function') {
180     callback = mode;
181     mode = fs.F_OK;
182   } else if (typeof callback !== 'function') {
183     throw new TypeError('callback must be a function');
184   }
185
186   if (!nullCheck(path, callback))
187     return;
188
189   mode = mode | 0;
190   var req = new FSReqWrap();
191   req.oncomplete = makeCallback(callback);
192   binding.access(pathModule._makeLong(path), mode, req);
193 };
194
195 fs.accessSync = function(path, mode) {
196   nullCheck(path);
197
198   if (mode === undefined)
199     mode = fs.F_OK;
200   else
201     mode = mode | 0;
202
203   binding.access(pathModule._makeLong(path), mode);
204 };
205
206 fs.exists = function(path, callback) {
207   if (!nullCheck(path, cb)) return;
208   var req = new FSReqWrap();
209   req.oncomplete = cb;
210   binding.stat(pathModule._makeLong(path), req);
211   function cb(err, stats) {
212     if (callback) callback(err ? false : true);
213   }
214 };
215
216 fs.existsSync = function(path) {
217   try {
218     nullCheck(path);
219     binding.stat(pathModule._makeLong(path));
220     return true;
221   } catch (e) {
222     return false;
223   }
224 };
225
226 fs.readFile = function(path, options, callback_) {
227   var callback = maybeCallback(arguments[arguments.length - 1]);
228
229   if (!options || typeof options === 'function') {
230     options = { encoding: null, flag: 'r' };
231   } else if (typeof options === 'string') {
232     options = { encoding: options, flag: 'r' };
233   } else if (typeof options !== 'object') {
234     throwOptionsError(options);
235   }
236
237   var encoding = options.encoding;
238   assertEncoding(encoding);
239
240   var flag = options.flag || 'r';
241
242   if (!nullCheck(path, callback))
243     return;
244
245   var context = new ReadFileContext(callback, encoding);
246   var req = new FSReqWrap();
247   req.context = context;
248   req.oncomplete = readFileAfterOpen;
249
250   binding.open(pathModule._makeLong(path),
251                stringToFlags(flag),
252                0o666,
253                req);
254 };
255
256 const kReadFileBufferLength = 8 * 1024;
257
258 function ReadFileContext(callback, encoding) {
259   this.fd = undefined;
260   this.size = undefined;
261   this.callback = callback;
262   this.buffers = null;
263   this.buffer = null;
264   this.pos = 0;
265   this.encoding = encoding;
266   this.err = null;
267 }
268
269 ReadFileContext.prototype.read = function() {
270   var buffer;
271   var offset;
272   var length;
273
274   if (this.size === 0) {
275     buffer = this.buffer = new SlowBuffer(kReadFileBufferLength);
276     offset = 0;
277     length = kReadFileBufferLength;
278   } else {
279     buffer = this.buffer;
280     offset = this.pos;
281     length = this.size - this.pos;
282   }
283
284   var req = new FSReqWrap();
285   req.oncomplete = readFileAfterRead;
286   req.context = this;
287
288   binding.read(this.fd, buffer, offset, length, -1, req);
289 };
290
291 ReadFileContext.prototype.close = function(err) {
292   var req = new FSReqWrap();
293   req.oncomplete = readFileAfterClose;
294   req.context = this;
295   this.err = err;
296   binding.close(this.fd, req);
297 };
298
299 function readFileAfterOpen(err, fd) {
300   var context = this.context;
301
302   if (err) {
303     context.callback(err);
304     return;
305   }
306
307   context.fd = fd;
308
309   var req = new FSReqWrap();
310   req.oncomplete = readFileAfterStat;
311   req.context = context;
312   binding.fstat(fd, req);
313 }
314
315 function readFileAfterStat(err, st) {
316   var context = this.context;
317
318   if (err)
319     return context.close(err);
320
321   var size = context.size = st.isFile() ? st.size : 0;
322
323   if (size === 0) {
324     context.buffers = [];
325     context.read();
326     return;
327   }
328
329   if (size > kMaxLength) {
330     err = new RangeError('File size is greater than possible Buffer: ' +
331                          `0x${kMaxLength.toString(16)} bytes`);
332     return context.close(err);
333   }
334
335   context.buffer = new SlowBuffer(size);
336   context.read();
337 }
338
339 function readFileAfterRead(err, bytesRead) {
340   var context = this.context;
341
342   if (err)
343     return context.close(err);
344
345   if (bytesRead === 0)
346     return context.close();
347
348   context.pos += bytesRead;
349
350   if (context.size !== 0) {
351     if (context.pos === context.size)
352       context.close();
353     else
354       context.read();
355   } else {
356     // unknown size, just read until we don't get bytes.
357     context.buffers.push(context.buffer.slice(0, bytesRead));
358     context.read();
359   }
360 }
361
362 function readFileAfterClose(err) {
363   var context = this.context;
364   var buffer = null;
365   var callback = context.callback;
366
367   if (context.err)
368     return callback(context.err);
369
370   if (context.size === 0)
371     buffer = Buffer.concat(context.buffers, context.pos);
372   else if (context.pos < context.size)
373     buffer = context.buffer.slice(0, context.pos);
374   else
375     buffer = context.buffer;
376
377   if (context.encoding)
378     buffer = buffer.toString(context.encoding);
379
380   callback(err, buffer);
381 }
382
383
384 fs.readFileSync = function(path, options) {
385   if (!options) {
386     options = { encoding: null, flag: 'r' };
387   } else if (typeof options === 'string') {
388     options = { encoding: options, flag: 'r' };
389   } else if (typeof options !== 'object') {
390     throwOptionsError(options);
391   }
392
393   var encoding = options.encoding;
394   assertEncoding(encoding);
395
396   var flag = options.flag || 'r';
397   var fd = fs.openSync(path, flag, 0o666);
398
399   var st;
400   var size;
401   var threw = true;
402   try {
403     st = fs.fstatSync(fd);
404     size = st.isFile() ? st.size : 0;
405     threw = false;
406   } finally {
407     if (threw) fs.closeSync(fd);
408   }
409
410   var pos = 0;
411   var buffer; // single buffer with file data
412   var buffers; // list for when size is unknown
413
414   if (size === 0) {
415     buffers = [];
416   } else {
417     threw = true;
418     try {
419       buffer = new Buffer(size);
420       threw = false;
421     } finally {
422       if (threw) fs.closeSync(fd);
423     }
424   }
425
426   var done = false;
427   var bytesRead;
428
429   while (!done) {
430     threw = true;
431     try {
432       if (size !== 0) {
433         bytesRead = fs.readSync(fd, buffer, pos, size - pos);
434       } else {
435         // the kernel lies about many files.
436         // Go ahead and try to read some bytes.
437         buffer = new Buffer(8192);
438         bytesRead = fs.readSync(fd, buffer, 0, 8192);
439         if (bytesRead) {
440           buffers.push(buffer.slice(0, bytesRead));
441         }
442       }
443       threw = false;
444     } finally {
445       if (threw) fs.closeSync(fd);
446     }
447
448     pos += bytesRead;
449     done = (bytesRead === 0) || (size !== 0 && pos >= size);
450   }
451
452   fs.closeSync(fd);
453
454   if (size === 0) {
455     // data was collected into the buffers list.
456     buffer = Buffer.concat(buffers, pos);
457   } else if (pos < size) {
458     buffer = buffer.slice(0, pos);
459   }
460
461   if (encoding) buffer = buffer.toString(encoding);
462   return buffer;
463 };
464
465
466 // Used by binding.open and friends
467 function stringToFlags(flag) {
468   // Only mess with strings
469   if (typeof flag !== 'string') {
470     return flag;
471   }
472
473   switch (flag) {
474     case 'r' : return O_RDONLY;
475     case 'rs' : // fall through
476     case 'sr' : return O_RDONLY | O_SYNC;
477     case 'r+' : return O_RDWR;
478     case 'rs+' : // fall through
479     case 'sr+' : return O_RDWR | O_SYNC;
480
481     case 'w' : return O_TRUNC | O_CREAT | O_WRONLY;
482     case 'wx' : // fall through
483     case 'xw' : return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;
484
485     case 'w+' : return O_TRUNC | O_CREAT | O_RDWR;
486     case 'wx+': // fall through
487     case 'xw+': return O_TRUNC | O_CREAT | O_RDWR | O_EXCL;
488
489     case 'a' : return O_APPEND | O_CREAT | O_WRONLY;
490     case 'ax' : // fall through
491     case 'xa' : return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
492
493     case 'a+' : return O_APPEND | O_CREAT | O_RDWR;
494     case 'ax+': // fall through
495     case 'xa+': return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
496   }
497
498   throw new Error('Unknown file open flag: ' + flag);
499 }
500
501 // exported but hidden, only used by test/simple/test-fs-open-flags.js
502 Object.defineProperty(exports, '_stringToFlags', {
503   enumerable: false,
504   value: stringToFlags
505 });
506
507
508 // Yes, the follow could be easily DRYed up but I provide the explicit
509 // list to make the arguments clear.
510
511 fs.close = function(fd, callback) {
512   var req = new FSReqWrap();
513   req.oncomplete = makeCallback(callback);
514   binding.close(fd, req);
515 };
516
517 fs.closeSync = function(fd) {
518   return binding.close(fd);
519 };
520
521 function modeNum(m, def) {
522   if (typeof m === 'number')
523     return m;
524   if (typeof m === 'string')
525     return parseInt(m, 8);
526   if (def)
527     return modeNum(def);
528   return undefined;
529 }
530
531 fs.open = function(path, flags, mode, callback_) {
532   var callback = makeCallback(arguments[arguments.length - 1]);
533   mode = modeNum(mode, 0o666);
534
535   if (!nullCheck(path, callback)) return;
536
537   var req = new FSReqWrap();
538   req.oncomplete = callback;
539
540   binding.open(pathModule._makeLong(path),
541                stringToFlags(flags),
542                mode,
543                req);
544 };
545
546 fs.openSync = function(path, flags, mode) {
547   mode = modeNum(mode, 0o666);
548   nullCheck(path);
549   return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
550 };
551
552 fs.read = function(fd, buffer, offset, length, position, callback) {
553   if (!(buffer instanceof Buffer)) {
554     // legacy string interface (fd, length, position, encoding, callback)
555     var cb = arguments[4],
556         encoding = arguments[3];
557
558     assertEncoding(encoding);
559
560     position = arguments[2];
561     length = arguments[1];
562     buffer = new Buffer(length);
563     offset = 0;
564
565     callback = function(err, bytesRead) {
566       if (!cb) return;
567
568       var str = (bytesRead > 0) ? buffer.toString(encoding, 0, bytesRead) : '';
569
570       (cb)(err, str, bytesRead);
571     };
572   }
573
574   function wrapper(err, bytesRead) {
575     // Retain a reference to buffer so that it can't be GC'ed too soon.
576     callback && callback(err, bytesRead || 0, buffer);
577   }
578
579   var req = new FSReqWrap();
580   req.oncomplete = wrapper;
581
582   binding.read(fd, buffer, offset, length, position, req);
583 };
584
585 fs.readSync = function(fd, buffer, offset, length, position) {
586   var legacy = false;
587   var encoding;
588
589   if (!(buffer instanceof Buffer)) {
590     // legacy string interface (fd, length, position, encoding, callback)
591     legacy = true;
592     encoding = arguments[3];
593
594     assertEncoding(encoding);
595
596     position = arguments[2];
597     length = arguments[1];
598     buffer = new Buffer(length);
599
600     offset = 0;
601   }
602
603   var r = binding.read(fd, buffer, offset, length, position);
604   if (!legacy) {
605     return r;
606   }
607
608   var str = (r > 0) ? buffer.toString(encoding, 0, r) : '';
609   return [str, r];
610 };
611
612 // usage:
613 //  fs.write(fd, buffer, offset, length[, position], callback);
614 // OR
615 //  fs.write(fd, string[, position[, encoding]], callback);
616 fs.write = function(fd, buffer, offset, length, position, callback) {
617   function wrapper(err, written) {
618     // Retain a reference to buffer so that it can't be GC'ed too soon.
619     callback(err, written || 0, buffer);
620   }
621
622   var req = new FSReqWrap();
623   req.oncomplete = wrapper;
624
625   if (buffer instanceof Buffer) {
626     // if no position is passed then assume null
627     if (typeof position === 'function') {
628       callback = position;
629       position = null;
630     }
631     callback = maybeCallback(callback);
632     return binding.writeBuffer(fd, buffer, offset, length, position, req);
633   }
634
635   if (typeof buffer !== 'string')
636     buffer += '';
637   if (typeof position !== 'function') {
638     if (typeof offset === 'function') {
639       position = offset;
640       offset = null;
641     } else {
642       position = length;
643     }
644     length = 'utf8';
645   }
646   callback = maybeCallback(position);
647   return binding.writeString(fd, buffer, offset, length, req);
648 };
649
650 // usage:
651 //  fs.writeSync(fd, buffer, offset, length[, position]);
652 // OR
653 //  fs.writeSync(fd, string[, position[, encoding]]);
654 fs.writeSync = function(fd, buffer, offset, length, position) {
655   if (buffer instanceof Buffer) {
656     if (position === undefined)
657       position = null;
658     return binding.writeBuffer(fd, buffer, offset, length, position);
659   }
660   if (typeof buffer !== 'string')
661     buffer += '';
662   if (offset === undefined)
663     offset = null;
664   return binding.writeString(fd, buffer, offset, length, position);
665 };
666
667 fs.rename = function(oldPath, newPath, callback) {
668   callback = makeCallback(callback);
669   if (!nullCheck(oldPath, callback)) return;
670   if (!nullCheck(newPath, callback)) return;
671   var req = new FSReqWrap();
672   req.oncomplete = callback;
673   binding.rename(pathModule._makeLong(oldPath),
674                  pathModule._makeLong(newPath),
675                  req);
676 };
677
678 fs.renameSync = function(oldPath, newPath) {
679   nullCheck(oldPath);
680   nullCheck(newPath);
681   return binding.rename(pathModule._makeLong(oldPath),
682                         pathModule._makeLong(newPath));
683 };
684
685 fs.truncate = function(path, len, callback) {
686   if (typeof path === 'number') {
687     return fs.ftruncate(path, len, callback);
688   }
689   if (typeof len === 'function') {
690     callback = len;
691     len = 0;
692   } else if (len === undefined) {
693     len = 0;
694   }
695
696   callback = maybeCallback(callback);
697   fs.open(path, 'r+', function(er, fd) {
698     if (er) return callback(er);
699     var req = new FSReqWrap();
700     req.oncomplete = function ftruncateCb(er) {
701       fs.close(fd, function(er2) {
702         callback(er || er2);
703       });
704     };
705     binding.ftruncate(fd, len, req);
706   });
707 };
708
709 fs.truncateSync = function(path, len) {
710   if (typeof path === 'number') {
711     // legacy
712     return fs.ftruncateSync(path, len);
713   }
714   if (len === undefined) {
715     len = 0;
716   }
717   // allow error to be thrown, but still close fd.
718   var fd = fs.openSync(path, 'r+');
719   var ret;
720
721   try {
722     ret = fs.ftruncateSync(fd, len);
723   } finally {
724     fs.closeSync(fd);
725   }
726   return ret;
727 };
728
729 fs.ftruncate = function(fd, len, callback) {
730   if (typeof len === 'function') {
731     callback = len;
732     len = 0;
733   } else if (len === undefined) {
734     len = 0;
735   }
736   var req = new FSReqWrap();
737   req.oncomplete = makeCallback(callback);
738   binding.ftruncate(fd, len, req);
739 };
740
741 fs.ftruncateSync = function(fd, len) {
742   if (len === undefined) {
743     len = 0;
744   }
745   return binding.ftruncate(fd, len);
746 };
747
748 fs.rmdir = function(path, callback) {
749   callback = maybeCallback(callback);
750   if (!nullCheck(path, callback)) return;
751   var req = new FSReqWrap();
752   req.oncomplete = callback;
753   binding.rmdir(pathModule._makeLong(path), req);
754 };
755
756 fs.rmdirSync = function(path) {
757   nullCheck(path);
758   return binding.rmdir(pathModule._makeLong(path));
759 };
760
761 fs.fdatasync = function(fd, callback) {
762   var req = new FSReqWrap();
763   req.oncomplete = makeCallback(callback);
764   binding.fdatasync(fd, req);
765 };
766
767 fs.fdatasyncSync = function(fd) {
768   return binding.fdatasync(fd);
769 };
770
771 fs.fsync = function(fd, callback) {
772   var req = new FSReqWrap();
773   req.oncomplete = makeCallback(callback);
774   binding.fsync(fd, req);
775 };
776
777 fs.fsyncSync = function(fd) {
778   return binding.fsync(fd);
779 };
780
781 fs.mkdir = function(path, mode, callback) {
782   if (typeof mode === 'function') callback = mode;
783   callback = makeCallback(callback);
784   if (!nullCheck(path, callback)) return;
785   var req = new FSReqWrap();
786   req.oncomplete = callback;
787   binding.mkdir(pathModule._makeLong(path),
788                 modeNum(mode, 0o777),
789                 req);
790 };
791
792 fs.mkdirSync = function(path, mode) {
793   nullCheck(path);
794   return binding.mkdir(pathModule._makeLong(path),
795                        modeNum(mode, 0o777));
796 };
797
798 fs.readdir = function(path, callback) {
799   callback = makeCallback(callback);
800   if (!nullCheck(path, callback)) return;
801   var req = new FSReqWrap();
802   req.oncomplete = callback;
803   binding.readdir(pathModule._makeLong(path), req);
804 };
805
806 fs.readdirSync = function(path) {
807   nullCheck(path);
808   return binding.readdir(pathModule._makeLong(path));
809 };
810
811 fs.fstat = function(fd, callback) {
812   var req = new FSReqWrap();
813   req.oncomplete = makeCallback(callback);
814   binding.fstat(fd, req);
815 };
816
817 fs.lstat = function(path, callback) {
818   callback = makeCallback(callback);
819   if (!nullCheck(path, callback)) return;
820   var req = new FSReqWrap();
821   req.oncomplete = callback;
822   binding.lstat(pathModule._makeLong(path), req);
823 };
824
825 fs.stat = function(path, callback) {
826   callback = makeCallback(callback);
827   if (!nullCheck(path, callback)) return;
828   var req = new FSReqWrap();
829   req.oncomplete = callback;
830   binding.stat(pathModule._makeLong(path), req);
831 };
832
833 fs.fstatSync = function(fd) {
834   return binding.fstat(fd);
835 };
836
837 fs.lstatSync = function(path) {
838   nullCheck(path);
839   return binding.lstat(pathModule._makeLong(path));
840 };
841
842 fs.statSync = function(path) {
843   nullCheck(path);
844   return binding.stat(pathModule._makeLong(path));
845 };
846
847 fs.readlink = function(path, callback) {
848   callback = makeCallback(callback);
849   if (!nullCheck(path, callback)) return;
850   var req = new FSReqWrap();
851   req.oncomplete = callback;
852   binding.readlink(pathModule._makeLong(path), req);
853 };
854
855 fs.readlinkSync = function(path) {
856   nullCheck(path);
857   return binding.readlink(pathModule._makeLong(path));
858 };
859
860 function preprocessSymlinkDestination(path, type, linkPath) {
861   if (!isWindows) {
862     // No preprocessing is needed on Unix.
863     return path;
864   } else if (type === 'junction') {
865     // Junctions paths need to be absolute and \\?\-prefixed.
866     // A relative target is relative to the link's parent directory.
867     path = pathModule.resolve(linkPath, '..', path);
868     return pathModule._makeLong(path);
869   } else {
870     // Windows symlinks don't tolerate forward slashes.
871     return ('' + path).replace(/\//g, '\\');
872   }
873 }
874
875 fs.symlink = function(target, path, type_, callback_) {
876   var type = (typeof type_ === 'string' ? type_ : null);
877   var callback = makeCallback(arguments[arguments.length - 1]);
878
879   if (!nullCheck(target, callback)) return;
880   if (!nullCheck(path, callback)) return;
881
882   var req = new FSReqWrap();
883   req.oncomplete = callback;
884
885   binding.symlink(preprocessSymlinkDestination(target, type, path),
886                   pathModule._makeLong(path),
887                   type,
888                   req);
889 };
890
891 fs.symlinkSync = function(target, path, type) {
892   type = (typeof type === 'string' ? type : null);
893
894   nullCheck(target);
895   nullCheck(path);
896
897   return binding.symlink(preprocessSymlinkDestination(target, type, path),
898                          pathModule._makeLong(path),
899                          type);
900 };
901
902 fs.link = function(srcpath, dstpath, callback) {
903   callback = makeCallback(callback);
904   if (!nullCheck(srcpath, callback)) return;
905   if (!nullCheck(dstpath, callback)) return;
906
907   var req = new FSReqWrap();
908   req.oncomplete = callback;
909
910   binding.link(pathModule._makeLong(srcpath),
911                pathModule._makeLong(dstpath),
912                req);
913 };
914
915 fs.linkSync = function(srcpath, dstpath) {
916   nullCheck(srcpath);
917   nullCheck(dstpath);
918   return binding.link(pathModule._makeLong(srcpath),
919                       pathModule._makeLong(dstpath));
920 };
921
922 fs.unlink = function(path, callback) {
923   callback = makeCallback(callback);
924   if (!nullCheck(path, callback)) return;
925   var req = new FSReqWrap();
926   req.oncomplete = callback;
927   binding.unlink(pathModule._makeLong(path), req);
928 };
929
930 fs.unlinkSync = function(path) {
931   nullCheck(path);
932   return binding.unlink(pathModule._makeLong(path));
933 };
934
935 fs.fchmod = function(fd, mode, callback) {
936   var req = new FSReqWrap();
937   req.oncomplete = makeCallback(callback);
938   binding.fchmod(fd, modeNum(mode), req);
939 };
940
941 fs.fchmodSync = function(fd, mode) {
942   return binding.fchmod(fd, modeNum(mode));
943 };
944
945 if (constants.hasOwnProperty('O_SYMLINK')) {
946   fs.lchmod = function(path, mode, callback) {
947     callback = maybeCallback(callback);
948     fs.open(path, constants.O_WRONLY | constants.O_SYMLINK, function(err, fd) {
949       if (err) {
950         callback(err);
951         return;
952       }
953       // prefer to return the chmod error, if one occurs,
954       // but still try to close, and report closing errors if they occur.
955       fs.fchmod(fd, mode, function(err) {
956         fs.close(fd, function(err2) {
957           callback(err || err2);
958         });
959       });
960     });
961   };
962
963   fs.lchmodSync = function(path, mode) {
964     var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK);
965
966     // prefer to return the chmod error, if one occurs,
967     // but still try to close, and report closing errors if they occur.
968     var err, err2, ret;
969     try {
970       ret = fs.fchmodSync(fd, mode);
971     } catch (er) {
972       err = er;
973     }
974     try {
975       fs.closeSync(fd);
976     } catch (er) {
977       err2 = er;
978     }
979     if (err || err2) throw (err || err2);
980     return ret;
981   };
982 }
983
984
985 fs.chmod = function(path, mode, callback) {
986   callback = makeCallback(callback);
987   if (!nullCheck(path, callback)) return;
988   var req = new FSReqWrap();
989   req.oncomplete = callback;
990   binding.chmod(pathModule._makeLong(path),
991                 modeNum(mode),
992                 req);
993 };
994
995 fs.chmodSync = function(path, mode) {
996   nullCheck(path);
997   return binding.chmod(pathModule._makeLong(path), modeNum(mode));
998 };
999
1000 if (constants.hasOwnProperty('O_SYMLINK')) {
1001   fs.lchown = function(path, uid, gid, callback) {
1002     callback = maybeCallback(callback);
1003     fs.open(path, constants.O_WRONLY | constants.O_SYMLINK, function(err, fd) {
1004       if (err) {
1005         callback(err);
1006         return;
1007       }
1008       fs.fchown(fd, uid, gid, callback);
1009     });
1010   };
1011
1012   fs.lchownSync = function(path, uid, gid) {
1013     var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK);
1014     return fs.fchownSync(fd, uid, gid);
1015   };
1016 }
1017
1018 fs.fchown = function(fd, uid, gid, callback) {
1019   var req = new FSReqWrap();
1020   req.oncomplete = makeCallback(callback);
1021   binding.fchown(fd, uid, gid, req);
1022 };
1023
1024 fs.fchownSync = function(fd, uid, gid) {
1025   return binding.fchown(fd, uid, gid);
1026 };
1027
1028 fs.chown = function(path, uid, gid, callback) {
1029   callback = makeCallback(callback);
1030   if (!nullCheck(path, callback)) return;
1031   var req = new FSReqWrap();
1032   req.oncomplete = callback;
1033   binding.chown(pathModule._makeLong(path), uid, gid, req);
1034 };
1035
1036 fs.chownSync = function(path, uid, gid) {
1037   nullCheck(path);
1038   return binding.chown(pathModule._makeLong(path), uid, gid);
1039 };
1040
1041 // converts Date or number to a fractional UNIX timestamp
1042 function toUnixTimestamp(time) {
1043   if (typeof time === 'string' && +time == time) {
1044     return +time;
1045   }
1046   if (typeof time === 'number') {
1047     if (!Number.isFinite(time) || time < 0) {
1048       return Date.now() / 1000;
1049     }
1050     return time;
1051   }
1052   if (util.isDate(time)) {
1053     // convert to 123.456 UNIX timestamp
1054     return time.getTime() / 1000;
1055   }
1056   throw new Error('Cannot parse time: ' + time);
1057 }
1058
1059 // exported for unit tests, not for public consumption
1060 fs._toUnixTimestamp = toUnixTimestamp;
1061
1062 fs.utimes = function(path, atime, mtime, callback) {
1063   callback = makeCallback(callback);
1064   if (!nullCheck(path, callback)) return;
1065   var req = new FSReqWrap();
1066   req.oncomplete = callback;
1067   binding.utimes(pathModule._makeLong(path),
1068                  toUnixTimestamp(atime),
1069                  toUnixTimestamp(mtime),
1070                  req);
1071 };
1072
1073 fs.utimesSync = function(path, atime, mtime) {
1074   nullCheck(path);
1075   atime = toUnixTimestamp(atime);
1076   mtime = toUnixTimestamp(mtime);
1077   binding.utimes(pathModule._makeLong(path), atime, mtime);
1078 };
1079
1080 fs.futimes = function(fd, atime, mtime, callback) {
1081   atime = toUnixTimestamp(atime);
1082   mtime = toUnixTimestamp(mtime);
1083   var req = new FSReqWrap();
1084   req.oncomplete = makeCallback(callback);
1085   binding.futimes(fd, atime, mtime, req);
1086 };
1087
1088 fs.futimesSync = function(fd, atime, mtime) {
1089   atime = toUnixTimestamp(atime);
1090   mtime = toUnixTimestamp(mtime);
1091   binding.futimes(fd, atime, mtime);
1092 };
1093
1094 function writeAll(fd, buffer, offset, length, position, callback_) {
1095   var callback = maybeCallback(arguments[arguments.length - 1]);
1096
1097   // write(fd, buffer, offset, length, position, callback)
1098   fs.write(fd, buffer, offset, length, position, function(writeErr, written) {
1099     if (writeErr) {
1100       fs.close(fd, function() {
1101         if (callback) callback(writeErr);
1102       });
1103     } else {
1104       if (written === length) {
1105         fs.close(fd, callback);
1106       } else {
1107         offset += written;
1108         length -= written;
1109         if (position !== null) {
1110           position += written;
1111         }
1112         writeAll(fd, buffer, offset, length, position, callback);
1113       }
1114     }
1115   });
1116 }
1117
1118 fs.writeFile = function(path, data, options, callback_) {
1119   var callback = maybeCallback(arguments[arguments.length - 1]);
1120
1121   if (!options || typeof options === 'function') {
1122     options = { encoding: 'utf8', mode: 0o666, flag: 'w' };
1123   } else if (typeof options === 'string') {
1124     options = { encoding: options, mode: 0o666, flag: 'w' };
1125   } else if (typeof options !== 'object') {
1126     throwOptionsError(options);
1127   }
1128
1129   assertEncoding(options.encoding);
1130
1131   var flag = options.flag || 'w';
1132   fs.open(path, flag, options.mode, function(openErr, fd) {
1133     if (openErr) {
1134       if (callback) callback(openErr);
1135     } else {
1136       var buffer = (data instanceof Buffer) ? data : new Buffer('' + data,
1137           options.encoding || 'utf8');
1138       var position = /a/.test(flag) ? null : 0;
1139       writeAll(fd, buffer, 0, buffer.length, position, callback);
1140     }
1141   });
1142 };
1143
1144 fs.writeFileSync = function(path, data, options) {
1145   if (!options) {
1146     options = { encoding: 'utf8', mode: 0o666, flag: 'w' };
1147   } else if (typeof options === 'string') {
1148     options = { encoding: options, mode: 0o666, flag: 'w' };
1149   } else if (typeof options !== 'object') {
1150     throwOptionsError(options);
1151   }
1152
1153   assertEncoding(options.encoding);
1154
1155   var flag = options.flag || 'w';
1156   var fd = fs.openSync(path, flag, options.mode);
1157   if (!(data instanceof Buffer)) {
1158     data = new Buffer('' + data, options.encoding || 'utf8');
1159   }
1160   var offset = 0;
1161   var length = data.length;
1162   var position = /a/.test(flag) ? null : 0;
1163   try {
1164     while (length > 0) {
1165       var written = fs.writeSync(fd, data, offset, length, position);
1166       offset += written;
1167       length -= written;
1168       if (position !== null) {
1169         position += written;
1170       }
1171     }
1172   } finally {
1173     fs.closeSync(fd);
1174   }
1175 };
1176
1177 fs.appendFile = function(path, data, options, callback_) {
1178   var callback = maybeCallback(arguments[arguments.length - 1]);
1179
1180   if (!options || typeof options === 'function') {
1181     options = { encoding: 'utf8', mode: 0o666, flag: 'a' };
1182   } else if (typeof options === 'string') {
1183     options = { encoding: options, mode: 0o666, flag: 'a' };
1184   } else if (typeof options !== 'object') {
1185     throwOptionsError(options);
1186   }
1187
1188   if (!options.flag)
1189     options = util._extend({ flag: 'a' }, options);
1190   fs.writeFile(path, data, options, callback);
1191 };
1192
1193 fs.appendFileSync = function(path, data, options) {
1194   if (!options) {
1195     options = { encoding: 'utf8', mode: 0o666, flag: 'a' };
1196   } else if (typeof options === 'string') {
1197     options = { encoding: options, mode: 0o666, flag: 'a' };
1198   } else if (typeof options !== 'object') {
1199     throwOptionsError(options);
1200   }
1201   if (!options.flag)
1202     options = util._extend({ flag: 'a' }, options);
1203
1204   fs.writeFileSync(path, data, options);
1205 };
1206
1207 function FSWatcher() {
1208   EventEmitter.call(this);
1209
1210   var self = this;
1211   this._handle = new FSEvent();
1212   this._handle.owner = this;
1213
1214   this._handle.onchange = function(status, event, filename) {
1215     if (status < 0) {
1216       self._handle.close();
1217       const error = errnoException(status, `watch ${filename}`);
1218       error.filename = filename;
1219       self.emit('error', error);
1220     } else {
1221       self.emit('change', event, filename);
1222     }
1223   };
1224 }
1225 util.inherits(FSWatcher, EventEmitter);
1226
1227 FSWatcher.prototype.start = function(filename, persistent, recursive) {
1228   nullCheck(filename);
1229   var err = this._handle.start(pathModule._makeLong(filename),
1230                                persistent,
1231                                recursive);
1232   if (err) {
1233     this._handle.close();
1234     const error = errnoException(err, `watch ${filename}`);
1235     error.filename = filename;
1236     throw error;
1237   }
1238 };
1239
1240 FSWatcher.prototype.close = function() {
1241   this._handle.close();
1242 };
1243
1244 fs.watch = function(filename) {
1245   nullCheck(filename);
1246   var watcher;
1247   var options;
1248   var listener;
1249
1250   if (arguments[1] !== null && typeof arguments[1] === 'object') {
1251     options = arguments[1];
1252     listener = arguments[2];
1253   } else {
1254     options = {};
1255     listener = arguments[1];
1256   }
1257
1258   if (options.persistent === undefined) options.persistent = true;
1259   if (options.recursive === undefined) options.recursive = false;
1260
1261   watcher = new FSWatcher();
1262   watcher.start(filename, options.persistent, options.recursive);
1263
1264   if (listener) {
1265     watcher.addListener('change', listener);
1266   }
1267
1268   return watcher;
1269 };
1270
1271
1272 // Stat Change Watchers
1273
1274 function StatWatcher() {
1275   EventEmitter.call(this);
1276
1277   var self = this;
1278   this._handle = new binding.StatWatcher();
1279
1280   // uv_fs_poll is a little more powerful than ev_stat but we curb it for
1281   // the sake of backwards compatibility
1282   var oldStatus = -1;
1283
1284   this._handle.onchange = function(current, previous, newStatus) {
1285     if (oldStatus === -1 &&
1286         newStatus === -1 &&
1287         current.nlink === previous.nlink) return;
1288
1289     oldStatus = newStatus;
1290     self.emit('change', current, previous);
1291   };
1292
1293   this._handle.onstop = function() {
1294     self.emit('stop');
1295   };
1296 }
1297 util.inherits(StatWatcher, EventEmitter);
1298
1299
1300 StatWatcher.prototype.start = function(filename, persistent, interval) {
1301   nullCheck(filename);
1302   this._handle.start(pathModule._makeLong(filename), persistent, interval);
1303 };
1304
1305
1306 StatWatcher.prototype.stop = function() {
1307   this._handle.stop();
1308 };
1309
1310
1311 const statWatchers = new Map();
1312
1313 fs.watchFile = function(filename, options, listener) {
1314   nullCheck(filename);
1315   filename = pathModule.resolve(filename);
1316   var stat;
1317
1318   var defaults = {
1319     // Poll interval in milliseconds. 5007 is what libev used to use. It's
1320     // a little on the slow side but let's stick with it for now to keep
1321     // behavioral changes to a minimum.
1322     interval: 5007,
1323     persistent: true
1324   };
1325
1326   if (options !== null && typeof options === 'object') {
1327     options = util._extend(defaults, options);
1328   } else {
1329     listener = options;
1330     options = defaults;
1331   }
1332
1333   if (typeof listener !== 'function') {
1334     throw new Error('watchFile requires a listener function');
1335   }
1336
1337   stat = statWatchers.get(filename);
1338
1339   if (stat === undefined) {
1340     stat = new StatWatcher();
1341     stat.start(filename, options.persistent, options.interval);
1342     statWatchers.set(filename, stat);
1343   }
1344
1345   stat.addListener('change', listener);
1346   return stat;
1347 };
1348
1349 fs.unwatchFile = function(filename, listener) {
1350   nullCheck(filename);
1351   filename = pathModule.resolve(filename);
1352   var stat = statWatchers.get(filename);
1353
1354   if (stat === undefined) return;
1355
1356   if (typeof listener === 'function') {
1357     stat.removeListener('change', listener);
1358   } else {
1359     stat.removeAllListeners('change');
1360   }
1361
1362   if (stat.listenerCount('change') === 0) {
1363     stat.stop();
1364     statWatchers.delete(filename);
1365   }
1366 };
1367
1368 // Regexp that finds the next partion of a (partial) path
1369 // result is [base_with_slash, base], e.g. ['somedir/', 'somedir']
1370 if (isWindows) {
1371   var nextPartRe = /(.*?)(?:[\/\\]+|$)/g;
1372 } else {
1373   var nextPartRe = /(.*?)(?:[\/]+|$)/g;
1374 }
1375
1376 // Regex to find the device root, including trailing slash. E.g. 'c:\\'.
1377 if (isWindows) {
1378   var splitRootRe = /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/;
1379 } else {
1380   var splitRootRe = /^[\/]*/;
1381 }
1382
1383 fs.realpathSync = function realpathSync(p, cache) {
1384   // make p is absolute
1385   p = pathModule.resolve(p);
1386
1387   if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
1388     return cache[p];
1389   }
1390
1391   var original = p,
1392       seenLinks = {},
1393       knownHard = {};
1394
1395   // current character position in p
1396   var pos;
1397   // the partial path so far, including a trailing slash if any
1398   var current;
1399   // the partial path without a trailing slash (except when pointing at a root)
1400   var base;
1401   // the partial path scanned in the previous round, with slash
1402   var previous;
1403
1404   start();
1405
1406   function start() {
1407     // Skip over roots
1408     var m = splitRootRe.exec(p);
1409     pos = m[0].length;
1410     current = m[0];
1411     base = m[0];
1412     previous = '';
1413
1414     // On windows, check that the root exists. On unix there is no need.
1415     if (isWindows && !knownHard[base]) {
1416       fs.lstatSync(base);
1417       knownHard[base] = true;
1418     }
1419   }
1420
1421   // walk down the path, swapping out linked pathparts for their real
1422   // values
1423   // NB: p.length changes.
1424   while (pos < p.length) {
1425     // find the next part
1426     nextPartRe.lastIndex = pos;
1427     var result = nextPartRe.exec(p);
1428     previous = current;
1429     current += result[0];
1430     base = previous + result[1];
1431     pos = nextPartRe.lastIndex;
1432
1433     // continue if not a symlink
1434     if (knownHard[base] || (cache && cache[base] === base)) {
1435       continue;
1436     }
1437
1438     var resolvedLink;
1439     if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
1440       // some known symbolic link.  no need to stat again.
1441       resolvedLink = cache[base];
1442     } else {
1443       var stat = fs.lstatSync(base);
1444       if (!stat.isSymbolicLink()) {
1445         knownHard[base] = true;
1446         if (cache) cache[base] = base;
1447         continue;
1448       }
1449
1450       // read the link if it wasn't read before
1451       // dev/ino always return 0 on windows, so skip the check.
1452       var linkTarget = null;
1453       if (!isWindows) {
1454         var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
1455         if (seenLinks.hasOwnProperty(id)) {
1456           linkTarget = seenLinks[id];
1457         }
1458       }
1459       if (linkTarget === null) {
1460         fs.statSync(base);
1461         linkTarget = fs.readlinkSync(base);
1462       }
1463       resolvedLink = pathModule.resolve(previous, linkTarget);
1464       // track this, if given a cache.
1465       if (cache) cache[base] = resolvedLink;
1466       if (!isWindows) seenLinks[id] = linkTarget;
1467     }
1468
1469     // resolve the link, then start over
1470     p = pathModule.resolve(resolvedLink, p.slice(pos));
1471     start();
1472   }
1473
1474   if (cache) cache[original] = p;
1475
1476   return p;
1477 };
1478
1479
1480 fs.realpath = function realpath(p, cache, cb) {
1481   if (typeof cb !== 'function') {
1482     cb = maybeCallback(cache);
1483     cache = null;
1484   }
1485
1486   // make p is absolute
1487   p = pathModule.resolve(p);
1488
1489   if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
1490     return process.nextTick(cb.bind(null, null, cache[p]));
1491   }
1492
1493   var original = p,
1494       seenLinks = {},
1495       knownHard = {};
1496
1497   // current character position in p
1498   var pos;
1499   // the partial path so far, including a trailing slash if any
1500   var current;
1501   // the partial path without a trailing slash (except when pointing at a root)
1502   var base;
1503   // the partial path scanned in the previous round, with slash
1504   var previous;
1505
1506   start();
1507
1508   function start() {
1509     // Skip over roots
1510     var m = splitRootRe.exec(p);
1511     pos = m[0].length;
1512     current = m[0];
1513     base = m[0];
1514     previous = '';
1515
1516     // On windows, check that the root exists. On unix there is no need.
1517     if (isWindows && !knownHard[base]) {
1518       fs.lstat(base, function(err) {
1519         if (err) return cb(err);
1520         knownHard[base] = true;
1521         LOOP();
1522       });
1523     } else {
1524       process.nextTick(LOOP);
1525     }
1526   }
1527
1528   // walk down the path, swapping out linked pathparts for their real
1529   // values
1530   function LOOP() {
1531     // stop if scanned past end of path
1532     if (pos >= p.length) {
1533       if (cache) cache[original] = p;
1534       return cb(null, p);
1535     }
1536
1537     // find the next part
1538     nextPartRe.lastIndex = pos;
1539     var result = nextPartRe.exec(p);
1540     previous = current;
1541     current += result[0];
1542     base = previous + result[1];
1543     pos = nextPartRe.lastIndex;
1544
1545     // continue if not a symlink
1546     if (knownHard[base] || (cache && cache[base] === base)) {
1547       return process.nextTick(LOOP);
1548     }
1549
1550     if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
1551       // known symbolic link.  no need to stat again.
1552       return gotResolvedLink(cache[base]);
1553     }
1554
1555     return fs.lstat(base, gotStat);
1556   }
1557
1558   function gotStat(err, stat) {
1559     if (err) return cb(err);
1560
1561     // if not a symlink, skip to the next path part
1562     if (!stat.isSymbolicLink()) {
1563       knownHard[base] = true;
1564       if (cache) cache[base] = base;
1565       return process.nextTick(LOOP);
1566     }
1567
1568     // stat & read the link if not read before
1569     // call gotTarget as soon as the link target is known
1570     // dev/ino always return 0 on windows, so skip the check.
1571     if (!isWindows) {
1572       var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
1573       if (seenLinks.hasOwnProperty(id)) {
1574         return gotTarget(null, seenLinks[id], base);
1575       }
1576     }
1577     fs.stat(base, function(err) {
1578       if (err) return cb(err);
1579
1580       fs.readlink(base, function(err, target) {
1581         if (!isWindows) seenLinks[id] = target;
1582         gotTarget(err, target);
1583       });
1584     });
1585   }
1586
1587   function gotTarget(err, target, base) {
1588     if (err) return cb(err);
1589
1590     var resolvedLink = pathModule.resolve(previous, target);
1591     if (cache) cache[base] = resolvedLink;
1592     gotResolvedLink(resolvedLink);
1593   }
1594
1595   function gotResolvedLink(resolvedLink) {
1596     // resolve the link, then start over
1597     p = pathModule.resolve(resolvedLink, p.slice(pos));
1598     start();
1599   }
1600 };
1601
1602
1603 var pool;
1604
1605 function allocNewPool(poolSize) {
1606   pool = new Buffer(poolSize);
1607   pool.used = 0;
1608 }
1609
1610
1611 fs.createReadStream = function(path, options) {
1612   return new ReadStream(path, options);
1613 };
1614
1615 util.inherits(ReadStream, Readable);
1616 fs.ReadStream = ReadStream;
1617
1618 function ReadStream(path, options) {
1619   if (!(this instanceof ReadStream))
1620     return new ReadStream(path, options);
1621
1622   if (options === undefined)
1623     options = {};
1624   else if (typeof options === 'string')
1625     options = { encoding: options };
1626   else if (options === null || typeof options !== 'object')
1627     throw new TypeError('options must be a string or an object');
1628
1629   // a little bit bigger buffer and water marks by default
1630   options = Object.create(options);
1631   if (options.highWaterMark === undefined)
1632     options.highWaterMark = 64 * 1024;
1633
1634   Readable.call(this, options);
1635
1636   this.path = path;
1637   this.fd = options.fd === undefined ? null : options.fd;
1638   this.flags = options.flags === undefined ? 'r' : options.flags;
1639   this.mode = options.mode === undefined ? 0o666 : options.mode;
1640
1641   this.start = options.start;
1642   this.end = options.end;
1643   this.autoClose = options.autoClose === undefined ? true : options.autoClose;
1644   this.pos = undefined;
1645
1646   if (this.start !== undefined) {
1647     if (typeof this.start !== 'number') {
1648       throw new TypeError('start must be a Number');
1649     }
1650     if (this.end === undefined) {
1651       this.end = Infinity;
1652     } else if (typeof this.end !== 'number') {
1653       throw new TypeError('end must be a Number');
1654     }
1655
1656     if (this.start > this.end) {
1657       throw new Error('start must be <= end');
1658     }
1659
1660     this.pos = this.start;
1661   }
1662
1663   if (typeof this.fd !== 'number')
1664     this.open();
1665
1666   this.on('end', function() {
1667     if (this.autoClose) {
1668       this.destroy();
1669     }
1670   });
1671 }
1672
1673 fs.FileReadStream = fs.ReadStream; // support the legacy name
1674
1675 ReadStream.prototype.open = function() {
1676   var self = this;
1677   fs.open(this.path, this.flags, this.mode, function(er, fd) {
1678     if (er) {
1679       if (self.autoClose) {
1680         self.destroy();
1681       }
1682       self.emit('error', er);
1683       return;
1684     }
1685
1686     self.fd = fd;
1687     self.emit('open', fd);
1688     // start the flow of data.
1689     self.read();
1690   });
1691 };
1692
1693 ReadStream.prototype._read = function(n) {
1694   if (typeof this.fd !== 'number')
1695     return this.once('open', function() {
1696       this._read(n);
1697     });
1698
1699   if (this.destroyed)
1700     return;
1701
1702   if (!pool || pool.length - pool.used < kMinPoolSpace) {
1703     // discard the old pool.
1704     pool = null;
1705     allocNewPool(this._readableState.highWaterMark);
1706   }
1707
1708   // Grab another reference to the pool in the case that while we're
1709   // in the thread pool another read() finishes up the pool, and
1710   // allocates a new one.
1711   var thisPool = pool;
1712   var toRead = Math.min(pool.length - pool.used, n);
1713   var start = pool.used;
1714
1715   if (this.pos !== undefined)
1716     toRead = Math.min(this.end - this.pos + 1, toRead);
1717
1718   // already read everything we were supposed to read!
1719   // treat as EOF.
1720   if (toRead <= 0)
1721     return this.push(null);
1722
1723   // the actual read.
1724   var self = this;
1725   fs.read(this.fd, pool, pool.used, toRead, this.pos, onread);
1726
1727   // move the pool positions, and internal position for reading.
1728   if (this.pos !== undefined)
1729     this.pos += toRead;
1730   pool.used += toRead;
1731
1732   function onread(er, bytesRead) {
1733     if (er) {
1734       if (self.autoClose) {
1735         self.destroy();
1736       }
1737       self.emit('error', er);
1738     } else {
1739       var b = null;
1740       if (bytesRead > 0)
1741         b = thisPool.slice(start, start + bytesRead);
1742
1743       self.push(b);
1744     }
1745   }
1746 };
1747
1748
1749 ReadStream.prototype.destroy = function() {
1750   if (this.destroyed)
1751     return;
1752   this.destroyed = true;
1753   this.close();
1754 };
1755
1756
1757 ReadStream.prototype.close = function(cb) {
1758   var self = this;
1759   if (cb)
1760     this.once('close', cb);
1761   if (this.closed || typeof this.fd !== 'number') {
1762     if (typeof this.fd !== 'number') {
1763       this.once('open', close);
1764       return;
1765     }
1766     return process.nextTick(this.emit.bind(this, 'close'));
1767   }
1768   this.closed = true;
1769   close();
1770
1771   function close(fd) {
1772     fs.close(fd || self.fd, function(er) {
1773       if (er)
1774         self.emit('error', er);
1775       else
1776         self.emit('close');
1777     });
1778     self.fd = null;
1779   }
1780 };
1781
1782
1783 fs.createWriteStream = function(path, options) {
1784   return new WriteStream(path, options);
1785 };
1786
1787 util.inherits(WriteStream, Writable);
1788 fs.WriteStream = WriteStream;
1789 function WriteStream(path, options) {
1790   if (!(this instanceof WriteStream))
1791     return new WriteStream(path, options);
1792
1793   if (options === undefined)
1794     options = {};
1795   else if (typeof options === 'string')
1796     options = { encoding: options };
1797   else if (options === null || typeof options !== 'object')
1798     throw new TypeError('options must be a string or an object');
1799
1800   options = Object.create(options);
1801
1802   Writable.call(this, options);
1803
1804   this.path = path;
1805   this.fd = options.fd === undefined ? null : options.fd;
1806   this.flags = options.flags === undefined ? 'w' : options.flags;
1807   this.mode = options.mode === undefined ? 0o666 : options.mode;
1808
1809   this.start = options.start;
1810   this.pos = undefined;
1811   this.bytesWritten = 0;
1812
1813   if (this.start !== undefined) {
1814     if (typeof this.start !== 'number') {
1815       throw new TypeError('start must be a Number');
1816     }
1817     if (this.start < 0) {
1818       throw new Error('start must be >= zero');
1819     }
1820
1821     this.pos = this.start;
1822   }
1823
1824   if (options.encoding)
1825     this.setDefaultEncoding(options.encoding);
1826
1827   if (typeof this.fd !== 'number')
1828     this.open();
1829
1830   // dispose on finish.
1831   this.once('finish', this.close);
1832 }
1833
1834 fs.FileWriteStream = fs.WriteStream; // support the legacy name
1835
1836
1837 WriteStream.prototype.open = function() {
1838   fs.open(this.path, this.flags, this.mode, function(er, fd) {
1839     if (er) {
1840       this.destroy();
1841       this.emit('error', er);
1842       return;
1843     }
1844
1845     this.fd = fd;
1846     this.emit('open', fd);
1847   }.bind(this));
1848 };
1849
1850
1851 WriteStream.prototype._write = function(data, encoding, cb) {
1852   if (!(data instanceof Buffer))
1853     return this.emit('error', new Error('Invalid data'));
1854
1855   if (typeof this.fd !== 'number')
1856     return this.once('open', function() {
1857       this._write(data, encoding, cb);
1858     });
1859
1860   var self = this;
1861   fs.write(this.fd, data, 0, data.length, this.pos, function(er, bytes) {
1862     if (er) {
1863       self.destroy();
1864       return cb(er);
1865     }
1866     self.bytesWritten += bytes;
1867     cb();
1868   });
1869
1870   if (this.pos !== undefined)
1871     this.pos += data.length;
1872 };
1873
1874
1875 function writev(fd, chunks, position, callback) {
1876   function wrapper(err, written) {
1877     // Retain a reference to chunks so that they can't be GC'ed too soon.
1878     callback(err, written || 0, chunks);
1879   }
1880
1881   const req = new FSReqWrap();
1882   req.oncomplete = wrapper;
1883   binding.writeBuffers(fd, chunks, position, req);
1884 }
1885
1886
1887 WriteStream.prototype._writev = function(data, cb) {
1888   if (typeof this.fd !== 'number')
1889     return this.once('open', function() {
1890       this._writev(data, cb);
1891     });
1892
1893   const self = this;
1894   const len = data.length;
1895   const chunks = new Array(len);
1896   var size = 0;
1897
1898   for (var i = 0; i < len; i++) {
1899     var chunk = data[i].chunk;
1900
1901     chunks[i] = chunk;
1902     size += chunk.length;
1903   }
1904
1905   writev(this.fd, chunks, this.pos, function(er, bytes) {
1906     if (er) {
1907       self.destroy();
1908       return cb(er);
1909     }
1910     self.bytesWritten += bytes;
1911     cb();
1912   });
1913
1914   if (this.pos !== undefined)
1915     this.pos += size;
1916 };
1917
1918
1919 WriteStream.prototype.destroy = ReadStream.prototype.destroy;
1920 WriteStream.prototype.close = ReadStream.prototype.close;
1921
1922 // There is no shutdown() for files.
1923 WriteStream.prototype.destroySoon = WriteStream.prototype.end;
1924
1925
1926 // SyncWriteStream is internal. DO NOT USE.
1927 // Temporary hack for process.stdout and process.stderr when piped to files.
1928 function SyncWriteStream(fd, options) {
1929   Stream.call(this);
1930
1931   options = options || {};
1932
1933   this.fd = fd;
1934   this.writable = true;
1935   this.readable = false;
1936   this.autoClose = options.autoClose === undefined ? true : options.autoClose;
1937 }
1938
1939 util.inherits(SyncWriteStream, Stream);
1940
1941
1942 // Export
1943 Object.defineProperty(fs, 'SyncWriteStream', {
1944     configurable: true,
1945     writable: true,
1946     value: SyncWriteStream
1947 });
1948
1949 SyncWriteStream.prototype.write = function(data, arg1, arg2) {
1950   var encoding, cb;
1951
1952   // parse arguments
1953   if (arg1) {
1954     if (typeof arg1 === 'string') {
1955       encoding = arg1;
1956       cb = arg2;
1957     } else if (typeof arg1 === 'function') {
1958       cb = arg1;
1959     } else {
1960       throw new Error('bad arg');
1961     }
1962   }
1963   assertEncoding(encoding);
1964
1965   // Change strings to buffers. SLOW
1966   if (typeof data === 'string') {
1967     data = new Buffer(data, encoding);
1968   }
1969
1970   fs.writeSync(this.fd, data, 0, data.length);
1971
1972   if (cb) {
1973     process.nextTick(cb);
1974   }
1975
1976   return true;
1977 };
1978
1979
1980 SyncWriteStream.prototype.end = function(data, arg1, arg2) {
1981   if (data) {
1982     this.write(data, arg1, arg2);
1983   }
1984   this.destroy();
1985 };
1986
1987
1988 SyncWriteStream.prototype.destroy = function() {
1989   if (this.autoClose)
1990     fs.closeSync(this.fd);
1991   this.fd = null;
1992   this.emit('close');
1993   return true;
1994 };
1995
1996 SyncWriteStream.prototype.destroySoon = SyncWriteStream.prototype.destroy;