Skip to content
181 changes: 161 additions & 20 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -636,12 +636,22 @@ fs.readFileSync = function(path, options) {
};

fs.close = function(fd, callback) {
var req = new FSReqWrap();
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');

const req = new FSReqWrap();
req.oncomplete = makeCallback(callback);
binding.close(fd, req);
};

fs.closeSync = function(fd) {
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');

return binding.close(fd);
};

Expand Down Expand Up @@ -681,18 +691,38 @@ fs.openSync = function(path, flags, mode) {
};

fs.read = function(fd, buffer, offset, length, position, callback) {
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
if (!isUint8Array(buffer))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'buffer',
['Buffer', 'Uint8Array']);

offset |= 0;
length |= 0;

if (length === 0) {
return process.nextTick(function() {
callback && callback(null, 0, buffer);
});
}

if (offset < 0 || offset >= buffer.length)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'offset');

if (length < 0 || offset + length > buffer.length)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'length');

if (!Number.isInteger(position))
position = -1;

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);
}

var req = new FSReqWrap();
const req = new FSReqWrap();
req.oncomplete = wrapper;

binding.read(fd, buffer, offset, length, position, req);
Expand All @@ -702,10 +732,30 @@ Object.defineProperty(fs.read, internalUtil.customPromisifyArgs,
{ value: ['bytesRead', 'buffer'], enumerable: false });

fs.readSync = function(fd, buffer, offset, length, position) {
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
if (!isUint8Array(buffer))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'buffer',
['Buffer', 'Uint8Array']);

offset |= 0;
length |= 0;

if (length === 0) {
return 0;
}

if (offset < 0 || offset >= buffer.length)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'offset');

if (length < 0 || offset + length > buffer.length)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'length');

if (!Number.isInteger(position))
position = -1;

return binding.read(fd, buffer, offset, length, position);
};

Expand Down Expand Up @@ -854,7 +904,14 @@ fs.ftruncate = function(fd, len, callback) {
} else if (len === undefined) {
len = 0;
}
var req = new FSReqWrap();
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
if (!Number.isInteger(len))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'len', 'number');
len = Math.max(0, len);
const req = new FSReqWrap();
req.oncomplete = makeCallback(callback);
binding.ftruncate(fd, len, req);
};
Expand All @@ -863,6 +920,13 @@ fs.ftruncateSync = function(fd, len) {
if (len === undefined) {
len = 0;
}
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
if (!Number.isInteger(len))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'len', 'number');
len = Math.max(0, len);
return binding.ftruncate(fd, len);
};

Expand All @@ -883,22 +947,38 @@ fs.rmdirSync = function(path) {
};

fs.fdatasync = function(fd, callback) {
var req = new FSReqWrap();
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
const req = new FSReqWrap();
req.oncomplete = makeCallback(callback);
binding.fdatasync(fd, req);
};

fs.fdatasyncSync = function(fd) {
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
return binding.fdatasync(fd);
};

fs.fsync = function(fd, callback) {
var req = new FSReqWrap();
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
const req = new FSReqWrap();
req.oncomplete = makeCallback(callback);
binding.fsync(fd, req);
};

fs.fsyncSync = function(fd) {
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
return binding.fsync(fd);
};

Expand Down Expand Up @@ -941,7 +1021,11 @@ fs.readdirSync = function(path, options) {
};

fs.fstat = function(fd, callback) {
var req = new FSReqWrap();
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
const req = new FSReqWrap();
req.oncomplete = makeStatsCallback(callback);
binding.fstat(fd, req);
};
Expand All @@ -967,6 +1051,10 @@ fs.stat = function(path, callback) {
};

fs.fstatSync = function(fd) {
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
binding.fstat(fd);
return statsFromValues();
};
Expand Down Expand Up @@ -1098,13 +1186,32 @@ fs.unlinkSync = function(path) {
};

fs.fchmod = function(fd, mode, callback) {
var req = new FSReqWrap();
mode = modeNum(mode);
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
if (!Number.isInteger(mode))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'mode', 'number');
if (mode < 0 || mode > 0o777)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'mode');

const req = new FSReqWrap();
req.oncomplete = makeCallback(callback);
binding.fchmod(fd, modeNum(mode), req);
binding.fchmod(fd, mode, req);
};

fs.fchmodSync = function(fd, mode) {
return binding.fchmod(fd, modeNum(mode));
mode = modeNum(mode);
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
if (!Number.isInteger(mode))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'mode', 'number');
if (mode < 0 || mode > 0o777)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'mode');
return binding.fchmod(fd, mode);
};

if (constants.O_SYMLINK !== undefined) {
Expand Down Expand Up @@ -1182,12 +1289,38 @@ if (constants.O_SYMLINK !== undefined) {
}

fs.fchown = function(fd, uid, gid, callback) {
var req = new FSReqWrap();
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
if (!Number.isInteger(uid))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'uid', 'number');
if (uid < 0)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'uid');
if (!Number.isInteger(gid))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'gid', 'number');
if (gid < 0)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'gid');

const req = new FSReqWrap();
req.oncomplete = makeCallback(callback);
binding.fchown(fd, uid, gid, req);
};

fs.fchownSync = function(fd, uid, gid) {
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
if (!Number.isInteger(uid))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'uid', 'number');
if (uid < 0)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'uid');
if (!Number.isInteger(gid))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'gid', 'number');
if (gid < 0)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'gid');

return binding.fchown(fd, uid, gid);
};

Expand All @@ -1208,7 +1341,7 @@ fs.chownSync = function(path, uid, gid) {
};

// converts Date or number to a fractional UNIX timestamp
function toUnixTimestamp(time) {
function toUnixTimestamp(time, name = 'time') {
// eslint-disable-next-line eqeqeq
if (typeof time === 'string' && +time == time) {
return +time;
Expand All @@ -1223,10 +1356,10 @@ function toUnixTimestamp(time) {
// convert to 123.456 UNIX timestamp
return time.getTime() / 1000;
}
throw new errors.Error('ERR_INVALID_ARG_TYPE',
'time',
['Date', 'Time in seconds'],
time);
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
name,
['Date', 'Time in seconds'],
time);
}

// exported for unit tests, not for public consumption
Expand Down Expand Up @@ -1254,16 +1387,24 @@ fs.utimesSync = function(path, atime, mtime) {
};

fs.futimes = function(fd, atime, mtime, callback) {
atime = toUnixTimestamp(atime);
mtime = toUnixTimestamp(mtime);
var req = new FSReqWrap();
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
atime = toUnixTimestamp(atime, 'atime');
mtime = toUnixTimestamp(mtime, 'mtime');
const req = new FSReqWrap();
req.oncomplete = makeCallback(callback);
binding.futimes(fd, atime, mtime, req);
};

fs.futimesSync = function(fd, atime, mtime) {
atime = toUnixTimestamp(atime);
mtime = toUnixTimestamp(mtime);
if (!Number.isInteger(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'number');
if (fd < 0 || fd > 0xFFFFFFFF)
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'fd');
atime = toUnixTimestamp(atime, 'atime');
mtime = toUnixTimestamp(mtime, 'mtime');
binding.futimes(fd, atime, mtime);
};

Expand Down
Loading