| // Copyright Joyent, Inc. and other Node contributors. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a |
| // copy of this software and associated documentation files (the |
| // "Software"), to deal in the Software without restriction, including |
| // without limitation the rights to use, copy, modify, merge, publish, |
| // distribute, sublicense, and/or sell copies of the Software, and to permit |
| // persons to whom the Software is furnished to do so, subject to the |
| // following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included |
| // in all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
| // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
| // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
| // USE OR OTHER DEALINGS IN THE SOFTWARE. |
| |
| // Maintainers, keep in mind that octal literals are not allowed |
| // in strict mode. Use the decimal value and add a comment with |
| // the octal value. Example: |
| // |
| // var mode = 438; /* mode=0666 */ |
| |
| var util = require('util'); |
| var pathModule = require('path'); |
| |
| var binding = process.binding('fs'); |
| var constants = process.binding('constants'); |
| var fs = exports; |
| var Stream = require('stream').Stream; |
| var EventEmitter = require('events').EventEmitter; |
| |
| var Readable = Stream.Readable; |
| var Writable = Stream.Writable; |
| |
| var kMinPoolSpace = 128; |
| |
| var O_APPEND = constants.O_APPEND || 0; |
| var O_CREAT = constants.O_CREAT || 0; |
| var O_DIRECTORY = constants.O_DIRECTORY || 0; |
| var O_EXCL = constants.O_EXCL || 0; |
| var O_NOCTTY = constants.O_NOCTTY || 0; |
| var O_NOFOLLOW = constants.O_NOFOLLOW || 0; |
| var O_RDONLY = constants.O_RDONLY || 0; |
| var O_RDWR = constants.O_RDWR || 0; |
| var O_SYMLINK = constants.O_SYMLINK || 0; |
| var O_SYNC = constants.O_SYNC || 0; |
| var O_TRUNC = constants.O_TRUNC || 0; |
| var O_WRONLY = constants.O_WRONLY || 0; |
| |
| var isWindows = process.platform === 'win32'; |
| |
| var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG); |
| |
| function rethrow() { |
| // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and |
| // is fairly slow to generate. |
| var callback; |
| if (DEBUG) { |
| var backtrace = new Error; |
| callback = debugCallback; |
| } else |
| callback = missingCallback; |
| |
| return callback; |
| |
| function debugCallback(err) { |
| if (err) { |
| backtrace.message = err.message; |
| err = backtrace; |
| missingCallback(err); |
| } |
| } |
| |
| function missingCallback(err) { |
| if (err) { |
| if (process.throwDeprecation) |
| throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs |
| else if (!process.noDeprecation) { |
| var msg = 'fs: missing callback ' + (err.stack || err.message); |
| if (process.traceDeprecation) |
| console.trace(msg); |
| else |
| console.error(msg); |
| } |
| } |
| } |
| } |
| |
| function maybeCallback(cb) { |
| return typeof cb === 'function' ? cb : rethrow(); |
| } |
| |
| // Ensure that callbacks run in the global context. Only use this function |
| // for callbacks that are passed to the binding layer, callbacks that are |
| // invoked from JS already run in the proper scope. |
| function makeCallback(cb) { |
| if (typeof cb !== 'function') { |
| return rethrow(); |
| } |
| |
| return function() { |
| return cb.apply(null, arguments); |
| }; |
| } |
| |
| function assertEncoding(encoding) { |
| if (encoding && !Buffer.isEncoding(encoding)) { |
| throw new Error('Unknown encoding: ' + encoding); |
| } |
| } |
| |
| function nullCheck(path, callback) { |
| if (('' + path).indexOf('\u0000') !== -1) { |
| var er = new Error('Path must be a string without null bytes.'); |
| if (!callback) |
| throw er; |
| process.nextTick(function() { |
| callback(er); |
| }); |
| return false; |
| } |
| return true; |
| } |
| |
| fs.Stats = binding.Stats; |
| |
| fs.Stats.prototype._checkModeProperty = function(property) { |
| return ((this.mode & constants.S_IFMT) === property); |
| }; |
| |
| fs.Stats.prototype.isDirectory = function() { |
| return this._checkModeProperty(constants.S_IFDIR); |
| }; |
| |
| fs.Stats.prototype.isFile = function() { |
| return this._checkModeProperty(constants.S_IFREG); |
| }; |
| |
| fs.Stats.prototype.isBlockDevice = function() { |
| return this._checkModeProperty(constants.S_IFBLK); |
| }; |
| |
| fs.Stats.prototype.isCharacterDevice = function() { |
| return this._checkModeProperty(constants.S_IFCHR); |
| }; |
| |
| fs.Stats.prototype.isSymbolicLink = function() { |
| return this._checkModeProperty(constants.S_IFLNK); |
| }; |
| |
| fs.Stats.prototype.isFIFO = function() { |
| return this._checkModeProperty(constants.S_IFIFO); |
| }; |
| |
| fs.Stats.prototype.isSocket = function() { |
| return this._checkModeProperty(constants.S_IFSOCK); |
| }; |
| |
| fs.exists = function(path, callback) { |
| if (!nullCheck(path, cb)) return; |
| binding.stat(pathModule._makeLong(path), cb); |
| function cb(err, stats) { |
| if (callback) callback(err ? false : true); |
| } |
| }; |
| |
| fs.existsSync = function(path) { |
| try { |
| nullCheck(path); |
| binding.stat(pathModule._makeLong(path)); |
| return true; |
| } catch (e) { |
| return false; |
| } |
| }; |
| |
| fs.readFile = function(path, options, callback_) { |
| var callback = maybeCallback(arguments[arguments.length - 1]); |
| |
| if (typeof options === 'function' || !options) { |
| options = { encoding: null, flag: 'r' }; |
| } else if (typeof options === 'string') { |
| options = { encoding: options, flag: 'r' }; |
| } else if (!options) { |
| options = { encoding: null, flag: 'r' }; |
| } else if (typeof options !== 'object') { |
| throw new TypeError('Bad arguments'); |
| } |
| |
| var encoding = options.encoding; |
| assertEncoding(encoding); |
| |
| // first, stat the file, so we know the size. |
| var size; |
| var buffer; // single buffer with file data |
| var buffers; // list for when size is unknown |
| var pos = 0; |
| var fd; |
| |
| var flag = options.flag || 'r'; |
| fs.open(path, flag, 438 /*=0666*/, function(er, fd_) { |
| if (er) return callback(er); |
| fd = fd_; |
| |
| fs.fstat(fd, function(er, st) { |
| if (er) return callback(er); |
| size = st.size; |
| if (size === 0) { |
| // the kernel lies about many files. |
| // Go ahead and try to read some bytes. |
| buffers = []; |
| return read(); |
| } |
| |
| buffer = new Buffer(size); |
| read(); |
| }); |
| }); |
| |
| function read() { |
| if (size === 0) { |
| buffer = new Buffer(8192); |
| fs.read(fd, buffer, 0, 8192, -1, afterRead); |
| } else { |
| fs.read(fd, buffer, pos, size - pos, -1, afterRead); |
| } |
| } |
| |
| function afterRead(er, bytesRead) { |
| if (er) { |
| return fs.close(fd, function(er2) { |
| return callback(er); |
| }); |
| } |
| |
| if (bytesRead === 0) { |
| return close(); |
| } |
| |
| pos += bytesRead; |
| if (size !== 0) { |
| if (pos === size) close(); |
| else read(); |
| } else { |
| // unknown size, just read until we don't get bytes. |
| buffers.push(buffer.slice(0, bytesRead)); |
| read(); |
| } |
| } |
| |
| function close() { |
| fs.close(fd, function(er) { |
| if (size === 0) { |
| // collected the data into the buffers list. |
| buffer = Buffer.concat(buffers, pos); |
| } else if (pos < size) { |
| buffer = buffer.slice(0, pos); |
| } |
| |
| if (encoding) buffer = buffer.toString(encoding); |
| return callback(er, buffer); |
| }); |
| } |
| }; |
| |
| fs.readFileSync = function(path, options) { |
| if (!options) { |
| options = { encoding: null, flag: 'r' }; |
| } else if (typeof options === 'string') { |
| options = { encoding: options, flag: 'r' }; |
| } else if (typeof options !== 'object') { |
| throw new TypeError('Bad arguments'); |
| } |
| |
| var encoding = options.encoding; |
| assertEncoding(encoding); |
| |
| var flag = options.flag || 'r'; |
| var fd = fs.openSync(path, flag, 438 /*=0666*/); |
| |
| var size; |
| var threw = true; |
| try { |
| size = fs.fstatSync(fd).size; |
| threw = false; |
| } finally { |
| if (threw) fs.closeSync(fd); |
| } |
| |
| var pos = 0; |
| var buffer; // single buffer with file data |
| var buffers; // list for when size is unknown |
| |
| if (size === 0) { |
| buffers = []; |
| } else { |
| buffer = new Buffer(size); |
| } |
| |
| var done = false; |
| while (!done) { |
| var threw = true; |
| try { |
| if (size !== 0) { |
| var bytesRead = fs.readSync(fd, buffer, pos, size - pos); |
| } else { |
| // the kernel lies about many files. |
| // Go ahead and try to read some bytes. |
| buffer = new Buffer(8192); |
| var bytesRead = fs.readSync(fd, buffer, 0, 8192); |
| if (bytesRead) { |
| buffers.push(buffer.slice(0, bytesRead)); |
| } |
| } |
| threw = false; |
| } finally { |
| if (threw) fs.closeSync(fd); |
| } |
| |
| pos += bytesRead; |
| done = (bytesRead === 0) || (size !== 0 && pos >= size); |
| } |
| |
| fs.closeSync(fd); |
| |
| if (size === 0) { |
| // data was collected into the buffers list. |
| buffer = Buffer.concat(buffers, pos); |
| } else if (pos < size) { |
| buffer = buffer.slice(0, pos); |
| } |
| |
| if (encoding) buffer = buffer.toString(encoding); |
| return buffer; |
| }; |
| |
| |
| // Used by binding.open and friends |
| function stringToFlags(flag) { |
| // Only mess with strings |
| if (typeof flag !== 'string') { |
| return flag; |
| } |
| |
| // O_EXCL is mandated by POSIX, Windows supports it too. |
| // Let's add a check anyway, just in case. |
| if (!O_EXCL && ~flag.indexOf('x')) { |
| throw errnoException('ENOSYS', 'fs.open(O_EXCL)'); |
| } |
| |
| switch (flag) { |
| case 'r' : return O_RDONLY; |
| case 'rs' : return O_RDONLY | O_SYNC; |
| case 'r+' : return O_RDWR; |
| case 'rs+' : return O_RDWR | O_SYNC; |
| |
| case 'w' : return O_TRUNC | O_CREAT | O_WRONLY; |
| case 'wx' : // fall through |
| case 'xw' : return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL; |
| |
| case 'w+' : return O_TRUNC | O_CREAT | O_RDWR; |
| case 'wx+': // fall through |
| case 'xw+': return O_TRUNC | O_CREAT | O_RDWR | O_EXCL; |
| |
| case 'a' : return O_APPEND | O_CREAT | O_WRONLY; |
| case 'ax' : // fall through |
| case 'xa' : return O_APPEND | O_CREAT | O_WRONLY | O_EXCL; |
| |
| case 'a+' : return O_APPEND | O_CREAT | O_RDWR; |
| case 'ax+': // fall through |
| case 'xa+': return O_APPEND | O_CREAT | O_RDWR | O_EXCL; |
| } |
| |
| throw new Error('Unknown file open flag: ' + flag); |
| } |
| |
| // exported but hidden, only used by test/simple/test-fs-open-flags.js |
| Object.defineProperty(exports, '_stringToFlags', { |
| enumerable: false, |
| value: stringToFlags |
| }); |
| |
| |
| // Yes, the follow could be easily DRYed up but I provide the explicit |
| // list to make the arguments clear. |
| |
| fs.close = function(fd, callback) { |
| binding.close(fd, makeCallback(callback)); |
| }; |
| |
| fs.closeSync = function(fd) { |
| return binding.close(fd); |
| }; |
| |
| function modeNum(m, def) { |
| switch (typeof m) { |
| case 'number': return m; |
| case 'string': return parseInt(m, 8); |
| default: |
| if (def) { |
| return modeNum(def); |
| } else { |
| return undefined; |
| } |
| } |
| } |
| |
| fs.open = function(path, flags, mode, callback) { |
| callback = makeCallback(arguments[arguments.length - 1]); |
| mode = modeNum(mode, 438 /*=0666*/); |
| |
| if (!nullCheck(path, callback)) return; |
| binding.open(pathModule._makeLong(path), |
| stringToFlags(flags), |
| mode, |
| callback); |
| }; |
| |
| fs.openSync = function(path, flags, mode) { |
| mode = modeNum(mode, 438 /*=0666*/); |
| nullCheck(path); |
| return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode); |
| }; |
| |
| fs.read = function(fd, buffer, offset, length, position, callback) { |
| if (!Buffer.isBuffer(buffer)) { |
| // legacy string interface (fd, length, position, encoding, callback) |
| var cb = arguments[4], |
| encoding = arguments[3]; |
| |
| assertEncoding(encoding); |
| |
| position = arguments[2]; |
| length = arguments[1]; |
| buffer = new Buffer(length); |
| offset = 0; |
| |
| callback = function(err, bytesRead) { |
| if (!cb) return; |
| |
| var str = (bytesRead > 0) ? buffer.toString(encoding, 0, bytesRead) : ''; |
| |
| (cb)(err, str, bytesRead); |
| }; |
| } |
| |
| function wrapper(err, bytesRead) { |
| // Retain a reference to buffer so that it can't be GC'ed too soon. |
| callback && callback(err, bytesRead || 0, buffer); |
| } |
| |
| binding.read(fd, buffer, offset, length, position, wrapper); |
| }; |
| |
| fs.readSync = function(fd, buffer, offset, length, position) { |
| var legacy = false; |
| if (!Buffer.isBuffer(buffer)) { |
| // legacy string interface (fd, length, position, encoding, callback) |
| legacy = true; |
| var encoding = arguments[3]; |
| |
| assertEncoding(encoding); |
| |
| position = arguments[2]; |
| length = arguments[1]; |
| buffer = new Buffer(length); |
| |
| offset = 0; |
| } |
| |
| var r = binding.read(fd, buffer, offset, length, position); |
| if (!legacy) { |
| return r; |
| } |
| |
| var str = (r > 0) ? buffer.toString(encoding, 0, r) : ''; |
| return [str, r]; |
| }; |
| |
| fs.write = function(fd, buffer, offset, length, position, callback) { |
| if (!Buffer.isBuffer(buffer)) { |
| // legacy string interface (fd, data, position, encoding, callback) |
| callback = arguments[4]; |
| position = arguments[2]; |
| assertEncoding(arguments[3]); |
| |
| buffer = new Buffer('' + arguments[1], arguments[3]); |
| offset = 0; |
| length = buffer.length; |
| } |
| |
| if (!length) { |
| if (typeof callback == 'function') { |
| process.nextTick(function() { |
| callback(undefined, 0); |
| }); |
| } |
| return; |
| } |
| |
| callback = maybeCallback(callback); |
| |
| function wrapper(err, written) { |
| // Retain a reference to buffer so that it can't be GC'ed too soon. |
| callback(err, written || 0, buffer); |
| } |
| |
| binding.write(fd, buffer, offset, length, position, wrapper); |
| }; |
| |
| fs.writeSync = function(fd, buffer, offset, length, position) { |
| if (!Buffer.isBuffer(buffer)) { |
| // legacy string interface (fd, data, position, encoding) |
| position = arguments[2]; |
| assertEncoding(arguments[3]); |
| |
| buffer = new Buffer('' + arguments[1], arguments[3]); |
| offset = 0; |
| length = buffer.length; |
| } |
| if (!length) return 0; |
| |
| return binding.write(fd, buffer, offset, length, position); |
| }; |
| |
| fs.rename = function(oldPath, newPath, callback) { |
| callback = makeCallback(callback); |
| if (!nullCheck(oldPath, callback)) return; |
| if (!nullCheck(newPath, callback)) return; |
| binding.rename(pathModule._makeLong(oldPath), |
| pathModule._makeLong(newPath), |
| callback); |
| }; |
| |
| fs.renameSync = function(oldPath, newPath) { |
| nullCheck(oldPath); |
| nullCheck(newPath); |
| return binding.rename(pathModule._makeLong(oldPath), |
| pathModule._makeLong(newPath)); |
| }; |
| |
| fs.truncate = function(path, len, callback) { |
| if (typeof path === 'number') { |
| // legacy |
| return fs.ftruncate(path, len, callback); |
| } |
| if (typeof len === 'function') { |
| callback = len; |
| len = 0; |
| } else if (typeof len === 'undefined') { |
| len = 0; |
| } |
| callback = maybeCallback(callback); |
| fs.open(path, 'r+', function(er, fd) { |
| if (er) return callback(er); |
| binding.ftruncate(fd, len, function(er) { |
| fs.close(fd, function(er2) { |
| callback(er || er2); |
| }); |
| }); |
| }); |
| }; |
| |
| fs.truncateSync = function(path, len) { |
| if (typeof path === 'number') { |
| // legacy |
| return fs.ftruncateSync(path, len); |
| } |
| if (typeof len === 'undefined') { |
| len = 0; |
| } |
| // allow error to be thrown, but still close fd. |
| var fd = fs.openSync(path, 'r+'); |
| try { |
| var ret = fs.ftruncateSync(fd, len); |
| } finally { |
| fs.closeSync(fd); |
| } |
| return ret; |
| }; |
| |
| fs.ftruncate = function(fd, len, callback) { |
| if (typeof len === 'function') { |
| callback = len; |
| len = 0; |
| } else if (typeof len === 'undefined') { |
| len = 0; |
| } |
| binding.ftruncate(fd, len, makeCallback(callback)); |
| }; |
| |
| fs.ftruncateSync = function(fd, len) { |
| if (typeof len === 'undefined') { |
| len = 0; |
| } |
| return binding.ftruncate(fd, len); |
| }; |
| |
| fs.rmdir = function(path, callback) { |
| callback = makeCallback(callback); |
| if (!nullCheck(path, callback)) return; |
| binding.rmdir(pathModule._makeLong(path), callback); |
| }; |
| |
| fs.rmdirSync = function(path) { |
| nullCheck(path); |
| return binding.rmdir(pathModule._makeLong(path)); |
| }; |
| |
| fs.fdatasync = function(fd, callback) { |
| binding.fdatasync(fd, makeCallback(callback)); |
| }; |
| |
| fs.fdatasyncSync = function(fd) { |
| return binding.fdatasync(fd); |
| }; |
| |
| fs.fsync = function(fd, callback) { |
| binding.fsync(fd, makeCallback(callback)); |
| }; |
| |
| fs.fsyncSync = function(fd) { |
| return binding.fsync(fd); |
| }; |
| |
| fs.mkdir = function(path, mode, callback) { |
| if (typeof mode === 'function') callback = mode; |
| callback = makeCallback(callback); |
| if (!nullCheck(path, callback)) return; |
| binding.mkdir(pathModule._makeLong(path), |
| modeNum(mode, 511 /*=0777*/), |
| callback); |
| }; |
| |
| fs.mkdirSync = function(path, mode) { |
| nullCheck(path); |
| return binding.mkdir(pathModule._makeLong(path), |
| modeNum(mode, 511 /*=0777*/)); |
| }; |
| |
| fs.readdir = function(path, callback) { |
| callback = makeCallback(callback); |
| if (!nullCheck(path, callback)) return; |
| binding.readdir(pathModule._makeLong(path), callback); |
| }; |
| |
| fs.readdirSync = function(path) { |
| nullCheck(path); |
| return binding.readdir(pathModule._makeLong(path)); |
| }; |
| |
| fs.fstat = function(fd, callback) { |
| binding.fstat(fd, makeCallback(callback)); |
| }; |
| |
| fs.lstat = function(path, callback) { |
| callback = makeCallback(callback); |
| if (!nullCheck(path, callback)) return; |
| binding.lstat(pathModule._makeLong(path), callback); |
| }; |
| |
| fs.stat = function(path, callback) { |
| callback = makeCallback(callback); |
| if (!nullCheck(path, callback)) return; |
| binding.stat(pathModule._makeLong(path), callback); |
| }; |
| |
| fs.fstatSync = function(fd) { |
| return binding.fstat(fd); |
| }; |
| |
| fs.lstatSync = function(path) { |
| nullCheck(path); |
| return binding.lstat(pathModule._makeLong(path)); |
| }; |
| |
| fs.statSync = function(path) { |
| nullCheck(path); |
| return binding.stat(pathModule._makeLong(path)); |
| }; |
| |
| fs.readlink = function(path, callback) { |
| callback = makeCallback(callback); |
| if (!nullCheck(path, callback)) return; |
| binding.readlink(pathModule._makeLong(path), callback); |
| }; |
| |
| fs.readlinkSync = function(path) { |
| nullCheck(path); |
| return binding.readlink(pathModule._makeLong(path)); |
| }; |
| |
| function preprocessSymlinkDestination(path, type) { |
| if (!isWindows) { |
| // No preprocessing is needed on Unix. |
| return path; |
| } else if (type === 'junction') { |
| // Junctions paths need to be absolute and \\?\-prefixed. |
| return pathModule._makeLong(path); |
| } else { |
| // Windows symlinks don't tolerate forward slashes. |
| return ('' + path).replace(/\//g, '\\'); |
| } |
| } |
| |
| fs.symlink = function(destination, path, type_, callback) { |
| var type = (typeof type_ === 'string' ? type_ : null); |
| var callback = makeCallback(arguments[arguments.length - 1]); |
| |
| if (!nullCheck(destination, callback)) return; |
| if (!nullCheck(path, callback)) return; |
| |
| binding.symlink(preprocessSymlinkDestination(destination, type), |
| pathModule._makeLong(path), |
| type, |
| callback); |
| }; |
| |
| fs.symlinkSync = function(destination, path, type) { |
| type = (typeof type === 'string' ? type : null); |
| |
| nullCheck(destination); |
| nullCheck(path); |
| |
| return binding.symlink(preprocessSymlinkDestination(destination, type), |
| pathModule._makeLong(path), |
| type); |
| }; |
| |
| fs.link = function(srcpath, dstpath, callback) { |
| callback = makeCallback(callback); |
| if (!nullCheck(srcpath, callback)) return; |
| if (!nullCheck(dstpath, callback)) return; |
| |
| binding.link(pathModule._makeLong(srcpath), |
| pathModule._makeLong(dstpath), |
| callback); |
| }; |
| |
| fs.linkSync = function(srcpath, dstpath) { |
| nullCheck(srcpath); |
| nullCheck(dstpath); |
| return binding.link(pathModule._makeLong(srcpath), |
| pathModule._makeLong(dstpath)); |
| }; |
| |
| fs.unlink = function(path, callback) { |
| callback = makeCallback(callback); |
| if (!nullCheck(path, callback)) return; |
| binding.unlink(pathModule._makeLong(path), callback); |
| }; |
| |
| fs.unlinkSync = function(path) { |
| nullCheck(path); |
| return binding.unlink(pathModule._makeLong(path)); |
| }; |
| |
| fs.fchmod = function(fd, mode, callback) { |
| binding.fchmod(fd, modeNum(mode), makeCallback(callback)); |
| }; |
| |
| fs.fchmodSync = function(fd, mode) { |
| return binding.fchmod(fd, modeNum(mode)); |
| }; |
| |
| if (constants.hasOwnProperty('O_SYMLINK')) { |
| fs.lchmod = function(path, mode, callback) { |
| callback = maybeCallback(callback); |
| fs.open(path, constants.O_WRONLY | constants.O_SYMLINK, function(err, fd) { |
| if (err) { |
| callback(err); |
| return; |
| } |
| // prefer to return the chmod error, if one occurs, |
| // but still try to close, and report closing errors if they occur. |
| fs.fchmod(fd, mode, function(err) { |
| fs.close(fd, function(err2) { |
| callback(err || err2); |
| }); |
| }); |
| }); |
| }; |
| |
| fs.lchmodSync = function(path, mode) { |
| var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK); |
| |
| // prefer to return the chmod error, if one occurs, |
| // but still try to close, and report closing errors if they occur. |
| var err, err2; |
| try { |
| var ret = fs.fchmodSync(fd, mode); |
| } catch (er) { |
| err = er; |
| } |
| try { |
| fs.closeSync(fd); |
| } catch (er) { |
| err2 = er; |
| } |
| if (err || err2) throw (err || err2); |
| return ret; |
| }; |
| } |
| |
| |
| fs.chmod = function(path, mode, callback) { |
| callback = makeCallback(callback); |
| if (!nullCheck(path, callback)) return; |
| binding.chmod(pathModule._makeLong(path), |
| modeNum(mode), |
| callback); |
| }; |
| |
| fs.chmodSync = function(path, mode) { |
| nullCheck(path); |
| return binding.chmod(pathModule._makeLong(path), modeNum(mode)); |
| }; |
| |
| if (constants.hasOwnProperty('O_SYMLINK')) { |
| fs.lchown = function(path, uid, gid, callback) { |
| callback = maybeCallback(callback); |
| fs.open(path, constants.O_WRONLY | constants.O_SYMLINK, function(err, fd) { |
| if (err) { |
| callback(err); |
| return; |
| } |
| fs.fchown(fd, uid, gid, callback); |
| }); |
| }; |
| |
| fs.lchownSync = function(path, uid, gid) { |
| var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK); |
| return fs.fchownSync(fd, uid, gid); |
| }; |
| } |
| |
| fs.fchown = function(fd, uid, gid, callback) { |
| binding.fchown(fd, uid, gid, makeCallback(callback)); |
| }; |
| |
| fs.fchownSync = function(fd, uid, gid) { |
| return binding.fchown(fd, uid, gid); |
| }; |
| |
| fs.chown = function(path, uid, gid, callback) { |
| callback = makeCallback(callback); |
| if (!nullCheck(path, callback)) return; |
| binding.chown(pathModule._makeLong(path), uid, gid, callback); |
| }; |
| |
| fs.chownSync = function(path, uid, gid) { |
| nullCheck(path); |
| return binding.chown(pathModule._makeLong(path), uid, gid); |
| }; |
| |
| // converts Date or number to a fractional UNIX timestamp |
| function toUnixTimestamp(time) { |
| if (typeof time == 'number') { |
| return time; |
| } |
| if (time instanceof Date) { |
| // convert to 123.456 UNIX timestamp |
| return time.getTime() / 1000; |
| } |
| throw new Error('Cannot parse time: ' + time); |
| } |
| |
| // exported for unit tests, not for public consumption |
| fs._toUnixTimestamp = toUnixTimestamp; |
| |
| fs.utimes = function(path, atime, mtime, callback) { |
| callback = makeCallback(callback); |
| if (!nullCheck(path, callback)) return; |
| binding.utimes(pathModule._makeLong(path), |
| toUnixTimestamp(atime), |
| toUnixTimestamp(mtime), |
| callback); |
| }; |
| |
| fs.utimesSync = function(path, atime, mtime) { |
| nullCheck(path); |
| atime = toUnixTimestamp(atime); |
| mtime = toUnixTimestamp(mtime); |
| binding.utimes(pathModule._makeLong(path), atime, mtime); |
| }; |
| |
| fs.futimes = function(fd, atime, mtime, callback) { |
| atime = toUnixTimestamp(atime); |
| mtime = toUnixTimestamp(mtime); |
| binding.futimes(fd, atime, mtime, makeCallback(callback)); |
| }; |
| |
| fs.futimesSync = function(fd, atime, mtime) { |
| atime = toUnixTimestamp(atime); |
| mtime = toUnixTimestamp(mtime); |
| binding.futimes(fd, atime, mtime); |
| }; |
| |
| function writeAll(fd, buffer, offset, length, position, callback) { |
| callback = maybeCallback(arguments[arguments.length - 1]); |
| |
| // write(fd, buffer, offset, length, position, callback) |
| fs.write(fd, buffer, offset, length, position, function(writeErr, written) { |
| if (writeErr) { |
| fs.close(fd, function() { |
| if (callback) callback(writeErr); |
| }); |
| } else { |
| if (written === length) { |
| fs.close(fd, callback); |
| } else { |
| offset += written; |
| length -= written; |
| position += written; |
| writeAll(fd, buffer, offset, length, position, callback); |
| } |
| } |
| }); |
| } |
| |
| fs.writeFile = function(path, data, options, callback) { |
| var callback = maybeCallback(arguments[arguments.length - 1]); |
| |
| if (typeof options === 'function' || !options) { |
| options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' }; |
| } else if (typeof options === 'string') { |
| options = { encoding: options, mode: 438, flag: 'w' }; |
| } else if (!options) { |
| options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' }; |
| } else if (typeof options !== 'object') { |
| throw new TypeError('Bad arguments'); |
| } |
| |
| assertEncoding(options.encoding); |
| |
| var flag = options.flag || 'w'; |
| fs.open(path, options.flag || 'w', options.mode, function(openErr, fd) { |
| if (openErr) { |
| if (callback) callback(openErr); |
| } else { |
| var buffer = Buffer.isBuffer(data) ? data : new Buffer('' + data, |
| options.encoding || 'utf8'); |
| var position = /a/.test(flag) ? null : 0; |
| writeAll(fd, buffer, 0, buffer.length, position, callback); |
| } |
| }); |
| }; |
| |
| fs.writeFileSync = function(path, data, options) { |
| if (!options) { |
| options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' }; |
| } else if (typeof options === 'string') { |
| options = { encoding: options, mode: 438, flag: 'w' }; |
| } else if (typeof options !== 'object') { |
| throw new TypeError('Bad arguments'); |
| } |
| |
| assertEncoding(options.encoding); |
| |
| var flag = options.flag || 'w'; |
| var fd = fs.openSync(path, flag, options.mode); |
| if (!Buffer.isBuffer(data)) { |
| data = new Buffer('' + data, options.encoding || 'utf8'); |
| } |
| var written = 0; |
| var length = data.length; |
| var position = /a/.test(flag) ? null : 0; |
| try { |
| while (written < length) { |
| written += fs.writeSync(fd, data, written, length - written, position); |
| position += written; |
| } |
| } finally { |
| fs.closeSync(fd); |
| } |
| }; |
| |
| fs.appendFile = function(path, data, options, callback_) { |
| var callback = maybeCallback(arguments[arguments.length - 1]); |
| |
| if (typeof options === 'function' || !options) { |
| options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' }; |
| } else if (typeof options === 'string') { |
| options = { encoding: options, mode: 438, flag: 'a' }; |
| } else if (!options) { |
| options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' }; |
| } else if (typeof options !== 'object') { |
| throw new TypeError('Bad arguments'); |
| } |
| |
| if (!options.flag) |
| options = util._extend({ flag: 'a' }, options); |
| fs.writeFile(path, data, options, callback); |
| }; |
| |
| fs.appendFileSync = function(path, data, options) { |
| if (!options) { |
| options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' }; |
| } else if (typeof options === 'string') { |
| options = { encoding: options, mode: 438, flag: 'a' }; |
| } else if (typeof options !== 'object') { |
| throw new TypeError('Bad arguments'); |
| } |
| if (!options.flag) |
| options = util._extend({ flag: 'a' }, options); |
| |
| fs.writeFileSync(path, data, options); |
| }; |
| |
| function errnoException(errorno, syscall) { |
| // TODO make this more compatible with ErrnoException from src/node.cc |
| // Once all of Node is using this function the ErrnoException from |
| // src/node.cc should be removed. |
| var e = new Error(syscall + ' ' + errorno); |
| e.errno = e.code = errorno; |
| e.syscall = syscall; |
| return e; |
| } |
| |
| |
| function FSWatcher() { |
| EventEmitter.call(this); |
| |
| var self = this; |
| var FSEvent = process.binding('fs_event_wrap').FSEvent; |
| this._handle = new FSEvent(); |
| this._handle.owner = this; |
| |
| this._handle.onchange = function(status, event, filename) { |
| if (status) { |
| self._handle.close(); |
| self.emit('error', errnoException(process._errno, 'watch')); |
| } else { |
| self.emit('change', event, filename); |
| } |
| }; |
| } |
| util.inherits(FSWatcher, EventEmitter); |
| |
| FSWatcher.prototype.start = function(filename, persistent) { |
| nullCheck(filename); |
| var r = this._handle.start(pathModule._makeLong(filename), persistent); |
| |
| if (r) { |
| this._handle.close(); |
| throw errnoException(process._errno, 'watch'); |
| } |
| }; |
| |
| FSWatcher.prototype.close = function() { |
| this._handle.close(); |
| }; |
| |
| fs.watch = function(filename) { |
| nullCheck(filename); |
| var watcher; |
| var options; |
| var listener; |
| |
| if ('object' == typeof arguments[1]) { |
| options = arguments[1]; |
| listener = arguments[2]; |
| } else { |
| options = {}; |
| listener = arguments[1]; |
| } |
| |
| if (options.persistent === undefined) options.persistent = true; |
| |
| watcher = new FSWatcher(); |
| watcher.start(filename, options.persistent); |
| |
| if (listener) { |
| watcher.addListener('change', listener); |
| } |
| |
| return watcher; |
| }; |
| |
| |
| // Stat Change Watchers |
| |
| function StatWatcher() { |
| EventEmitter.call(this); |
| |
| var self = this; |
| this._handle = new binding.StatWatcher(); |
| |
| // uv_fs_poll is a little more powerful than ev_stat but we curb it for |
| // the sake of backwards compatibility |
| var oldStatus = -1; |
| |
| this._handle.onchange = function(current, previous, newStatus) { |
| if (oldStatus === -1 && |
| newStatus === -1 && |
| current.nlink === previous.nlink) return; |
| |
| oldStatus = newStatus; |
| self.emit('change', current, previous); |
| }; |
| |
| this._handle.onstop = function() { |
| self.emit('stop'); |
| }; |
| } |
| util.inherits(StatWatcher, EventEmitter); |
| |
| |
| StatWatcher.prototype.start = function(filename, persistent, interval) { |
| nullCheck(filename); |
| this._handle.start(pathModule._makeLong(filename), persistent, interval); |
| }; |
| |
| |
| StatWatcher.prototype.stop = function() { |
| this._handle.stop(); |
| }; |
| |
| |
| var statWatchers = {}; |
| function inStatWatchers(filename) { |
| return Object.prototype.hasOwnProperty.call(statWatchers, filename) && |
| statWatchers[filename]; |
| } |
| |
| |
| fs.watchFile = function(filename) { |
| nullCheck(filename); |
| var stat; |
| var listener; |
| |
| var options = { |
| // Poll interval in milliseconds. 5007 is what libev used to use. It's |
| // a little on the slow side but let's stick with it for now to keep |
| // behavioral changes to a minimum. |
| interval: 5007, |
| persistent: true |
| }; |
| |
| if ('object' == typeof arguments[1]) { |
| options = util._extend(options, arguments[1]); |
| listener = arguments[2]; |
| } else { |
| listener = arguments[1]; |
| } |
| |
| if (!listener) { |
| throw new Error('watchFile requires a listener function'); |
| } |
| |
| if (inStatWatchers(filename)) { |
| stat = statWatchers[filename]; |
| } else { |
| stat = statWatchers[filename] = new StatWatcher(); |
| stat.start(filename, options.persistent, options.interval); |
| } |
| stat.addListener('change', listener); |
| return stat; |
| }; |
| |
| fs.unwatchFile = function(filename, listener) { |
| nullCheck(filename); |
| if (!inStatWatchers(filename)) return; |
| |
| var stat = statWatchers[filename]; |
| |
| if (typeof listener === 'function') { |
| stat.removeListener('change', listener); |
| } else { |
| stat.removeAllListeners('change'); |
| } |
| |
| if (EventEmitter.listenerCount(stat, 'change') === 0) { |
| stat.stop(); |
| statWatchers[filename] = undefined; |
| } |
| }; |
| |
| // Realpath |
| // Not using realpath(2) because it's bad. |
| // See: http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html |
| |
| var normalize = pathModule.normalize; |
| |
| // Regexp that finds the next partion of a (partial) path |
| // result is [base_with_slash, base], e.g. ['somedir/', 'somedir'] |
| if (isWindows) { |
| var nextPartRe = /(.*?)(?:[\/\\]+|$)/g; |
| } else { |
| var nextPartRe = /(.*?)(?:[\/]+|$)/g; |
| } |
| |
| // Regex to find the device root, including trailing slash. E.g. 'c:\\'. |
| if (isWindows) { |
| var splitRootRe = /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/; |
| } else { |
| var splitRootRe = /^[\/]*/; |
| } |
| |
| fs.realpathSync = function realpathSync(p, cache) { |
| // make p is absolute |
| p = pathModule.resolve(p); |
| |
| if (cache && Object.prototype.hasOwnProperty.call(cache, p)) { |
| return cache[p]; |
| } |
| |
| var original = p, |
| seenLinks = {}, |
| knownHard = {}; |
| |
| // current character position in p |
| var pos; |
| // the partial path so far, including a trailing slash if any |
| var current; |
| // the partial path without a trailing slash (except when pointing at a root) |
| var base; |
| // the partial path scanned in the previous round, with slash |
| var previous; |
| |
| start(); |
| |
| function start() { |
| // Skip over roots |
| var m = splitRootRe.exec(p); |
| pos = m[0].length; |
| current = m[0]; |
| base = m[0]; |
| previous = ''; |
| |
| // On windows, check that the root exists. On unix there is no need. |
| if (isWindows && !knownHard[base]) { |
| fs.lstatSync(base); |
| knownHard[base] = true; |
| } |
| } |
| |
| // walk down the path, swapping out linked pathparts for their real |
| // values |
| // NB: p.length changes. |
| while (pos < p.length) { |
| // find the next part |
| nextPartRe.lastIndex = pos; |
| var result = nextPartRe.exec(p); |
| previous = current; |
| current += result[0]; |
| base = previous + result[1]; |
| pos = nextPartRe.lastIndex; |
| |
| // continue if not a symlink |
| if (knownHard[base] || (cache && cache[base] === base)) { |
| continue; |
| } |
| |
| var resolvedLink; |
| if (cache && Object.prototype.hasOwnProperty.call(cache, base)) { |
| // some known symbolic link. no need to stat again. |
| resolvedLink = cache[base]; |
| } else { |
| var stat = fs.lstatSync(base); |
| if (!stat.isSymbolicLink()) { |
| knownHard[base] = true; |
| if (cache) cache[base] = base; |
| continue; |
| } |
| |
| // read the link if it wasn't read before |
| // dev/ino always return 0 on windows, so skip the check. |
| var linkTarget = null; |
| if (!isWindows) { |
| var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); |
| if (seenLinks.hasOwnProperty(id)) { |
| linkTarget = seenLinks[id]; |
| } |
| } |
| if (linkTarget === null) { |
| fs.statSync(base); |
| linkTarget = fs.readlinkSync(base); |
| } |
| resolvedLink = pathModule.resolve(previous, linkTarget); |
| // track this, if given a cache. |
| if (cache) cache[base] = resolvedLink; |
| if (!isWindows) seenLinks[id] = linkTarget; |
| } |
| |
| // resolve the link, then start over |
| p = pathModule.resolve(resolvedLink, p.slice(pos)); |
| start(); |
| } |
| |
| if (cache) cache[original] = p; |
| |
| return p; |
| }; |
| |
| |
| fs.realpath = function realpath(p, cache, cb) { |
| if (typeof cb !== 'function') { |
| cb = maybeCallback(cache); |
| cache = null; |
| } |
| |
| // make p is absolute |
| p = pathModule.resolve(p); |
| |
| if (cache && Object.prototype.hasOwnProperty.call(cache, p)) { |
| return process.nextTick(cb.bind(null, null, cache[p])); |
| } |
| |
| var original = p, |
| seenLinks = {}, |
| knownHard = {}; |
| |
| // current character position in p |
| var pos; |
| // the partial path so far, including a trailing slash if any |
| var current; |
| // the partial path without a trailing slash (except when pointing at a root) |
| var base; |
| // the partial path scanned in the previous round, with slash |
| var previous; |
| |
| start(); |
| |
| function start() { |
| // Skip over roots |
| var m = splitRootRe.exec(p); |
| pos = m[0].length; |
| current = m[0]; |
| base = m[0]; |
| previous = ''; |
| |
| // On windows, check that the root exists. On unix there is no need. |
| if (isWindows && !knownHard[base]) { |
| fs.lstat(base, function(err) { |
| if (err) return cb(err); |
| knownHard[base] = true; |
| LOOP(); |
| }); |
| } else { |
| process.nextTick(LOOP); |
| } |
| } |
| |
| // walk down the path, swapping out linked pathparts for their real |
| // values |
| function LOOP() { |
| // stop if scanned past end of path |
| if (pos >= p.length) { |
| if (cache) cache[original] = p; |
| return cb(null, p); |
| } |
| |
| // find the next part |
| nextPartRe.lastIndex = pos; |
| var result = nextPartRe.exec(p); |
| previous = current; |
| current += result[0]; |
| base = previous + result[1]; |
| pos = nextPartRe.lastIndex; |
| |
| // continue if not a symlink |
| if (knownHard[base] || (cache && cache[base] === base)) { |
| return process.nextTick(LOOP); |
| } |
| |
| if (cache && Object.prototype.hasOwnProperty.call(cache, base)) { |
| // known symbolic link. no need to stat again. |
| return gotResolvedLink(cache[base]); |
| } |
| |
| return fs.lstat(base, gotStat); |
| } |
| |
| function gotStat(err, stat) { |
| if (err) return cb(err); |
| |
| // if not a symlink, skip to the next path part |
| if (!stat.isSymbolicLink()) { |
| knownHard[base] = true; |
| if (cache) cache[base] = base; |
| return process.nextTick(LOOP); |
| } |
| |
| // stat & read the link if not read before |
| // call gotTarget as soon as the link target is known |
| // dev/ino always return 0 on windows, so skip the check. |
| if (!isWindows) { |
| var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); |
| if (seenLinks.hasOwnProperty(id)) { |
| return gotTarget(null, seenLinks[id], base); |
| } |
| } |
| fs.stat(base, function(err) { |
| if (err) return cb(err); |
| |
| fs.readlink(base, function(err, target) { |
| if (!isWindows) seenLinks[id] = target; |
| gotTarget(err, target); |
| }); |
| }); |
| } |
| |
| function gotTarget(err, target, base) { |
| if (err) return cb(err); |
| |
| var resolvedLink = pathModule.resolve(previous, target); |
| if (cache) cache[base] = resolvedLink; |
| gotResolvedLink(resolvedLink); |
| } |
| |
| function gotResolvedLink(resolvedLink) { |
| // resolve the link, then start over |
| p = pathModule.resolve(resolvedLink, p.slice(pos)); |
| start(); |
| } |
| }; |
| |
| |
| |
| var pool; |
| |
| function allocNewPool(poolSize) { |
| pool = new Buffer(poolSize); |
| pool.used = 0; |
| } |
| |
| |
| |
| fs.createReadStream = function(path, options) { |
| return new ReadStream(path, options); |
| }; |
| |
| util.inherits(ReadStream, Readable); |
| fs.ReadStream = ReadStream; |
| |
| function ReadStream(path, options) { |
| if (!(this instanceof ReadStream)) |
| return new ReadStream(path, options); |
| |
| // a little bit bigger buffer and water marks by default |
| options = util._extend({ |
| highWaterMark: 64 * 1024 |
| }, options || {}); |
| |
| Readable.call(this, options); |
| |
| this.path = path; |
| this.fd = options.hasOwnProperty('fd') ? options.fd : null; |
| this.flags = options.hasOwnProperty('flags') ? options.flags : 'r'; |
| this.mode = options.hasOwnProperty('mode') ? options.mode : 438; /*=0666*/ |
| |
| this.start = options.hasOwnProperty('start') ? options.start : undefined; |
| this.end = options.hasOwnProperty('end') ? options.end : undefined; |
| this.autoClose = options.hasOwnProperty('autoClose') ? |
| options.autoClose : true; |
| this.pos = undefined; |
| |
| if (this.start !== undefined) { |
| if ('number' !== typeof this.start) { |
| throw TypeError('start must be a Number'); |
| } |
| if (this.end === undefined) { |
| this.end = Infinity; |
| } else if ('number' !== typeof this.end) { |
| throw TypeError('end must be a Number'); |
| } |
| |
| if (this.start > this.end) { |
| throw new Error('start must be <= end'); |
| } |
| |
| this.pos = this.start; |
| } |
| |
| if (typeof this.fd !== 'number') |
| this.open(); |
| |
| this.on('end', function() { |
| if (this.autoClose) { |
| this.destroy(); |
| } |
| }); |
| } |
| |
| fs.FileReadStream = fs.ReadStream; // support the legacy name |
| |
| ReadStream.prototype.open = function() { |
| var self = this; |
| fs.open(this.path, this.flags, this.mode, function(er, fd) { |
| if (er) { |
| if (self.autoClose) { |
| self.destroy(); |
| } |
| self.emit('error', er); |
| return; |
| } |
| |
| self.fd = fd; |
| self.emit('open', fd); |
| // start the flow of data. |
| self.read(); |
| }); |
| }; |
| |
| ReadStream.prototype._read = function(n) { |
| if (typeof this.fd !== 'number') |
| return this.once('open', function() { |
| this._read(n); |
| }); |
| |
| if (this.destroyed) |
| return; |
| |
| if (!pool || pool.length - pool.used < kMinPoolSpace) { |
| // discard the old pool. |
| pool = null; |
| allocNewPool(this._readableState.highWaterMark); |
| } |
| |
| // Grab another reference to the pool in the case that while we're |
| // in the thread pool another read() finishes up the pool, and |
| // allocates a new one. |
| var thisPool = pool; |
| var toRead = Math.min(pool.length - pool.used, n); |
| var start = pool.used; |
| |
| if (this.pos !== undefined) |
| toRead = Math.min(this.end - this.pos + 1, toRead); |
| |
| // already read everything we were supposed to read! |
| // treat as EOF. |
| if (toRead <= 0) |
| return this.push(null); |
| |
| // the actual read. |
| var self = this; |
| fs.read(this.fd, pool, pool.used, toRead, this.pos, onread); |
| |
| // move the pool positions, and internal position for reading. |
| if (this.pos !== undefined) |
| this.pos += toRead; |
| pool.used += toRead; |
| |
| function onread(er, bytesRead) { |
| if (er) { |
| if (self.autoClose) { |
| self.destroy(); |
| } |
| self.emit('error', er); |
| } else { |
| var b = null; |
| if (bytesRead > 0) |
| b = thisPool.slice(start, start + bytesRead); |
| |
| self.push(b); |
| } |
| } |
| }; |
| |
| |
| ReadStream.prototype.destroy = function() { |
| if (this.destroyed) |
| return; |
| this.destroyed = true; |
| |
| if ('number' === typeof this.fd) |
| this.close(); |
| }; |
| |
| |
| ReadStream.prototype.close = function(cb) { |
| var self = this; |
| if (cb) |
| this.once('close', cb); |
| if (this.closed || 'number' !== typeof this.fd) { |
| if ('number' !== typeof this.fd) { |
| this.once('open', close); |
| return; |
| } |
| return process.nextTick(this.emit.bind(this, 'close')); |
| } |
| this.closed = true; |
| close(); |
| |
| function close(fd) { |
| fs.close(fd || self.fd, function(er) { |
| if (er) |
| self.emit('error', er); |
| else |
| self.emit('close'); |
| }); |
| self.fd = null; |
| } |
| }; |
| |
| |
| |
| |
| fs.createWriteStream = function(path, options) { |
| return new WriteStream(path, options); |
| }; |
| |
| util.inherits(WriteStream, Writable); |
| fs.WriteStream = WriteStream; |
| function WriteStream(path, options) { |
| if (!(this instanceof WriteStream)) |
| return new WriteStream(path, options); |
| |
| options = options || {}; |
| |
| Writable.call(this, options); |
| |
| this.path = path; |
| this.fd = null; |
| |
| this.fd = options.hasOwnProperty('fd') ? options.fd : null; |
| this.flags = options.hasOwnProperty('flags') ? options.flags : 'w'; |
| this.mode = options.hasOwnProperty('mode') ? options.mode : 438; /*=0666*/ |
| |
| this.start = options.hasOwnProperty('start') ? options.start : undefined; |
| this.pos = undefined; |
| this.bytesWritten = 0; |
| |
| if (this.start !== undefined) { |
| if ('number' !== typeof this.start) { |
| throw TypeError('start must be a Number'); |
| } |
| if (this.start < 0) { |
| throw new Error('start must be >= zero'); |
| } |
| |
| this.pos = this.start; |
| } |
| |
| if ('number' !== typeof this.fd) |
| this.open(); |
| |
| // dispose on finish. |
| this.once('finish', this.close); |
| } |
| |
| fs.FileWriteStream = fs.WriteStream; // support the legacy name |
| |
| |
| WriteStream.prototype.open = function() { |
| fs.open(this.path, this.flags, this.mode, function(er, fd) { |
| if (er) { |
| this.destroy(); |
| this.emit('error', er); |
| return; |
| } |
| |
| this.fd = fd; |
| this.emit('open', fd); |
| }.bind(this)); |
| }; |
| |
| |
| WriteStream.prototype._write = function(data, encoding, cb) { |
| if (!Buffer.isBuffer(data)) |
| return this.emit('error', new Error('Invalid data')); |
| |
| if (typeof this.fd !== 'number') |
| return this.once('open', function() { |
| this._write(data, encoding, cb); |
| }); |
| |
| var self = this; |
| fs.write(this.fd, data, 0, data.length, this.pos, function(er, bytes) { |
| if (er) { |
| self.destroy(); |
| return cb(er); |
| } |
| self.bytesWritten += bytes; |
| cb(); |
| }); |
| |
| if (this.pos !== undefined) |
| this.pos += data.length; |
| }; |
| |
| |
| WriteStream.prototype.destroy = ReadStream.prototype.destroy; |
| WriteStream.prototype.close = ReadStream.prototype.close; |
| |
| // There is no shutdown() for files. |
| WriteStream.prototype.destroySoon = WriteStream.prototype.end; |
| |
| |
| // SyncWriteStream is internal. DO NOT USE. |
| // Temporary hack for process.stdout and process.stderr when piped to files. |
| function SyncWriteStream(fd) { |
| Stream.call(this); |
| |
| this.fd = fd; |
| this.writable = true; |
| this.readable = false; |
| } |
| |
| util.inherits(SyncWriteStream, Stream); |
| |
| |
| // Export |
| fs.SyncWriteStream = SyncWriteStream; |
| |
| |
| SyncWriteStream.prototype.write = function(data, arg1, arg2) { |
| var encoding, cb; |
| |
| // parse arguments |
| if (arg1) { |
| if (typeof arg1 === 'string') { |
| encoding = arg1; |
| cb = arg2; |
| } else if (typeof arg1 === 'function') { |
| cb = arg1; |
| } else { |
| throw new Error('bad arg'); |
| } |
| } |
| assertEncoding(encoding); |
| |
| // Change strings to buffers. SLOW |
| if (typeof data == 'string') { |
| data = new Buffer(data, encoding); |
| } |
| |
| fs.writeSync(this.fd, data, 0, data.length); |
| |
| if (cb) { |
| process.nextTick(cb); |
| } |
| |
| return true; |
| }; |
| |
| |
| SyncWriteStream.prototype.end = function(data, arg1, arg2) { |
| if (data) { |
| this.write(data, arg1, arg2); |
| } |
| this.destroy(); |
| }; |
| |
| |
| SyncWriteStream.prototype.destroy = function() { |
| fs.closeSync(this.fd); |
| this.fd = null; |
| this.emit('close'); |
| return true; |
| }; |
| |
| SyncWriteStream.prototype.destroySoon = SyncWriteStream.prototype.destroy; |