var sys = require('sys'); var events = require('events'); var Buffer = require('buffer').Buffer; var binding = process.binding('fs'); var constants = process.binding('constants'); var fs = exports; var kMinPoolSpace = 128; var kPoolSize = 40 * 1024; 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.readFile = function (path, encoding_, callback){ var encoding = typeof (encoding_) == 'string'? encoding_: null ; var callback_ = arguments[_AN_Read_length('length', arguments) - 1]; var callback = (typeof (callback_) == 'function'? callback_: noop); binding.stat(path, function (err, stat){ if (err) { callback(err); return ; } _AN_Call_open('open', binding, path, constants.O_RDONLY, 438, function (err, fd){ if (err) { callback(err); return ; } var size = stat.size; var buffer = new Buffer(size); var offset = 0; function doRead(){ if (size < 1) { binding.close(fd); callback(null , encoding? '': buffer); return ; } binding.read(fd, buffer, offset, size - offset, offset || null , function (err, amount){ if (err) { callback(err); binding.close(fd); return ; } if (amount + offset < size) { offset += amount; doRead(); return ; } binding.close(fd); if (encoding) { try { var str = buffer.toString(encoding); } catch (err) { callback(err); return ; } callback(null , str); } else { callback(null , buffer); } } ); } doRead(); } ); } ); } ; fs.readFileSync = function (path, encoding){ var fd = fs.openSync(path, constants.O_RDONLY, 438); var stat = fs.statSync(path); var buffer = new Buffer(stat.size); var nread = 0; while (nread < _AN_Read_length('length', buffer)){ nread += fs.readSync(fd, buffer, nread, _AN_Read_length('length', buffer) - nread, null ); } fs.closeSync(fd); if (encoding) { return buffer.toString(encoding); } else { return buffer; } } ; function stringToFlags(flag){ if (typeof flag !== 'string') { return flag; } switch (flag){ case "r": return constants.O_RDONLY; case "r+": return constants.O_RDWR; case "w": return constants.O_CREAT | constants.O_TRUNC | constants.O_WRONLY; case "w+": return constants.O_CREAT | constants.O_TRUNC | constants.O_RDWR; case "a": return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY; case "a+": return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR; default : { throw new Error("Unknown file open flag: " + flag) } } } function noop(){ } fs.close = function (fd, callback){ return binding.close(fd, callback || noop); } ; fs.closeSync = function (fd){ return binding.close(fd); } ; fs.open = function (path, flags, mode_, callback){ var mode = (typeof (mode_) == 'number'? mode_: 438); var callback_ = arguments[_AN_Read_length('length', arguments) - 1]; var callback = (typeof (callback_) == 'function'? callback_: null ); return _AN_Call_open('open', binding, path, stringToFlags(flags), mode, callback || noop); } ; fs.openSync = function (path, flags, mode){ if (mode === undefined) { mode = 438; } return _AN_Call_open('open', binding, path, stringToFlags(flags), mode); } ; fs.read = function (fd, buffer, offset, length, position, callback){ if (!Buffer.isBuffer(buffer)) { var cb = arguments[4], encoding = arguments[3]; 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); } ; } return binding.read(fd, buffer, offset, length, position, callback || noop); } ; fs.readSync = function (fd, buffer, offset, length, position){ var legacy = false ; if (!Buffer.isBuffer(buffer)) { legacy = true ; encoding = arguments[3]; 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)) { callback = arguments[4]; position = arguments[2]; buffer = new Buffer('' + arguments[1], arguments[3]); offset = 0; length = _AN_Read_length('length', buffer); } if (!length) { if (typeof callback == 'function') { process.nextTick(function (){ callback(undefined, 0); } ); } return ; } return _AN_Call_write('write', binding, fd, buffer, offset, length, position, callback || noop); } ; fs.writeSync = function (fd, buffer, offset, length, position){ if (!Buffer.isBuffer(buffer)) { position = arguments[2]; buffer = new Buffer('' + arguments[1], arguments[3]); offset = 0; length = _AN_Read_length('length', buffer); } if (!length) return 0; return _AN_Call_write('write', binding, fd, buffer, offset, length, position); } ; fs.rename = function (oldPath, newPath, callback){ return binding.rename(oldPath, newPath, callback || noop); } ; fs.renameSync = function (oldPath, newPath){ return binding.rename(oldPath, newPath); } ; fs.truncate = function (fd, len, callback){ return binding.truncate(fd, len, callback || noop); } ; fs.truncateSync = function (fd, len){ return binding.truncate(fd, len); } ; fs.rmdir = function (path, callback){ return binding.rmdir(path, callback || noop); } ; fs.rmdirSync = function (path){ return binding.rmdir(path); } ; fs.fdatasync = function (fd, callback){ binding.fdatasync(fd, callback || noop); } ; fs.fdatasyncSync = function (fd){ return binding.fdatasync(fd); } ; fs.fsync = function (fd, callback){ return binding.fsync(fd, callback || noop); } ; fs.fsyncSync = function (fd){ return binding.fsync(fd); } ; fs.mkdir = function (path, mode, callback){ binding.mkdir(path, mode, callback || noop); } ; fs.mkdirSync = function (path, mode){ return binding.mkdir(path, mode); } ; fs.sendfile = function (outFd, inFd, inOffset, length, callback){ return binding.sendfile(outFd, inFd, inOffset, length, callback || noop); } ; fs.sendfileSync = function (outFd, inFd, inOffset, length){ return binding.sendfile(outFd, inFd, inOffset, length); } ; fs.readdir = function (path, callback){ return binding.readdir(path, callback || noop); } ; fs.readdirSync = function (path){ return binding.readdir(path); } ; fs.fstat = function (fd, callback){ return binding.fstat(fd, callback || noop); } ; fs.lstat = function (path, callback){ return binding.lstat(path, callback || noop); } ; fs.stat = function (path, callback){ return binding.stat(path, callback || noop); } ; fs.fstatSync = function (fd){ return binding.fstat(fd); } ; fs.lstatSync = function (path){ return binding.lstat(path); } ; fs.statSync = function (path){ return binding.stat(path); } ; fs.readlink = function (path, callback){ return binding.readlink(path, callback || noop); } ; fs.readlinkSync = function (path){ return binding.readlink(path); } ; fs.symlink = function (destination, path, callback){ return binding.symlink(destination, path, callback || noop); } ; fs.symlinkSync = function (destination, path){ return binding.symlink(destination, path); } ; fs.link = function (srcpath, dstpath, callback){ return binding.link(srcpath, dstpath, callback || noop); } ; fs.linkSync = function (srcpath, dstpath){ return binding.link(srcpath, dstpath); } ; fs.unlink = function (path, callback){ return binding.unlink(path, callback || noop); } ; fs.unlinkSync = function (path){ return binding.unlink(path); } ; fs.chmod = function (path, mode, callback){ return binding.chmod(path, mode, callback || noop); } ; fs.chmodSync = function (path, mode){ return binding.chmod(path, mode); } ; fs.chown = function (path, uid, gid, callback){ return binding.chown(path, uid, gid, callback || noop); } ; fs.chownSync = function (path, uid, gid){ return binding.chown(path, uid, gid); } ; function writeAll(fd, buffer, callback){ _AN_Call_write('write', fs, fd, buffer, 0, _AN_Read_length('length', buffer), null , function (writeErr, written){ if (writeErr) { fs.close(fd, function (){ if (callback) callback(writeErr); } ); } else { if (written === _AN_Read_length('length', buffer)) { fs.close(fd, callback); } else { writeAll(fd, buffer.slice(written), callback); } } } ); } fs.writeFile = function (path, data, encoding_, callback){ var encoding = (typeof (encoding_) == 'string'? encoding_: 'utf8'); var callback_ = arguments[_AN_Read_length('length', arguments) - 1]; var callback = (typeof (callback_) == 'function'? callback_: null ); _AN_Call_open('open', fs, path, 'w', 438, function (openErr, fd){ if (openErr) { if (callback) callback(openErr); } else { var buffer = Buffer.isBuffer(data)? data: new Buffer(data, encoding); writeAll(fd, buffer, callback); } } ); } ; fs.writeFileSync = function (path, data, encoding){ encoding = encoding || "utf8"; var fd = fs.openSync(path, "w"); var written = 0; while (written < _AN_Read_length("length", data)){ written += fs.writeSync(fd, data, 0, encoding); data = data.slice(written); } fs.closeSync(fd); } ; fs.cat = function (){ throw new Error("fs.cat is deprecated. Please use fs.readFile instead.") } ; fs.catSync = function (){ throw new Error("fs.catSync is deprecated. Please use fs.readFileSync instead.") } ; var statWatchers = { } ; fs.watchFile = function (filename){ var stat; 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 ; if (options.interval === undefined) options.interval = 0; if (statWatchers[filename]) { stat = statWatchers[filename]; } else { statWatchers[filename] = new binding.StatWatcher(); stat = statWatchers[filename]; stat.start(filename, options.persistent, options.interval); } stat.callback = listener; return stat; } ; fs.unwatchFile = function (filename){ if (statWatchers[filename]) { stat = statWatchers[filename]; stat.stop(); statWatchers[filename] = undefined; } } ; var path = require('path'); var normalize = path.normalize; var normalizeArray = path.normalizeArray; fs.realpathSync = realpathSync; fs.realpath = realpath; function realpathSync(p){ if (p.charAt(0) !== '/') { p = path.join(process.cwd(), p); } p = p.split('/'); var buf = [''] ; var seenLinks = { } ; var knownHard = { } ; for (var i = 0; i < _AN_Read_length('length', p); i++ ){ if (p[i] === '') continue ; var part = buf.join('/') + '/' + p[i]; if (knownHard[part]) { buf.push(p[i]); continue ; } var stat = fs.lstatSync(part); if (!stat.isSymbolicLink()) { knownHard[part] = true ; buf.push(p[i]); continue ; } var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); if (seenLinks[id]) throw new Error("cyclic link at " + part) seenLinks[id] = true ; var target = fs.readlinkSync(part); if (target.charAt(0) === '/') { buf = [''] ; p = path.normalizeArray(target.split('/').concat(p.slice(i + 1))); i = 0; continue ; } target = target.split('/'); Array.prototype.splice.apply(p, [i, 1] .concat(target)); p = path.normalizeArray(p); i = 0; buf = [''] ; } return buf.join('/') || '/'; } function realpath(p, cb){ if (p.charAt(0) !== '/') { p = path.join(process.cwd(), p); } p = p.split('/'); var buf = [''] ; var seenLinks = { } ; var knownHard = { } ; var i = 0; var part; LOOP(); function LOOP(){ i++ ; if (!(i < _AN_Read_length('length', p))) return exit(); if (p[i] === '') return process.nextTick(LOOP); part = buf.join('/') + '/' + p[i]; if (knownHard[part]) { buf.push(p[i]); return process.nextTick(LOOP); } return fs.lstat(part, gotStat); } function gotStat(er, stat){ if (er) return cb(er); if (!stat.isSymbolicLink()) { knownHard[part] = true ; buf.push(p[i]); return process.nextTick(LOOP); } var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); if (seenLinks[id]) return cb(new Error("cyclic link at " + part)); seenLinks[id] = true ; fs.readlink(part, gotTarget); } function gotTarget(er, target){ if (er) return cb(er); if (target.charAt(0) === '/') { buf = [''] ; p = path.normalizeArray(target.split('/').concat(p.slice(i + 1))); i = 0; return process.nextTick(LOOP); } target = target.split('/'); Array.prototype.splice.apply(p, [i, 1] .concat(target)); p = path.normalizeArray(p); i = 0; buf = [''] ; return process.nextTick(LOOP); } function exit(){ cb(null , buf.join('/') || '/'); } } var pool; function allocNewPool(){ pool = new Buffer(kPoolSize); pool.used = 0; } fs.createReadStream = function (path, options){ return new ReadStream(path, options); } ; var ReadStream = fs.ReadStream = function (path, options){ if (!(this instanceof ReadStream)) return new ReadStream(path, options); events.EventEmitter.call(this); var self = this; this.path = path; this.fd = null ; this.readable = true ; this.paused = false ; this.flags = 'r'; this.mode = 438; this.bufferSize = 64 * 1024; options = options || { } ; var keys = Object.keys(options); for (var index = 0, length = _AN_Read_length('length', keys); index < length; index++ ){ var key = keys[index]; this[key] = options[key]; } if (this.start || this.end) { if (this.start === undefined || this.end === undefined) { this.emit('error', new Error('Both start and end are needed for range streaming.')); } else if (this.start > this.end) { this.emit('error', new Error('start must be <= end')); } else { this.firstRead = true ; } } if (this.fd !== null ) { return ; } _AN_Call_open('open', fs, this.path, this.flags, this.mode, function (err, fd){ if (err) { self.emit('error', err); self.readable = false ; return ; } self.fd = fd; self.emit('open', fd); self._read(); } ); } ; sys.inherits(ReadStream, events.EventEmitter); fs.FileReadStream = fs.ReadStream; ReadStream.prototype.setEncoding = function (encoding){ var StringDecoder = require("string_decoder").StringDecoder; this._decoder = new StringDecoder(encoding); } ; ReadStream.prototype._read = function (){ var self = this; if (!self.readable || self.paused) return ; if (!pool || _AN_Read_length("length", pool) - pool.used < kMinPoolSpace) { pool = null ; allocNewPool(); } if (this.start && this.firstRead) { this.pos = this.start; this.firstRead = false ; } var thisPool = pool; var toRead = Math.min(_AN_Read_length("length", pool) - pool.used, this.bufferSize); var start = pool.used; if (this.pos) { toRead = Math.min(this.end - this.pos + 1, toRead); } function afterRead(err, bytesRead){ if (err) { self.emit('error', err); self.readable = false ; return ; } if (bytesRead === 0) { self.emit('end'); self.destroy(); return ; } var b = thisPool.slice(start, start + bytesRead); if (self.paused) { self.buffer = b; return ; } if (!self.readable) return ; self._emitData(b); self._read(); } fs.read(self.fd, pool, pool.used, toRead, this.pos, afterRead); if (self.pos) { self.pos += toRead; } pool.used += toRead; } ; ReadStream.prototype._emitData = function (d){ if (this._decoder) { var string = _AN_Call_write('write', this._decoder, d); if (string.length) this.emit('data', string); } else { this.emit('data', d); } } ; var readStreamForceCloseWarning; ReadStream.prototype.forceClose = function (cb){ if (!readStreamForceCloseWarning) { readStreamForceCloseWarning = "ReadStream.prototype.forceClose renamed to destroy()"; sys.error(readStreamForceCloseWarning); } return this.destroy(cb); } ; ReadStream.prototype.destroy = function (cb){ var self = this; this.readable = false ; function close(){ fs.close(self.fd, function (err){ if (err) { if (cb) cb(err); self.emit('error', err); return ; } if (cb) cb(null ); self.emit('close'); } ); } if (this.fd) { close(); } else { this.addListener('open', close); } } ; ReadStream.prototype.pause = function (){ this.paused = true ; } ; ReadStream.prototype.resume = function (){ this.paused = false ; if (this.buffer) { this._emitData(this.buffer); this.buffer = null ; } this._read(); } ; fs.createWriteStream = function (path, options){ return new WriteStream(path, options); } ; var WriteStream = fs.WriteStream = function (path, options){ if (!(this instanceof WriteStream)) return new WriteStream(path, options); events.EventEmitter.call(this); this.path = path; this.fd = null ; this.writeable = true ; this.flags = 'w'; this.encoding = 'binary'; this.mode = 438; options = options || { } ; var keys = Object.keys(options); for (var index = 0, length = _AN_Read_length('length', keys); index < length; index++ ){ var key = keys[index]; this[key] = options[key]; } this.busy = false ; this._queue = [] ; if (this.fd === null ) { this._queue.push([fs.open, this.path, this.flags, this.mode, undefined] ); this.flush(); } } ; sys.inherits(WriteStream, events.EventEmitter); fs.FileWriteStream = fs.WriteStream; WriteStream.prototype.flush = function (){ if (this.busy) return ; var self = this; var args = this._queue.shift(); if (!args) { if (this.drainable) { self.emit('drain'); } return ; } this.busy = true ; var method = args.shift(), cb = args.pop(); var self = this; args.push(function (err){ self.busy = false ; if (err) { self.writeable = false ; if (cb) { cb(err); } self.emit('error', err); return ; } if (method === fs.close) { if (cb) { cb(null ); } self.emit('close'); return ; } if (method === fs.open) { self.fd = arguments[1]; self.emit('open', self.fd); } else if (cb) { cb(null , arguments[1]); } self.flush(); } ); if (method !== fs.open) { args.unshift(self.fd); } method.apply(this, args); } ; WriteStream.prototype.write = function (data){ if (!this.writeable) { throw new Error('stream not writeable') } this.drainable = true ; var cb; if (typeof (arguments[_AN_Read_length('length', arguments) - 1]) == 'function') { cb = arguments[_AN_Read_length('length', arguments) - 1]; } if (Buffer.isBuffer(data)) { this._queue.push([fs.write, data, 0, _AN_Read_length('length', data), null , cb] ); } else { var encoding = 'utf8'; if (typeof (arguments[1]) == 'string') encoding = arguments[1]; this._queue.push([fs.write, data, undefined, encoding, cb] ); } this.flush(); return false ; } ; var writeStreamCloseWarning; WriteStream.prototype.close = function (cb){ if (!writeStreamCloseWarning) { writeStreamCloseWarning = "WriteStream.prototype.close renamed to end()"; sys.error(writeStreamCloseWarning); } return this.end(cb); } ; WriteStream.prototype.end = function (cb){ this.writeable = false ; this._queue.push([fs.close, cb] ); this.flush(); } ; var writeStreamForceCloseWarning; WriteStream.prototype.forceClose = function (cb){ if (!writeStreamForceCloseWarning) { writeStreamForceCloseWarning = "WriteStream.prototype.forceClose renamed to destroy()"; sys.error(writeStreamForceCloseWarning); } return this.destroy(cb); } ; WriteStream.prototype.destroy = function (cb){ var self = this; this.writeable = false ; function close(){ fs.close(self.fd, function (err){ if (err) { if (cb) { cb(err); } self.emit('error', err); return ; } if (cb) { cb(null ); } self.emit('close'); } ); } if (this.fd) { close(); } else { this.addListener('open', close); } } ;