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