The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / lib / fs.js @ cc08106d

History | View | Annotate | Download (44.6 KB)

1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21

    
22
// Maintainers, keep in mind that octal literals are not allowed
23
// in strict mode. Use the decimal value and add a comment with
24
// the octal value. Example:
25
//
26
//   var mode = 438; /* mode=0666 */
27

    
28
var util = require('util');
29
var pathModule = require('path');
30

    
31
var binding = process.binding('fs');
32
var constants = process.binding('constants');
33
var fs = exports;
34
var Stream = require('stream').Stream;
35
var EventEmitter = require('events').EventEmitter;
36

    
37
var Readable = Stream.Readable;
38
var Writable = Stream.Writable;
39

    
40
var kMinPoolSpace = 128;
41

    
42
var O_APPEND = constants.O_APPEND || 0;
43
var O_CREAT = constants.O_CREAT || 0;
44
var O_DIRECTORY = constants.O_DIRECTORY || 0;
45
var O_EXCL = constants.O_EXCL || 0;
46
var O_NOCTTY = constants.O_NOCTTY || 0;
47
var O_NOFOLLOW = constants.O_NOFOLLOW || 0;
48
var O_RDONLY = constants.O_RDONLY || 0;
49
var O_RDWR = constants.O_RDWR || 0;
50
var O_SYMLINK = constants.O_SYMLINK || 0;
51
var O_SYNC = constants.O_SYNC || 0;
52
var O_TRUNC = constants.O_TRUNC || 0;
53
var O_WRONLY = constants.O_WRONLY || 0;
54

    
55
var isWindows = process.platform === 'win32';
56

    
57
var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG);
58

    
59
function rethrow() {
60
  // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and
61
  // is fairly slow to generate.
62
  var callback;
63
  if (DEBUG) {
64
    var backtrace = new Error;
65
    callback = debugCallback;
66
  } else
67
    callback = missingCallback;
68

    
69
  return callback;
70

    
71
  function debugCallback(err) {
72
    if (err) {
73
      backtrace.message = err.message;
74
      err = backtrace;
75
      missingCallback(err);
76
    }
77
  }
78

    
79
  function missingCallback(err) {
80
    if (err) {
81
      if (process.throwDeprecation)
82
        throw err;  // Forgot a callback but don't know where? Use NODE_DEBUG=fs
83
      else if (!process.noDeprecation) {
84
        var msg = 'fs: missing callback ' + (err.stack || err.message);
85
        if (process.traceDeprecation)
86
          console.trace(msg);
87
        else
88
          console.error(msg);
89
      }
90
    }
91
  }
92
}
93

    
94
function maybeCallback(cb) {
95
  return typeof cb === 'function' ? cb : rethrow();
96
}
97

    
98
// Ensure that callbacks run in the global context. Only use this function
99
// for callbacks that are passed to the binding layer, callbacks that are
100
// invoked from JS already run in the proper scope.
101
function makeCallback(cb) {
102
  if (typeof cb !== 'function') {
103
    return rethrow();
104
  }
105

    
106
  return function() {
107
    return cb.apply(null, arguments);
108
  };
109
}
110

    
111
function assertEncoding(encoding) {
112
  if (encoding && !Buffer.isEncoding(encoding)) {
113
    throw new Error('Unknown encoding: ' + encoding);
114
  }
115
}
116

    
117
function nullCheck(path, callback) {
118
  if (('' + path).indexOf('\u0000') !== -1) {
119
    var er = new Error('Path must be a string without null bytes.');
120
    if (!callback)
121
      throw er;
122
    process.nextTick(function() {
123
      callback(er);
124
    });
125
    return false;
126
  }
127
  return true;
128
}
129

    
130
fs.Stats = binding.Stats;
131

    
132
fs.Stats.prototype._checkModeProperty = function(property) {
133
  return ((this.mode & constants.S_IFMT) === property);
134
};
135

    
136
fs.Stats.prototype.isDirectory = function() {
137
  return this._checkModeProperty(constants.S_IFDIR);
138
};
139

    
140
fs.Stats.prototype.isFile = function() {
141
  return this._checkModeProperty(constants.S_IFREG);
142
};
143

    
144
fs.Stats.prototype.isBlockDevice = function() {
145
  return this._checkModeProperty(constants.S_IFBLK);
146
};
147

    
148
fs.Stats.prototype.isCharacterDevice = function() {
149
  return this._checkModeProperty(constants.S_IFCHR);
150
};
151

    
152
fs.Stats.prototype.isSymbolicLink = function() {
153
  return this._checkModeProperty(constants.S_IFLNK);
154
};
155

    
156
fs.Stats.prototype.isFIFO = function() {
157
  return this._checkModeProperty(constants.S_IFIFO);
158
};
159

    
160
fs.Stats.prototype.isSocket = function() {
161
  return this._checkModeProperty(constants.S_IFSOCK);
162
};
163

    
164
fs.exists = function(path, callback) {
165
  if (!nullCheck(path, cb)) return;
166
  binding.stat(pathModule._makeLong(path), cb);
167
  function cb(err, stats) {
168
    if (callback) callback(err ? false : true);
169
  }
170
};
171

    
172
fs.existsSync = function(path) {
173
  try {
174
    nullCheck(path);
175
    binding.stat(pathModule._makeLong(path));
176
    return true;
177
  } catch (e) {
178
    return false;
179
  }
180
};
181

    
182
fs.readFile = function(path, options, callback_) {
183
  var callback = maybeCallback(arguments[arguments.length - 1]);
184

    
185
  if (typeof options === 'function' || !options) {
186
    options = { encoding: null, flag: 'r' };
187
  } else if (typeof options === 'string') {
188
    options = { encoding: options, flag: 'r' };
189
  } else if (!options) {
190
    options = { encoding: null, flag: 'r' };
191
  } else if (typeof options !== 'object') {
192
    throw new TypeError('Bad arguments');
193
  }
194

    
195
  var encoding = options.encoding;
196
  assertEncoding(encoding);
197

    
198
  // first, stat the file, so we know the size.
199
  var size;
200
  var buffer; // single buffer with file data
201
  var buffers; // list for when size is unknown
202
  var pos = 0;
203
  var fd;
204

    
205
  var flag = options.flag || 'r';
206
  fs.open(path, flag, 438 /*=0666*/, function(er, fd_) {
207
    if (er) return callback(er);
208
    fd = fd_;
209

    
210
    fs.fstat(fd, function(er, st) {
211
      if (er) {
212
        return fs.close(fd, function() {
213
          callback(er);
214
        });
215
      }
216

    
217
      size = st.size;
218
      if (size === 0) {
219
        // the kernel lies about many files.
220
        // Go ahead and try to read some bytes.
221
        buffers = [];
222
        return read();
223
      }
224

    
225
      buffer = new Buffer(size);
226
      read();
227
    });
228
  });
229

    
230
  function read() {
231
    if (size === 0) {
232
      buffer = new Buffer(8192);
233
      fs.read(fd, buffer, 0, 8192, -1, afterRead);
234
    } else {
235
      fs.read(fd, buffer, pos, size - pos, -1, afterRead);
236
    }
237
  }
238

    
239
  function afterRead(er, bytesRead) {
240
    if (er) {
241
      return fs.close(fd, function(er2) {
242
        return callback(er);
243
      });
244
    }
245

    
246
    if (bytesRead === 0) {
247
      return close();
248
    }
249

    
250
    pos += bytesRead;
251
    if (size !== 0) {
252
      if (pos === size) close();
253
      else read();
254
    } else {
255
      // unknown size, just read until we don't get bytes.
256
      buffers.push(buffer.slice(0, bytesRead));
257
      read();
258
    }
259
  }
260

    
261
  function close() {
262
    fs.close(fd, function(er) {
263
      if (size === 0) {
264
        // collected the data into the buffers list.
265
        buffer = Buffer.concat(buffers, pos);
266
      } else if (pos < size) {
267
        buffer = buffer.slice(0, pos);
268
      }
269

    
270
      if (encoding) buffer = buffer.toString(encoding);
271
      return callback(er, buffer);
272
    });
273
  }
274
};
275

    
276
fs.readFileSync = function(path, options) {
277
  if (!options) {
278
    options = { encoding: null, flag: 'r' };
279
  } else if (typeof options === 'string') {
280
    options = { encoding: options, flag: 'r' };
281
  } else if (typeof options !== 'object') {
282
    throw new TypeError('Bad arguments');
283
  }
284

    
285
  var encoding = options.encoding;
286
  assertEncoding(encoding);
287

    
288
  var flag = options.flag || 'r';
289
  var fd = fs.openSync(path, flag, 438 /*=0666*/);
290

    
291
  var size;
292
  var threw = true;
293
  try {
294
    size = fs.fstatSync(fd).size;
295
    threw = false;
296
  } finally {
297
    if (threw) fs.closeSync(fd);
298
  }
299

    
300
  var pos = 0;
301
  var buffer; // single buffer with file data
302
  var buffers; // list for when size is unknown
303

    
304
  if (size === 0) {
305
    buffers = [];
306
  } else {
307
    var threw = true;
308
    try {
309
      buffer = new Buffer(size);
310
      threw = false;
311
    } finally {
312
      if (threw) fs.closeSync(fd);
313
    }
314
  }
315

    
316
  var done = false;
317
  while (!done) {
318
    var threw = true;
319
    try {
320
      if (size !== 0) {
321
        var bytesRead = fs.readSync(fd, buffer, pos, size - pos);
322
      } else {
323
        // the kernel lies about many files.
324
        // Go ahead and try to read some bytes.
325
        buffer = new Buffer(8192);
326
        var bytesRead = fs.readSync(fd, buffer, 0, 8192);
327
        if (bytesRead) {
328
          buffers.push(buffer.slice(0, bytesRead));
329
        }
330
      }
331
      threw = false;
332
    } finally {
333
      if (threw) fs.closeSync(fd);
334
    }
335

    
336
    pos += bytesRead;
337
    done = (bytesRead === 0) || (size !== 0 && pos >= size);
338
  }
339

    
340
  fs.closeSync(fd);
341

    
342
  if (size === 0) {
343
    // data was collected into the buffers list.
344
    buffer = Buffer.concat(buffers, pos);
345
  } else if (pos < size) {
346
    buffer = buffer.slice(0, pos);
347
  }
348

    
349
  if (encoding) buffer = buffer.toString(encoding);
350
  return buffer;
351
};
352

    
353

    
354
// Used by binding.open and friends
355
function stringToFlags(flag) {
356
  // Only mess with strings
357
  if (typeof flag !== 'string') {
358
    return flag;
359
  }
360

    
361
  // O_EXCL is mandated by POSIX, Windows supports it too.
362
  // Let's add a check anyway, just in case.
363
  if (!O_EXCL && ~flag.indexOf('x')) {
364
    throw errnoException('ENOSYS', 'fs.open(O_EXCL)');
365
  }
366

    
367
  switch (flag) {
368
    case 'r' : return O_RDONLY;
369
    case 'rs' : return O_RDONLY | O_SYNC;
370
    case 'r+' : return O_RDWR;
371
    case 'rs+' : return O_RDWR | O_SYNC;
372

    
373
    case 'w' : return O_TRUNC | O_CREAT | O_WRONLY;
374
    case 'wx' : // fall through
375
    case 'xw' : return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;
376

    
377
    case 'w+' : return O_TRUNC | O_CREAT | O_RDWR;
378
    case 'wx+': // fall through
379
    case 'xw+': return O_TRUNC | O_CREAT | O_RDWR | O_EXCL;
380

    
381
    case 'a' : return O_APPEND | O_CREAT | O_WRONLY;
382
    case 'ax' : // fall through
383
    case 'xa' : return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
384

    
385
    case 'a+' : return O_APPEND | O_CREAT | O_RDWR;
386
    case 'ax+': // fall through
387
    case 'xa+': return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
388
  }
389

    
390
  throw new Error('Unknown file open flag: ' + flag);
391
}
392

    
393
// exported but hidden, only used by test/simple/test-fs-open-flags.js
394
Object.defineProperty(exports, '_stringToFlags', {
395
  enumerable: false,
396
  value: stringToFlags
397
});
398

    
399

    
400
// Yes, the follow could be easily DRYed up but I provide the explicit
401
// list to make the arguments clear.
402

    
403
fs.close = function(fd, callback) {
404
  binding.close(fd, makeCallback(callback));
405
};
406

    
407
fs.closeSync = function(fd) {
408
  return binding.close(fd);
409
};
410

    
411
function modeNum(m, def) {
412
  switch (typeof m) {
413
    case 'number': return m;
414
    case 'string': return parseInt(m, 8);
415
    default:
416
      if (def) {
417
        return modeNum(def);
418
      } else {
419
        return undefined;
420
      }
421
  }
422
}
423

    
424
fs.open = function(path, flags, mode, callback) {
425
  callback = makeCallback(arguments[arguments.length - 1]);
426
  mode = modeNum(mode, 438 /*=0666*/);
427

    
428
  if (!nullCheck(path, callback)) return;
429
  binding.open(pathModule._makeLong(path),
430
               stringToFlags(flags),
431
               mode,
432
               callback);
433
};
434

    
435
fs.openSync = function(path, flags, mode) {
436
  mode = modeNum(mode, 438 /*=0666*/);
437
  nullCheck(path);
438
  return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
439
};
440

    
441
fs.read = function(fd, buffer, offset, length, position, callback) {
442
  if (!Buffer.isBuffer(buffer)) {
443
    // legacy string interface (fd, length, position, encoding, callback)
444
    var cb = arguments[4],
445
        encoding = arguments[3];
446

    
447
    assertEncoding(encoding);
448

    
449
    position = arguments[2];
450
    length = arguments[1];
451
    buffer = new Buffer(length);
452
    offset = 0;
453

    
454
    callback = function(err, bytesRead) {
455
      if (!cb) return;
456

    
457
      var str = (bytesRead > 0) ? buffer.toString(encoding, 0, bytesRead) : '';
458

    
459
      (cb)(err, str, bytesRead);
460
    };
461
  }
462

    
463
  function wrapper(err, bytesRead) {
464
    // Retain a reference to buffer so that it can't be GC'ed too soon.
465
    callback && callback(err, bytesRead || 0, buffer);
466
  }
467

    
468
  binding.read(fd, buffer, offset, length, position, wrapper);
469
};
470

    
471
fs.readSync = function(fd, buffer, offset, length, position) {
472
  var legacy = false;
473
  if (!Buffer.isBuffer(buffer)) {
474
    // legacy string interface (fd, length, position, encoding, callback)
475
    legacy = true;
476
    var encoding = arguments[3];
477

    
478
    assertEncoding(encoding);
479

    
480
    position = arguments[2];
481
    length = arguments[1];
482
    buffer = new Buffer(length);
483

    
484
    offset = 0;
485
  }
486

    
487
  var r = binding.read(fd, buffer, offset, length, position);
488
  if (!legacy) {
489
    return r;
490
  }
491

    
492
  var str = (r > 0) ? buffer.toString(encoding, 0, r) : '';
493
  return [str, r];
494
};
495

    
496
fs.write = function(fd, buffer, offset, length, position, callback) {
497
  if (!Buffer.isBuffer(buffer)) {
498
    // legacy string interface (fd, data, position, encoding, callback)
499
    callback = arguments[4];
500
    position = arguments[2];
501
    assertEncoding(arguments[3]);
502

    
503
    buffer = new Buffer('' + arguments[1], arguments[3]);
504
    offset = 0;
505
    length = buffer.length;
506
  }
507

    
508
  if (!length) {
509
    if (typeof callback == 'function') {
510
      process.nextTick(function() {
511
        callback(undefined, 0);
512
      });
513
    }
514
    return;
515
  }
516

    
517
  callback = maybeCallback(callback);
518

    
519
  function wrapper(err, written) {
520
    // Retain a reference to buffer so that it can't be GC'ed too soon.
521
    callback(err, written || 0, buffer);
522
  }
523

    
524
  binding.write(fd, buffer, offset, length, position, wrapper);
525
};
526

    
527
fs.writeSync = function(fd, buffer, offset, length, position) {
528
  if (!Buffer.isBuffer(buffer)) {
529
    // legacy string interface (fd, data, position, encoding)
530
    position = arguments[2];
531
    assertEncoding(arguments[3]);
532

    
533
    buffer = new Buffer('' + arguments[1], arguments[3]);
534
    offset = 0;
535
    length = buffer.length;
536
  }
537
  if (!length) return 0;
538

    
539
  return binding.write(fd, buffer, offset, length, position);
540
};
541

    
542
fs.rename = function(oldPath, newPath, callback) {
543
  callback = makeCallback(callback);
544
  if (!nullCheck(oldPath, callback)) return;
545
  if (!nullCheck(newPath, callback)) return;
546
  binding.rename(pathModule._makeLong(oldPath),
547
                 pathModule._makeLong(newPath),
548
                 callback);
549
};
550

    
551
fs.renameSync = function(oldPath, newPath) {
552
  nullCheck(oldPath);
553
  nullCheck(newPath);
554
  return binding.rename(pathModule._makeLong(oldPath),
555
                        pathModule._makeLong(newPath));
556
};
557

    
558
fs.truncate = function(path, len, callback) {
559
  if (typeof path === 'number') {
560
    // legacy
561
    return fs.ftruncate(path, len, callback);
562
  }
563
  if (typeof len === 'function') {
564
    callback = len;
565
    len = 0;
566
  } else if (typeof len === 'undefined') {
567
    len = 0;
568
  }
569
  callback = maybeCallback(callback);
570
  fs.open(path, 'r+', function(er, fd) {
571
    if (er) return callback(er);
572
    binding.ftruncate(fd, len, function(er) {
573
      fs.close(fd, function(er2) {
574
        callback(er || er2);
575
      });
576
    });
577
  });
578
};
579

    
580
fs.truncateSync = function(path, len) {
581
  if (typeof path === 'number') {
582
    // legacy
583
    return fs.ftruncateSync(path, len);
584
  }
585
  if (typeof len === 'undefined') {
586
    len = 0;
587
  }
588
  // allow error to be thrown, but still close fd.
589
  var fd = fs.openSync(path, 'r+');
590
  try {
591
    var ret = fs.ftruncateSync(fd, len);
592
  } finally {
593
    fs.closeSync(fd);
594
  }
595
  return ret;
596
};
597

    
598
fs.ftruncate = function(fd, len, callback) {
599
  if (typeof len === 'function') {
600
    callback = len;
601
    len = 0;
602
  } else if (typeof len === 'undefined') {
603
    len = 0;
604
  }
605
  binding.ftruncate(fd, len, makeCallback(callback));
606
};
607

    
608
fs.ftruncateSync = function(fd, len) {
609
  if (typeof len === 'undefined') {
610
    len = 0;
611
  }
612
  return binding.ftruncate(fd, len);
613
};
614

    
615
fs.rmdir = function(path, callback) {
616
  callback = makeCallback(callback);
617
  if (!nullCheck(path, callback)) return;
618
  binding.rmdir(pathModule._makeLong(path), callback);
619
};
620

    
621
fs.rmdirSync = function(path) {
622
  nullCheck(path);
623
  return binding.rmdir(pathModule._makeLong(path));
624
};
625

    
626
fs.fdatasync = function(fd, callback) {
627
  binding.fdatasync(fd, makeCallback(callback));
628
};
629

    
630
fs.fdatasyncSync = function(fd) {
631
  return binding.fdatasync(fd);
632
};
633

    
634
fs.fsync = function(fd, callback) {
635
  binding.fsync(fd, makeCallback(callback));
636
};
637

    
638
fs.fsyncSync = function(fd) {
639
  return binding.fsync(fd);
640
};
641

    
642
fs.mkdir = function(path, mode, callback) {
643
  if (typeof mode === 'function') callback = mode;
644
  callback = makeCallback(callback);
645
  if (!nullCheck(path, callback)) return;
646
  binding.mkdir(pathModule._makeLong(path),
647
                modeNum(mode, 511 /*=0777*/),
648
                callback);
649
};
650

    
651
fs.mkdirSync = function(path, mode) {
652
  nullCheck(path);
653
  return binding.mkdir(pathModule._makeLong(path),
654
                       modeNum(mode, 511 /*=0777*/));
655
};
656

    
657
fs.readdir = function(path, callback) {
658
  callback = makeCallback(callback);
659
  if (!nullCheck(path, callback)) return;
660
  binding.readdir(pathModule._makeLong(path), callback);
661
};
662

    
663
fs.readdirSync = function(path) {
664
  nullCheck(path);
665
  return binding.readdir(pathModule._makeLong(path));
666
};
667

    
668
fs.fstat = function(fd, callback) {
669
  binding.fstat(fd, makeCallback(callback));
670
};
671

    
672
fs.lstat = function(path, callback) {
673
  callback = makeCallback(callback);
674
  if (!nullCheck(path, callback)) return;
675
  binding.lstat(pathModule._makeLong(path), callback);
676
};
677

    
678
fs.stat = function(path, callback) {
679
  callback = makeCallback(callback);
680
  if (!nullCheck(path, callback)) return;
681
  binding.stat(pathModule._makeLong(path), callback);
682
};
683

    
684
fs.fstatSync = function(fd) {
685
  return binding.fstat(fd);
686
};
687

    
688
fs.lstatSync = function(path) {
689
  nullCheck(path);
690
  return binding.lstat(pathModule._makeLong(path));
691
};
692

    
693
fs.statSync = function(path) {
694
  nullCheck(path);
695
  return binding.stat(pathModule._makeLong(path));
696
};
697

    
698
fs.readlink = function(path, callback) {
699
  callback = makeCallback(callback);
700
  if (!nullCheck(path, callback)) return;
701
  binding.readlink(pathModule._makeLong(path), callback);
702
};
703

    
704
fs.readlinkSync = function(path) {
705
  nullCheck(path);
706
  return binding.readlink(pathModule._makeLong(path));
707
};
708

    
709
function preprocessSymlinkDestination(path, type) {
710
  if (!isWindows) {
711
    // No preprocessing is needed on Unix.
712
    return path;
713
  } else if (type === 'junction') {
714
    // Junctions paths need to be absolute and \\?\-prefixed.
715
    return pathModule._makeLong(path);
716
  } else {
717
    // Windows symlinks don't tolerate forward slashes.
718
    return ('' + path).replace(/\//g, '\\');
719
  }
720
}
721

    
722
fs.symlink = function(destination, path, type_, callback) {
723
  var type = (typeof type_ === 'string' ? type_ : null);
724
  var callback = makeCallback(arguments[arguments.length - 1]);
725

    
726
  if (!nullCheck(destination, callback)) return;
727
  if (!nullCheck(path, callback)) return;
728

    
729
  binding.symlink(preprocessSymlinkDestination(destination, type),
730
                  pathModule._makeLong(path),
731
                  type,
732
                  callback);
733
};
734

    
735
fs.symlinkSync = function(destination, path, type) {
736
  type = (typeof type === 'string' ? type : null);
737

    
738
  nullCheck(destination);
739
  nullCheck(path);
740

    
741
  return binding.symlink(preprocessSymlinkDestination(destination, type),
742
                         pathModule._makeLong(path),
743
                         type);
744
};
745

    
746
fs.link = function(srcpath, dstpath, callback) {
747
  callback = makeCallback(callback);
748
  if (!nullCheck(srcpath, callback)) return;
749
  if (!nullCheck(dstpath, callback)) return;
750

    
751
  binding.link(pathModule._makeLong(srcpath),
752
               pathModule._makeLong(dstpath),
753
               callback);
754
};
755

    
756
fs.linkSync = function(srcpath, dstpath) {
757
  nullCheck(srcpath);
758
  nullCheck(dstpath);
759
  return binding.link(pathModule._makeLong(srcpath),
760
                      pathModule._makeLong(dstpath));
761
};
762

    
763
fs.unlink = function(path, callback) {
764
  callback = makeCallback(callback);
765
  if (!nullCheck(path, callback)) return;
766
  binding.unlink(pathModule._makeLong(path), callback);
767
};
768

    
769
fs.unlinkSync = function(path) {
770
  nullCheck(path);
771
  return binding.unlink(pathModule._makeLong(path));
772
};
773

    
774
fs.fchmod = function(fd, mode, callback) {
775
  binding.fchmod(fd, modeNum(mode), makeCallback(callback));
776
};
777

    
778
fs.fchmodSync = function(fd, mode) {
779
  return binding.fchmod(fd, modeNum(mode));
780
};
781

    
782
if (constants.hasOwnProperty('O_SYMLINK')) {
783
  fs.lchmod = function(path, mode, callback) {
784
    callback = maybeCallback(callback);
785
    fs.open(path, constants.O_WRONLY | constants.O_SYMLINK, function(err, fd) {
786
      if (err) {
787
        callback(err);
788
        return;
789
      }
790
      // prefer to return the chmod error, if one occurs,
791
      // but still try to close, and report closing errors if they occur.
792
      fs.fchmod(fd, mode, function(err) {
793
        fs.close(fd, function(err2) {
794
          callback(err || err2);
795
        });
796
      });
797
    });
798
  };
799

    
800
  fs.lchmodSync = function(path, mode) {
801
    var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK);
802

    
803
    // prefer to return the chmod error, if one occurs,
804
    // but still try to close, and report closing errors if they occur.
805
    var err, err2;
806
    try {
807
      var ret = fs.fchmodSync(fd, mode);
808
    } catch (er) {
809
      err = er;
810
    }
811
    try {
812
      fs.closeSync(fd);
813
    } catch (er) {
814
      err2 = er;
815
    }
816
    if (err || err2) throw (err || err2);
817
    return ret;
818
  };
819
}
820

    
821

    
822
fs.chmod = function(path, mode, callback) {
823
  callback = makeCallback(callback);
824
  if (!nullCheck(path, callback)) return;
825
  binding.chmod(pathModule._makeLong(path),
826
                modeNum(mode),
827
                callback);
828
};
829

    
830
fs.chmodSync = function(path, mode) {
831
  nullCheck(path);
832
  return binding.chmod(pathModule._makeLong(path), modeNum(mode));
833
};
834

    
835
if (constants.hasOwnProperty('O_SYMLINK')) {
836
  fs.lchown = function(path, uid, gid, callback) {
837
    callback = maybeCallback(callback);
838
    fs.open(path, constants.O_WRONLY | constants.O_SYMLINK, function(err, fd) {
839
      if (err) {
840
        callback(err);
841
        return;
842
      }
843
      fs.fchown(fd, uid, gid, callback);
844
    });
845
  };
846

    
847
  fs.lchownSync = function(path, uid, gid) {
848
    var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK);
849
    return fs.fchownSync(fd, uid, gid);
850
  };
851
}
852

    
853
fs.fchown = function(fd, uid, gid, callback) {
854
  binding.fchown(fd, uid, gid, makeCallback(callback));
855
};
856

    
857
fs.fchownSync = function(fd, uid, gid) {
858
  return binding.fchown(fd, uid, gid);
859
};
860

    
861
fs.chown = function(path, uid, gid, callback) {
862
  callback = makeCallback(callback);
863
  if (!nullCheck(path, callback)) return;
864
  binding.chown(pathModule._makeLong(path), uid, gid, callback);
865
};
866

    
867
fs.chownSync = function(path, uid, gid) {
868
  nullCheck(path);
869
  return binding.chown(pathModule._makeLong(path), uid, gid);
870
};
871

    
872
// converts Date or number to a fractional UNIX timestamp
873
function toUnixTimestamp(time) {
874
  if (typeof time == 'number') {
875
    return time;
876
  }
877
  if (time instanceof Date) {
878
    // convert to 123.456 UNIX timestamp
879
    return time.getTime() / 1000;
880
  }
881
  throw new Error('Cannot parse time: ' + time);
882
}
883

    
884
// exported for unit tests, not for public consumption
885
fs._toUnixTimestamp = toUnixTimestamp;
886

    
887
fs.utimes = function(path, atime, mtime, callback) {
888
  callback = makeCallback(callback);
889
  if (!nullCheck(path, callback)) return;
890
  binding.utimes(pathModule._makeLong(path),
891
                 toUnixTimestamp(atime),
892
                 toUnixTimestamp(mtime),
893
                 callback);
894
};
895

    
896
fs.utimesSync = function(path, atime, mtime) {
897
  nullCheck(path);
898
  atime = toUnixTimestamp(atime);
899
  mtime = toUnixTimestamp(mtime);
900
  binding.utimes(pathModule._makeLong(path), atime, mtime);
901
};
902

    
903
fs.futimes = function(fd, atime, mtime, callback) {
904
  atime = toUnixTimestamp(atime);
905
  mtime = toUnixTimestamp(mtime);
906
  binding.futimes(fd, atime, mtime, makeCallback(callback));
907
};
908

    
909
fs.futimesSync = function(fd, atime, mtime) {
910
  atime = toUnixTimestamp(atime);
911
  mtime = toUnixTimestamp(mtime);
912
  binding.futimes(fd, atime, mtime);
913
};
914

    
915
function writeAll(fd, buffer, offset, length, position, callback) {
916
  callback = maybeCallback(arguments[arguments.length - 1]);
917

    
918
  // write(fd, buffer, offset, length, position, callback)
919
  fs.write(fd, buffer, offset, length, position, function(writeErr, written) {
920
    if (writeErr) {
921
      fs.close(fd, function() {
922
        if (callback) callback(writeErr);
923
      });
924
    } else {
925
      if (written === length) {
926
        fs.close(fd, callback);
927
      } else {
928
        offset += written;
929
        length -= written;
930
        position += written;
931
        writeAll(fd, buffer, offset, length, position, callback);
932
      }
933
    }
934
  });
935
}
936

    
937
fs.writeFile = function(path, data, options, callback) {
938
  var callback = maybeCallback(arguments[arguments.length - 1]);
939

    
940
  if (typeof options === 'function' || !options) {
941
    options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' };
942
  } else if (typeof options === 'string') {
943
    options = { encoding: options, mode: 438, flag: 'w' };
944
  } else if (!options) {
945
    options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' };
946
  } else if (typeof options !== 'object') {
947
    throw new TypeError('Bad arguments');
948
  }
949

    
950
  assertEncoding(options.encoding);
951

    
952
  var flag = options.flag || 'w';
953
  fs.open(path, flag, options.mode, function(openErr, fd) {
954
    if (openErr) {
955
      if (callback) callback(openErr);
956
    } else {
957
      var buffer = Buffer.isBuffer(data) ? data : new Buffer('' + data,
958
          options.encoding || 'utf8');
959
      var position = /a/.test(flag) ? null : 0;
960
      writeAll(fd, buffer, 0, buffer.length, position, callback);
961
    }
962
  });
963
};
964

    
965
fs.writeFileSync = function(path, data, options) {
966
  if (!options) {
967
    options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' };
968
  } else if (typeof options === 'string') {
969
    options = { encoding: options, mode: 438, flag: 'w' };
970
  } else if (typeof options !== 'object') {
971
    throw new TypeError('Bad arguments');
972
  }
973

    
974
  assertEncoding(options.encoding);
975

    
976
  var flag = options.flag || 'w';
977
  var fd = fs.openSync(path, flag, options.mode);
978
  if (!Buffer.isBuffer(data)) {
979
    data = new Buffer('' + data, options.encoding || 'utf8');
980
  }
981
  var written = 0;
982
  var length = data.length;
983
  var position = /a/.test(flag) ? null : 0;
984
  try {
985
    while (written < length) {
986
      written += fs.writeSync(fd, data, written, length - written, position);
987
      position += written;
988
    }
989
  } finally {
990
    fs.closeSync(fd);
991
  }
992
};
993

    
994
fs.appendFile = function(path, data, options, callback_) {
995
  var callback = maybeCallback(arguments[arguments.length - 1]);
996

    
997
  if (typeof options === 'function' || !options) {
998
    options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' };
999
  } else if (typeof options === 'string') {
1000
    options = { encoding: options, mode: 438, flag: 'a' };
1001
  } else if (!options) {
1002
    options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' };
1003
  } else if (typeof options !== 'object') {
1004
    throw new TypeError('Bad arguments');
1005
  }
1006

    
1007
  if (!options.flag)
1008
    options = util._extend({ flag: 'a' }, options);
1009
  fs.writeFile(path, data, options, callback);
1010
};
1011

    
1012
fs.appendFileSync = function(path, data, options) {
1013
  if (!options) {
1014
    options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' };
1015
  } else if (typeof options === 'string') {
1016
    options = { encoding: options, mode: 438, flag: 'a' };
1017
  } else if (typeof options !== 'object') {
1018
    throw new TypeError('Bad arguments');
1019
  }
1020
  if (!options.flag)
1021
    options = util._extend({ flag: 'a' }, options);
1022

    
1023
  fs.writeFileSync(path, data, options);
1024
};
1025

    
1026
function errnoException(errorno, syscall) {
1027
  // TODO make this more compatible with ErrnoException from src/node.cc
1028
  // Once all of Node is using this function the ErrnoException from
1029
  // src/node.cc should be removed.
1030
  var e = new Error(syscall + ' ' + errorno);
1031
  e.errno = e.code = errorno;
1032
  e.syscall = syscall;
1033
  return e;
1034
}
1035

    
1036

    
1037
function FSWatcher() {
1038
  EventEmitter.call(this);
1039

    
1040
  var self = this;
1041
  var FSEvent = process.binding('fs_event_wrap').FSEvent;
1042
  this._handle = new FSEvent();
1043
  this._handle.owner = this;
1044

    
1045
  this._handle.onchange = function(status, event, filename) {
1046
    if (status) {
1047
      self._handle.close();
1048
      self.emit('error', errnoException(process._errno, 'watch'));
1049
    } else {
1050
      self.emit('change', event, filename);
1051
    }
1052
  };
1053
}
1054
util.inherits(FSWatcher, EventEmitter);
1055

    
1056
FSWatcher.prototype.start = function(filename, persistent) {
1057
  nullCheck(filename);
1058
  var r = this._handle.start(pathModule._makeLong(filename), persistent);
1059

    
1060
  if (r) {
1061
    this._handle.close();
1062
    throw errnoException(process._errno, 'watch');
1063
  }
1064
};
1065

    
1066
FSWatcher.prototype.close = function() {
1067
  this._handle.close();
1068
};
1069

    
1070
fs.watch = function(filename) {
1071
  nullCheck(filename);
1072
  var watcher;
1073
  var options;
1074
  var listener;
1075

    
1076
  if ('object' == typeof arguments[1]) {
1077
    options = arguments[1];
1078
    listener = arguments[2];
1079
  } else {
1080
    options = {};
1081
    listener = arguments[1];
1082
  }
1083

    
1084
  if (options.persistent === undefined) options.persistent = true;
1085

    
1086
  watcher = new FSWatcher();
1087
  watcher.start(filename, options.persistent);
1088

    
1089
  if (listener) {
1090
    watcher.addListener('change', listener);
1091
  }
1092

    
1093
  return watcher;
1094
};
1095

    
1096

    
1097
// Stat Change Watchers
1098

    
1099
function StatWatcher() {
1100
  EventEmitter.call(this);
1101

    
1102
  var self = this;
1103
  this._handle = new binding.StatWatcher();
1104

    
1105
  // uv_fs_poll is a little more powerful than ev_stat but we curb it for
1106
  // the sake of backwards compatibility
1107
  var oldStatus = -1;
1108

    
1109
  this._handle.onchange = function(current, previous, newStatus) {
1110
    if (oldStatus === -1 &&
1111
        newStatus === -1 &&
1112
        current.nlink === previous.nlink) return;
1113

    
1114
    oldStatus = newStatus;
1115
    self.emit('change', current, previous);
1116
  };
1117

    
1118
  this._handle.onstop = function() {
1119
    self.emit('stop');
1120
  };
1121
}
1122
util.inherits(StatWatcher, EventEmitter);
1123

    
1124

    
1125
StatWatcher.prototype.start = function(filename, persistent, interval) {
1126
  nullCheck(filename);
1127
  this._handle.start(pathModule._makeLong(filename), persistent, interval);
1128
};
1129

    
1130

    
1131
StatWatcher.prototype.stop = function() {
1132
  this._handle.stop();
1133
};
1134

    
1135

    
1136
var statWatchers = {};
1137
function inStatWatchers(filename) {
1138
  return Object.prototype.hasOwnProperty.call(statWatchers, filename) &&
1139
      statWatchers[filename];
1140
}
1141

    
1142

    
1143
fs.watchFile = function(filename) {
1144
  nullCheck(filename);
1145
  filename = pathModule.resolve(filename);
1146
  var stat;
1147
  var listener;
1148

    
1149
  var options = {
1150
    // Poll interval in milliseconds. 5007 is what libev used to use. It's
1151
    // a little on the slow side but let's stick with it for now to keep
1152
    // behavioral changes to a minimum.
1153
    interval: 5007,
1154
    persistent: true
1155
  };
1156

    
1157
  if ('object' == typeof arguments[1]) {
1158
    options = util._extend(options, arguments[1]);
1159
    listener = arguments[2];
1160
  } else {
1161
    listener = arguments[1];
1162
  }
1163

    
1164
  if (!listener) {
1165
    throw new Error('watchFile requires a listener function');
1166
  }
1167

    
1168
  if (inStatWatchers(filename)) {
1169
    stat = statWatchers[filename];
1170
  } else {
1171
    stat = statWatchers[filename] = new StatWatcher();
1172
    stat.start(filename, options.persistent, options.interval);
1173
  }
1174
  stat.addListener('change', listener);
1175
  return stat;
1176
};
1177

    
1178
fs.unwatchFile = function(filename, listener) {
1179
  nullCheck(filename);
1180
  filename = pathModule.resolve(filename);
1181
  if (!inStatWatchers(filename)) return;
1182

    
1183
  var stat = statWatchers[filename];
1184

    
1185
  if (typeof listener === 'function') {
1186
    stat.removeListener('change', listener);
1187
  } else {
1188
    stat.removeAllListeners('change');
1189
  }
1190

    
1191
  if (EventEmitter.listenerCount(stat, 'change') === 0) {
1192
    stat.stop();
1193
    statWatchers[filename] = undefined;
1194
  }
1195
};
1196

    
1197
// Realpath
1198
// Not using realpath(2) because it's bad.
1199
// See: http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
1200

    
1201
var normalize = pathModule.normalize;
1202

    
1203
// Regexp that finds the next partion of a (partial) path
1204
// result is [base_with_slash, base], e.g. ['somedir/', 'somedir']
1205
if (isWindows) {
1206
  var nextPartRe = /(.*?)(?:[\/\\]+|$)/g;
1207
} else {
1208
  var nextPartRe = /(.*?)(?:[\/]+|$)/g;
1209
}
1210

    
1211
// Regex to find the device root, including trailing slash. E.g. 'c:\\'.
1212
if (isWindows) {
1213
  var splitRootRe = /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/;
1214
} else {
1215
  var splitRootRe = /^[\/]*/;
1216
}
1217

    
1218
fs.realpathSync = function realpathSync(p, cache) {
1219
  // make p is absolute
1220
  p = pathModule.resolve(p);
1221

    
1222
  if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
1223
    return cache[p];
1224
  }
1225

    
1226
  var original = p,
1227
      seenLinks = {},
1228
      knownHard = {};
1229

    
1230
  // current character position in p
1231
  var pos;
1232
  // the partial path so far, including a trailing slash if any
1233
  var current;
1234
  // the partial path without a trailing slash (except when pointing at a root)
1235
  var base;
1236
  // the partial path scanned in the previous round, with slash
1237
  var previous;
1238

    
1239
  start();
1240

    
1241
  function start() {
1242
    // Skip over roots
1243
    var m = splitRootRe.exec(p);
1244
    pos = m[0].length;
1245
    current = m[0];
1246
    base = m[0];
1247
    previous = '';
1248

    
1249
    // On windows, check that the root exists. On unix there is no need.
1250
    if (isWindows && !knownHard[base]) {
1251
      fs.lstatSync(base);
1252
      knownHard[base] = true;
1253
    }
1254
  }
1255

    
1256
  // walk down the path, swapping out linked pathparts for their real
1257
  // values
1258
  // NB: p.length changes.
1259
  while (pos < p.length) {
1260
    // find the next part
1261
    nextPartRe.lastIndex = pos;
1262
    var result = nextPartRe.exec(p);
1263
    previous = current;
1264
    current += result[0];
1265
    base = previous + result[1];
1266
    pos = nextPartRe.lastIndex;
1267

    
1268
    // continue if not a symlink
1269
    if (knownHard[base] || (cache && cache[base] === base)) {
1270
      continue;
1271
    }
1272

    
1273
    var resolvedLink;
1274
    if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
1275
      // some known symbolic link.  no need to stat again.
1276
      resolvedLink = cache[base];
1277
    } else {
1278
      var stat = fs.lstatSync(base);
1279
      if (!stat.isSymbolicLink()) {
1280
        knownHard[base] = true;
1281
        if (cache) cache[base] = base;
1282
        continue;
1283
      }
1284

    
1285
      // read the link if it wasn't read before
1286
      // dev/ino always return 0 on windows, so skip the check.
1287
      var linkTarget = null;
1288
      if (!isWindows) {
1289
        var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
1290
        if (seenLinks.hasOwnProperty(id)) {
1291
          linkTarget = seenLinks[id];
1292
        }
1293
      }
1294
      if (linkTarget === null) {
1295
        fs.statSync(base);
1296
        linkTarget = fs.readlinkSync(base);
1297
      }
1298
      resolvedLink = pathModule.resolve(previous, linkTarget);
1299
      // track this, if given a cache.
1300
      if (cache) cache[base] = resolvedLink;
1301
      if (!isWindows) seenLinks[id] = linkTarget;
1302
    }
1303

    
1304
    // resolve the link, then start over
1305
    p = pathModule.resolve(resolvedLink, p.slice(pos));
1306
    start();
1307
  }
1308

    
1309
  if (cache) cache[original] = p;
1310

    
1311
  return p;
1312
};
1313

    
1314

    
1315
fs.realpath = function realpath(p, cache, cb) {
1316
  if (typeof cb !== 'function') {
1317
    cb = maybeCallback(cache);
1318
    cache = null;
1319
  }
1320

    
1321
  // make p is absolute
1322
  p = pathModule.resolve(p);
1323

    
1324
  if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
1325
    return process.nextTick(cb.bind(null, null, cache[p]));
1326
  }
1327

    
1328
  var original = p,
1329
      seenLinks = {},
1330
      knownHard = {};
1331

    
1332
  // current character position in p
1333
  var pos;
1334
  // the partial path so far, including a trailing slash if any
1335
  var current;
1336
  // the partial path without a trailing slash (except when pointing at a root)
1337
  var base;
1338
  // the partial path scanned in the previous round, with slash
1339
  var previous;
1340

    
1341
  start();
1342

    
1343
  function start() {
1344
    // Skip over roots
1345
    var m = splitRootRe.exec(p);
1346
    pos = m[0].length;
1347
    current = m[0];
1348
    base = m[0];
1349
    previous = '';
1350

    
1351
    // On windows, check that the root exists. On unix there is no need.
1352
    if (isWindows && !knownHard[base]) {
1353
      fs.lstat(base, function(err) {
1354
        if (err) return cb(err);
1355
        knownHard[base] = true;
1356
        LOOP();
1357
      });
1358
    } else {
1359
      process.nextTick(LOOP);
1360
    }
1361
  }
1362

    
1363
  // walk down the path, swapping out linked pathparts for their real
1364
  // values
1365
  function LOOP() {
1366
    // stop if scanned past end of path
1367
    if (pos >= p.length) {
1368
      if (cache) cache[original] = p;
1369
      return cb(null, p);
1370
    }
1371

    
1372
    // find the next part
1373
    nextPartRe.lastIndex = pos;
1374
    var result = nextPartRe.exec(p);
1375
    previous = current;
1376
    current += result[0];
1377
    base = previous + result[1];
1378
    pos = nextPartRe.lastIndex;
1379

    
1380
    // continue if not a symlink
1381
    if (knownHard[base] || (cache && cache[base] === base)) {
1382
      return process.nextTick(LOOP);
1383
    }
1384

    
1385
    if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
1386
      // known symbolic link.  no need to stat again.
1387
      return gotResolvedLink(cache[base]);
1388
    }
1389

    
1390
    return fs.lstat(base, gotStat);
1391
  }
1392

    
1393
  function gotStat(err, stat) {
1394
    if (err) return cb(err);
1395

    
1396
    // if not a symlink, skip to the next path part
1397
    if (!stat.isSymbolicLink()) {
1398
      knownHard[base] = true;
1399
      if (cache) cache[base] = base;
1400
      return process.nextTick(LOOP);
1401
    }
1402

    
1403
    // stat & read the link if not read before
1404
    // call gotTarget as soon as the link target is known
1405
    // dev/ino always return 0 on windows, so skip the check.
1406
    if (!isWindows) {
1407
      var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
1408
      if (seenLinks.hasOwnProperty(id)) {
1409
        return gotTarget(null, seenLinks[id], base);
1410
      }
1411
    }
1412
    fs.stat(base, function(err) {
1413
      if (err) return cb(err);
1414

    
1415
      fs.readlink(base, function(err, target) {
1416
        if (!isWindows) seenLinks[id] = target;
1417
        gotTarget(err, target);
1418
      });
1419
    });
1420
  }
1421

    
1422
  function gotTarget(err, target, base) {
1423
    if (err) return cb(err);
1424

    
1425
    var resolvedLink = pathModule.resolve(previous, target);
1426
    if (cache) cache[base] = resolvedLink;
1427
    gotResolvedLink(resolvedLink);
1428
  }
1429

    
1430
  function gotResolvedLink(resolvedLink) {
1431
    // resolve the link, then start over
1432
    p = pathModule.resolve(resolvedLink, p.slice(pos));
1433
    start();
1434
  }
1435
};
1436

    
1437

    
1438

    
1439
var pool;
1440

    
1441
function allocNewPool(poolSize) {
1442
  pool = new Buffer(poolSize);
1443
  pool.used = 0;
1444
}
1445

    
1446

    
1447

    
1448
fs.createReadStream = function(path, options) {
1449
  return new ReadStream(path, options);
1450
};
1451

    
1452
util.inherits(ReadStream, Readable);
1453
fs.ReadStream = ReadStream;
1454

    
1455
function ReadStream(path, options) {
1456
  if (!(this instanceof ReadStream))
1457
    return new ReadStream(path, options);
1458

    
1459
  // a little bit bigger buffer and water marks by default
1460
  options = util._extend({
1461
    highWaterMark: 64 * 1024
1462
  }, options || {});
1463

    
1464
  Readable.call(this, options);
1465

    
1466
  this.path = path;
1467
  this.fd = options.hasOwnProperty('fd') ? options.fd : null;
1468
  this.flags = options.hasOwnProperty('flags') ? options.flags : 'r';
1469
  this.mode = options.hasOwnProperty('mode') ? options.mode : 438; /*=0666*/
1470

    
1471
  this.start = options.hasOwnProperty('start') ? options.start : undefined;
1472
  this.end = options.hasOwnProperty('end') ? options.end : undefined;
1473
  this.autoClose = options.hasOwnProperty('autoClose') ?
1474
      options.autoClose : true;
1475
  this.pos = undefined;
1476

    
1477
  if (this.start !== undefined) {
1478
    if ('number' !== typeof this.start) {
1479
      throw TypeError('start must be a Number');
1480
    }
1481
    if (this.end === undefined) {
1482
      this.end = Infinity;
1483
    } else if ('number' !== typeof this.end) {
1484
      throw TypeError('end must be a Number');
1485
    }
1486

    
1487
    if (this.start > this.end) {
1488
      throw new Error('start must be <= end');
1489
    }
1490

    
1491
    this.pos = this.start;
1492
  }
1493

    
1494
  if (typeof this.fd !== 'number')
1495
    this.open();
1496

    
1497
  this.on('end', function() {
1498
    if (this.autoClose) {
1499
      this.destroy();
1500
    }
1501
  });
1502
}
1503

    
1504
fs.FileReadStream = fs.ReadStream; // support the legacy name
1505

    
1506
ReadStream.prototype.open = function() {
1507
  var self = this;
1508
  fs.open(this.path, this.flags, this.mode, function(er, fd) {
1509
    if (er) {
1510
      if (self.autoClose) {
1511
        self.destroy();
1512
      }
1513
      self.emit('error', er);
1514
      return;
1515
    }
1516

    
1517
    self.fd = fd;
1518
    self.emit('open', fd);
1519
    // start the flow of data.
1520
    self.read();
1521
  });
1522
};
1523

    
1524
ReadStream.prototype._read = function(n) {
1525
  if (typeof this.fd !== 'number')
1526
    return this.once('open', function() {
1527
      this._read(n);
1528
    });
1529

    
1530
  if (this.destroyed)
1531
    return;
1532

    
1533
  if (!pool || pool.length - pool.used < kMinPoolSpace) {
1534
    // discard the old pool.
1535
    pool = null;
1536
    allocNewPool(this._readableState.highWaterMark);
1537
  }
1538

    
1539
  // Grab another reference to the pool in the case that while we're
1540
  // in the thread pool another read() finishes up the pool, and
1541
  // allocates a new one.
1542
  var thisPool = pool;
1543
  var toRead = Math.min(pool.length - pool.used, n);
1544
  var start = pool.used;
1545

    
1546
  if (this.pos !== undefined)
1547
    toRead = Math.min(this.end - this.pos + 1, toRead);
1548

    
1549
  // already read everything we were supposed to read!
1550
  // treat as EOF.
1551
  if (toRead <= 0)
1552
    return this.push(null);
1553

    
1554
  // the actual read.
1555
  var self = this;
1556
  fs.read(this.fd, pool, pool.used, toRead, this.pos, onread);
1557

    
1558
  // move the pool positions, and internal position for reading.
1559
  if (this.pos !== undefined)
1560
    this.pos += toRead;
1561
  pool.used += toRead;
1562

    
1563
  function onread(er, bytesRead) {
1564
    if (er) {
1565
      if (self.autoClose) {
1566
        self.destroy();
1567
      }
1568
      self.emit('error', er);
1569
    } else {
1570
      var b = null;
1571
      if (bytesRead > 0)
1572
        b = thisPool.slice(start, start + bytesRead);
1573

    
1574
      self.push(b);
1575
    }
1576
  }
1577
};
1578

    
1579

    
1580
ReadStream.prototype.destroy = function() {
1581
  if (this.destroyed)
1582
    return;
1583
  this.destroyed = true;
1584

    
1585
  if ('number' === typeof this.fd)
1586
    this.close();
1587
};
1588

    
1589

    
1590
ReadStream.prototype.close = function(cb) {
1591
  var self = this;
1592
  if (cb)
1593
    this.once('close', cb);
1594
  if (this.closed || 'number' !== typeof this.fd) {
1595
    if ('number' !== typeof this.fd) {
1596
      this.once('open', close);
1597
      return;
1598
    }
1599
    return process.nextTick(this.emit.bind(this, 'close'));
1600
  }
1601
  this.closed = true;
1602
  close();
1603

    
1604
  function close(fd) {
1605
    fs.close(fd || self.fd, function(er) {
1606
      if (er)
1607
        self.emit('error', er);
1608
      else
1609
        self.emit('close');
1610
    });
1611
    self.fd = null;
1612
  }
1613
};
1614

    
1615

    
1616

    
1617

    
1618
fs.createWriteStream = function(path, options) {
1619
  return new WriteStream(path, options);
1620
};
1621

    
1622
util.inherits(WriteStream, Writable);
1623
fs.WriteStream = WriteStream;
1624
function WriteStream(path, options) {
1625
  if (!(this instanceof WriteStream))
1626
    return new WriteStream(path, options);
1627

    
1628
  options = options || {};
1629

    
1630
  Writable.call(this, options);
1631

    
1632
  this.path = path;
1633
  this.fd = null;
1634

    
1635
  this.fd = options.hasOwnProperty('fd') ? options.fd : null;
1636
  this.flags = options.hasOwnProperty('flags') ? options.flags : 'w';
1637
  this.mode = options.hasOwnProperty('mode') ? options.mode : 438; /*=0666*/
1638

    
1639
  this.start = options.hasOwnProperty('start') ? options.start : undefined;
1640
  this.pos = undefined;
1641
  this.bytesWritten = 0;
1642

    
1643
  if (this.start !== undefined) {
1644
    if ('number' !== typeof this.start) {
1645
      throw TypeError('start must be a Number');
1646
    }
1647
    if (this.start < 0) {
1648
      throw new Error('start must be >= zero');
1649
    }
1650

    
1651
    this.pos = this.start;
1652
  }
1653

    
1654
  if ('number' !== typeof this.fd)
1655
    this.open();
1656

    
1657
  // dispose on finish.
1658
  this.once('finish', this.close);
1659
}
1660

    
1661
fs.FileWriteStream = fs.WriteStream; // support the legacy name
1662

    
1663

    
1664
WriteStream.prototype.open = function() {
1665
  fs.open(this.path, this.flags, this.mode, function(er, fd) {
1666
    if (er) {
1667
      this.destroy();
1668
      this.emit('error', er);
1669
      return;
1670
    }
1671

    
1672
    this.fd = fd;
1673
    this.emit('open', fd);
1674
  }.bind(this));
1675
};
1676

    
1677

    
1678
WriteStream.prototype._write = function(data, encoding, cb) {
1679
  if (!Buffer.isBuffer(data))
1680
    return this.emit('error', new Error('Invalid data'));
1681

    
1682
  if (typeof this.fd !== 'number')
1683
    return this.once('open', function() {
1684
      this._write(data, encoding, cb);
1685
    });
1686

    
1687
  var self = this;
1688
  fs.write(this.fd, data, 0, data.length, this.pos, function(er, bytes) {
1689
    if (er) {
1690
      self.destroy();
1691
      return cb(er);
1692
    }
1693
    self.bytesWritten += bytes;
1694
    cb();
1695
  });
1696

    
1697
  if (this.pos !== undefined)
1698
    this.pos += data.length;
1699
};
1700

    
1701

    
1702
WriteStream.prototype.destroy = ReadStream.prototype.destroy;
1703
WriteStream.prototype.close = ReadStream.prototype.close;
1704

    
1705
// There is no shutdown() for files.
1706
WriteStream.prototype.destroySoon = WriteStream.prototype.end;
1707

    
1708

    
1709
// SyncWriteStream is internal. DO NOT USE.
1710
// Temporary hack for process.stdout and process.stderr when piped to files.
1711
function SyncWriteStream(fd, options) {
1712
  Stream.call(this);
1713

    
1714
  options = options || {};
1715

    
1716
  this.fd = fd;
1717
  this.writable = true;
1718
  this.readable = false;
1719
  this.autoClose = options.hasOwnProperty('autoClose') ?
1720
      options.autoClose : true;
1721
}
1722

    
1723
util.inherits(SyncWriteStream, Stream);
1724

    
1725

    
1726
// Export
1727
fs.SyncWriteStream = SyncWriteStream;
1728

    
1729

    
1730
SyncWriteStream.prototype.write = function(data, arg1, arg2) {
1731
  var encoding, cb;
1732

    
1733
  // parse arguments
1734
  if (arg1) {
1735
    if (typeof arg1 === 'string') {
1736
      encoding = arg1;
1737
      cb = arg2;
1738
    } else if (typeof arg1 === 'function') {
1739
      cb = arg1;
1740
    } else {
1741
      throw new Error('bad arg');
1742
    }
1743
  }
1744
  assertEncoding(encoding);
1745

    
1746
  // Change strings to buffers. SLOW
1747
  if (typeof data == 'string') {
1748
    data = new Buffer(data, encoding);
1749
  }
1750

    
1751
  fs.writeSync(this.fd, data, 0, data.length);
1752

    
1753
  if (cb) {
1754
    process.nextTick(cb);
1755
  }
1756

    
1757
  return true;
1758
};
1759

    
1760

    
1761
SyncWriteStream.prototype.end = function(data, arg1, arg2) {
1762
  if (data) {
1763
    this.write(data, arg1, arg2);
1764
  }
1765
  this.destroy();
1766
};
1767

    
1768

    
1769
SyncWriteStream.prototype.destroy = function() {
1770
  if (this.autoClose)
1771
    fs.closeSync(this.fd);
1772
  this.fd = null;
1773
  this.emit('close');
1774
  return true;
1775
};
1776

    
1777
SyncWriteStream.prototype.destroySoon = SyncWriteStream.prototype.destroy;