UNPKG

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