UNPKG

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