Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
3cp committed May 8, 2021
1 parent 4836e6b commit 0aad557
Show file tree
Hide file tree
Showing 6 changed files with 1,853 additions and 133 deletions.
110 changes: 63 additions & 47 deletions lib/binding.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ const MODE_TO_KTYPE = {
const fsBinding = process.binding('fs');
const kUsePromises = fsBinding.kUsePromises;
let statValues;
let bigintStatValues;
if (fsBinding.statValues) {
statValues = fsBinding.statValues; // node 10+
bigintStatValues = fsBinding.bigintStatValues;
} else if (fsBinding.getStatValues) {
statValues = fsBinding.getStatValues(); // node 8
} else {
Expand Down Expand Up @@ -140,10 +142,12 @@ function wrapStatsCallback(callback) {
}
if (typeof callback === 'function') {
return function(err, stats) {
if (stats) {
fillStatsArray(stats, statValues);
// nodejs 10.0.0+ expects an array internally
// https://github.com/nodejs/node/commit/f7049a20068dc8a7e904b7cdd3d5b307b595dd3a
if (stats && process.version.major < 10) {
stats = new Stats(stats);
}
callback.apply(this, arguments);
callback.call(this, err, stats);
};
} else {
return callback;
Expand Down Expand Up @@ -177,9 +181,6 @@ function Stats(config) {
for (const key in config) {
this[key] = config[key];
}
// node 10 expects an array internally
// see https://github.com/nodejs/node/pull/19714
fillStatsArray(config, this);
}

/**
Expand Down Expand Up @@ -398,17 +399,20 @@ Binding.prototype.realpath = function(filepath, encoding, callback, ctx) {
* @param {Float64Array} statValues A Float64Array where stat values should be inserted
* @returns {void}
*/
function fillStatsArray(stats, statValues) {
statValues[0] = stats.dev;
statValues[1] = stats.mode;
statValues[2] = stats.nlink;
statValues[3] = stats.uid;
statValues[4] = stats.gid;
statValues[5] = stats.rdev;
statValues[6] = stats.blksize;
statValues[7] = stats.ino;
statValues[8] = stats.size;
statValues[9] = stats.blocks;
function fillStatsArray(stats, statValues, keepBigint) {
const convert = keepBigint ?
function(v) { return v} :
Number;
statValues[0] = convert(stats.dev);
statValues[1] = convert(stats.mode);
statValues[2] = convert(stats.nlink);
statValues[3] = convert(stats.uid);
statValues[4] = convert(stats.gid);
statValues[5] = convert(stats.rdev);
statValues[6] = convert(stats.blksize);
statValues[7] = convert(stats.ino);
statValues[8] = convert(stats.size);
statValues[9] = convert(stats.blocks);

if (statContainsNs) {
// nodejs v12.10.0+
Expand All @@ -426,14 +430,14 @@ function fillStatsArray(stats, statValues) {
statValues[17] = (stats.birthtimeMs % 1000) * 1000000;
} else {
// BigInt
statValues[10] = Number(stats.atimeNs / BigInt(1000000000));
statValues[11] = Number(stats.atimeNs % BigInt(1000000000));
statValues[12] = Number(stats.mtimeNs / BigInt(1000000000));
statValues[13] = Number(stats.mtimeNs % BigInt(1000000000));
statValues[14] = Number(stats.ctimeNs / BigInt(1000000000));
statValues[15] = Number(stats.ctimeNs % BigInt(1000000000));
statValues[16] = Number(stats.birthtimeNs / BigInt(1000000000));
statValues[17] = Number(stats.birthtimeNs % BigInt(1000000000));
statValues[10] = convert(stats.atimeNs / BigInt(1000000000));
statValues[11] = convert(stats.atimeNs % BigInt(1000000000));
statValues[12] = convert(stats.mtimeNs / BigInt(1000000000));
statValues[13] = convert(stats.mtimeNs % BigInt(1000000000));
statValues[14] = convert(stats.ctimeNs / BigInt(1000000000));
statValues[15] = convert(stats.ctimeNs % BigInt(1000000000));
statValues[16] = convert(stats.birthtimeNs / BigInt(1000000000));
statValues[17] = convert(stats.birthtimeNs % BigInt(1000000000));
}
} else {
// nodejs before v12.10.0
Expand All @@ -446,10 +450,10 @@ function fillStatsArray(stats, statValues) {
statValues[13] = stats.birthtimeMs;
} else {
// BigInt
statValues[10] = Number(stats.atimeNs / BigInt(1000000));
statValues[11] = Number(stats.mtimeNs / BigInt(1000000));
statValues[12] = Number(stats.ctimeNs / BigInt(1000000));
statValues[13] = Number(stats.birthtimeNs / BigInt(1000000));
statValues[10] = convert(stats.atimeNs / BigInt(1000000));
statValues[11] = convert(stats.mtimeNs / BigInt(1000000));
statValues[12] = convert(stats.ctimeNs / BigInt(1000000));
statValues[13] = convert(stats.birthtimeNs / BigInt(1000000));
}
}
}
Expand All @@ -462,11 +466,11 @@ function fillStatsArray(stats, statValues) {
* @param {Object} ctx Context object (optional), only for nodejs v10+.
* @return {Stats|undefined} Stats or undefined (if sync).
*/
Binding.prototype.stat = function(filepath, options, callback, ctx) {
Binding.prototype.stat = function(filepath, bigint, callback, ctx) {
// this seems wound not happen in nodejs v10+
if (arguments.length < 3) {
callback = options;
options = {};
callback = bigint;
bigint = false;
}

markSyscall(ctx, 'stat');
Expand All @@ -482,7 +486,7 @@ Binding.prototype.stat = function(filepath, options, callback, ctx) {
if (!item) {
throw new FSError('ENOENT', filepath);
}
const stats = item.getStats(options && options.bigint);
const stats = item.getStats(bigint);

// In Node 7.7.0+, binding.stat accepts a Float64Array as the second argument,
// which should be filled with stat values.
Expand All @@ -491,10 +495,14 @@ Binding.prototype.stat = function(filepath, options, callback, ctx) {
callback instanceof Float64Array ||
callback instanceof BigUint64Array
) {
fillStatsArray(stats, callback);
fillStatsArray(stats, callback, callback instanceof BigUint64Array);
} else {
fillStatsArray(stats, statValues);
return new Stats(stats);
if (typeof stats.dev === 'bigint') {
fillStatsArray(stats, bigintStatValues, true);
return bigintStatValues;
}
return statValues;
}
});
};
Expand All @@ -507,18 +515,18 @@ Binding.prototype.stat = function(filepath, options, callback, ctx) {
* @param {Object} ctx Context object (optional), only for nodejs v10+.
* @return {Stats|undefined} Stats or undefined (if sync).
*/
Binding.prototype.fstat = function(fd, options, callback, ctx) {
Binding.prototype.fstat = function(fd, bigint, callback, ctx) {
if (arguments.length < 3) {
callback = options;
options = {};
callback = bigint;
bigint = false;
}

markSyscall(ctx, 'fstat');

return maybeCallback(wrapStatsCallback(callback), ctx, this, function() {
const descriptor = this.getDescriptorById(fd);
const item = descriptor.getItem();
const stats = item.getStats(options && options.bigint);
const stats = item.getStats(bigint);

// In Node 7.7.0+, binding.stat accepts a Float64Array as the second argument,
// which should be filled with stat values.
Expand All @@ -527,10 +535,14 @@ Binding.prototype.fstat = function(fd, options, callback, ctx) {
callback instanceof Float64Array ||
callback instanceof BigUint64Array
) {
fillStatsArray(stats, callback);
fillStatsArray(stats, callback, callback instanceof BigUint64Array);
} else {
fillStatsArray(stats, statValues);
return new Stats(stats);
if (typeof stats.dev === 'bigint') {
fillStatsArray(stats, bigintStatValues, true);
return bigintStatValues;
}
return statValues;
}
});
};
Expand Down Expand Up @@ -1460,11 +1472,11 @@ Binding.prototype.readlink = function(pathname, encoding, callback, ctx) {
* @param {Object} ctx Context object (optional), only for nodejs v10+.
* @return {Stats|undefined} Stats or undefined (if sync).
*/
Binding.prototype.lstat = function(filepath, options, callback, ctx) {
Binding.prototype.lstat = function(filepath, bigint, callback, ctx) {
if (arguments.length < 3) {
// this would not happend in nodejs v10+
callback = options;
options = {};
callback = bigint;
bigint = false;
}

markSyscall(ctx, 'lstat');
Expand All @@ -1475,7 +1487,7 @@ Binding.prototype.lstat = function(filepath, options, callback, ctx) {
if (!item) {
throw new FSError('ENOENT', filepath);
}
const stats = item.getStats(options && options.bigint);
const stats = item.getStats(bigint);

// In Node 7.7.0+, binding.stat accepts a Float64Array as the second argument,
// which should be filled with stat values.
Expand All @@ -1484,10 +1496,14 @@ Binding.prototype.lstat = function(filepath, options, callback, ctx) {
callback instanceof Float64Array ||
callback instanceof BigUint64Array
) {
fillStatsArray(stats, callback);
fillStatsArray(stats, callback, callback instanceof BigUint64Array);
} else {
fillStatsArray(stats, statValues);
return new Stats(stats);
if (typeof stats.dev === 'bigint') {
fillStatsArray(stats, bigintStatValues, true);
return bigintStatValues;
}
return statValues;
}
});
};
Expand Down
14 changes: 13 additions & 1 deletion lib/item.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,19 @@ Item.prototype.getStats = function(bigint) {

// bigint option for v10.5.0
if (bigint && typeof BigInt === 'function') {
for (const key in Object.keys(stats)) {
for (const key of [
'dev',
'nlink',
'uid',
'gid',
'rdev',
'blksize',
'ino',
'atimeMs',
'mtimeMs',
'ctimeMs',
'birthtimeMs'
]) {
stats[key] = BigInt(stats[key]);
}
// Additional nanosecond-precision properties suffixed with Ns
Expand Down
Loading

0 comments on commit 0aad557

Please sign in to comment.