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