UNPKG

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