fs-mock
Version:
[ABANDONED] Simple fs mock with posix and windows file system styles
1,564 lines (1,146 loc) • 30.3 kB
JavaScript
(function() {
var escape = require('escape-regexp');
var Readable = require('stream').Readable;
var Writable = require('stream').Writable;
var Stats = require('./Stats');
var Errors = require('./Errors');
var FSWatcher = require('./FSWatcher');
var Helpers = require('./Helpers');
var bind = function(fn, self) {
return function() {
return fn.apply(self, arguments);
};
};
var isFunction = function(obj) {
return Object.prototype.toString.call(obj) === '[object Function]';
};
var isReadable = function(flags) {
return flags === 'r' || flags === 'r+' || flags === 'rs' || flags === 'rs+' || flags === 'w+' || flags === 'wx+' || flags === 'a+' || flags === 'ax+';
};
var isWritable = function(flags) {
return flags === 'r+' || flags === 'rs+' || flags === 'w' || flags === 'wx' || flags === 'w+' || flags === 'wx+';
};
var isCreatable = function(flags) {
return flags === 'w' || flags === 'w+' || flags === 'a' || flags === 'a+';
};
var toDate = function(time) {
if (typeof time === 'number') {
return new Date(time * 1000);
}
if (time instanceof Date) {
return time;
}
throw new Error("Cannot parse time: " + time);
};
var fs = function(tree, options) {
var drive, i;
if (tree == null) {
tree = {};
}
if (options == null) {
options = {};
}
this._data = {};
this._fileDescriptors = [];
if (typeof options.windows === 'undefined') {
options.windows = false;
}
if (typeof options.root === 'undefined') {
options.root = (options.windows ? fs.ROOT_DIRECTORY.windows : fs.ROOT_DIRECTORY.posix);
}
if (typeof options.drives === 'undefined') {
options.drives = [];
}
if (options.root) {
options.root = Helpers.normalizePath(options.windows, options.root);
if (options.windows) {
options.root = Helpers.normalizeDriveWindows(options.root);
}
options._root = escape(options.root);
}
options.delimiter = (options.windows ? fs.DELIMITER.windows : fs.DELIMITER.posix);
options._delimiter = escape(options.delimiter);
if (!options.windows && options.drives.length > 0) {
throw new Error('Options drive can be used only with windows options.');
}
this._options = options;
if (options.root) {
this._addPath(options.root, null, null, true);
}
for (i = 0; i < options.drives.length; i++) {
this._addPath(Helpers.normalizeDriveWindows(options.drives[i]), null, null, true);
}
this._setTree(tree, {});
this.rename = bind(this.rename, this);
this.renameSync = bind(this.renameSync, this);
this.ftruncate = bind(this.ftruncate, this);
this.ftruncateSync = bind(this.ftruncateSync, this);
this.truncate = bind(this.truncate, this);
this.truncateSync = bind(this.truncateSync, this);
this.chown = bind(this.chown, this);
this.chownSync = bind(this.chownSync, this);
this.fchown = bind(this.fchown, this);
this.fchownSync = bind(this.fchownSync, this);
this.lchown = bind(this.lchown, this);
this.lchownSync = bind(this.lchownSync, this);
this.chmod = bind(this.chmod, this);
this.chmodSync = bind(this.chmodSync, this);
this.fchmod = bind(this.fchmod, this);
this.fchmodSync = bind(this.fchmodSync, this);
this.lchmod = bind(this.lchmod, this);
this.lchmodSync = bind(this.lchmodSync, this);
this.stat = bind(this.stat, this);
this.statSync = bind(this.statSync, this);
this.lstat = bind(this.lstat, this);
this.lstatSync = bind(this.lstatSync, this);
this.fstat = bind(this.fstat, this);
this.fstatSync = bind(this.fstatSync, this);
this.link = bind(this.link, this);
this.linkSync = bind(this.linkSync, this);
this.symlink = bind(this.symlink, this);
this.symlinkSync = bind(this.symlinkSync, this);
this.readlink = bind(this.readlink, this);
this.readlinkSync = bind(this.readlinkSync, this);
this.realpath = bind(this.realpath, this);
this.realpathSync = bind(this.realpathSync, this);
this.unlink = bind(this.unlink, this);
this.unlinkSync = bind(this.unlinkSync, this);
this.rmdir = bind(this.rmdir, this);
this.rmdirSync = bind(this.rmdirSync, this);
this.mkdir = bind(this.mkdir, this);
this.mkdirSync = bind(this.mkdirSync, this);
this.readdir = bind(this.readdir, this);
this.readdirSync = bind(this.readdirSync, this);
this.close = bind(this.close, this);
this.closeSync = bind(this.closeSync, this);
this.open = bind(this.open, this);
this.openSync = bind(this.openSync, this);
this.utimes = bind(this.utimes, this);
this.utimesSync = bind(this.utimesSync, this);
this.futimes = bind(this.futimes, this);
this.futimesSync = bind(this.futimesSync, this);
this.fsync = bind(this.fsync, this);
this.fsyncSync = bind(this.fsyncSync, this);
this.write = bind(this.write, this);
this.writeSync = bind(this.writeSync, this);
this.read = bind(this.read, this);
this.readSync = bind(this.readSync, this);
this.readFile = bind(this.readFile, this);
this.readFileSync = bind(this.readFileSync, this);
this.writeFile = bind(this.writeFile, this);
this.writeFileSync = bind(this.writeFileSync, this);
this.appendFile = bind(this.appendFile, this);
this.appendFileSync = bind(this.appendFileSync, this);
this.watchFile = bind(this.watchFile, this);
this.unwatchFile = bind(this.unwatchFile, this);
this.watch = bind(this.watch, this);
this.exists = bind(this.exists, this);
this.existsSync = bind(this.existsSync, this);
this.createReadStream = bind(this.createReadStream, this);
this.createWriteStream = bind(this.createWriteStream, this);
};
fs.DELIMITER = {
posix: '/',
windows: '\\'
};
fs.ROOT_DIRECTORY = {
posix: fs.DELIMITER.posix,
windows: 'c:'
};
fs.prototype._options = null;
fs.prototype._data = null;
fs.prototype._fileDescriptors = null;
fs.prototype._fileDescriptorsCounter = 0;
fs.prototype._hasFd = function(fd) {
return typeof this._fileDescriptors[fd] !== 'undefined';
};
fs.prototype._hasSubPaths = function(path) {
var found;
for (found in this._data) {
if (this._data.hasOwnProperty(found)) {
if (path !== found && found.match(new RegExp('^' + escape(path))) !== null) {
return true;
}
}
}
return false;
};
fs.prototype._setAttributes = function(path, attributes) {
if (attributes == null) {
attributes = {};
}
return this._data[path].stats._setAttributes(attributes);
};
fs.prototype._addPath = function(path, data, info, root) {
var item, stats, subData, subPath, type;
if (data == null) {
data = '';
}
if (info == null) {
info = {};
}
if (root == null) {
root = false;
}
if (typeof info.stats === 'undefined') {
info.stats = {};
}
if (typeof info.mode === 'undefined') {
info.mode = 777;
}
if (typeof info.encoding === 'undefined') {
info.encoding = 'utf8';
}
if (typeof info.source === 'undefined') {
info.source = null;
}
if (path[0] === '@') {
return this.linkSync(data, path.substr(1));
}
if (root) {
type = 'directory';
info = {
paths: {}
};
} else if (path[0] === '%') {
type = 'symlink';
path = path.substr(1);
info = {
source: data
};
} else if (typeof data === 'string' || data instanceof Buffer) {
type = 'file';
info = {
data: data
};
} else if (Object.prototype.toString.call(data) === '[object Object]') {
type = 'directory';
info = {
paths: data
};
} else {
throw new Error('Unknown type');
}
if (!root && this._options.root && path.match(new RegExp('^' + this._options._root)) === null) {
path = Helpers.joinPaths(this._options.windows, this._options.root, path);
}
path = Helpers.normalizePath(this._options.windows, path);
stats = new Stats(path, info.stats);
stats.mode = info.mode;
this._data[path] = {};
item = this._data[path];
item.stats = stats;
switch (type) {
case 'directory':
stats._isDirectory = true;
if (typeof info.paths !== 'undefined') {
for (subPath in info.paths) {
if (info.paths.hasOwnProperty(subPath)) {
subData = info.paths[subPath];
this._addPath(Helpers.joinPaths(this._options.windows, path, subPath), subData);
}
}
}
break;
case 'file':
stats._isFile = true;
if (typeof info.data === 'undefined') {
item.data = new Buffer('', info.encoding);
} else if (info.data instanceof Buffer) {
item.data = info.data;
} else {
item.data = new Buffer(info.data, info.encoding);
}
stats.blksize = stats.size = item.data.length;
break;
case 'symlink':
stats._isSymlink = true;
item.source = info.source;
break;
default:
throw new Error("Type must be directory, file or symlink, " + type + " given.");
}
};
fs.prototype._expandPaths = function() {
var path;
for (path in this._data) {
if (this._data.hasOwnProperty(path)) {
this._expandPath(path);
}
}
};
fs.prototype._expandPath = function(path) {
var match, position, sub;
match = path.match(new RegExp(this._options._delimiter, 'g'));
if (match !== null && match.length > 1) {
sub = path;
while (sub !== null) {
position = sub.lastIndexOf(this._options.delimiter);
if (position > 0) {
sub = sub.substring(0, sub.lastIndexOf(this._options.delimiter));
if (typeof this._data[sub] === 'undefined') {
this._addPath(sub, {});
}
} else {
sub = null;
}
}
}
};
fs.prototype._setTree = function(tree, info) {
var path;
if (info == null) {
info = {};
}
for (path in tree) {
if (tree.hasOwnProperty(path)) {
this._addPath(path, tree[path]);
}
}
for (path in info) {
if (info.hasOwnProperty(path)) {
this._setAttributes(path, info[path]);
}
}
this._expandPaths();
};
fs.prototype._realpath = function(path) {
if (path[0] === '.') {
path = Helpers.joinPaths(this._options.windows, this._options.delimiter, path);
}
return Helpers.normalizePath(this._options.windows, path);
};
fs.prototype._getSourcePath = function(path) {
path = this._realpath(path);
if (!this._data[path]) {
return path;
}
if (this._data[path].stats.isSymbolicLink()) {
return this._data[path].source;
}
return path;
};
fs.prototype.rename = function(oldPath, newPath, callback) {
try {
this.renameSync(oldPath, newPath);
callback();
} catch (e) {
callback(e);
}
};
fs.prototype.renameSync = function(oldPath, newPath) {
oldPath = this.realpathSync(oldPath);
newPath = this._realpath(newPath);
if (!this.existsSync(oldPath)) {
Errors.notFound(oldPath);
}
if (this.existsSync(newPath)) {
Errors.alreadyExists(newPath);
}
this._data[newPath] = this._data[oldPath];
delete this._data[oldPath];
this._data[newPath].stats._path = newPath;
this._data[newPath].stats._modifiedAttributes('rename');
};
fs.prototype.ftruncate = function(fd, len, callback) {
try {
this.ftruncateSync(fd, len);
callback();
} catch (e) {
callback(e);
}
};
fs.prototype.ftruncateSync = function(fd, len) {
var data, item;
if (!this._hasFd(fd)) {
Errors.fdNotFound(fd);
}
item = this._data[this._fileDescriptors[fd].path];
data = item.data.toString('utf8');
if (item.data.length > len) {
data = data.substr(0, len);
}
return this.writeSync(fd, new Buffer(data), 0, data.length, null);
};
fs.prototype.truncate = function(path, len, callback) {
try {
this.truncateSync(path, len);
callback();
} catch (e) {
callback(e);
}
};
fs.prototype.truncateSync = function(path, len) {
var fd;
path = this._getSourcePath(path);
if (!this.existsSync(path)) {
Errors.notFound(path);
}
fd = this.openSync(path, 'w');
if (!this.fstatSync(fd).isFile()) {
Errors.notFile(path);
}
this.ftruncateSync(fd, len);
this.closeSync(fd);
};
fs.prototype.chown = function(path, uid, gid, callback) {
try {
this.chownSync(path, uid, gid);
callback();
} catch (e) {
callback(e);
}
};
fs.prototype.chownSync = function(path, uid, gid) {
var fd;
path = this._getSourcePath(path);
fd = this.openSync(path, 'r');
this.fchownSync(fd, uid, gid);
this.closeSync(fd);
};
fs.prototype.fchown = function(fd, uid, gid, callback) {
try {
this.fchownSync(fd, uid, gid);
callback();
} catch (e) {
callback(e);
}
};
fs.prototype.fchownSync = function(fd, uid, gid) {
if (!this._hasFd(fd)) {
Errors.fdNotFound(fd);
}
this._setAttributes(this._fileDescriptors[fd].path, {
uid: uid,
gid: gid
});
};
fs.prototype.lchown = function(path, uid, gid, callback) {
try {
this.lchownSync(path, uid, gid);
callback(null);
} catch (e) {
callback(e);
}
};
fs.prototype.lchownSync = function(path, uid, gid) {
path = this.realpathSync(path);
if (!this.existsSync(path)) {
Errors.notFound(path);
}
if (!this.lstatSync(path).isSymbolicLink()) {
Errors.notSymlink(path);
}
this._setAttributes(path, {
uid: uid,
gid: gid
});
};
fs.prototype.chmod = function(path, mode, callback) {
try {
this.chmodSync(path, mode);
callback();
} catch (e) {
callback(e);
}
};
fs.prototype.chmodSync = function(path, mode) {
var fd;
path = this._getSourcePath(path);
fd = this.openSync(path, 'r', mode);
this.fchmodSync(fd, mode);
this.closeSync(fd);
};
fs.prototype.fchmod = function(fd, mode, callback) {
try {
this.fchmodSync(fd, mode);
callback(null);
} catch (e) {
callback(e);
}
};
fs.prototype.fchmodSync = function(fd, mode) {
if (!this._hasFd(fd)) {
Errors.fdNotFound(fd);
}
this._setAttributes(this._fileDescriptors[fd].path, {
mode: mode
});
};
fs.prototype.lchmod = function(path, mode, callback) {
try {
this.lchmodSync(path, mode);
callback(null);
} catch (e) {
callback(e);
}
};
fs.prototype.lchmodSync = function(path, mode) {
path = this.realpathSync(path);
if (!this.existsSync(path)) {
Errors.notFound(path);
}
if (!this.lstatSync(path).isSymbolicLink()) {
Errors.notSymlink(path);
}
this._setAttributes(path, {
mode: mode
});
};
fs.prototype.stat = function(path, callback) {
try {
callback(null, this.statSync(path));
} catch (e) {
callback(e, null);
}
};
fs.prototype.statSync = function(path) {
var fd, result;
path = this._getSourcePath(path);
fd = this.openSync(path, 'r');
result = this.fstatSync(fd);
this.closeSync(fd);
return result;
};
fs.prototype.lstat = function(path, callback) {
try {
callback(null, this.lstatSync(path));
} catch (e) {
callback(e, null);
}
};
fs.prototype.lstatSync = function(path) {
var stats;
path = this.realpathSync(path);
if (!this.existsSync(path)) {
Error.notFound(path);
}
stats = this._data[path].stats;
return stats;
};
fs.prototype.fstat = function(fd, callback) {
try {
callback(null, this.fstatSync(fd));
} catch (e) {
callback(e, null);
}
};
fs.prototype.fstatSync = function(fd) {
if (!this._hasFd(fd)) {
Errors.fdNotFound(fd);
}
return this._data[this._fileDescriptors[fd].path].stats;
};
fs.prototype.link = function(srcpath, dstpath, callback) {
try {
this.linkSync(srcpath, dstpath);
callback(null);
} catch (e) {
callback(e);
}
};
fs.prototype.linkSync = function(srcpath, dstpath) {
srcpath = this.realpathSync(srcpath);
dstpath = this._realpath(dstpath);
if (!this.existsSync(srcpath)) {
Errors.notFound(srcpath);
}
return this._data[dstpath] = this._data[srcpath];
};
fs.prototype.symlink = function(srcpath, dstpath, type, callback) {
if (type == null) {
type = null;
}
if (isFunction(type)) {
callback = type;
type = null;
}
try {
this.symlinkSync(srcpath, dstpath);
callback(null);
} catch (e) {
callback(e);
}
};
fs.prototype.symlinkSync = function(srcpath, dstpath, type) {
if (type == null) {
type = null;
}
srcpath = this.realpathSync(srcpath);
dstpath = this._realpath(dstpath);
if (!this.existsSync(srcpath)) {
Errors.notFound(srcpath);
}
this._addPath('%' + dstpath, srcpath);
};
fs.prototype.readlink = function(path, callback) {
try {
callback(null, this.readlinkSync(path));
} catch (e) {
callback(e, null);
}
};
fs.prototype.readlinkSync = function(path) {
path = this._getSourcePath(path);
if (!this.existsSync(path)) {
Errors.notFound(path);
}
return path;
};
fs.prototype.realpath = function(path, cache, callback) {
if (cache == null) {
cache = null;
}
if (isFunction(cache)) {
callback = cache;
cache = null;
}
try {
callback(null, this.realpathSync(path, cache));
} catch (e) {
callback(e, null);
}
};
fs.prototype.realpathSync = function(path, cache) {
if (cache == null) {
cache = null;
}
if (cache !== null && typeof cache[path] !== 'undefined') {
return cache[path];
}
path = this._realpath(path);
if (!this.existsSync(path)) {
Errors.notFound(path);
}
return path;
};
fs.prototype.unlink = function(path, callback) {
try {
this.unlinkSync(path);
callback();
} catch (e) {
callback(e);
}
};
fs.prototype.unlinkSync = function(path) {
path = this.realpathSync(path);
if (!this.existsSync(path)) {
Errors.notFound(path);
}
if (!this.statSync(path).isFile()) {
Errors.notFile(path);
}
delete this._data[path];
};
fs.prototype.rmdir = function(path, callback) {
try {
this.rmdirSync(path);
callback();
} catch (e) {
callback(e);
}
};
fs.prototype.rmdirSync = function(path) {
path = this.realpathSync(path);
if (!this.existsSync(path)) {
Errors.notFound(path);
}
if (!this.statSync(path).isDirectory()) {
Errors.notDirectory(path);
}
if (this._hasSubPaths(path)) {
Errors.directoryNotEmpty(path);
}
delete this._data[path];
};
fs.prototype.mkdir = function(path, mode, callback) {
if (mode == null) {
mode = null;
}
if (isFunction(mode)) {
callback = mode;
mode = null;
}
try {
this.mkdirSync(path, mode);
callback();
} catch (e) {
callback(e);
}
};
fs.prototype.mkdirSync = function(path, mode) {
if (mode == null) {
mode = null;
}
path = this._realpath(path);
if (this.existsSync(path)) {
Errors.alreadyExists(path);
}
this._addPath(path, {}, {
mode: mode
});
this._expandPath(path);
};
fs.prototype.readdir = function(path, callback) {
try {
callback(null, this.readdirSync(path));
} catch (e) {
callback(e, null);
}
};
fs.prototype.readdirSync = function(path) {
var files, match, name, slashes;
path = this._getSourcePath(path);
if (!this.existsSync(path)) {
Errors.notFound(path);
}
if (!this.statSync(path).isDirectory()) {
Errors.notDirectory(path);
}
path = path === this._options.delimiter ? '' : path;
path = escape(path);
files = [];
for (name in this._data) {
if (this._data.hasOwnProperty(name) && name !== path && name !== this._options.delimiter && (match = name.match(new RegExp('^' + path + '(.+)$'))) !== null) {
slashes = match[1].match(new RegExp(this._options._delimiter, 'g'));
slashes = slashes === null ? 0 : slashes.length;
if (slashes === 1) {
files.push(match[1].substr(1));
}
}
}
return files;
};
fs.prototype.close = function(fd, callback) {
try {
this.closeSync(fd);
callback();
} catch (e) {
callback(e);
}
};
fs.prototype.closeSync = function(fd) {
if (!this._hasFd(fd)) {
Errors.fdNotFound(fd);
}
delete this._fileDescriptors[fd];
};
fs.prototype.open = function(path, flags, mode, callback) {
if (mode == null) {
mode = null;
}
if (isFunction(mode)) {
callback = mode;
mode = null;
}
try {
callback(null, this.openSync(path, flags, mode));
} catch (e) {
callback(e, null);
}
};
fs.prototype.openSync = function(path, flags, mode) {
var exists;
if (mode == null) {
mode = null;
}
path = this._getSourcePath(path);
exists = this.existsSync(path);
if ((flags === 'r' || flags === 'r+') && !exists) {
Errors.notFound(path);
}
if ((flags === 'wx' || flags === 'wx+' || flags === 'ax' || flags === 'ax+') && exists) {
Errors.alreadyExists(path);
}
this._fileDescriptors[this._fileDescriptorsCounter] = {
path: path,
flags: flags
};
if (isCreatable(flags) && !exists) {
this._addPath(path, '', {
mode: mode
});
}
this._fileDescriptorsCounter++;
return this._fileDescriptorsCounter - 1;
};
fs.prototype.utimes = function(path, atime, mtime, callback) {
try {
this.utimesSync(path, atime, mtime);
callback(null);
} catch (e) {
callback(e);
}
};
fs.prototype.utimesSync = function(path, atime, mtime) {
var fd;
path = this.realpathSync(path);
fd = this.openSync(path, 'r');
this.futimesSync(fd, atime, mtime);
this.closeSync(fd);
};
fs.prototype.futimes = function(fd, atime, mtime, callback) {
try {
this.futimesSync(fd, atime, mtime);
callback(null);
} catch (e) {
callback(e);
}
};
fs.prototype.futimesSync = function(fd, atime, mtime) {
if (!this._hasFd(fd)) {
Errors.fdNotFound(fd);
}
this._setAttributes(this._fileDescriptors[fd].path, {
atime: toDate(atime),
mtime: toDate(mtime)
});
};
fs.prototype.fsync = function(fd, callback) {
try {
this.fsyncSync(fd);
callback(null);
} catch (e) {
callback(e);
}
};
fs.prototype.fsyncSync = function(fd) {
if (!this._hasFd(fd)) {
return Errors.fdNotFound(fd);
}
};
fs.prototype.write = function(fd, buffer, offset, length, position, callback) {
if (position == null) {
position = null;
}
if (callback == null) {
callback = null;
}
try {
this.writeSync(fd, buffer, offset, length, position);
if (callback !== null) {
callback(null, length, buffer);
}
} catch (e) {
if (callback !== null) {
callback(e, null, buffer);
}
}
};
fs.prototype.writeSync = function(fd, buffer, offset, length, position) {
var data, fdData, item, oldData, oldFlags, path, stats;
if (position == null) {
position = null;
}
if (!this._hasFd(fd)) {
Errors.fdNotFound(fd);
}
fdData = this._fileDescriptors[fd];
path = fdData.path;
if (!isWritable(fdData.flags)) {
Errors.notWritable(path);
}
stats = this.fstatSync(fd);
if (!stats.isFile()) {
Errors.notFile(path);
}
item = this._data[path];
data = buffer.toString('utf8', offset).substr(0, length);
if (position !== null) {
buffer = new Buffer(stats.size);
oldFlags = fdData.flags;
fdData.flags = 'r';
this.readSync(fd, buffer, 0, stats.size, 0);
fdData.flags = oldFlags;
oldData = buffer.toString('utf8');
data = [oldData.slice(0, position), data, oldData.slice(position)].join('');
}
item.data = new Buffer(data);
item.stats.size = data.length;
item.stats.blksize = data.length;
item.stats._modified();
};
fs.prototype.read = function(fd, buffer, offset, length, position, callback) {
if (position == null) {
position = 0;
}
if (callback == null) {
callback = null;
}
try {
this.readSync(fd, buffer, offset, length, position);
if (callback !== null) {
callback(null, length, buffer);
}
} catch (e) {
if (callback !== null) {
callback(e, 0, buffer);
}
}
};
fs.prototype.readSync = function(fd, buffer, offset, length, position) {
var data, item, path;
if (position == null) {
position = 0;
}
if (!this._hasFd(fd)) {
Errors.fdNotFound(fd);
}
item = this._fileDescriptors[fd];
path = item.path;
if (!isReadable(item.flags)) {
Errors.notReadable(path);
}
if (!this.fstatSync(fd).isFile()) {
Errors.notFile(path);
}
item = this._data[path];
data = item.data.toString('utf8');
data = data.substr(position, length);
buffer.write(data, offset);
item.stats._accessed();
return length;
};
fs.prototype.readFile = function(filename, options, callback) {
if (options == null) {
options = {};
}
if (isFunction(options)) {
callback = options;
options = null;
}
try {
callback(null, this.readFileSync(filename, options));
} catch (e) {
callback(e, null);
}
};
fs.prototype.readFileSync = function(filename, options) {
var buffer, data, fd, size;
if (options == null) {
options = {};
}
if (typeof options.encoding === 'undefined') {
options.encoding = null;
}
if (typeof options.flag === 'undefined') {
options.flag = 'r';
}
fd = this.openSync(filename, options.flag);
size = this.fstatSync(fd).size;
buffer = new Buffer(size);
this.readSync(fd, buffer, 0, size, null);
this.closeSync(fd);
data = buffer;
if (options.encoding !== null) {
data = buffer.toString(options.encoding);
}
return data;
};
fs.prototype.writeFile = function(filename, data, options, callback) {
if (options == null) {
options = {};
}
if (isFunction(options)) {
callback = options;
options = null;
}
try {
callback(null, this.writeFileSync(filename, data, options));
} catch (e) {
callback(e, null);
}
};
fs.prototype.writeFileSync = function(filename, data, options) {
var fd;
if (options == null) {
options = {};
}
if (typeof options.encoding === 'undefined') {
options.encoding = 'utf8';
}
if (typeof options.mode === 'undefined') {
options.mode = 438;
}
if (typeof options.flag === 'undefined') {
options.flag = 'w';
}
filename = this._getSourcePath(filename);
fd = this.openSync(filename, options.flag, options.mode);
this.writeSync(fd, new Buffer(data, options.encoding), 0, data.length, null);
this.closeSync(fd);
this._expandPath(filename);
};
fs.prototype.appendFile = function(filename, data, options, callback) {
if (options == null) {
options = {};
}
if (isFunction(options)) {
callback = options;
options = null;
}
try {
callback(null, this.appendFileSync(filename, data, options));
} catch (e) {
callback(e, null);
}
};
fs.prototype.appendFileSync = function(filename, data, options) {
var fd, size;
if (options == null) {
options = {};
}
if (typeof options.encoding === 'undefined') {
options.encoding = 'utf8';
}
if (typeof options.mode === 'undefined') {
options.mode = 438;
}
if (typeof options.flag === 'undefined') {
options.flag = 'w';
}
if (typeof data === 'string') {
data = new Buffer(data, options.encoding);
}
fd = this.openSync(filename, options.flag, options.mode);
size = this.fstatSync(fd).size;
this.writeSync(fd, data, 0, data.length, size);
this.closeSync(fd);
};
fs.prototype.watchFile = function(filename, options, listener) {
return Errors.notImplemented('watchFile');
};
fs.prototype.unwatchFile = function(filename, listener) {
return Errors.notImplemented('unwatchFile');
};
fs.prototype.watch = function(filename, options, listener) {
var stats, watcher;
if (options == null) {
options = null;
}
if (listener == null) {
listener = null;
}
if (isFunction(options)) {
listener = options;
options = null;
}
if (!this.existsSync(filename)) {
Errors.notFound(filename);
}
watcher = new FSWatcher(listener);
stats = this.statSync(filename);
stats.on('modified', function(stats) {
return watcher.emit('change', 'change', stats._path);
});
stats.on('modifiedAttributes', function(stats, event) {
return watcher.emit('change', event, stats._path);
});
return watcher;
};
fs.prototype.exists = function(path, callback) {
callback(this.existsSync(path));
};
fs.prototype.existsSync = function(path) {
path = this._realpath(path);
return typeof this._data[path] !== 'undefined';
};
fs.prototype.createReadStream = function(path, options) {
var buffer, data, rs, size;
if (options == null) {
options = {};
}
if (typeof options.flags === 'undefined') {
options.flags = 'r';
}
if (typeof options.encoding === 'undefined') {
options.encoding = null;
}
if (typeof options.fd === 'undefined') {
options.fd = null;
}
if (typeof options.mode === 'undefined') {
options.mode = 666;
}
if (typeof options.autoClose === 'undefined') {
options.autoClose = true;
}
if (typeof options.start === 'undefined') {
options.start = null;
}
if (typeof options.end === 'undefined') {
options.end = null;
}
rs = new Readable;
try {
if (options.fd === null) {
options.fd = this.openSync(path, options.flags, options.mode);
}
process.nextTick(function() {
rs.emit('open', options.fd);
});
size = this.fstatSync(options.fd).size;
buffer = new Buffer(size);
this.readSync(options.fd, buffer, 0, size, 0);
data = buffer.toString(options.encoding);
if (options.start !== null && options.end !== null) {
data = data.substring(options.start, options.end);
}
rs.push(data);
rs.push(null);
if (options.autoClose) {
this.closeSync(options.fd);
}
} catch (e) {
process.nextTick(function() {
rs.emit('error', e);
});
}
return rs;
};
fs.prototype.createWriteStream = function(path, options) {
var fd, position, ws, self;
self = this;
if (options == null) {
options = {};
}
if (typeof options.flags === 'undefined') {
options.flags = 'w';
}
if (typeof options.encoding === 'undefined') {
options.encoding = null;
}
if (typeof options.mode === 'undefined') {
options.mode = 666;
}
if (typeof options.start === 'undefined') {
options.start = 0;
}
ws = Writable();
try {
fd = this.openSync(path, options.flags, options.mode);
process.nextTick(function() {
ws.emit('open', fd);
});
} catch (e) {
process.nextTick(function() {
ws.emit('error', e);
});
}
position = options.start;
ws._write = function(chunk, enc, next) {
if (typeof chunk === 'string') {
chunk = new Buffer(chunk);
}
self.write(fd, chunk, 0, chunk.length, position, function(err) {
position += chunk.length;
next(err);
});
};
ws.on('finish', function() {
self.closeSync(fd);
});
return ws;
};
module.exports = fs;
}).call(this);