Skip to content

Commit

Permalink
src: expand known issue
Browse files Browse the repository at this point in the history
  • Loading branch information
refack committed Nov 16, 2018
1 parent 01c7de7 commit 5e69527
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 16 deletions.
2 changes: 1 addition & 1 deletion doc/api/fs.md
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ The numeric identifier of the device containing the file.

The file system specific "Inode" number for the file.

*Note*: The `number` version is unreliable on Windows as values often overflow.
*Note*: The `number` version is unreliable as values often overflow.

### stats.mode

Expand Down
25 changes: 13 additions & 12 deletions src/node_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,22 +194,23 @@ constexpr uint64_t ToNative(uv_timespec_t ts) {
template <typename NativeT, typename V8T>
constexpr void FillStatsArray(AliasedBuffer<NativeT, V8T>* fields,
const uv_stat_t* s, const size_t offset = 0) {
fields->SetValue(offset + 0, gsl::narrow<NativeT>(s->st_dev));
fields->SetValue(offset + 1, gsl::narrow<NativeT>(s->st_mode));
fields->SetValue(offset + 2, gsl::narrow<NativeT>(s->st_nlink));
fields->SetValue(offset + 3, gsl::narrow<NativeT>(s->st_uid));
fields->SetValue(offset + 4, gsl::narrow<NativeT>(s->st_gid));
fields->SetValue(offset + 5, gsl::narrow<NativeT>(s->st_rdev));
fields->SetValue(offset + 0, gsl::narrow_cast<NativeT>(s->st_dev));
fields->SetValue(offset + 1, gsl::narrow_cast<NativeT>(s->st_mode));
fields->SetValue(offset + 2, gsl::narrow_cast<NativeT>(s->st_nlink));
fields->SetValue(offset + 3, gsl::narrow_cast<NativeT>(s->st_uid));
fields->SetValue(offset + 4, gsl::narrow_cast<NativeT>(s->st_gid));
fields->SetValue(offset + 5, gsl::narrow_cast<NativeT>(s->st_rdev));
#if defined(__POSIX__)
fields->SetValue(offset + 6, gsl::narrow<NativeT>(s->st_blksize));
fields->SetValue(offset + 7, gsl::narrow<NativeT>(s->st_ino));
fields->SetValue(offset + 8, gsl::narrow<NativeT>(s->st_size));
fields->SetValue(offset + 9, gsl::narrow<NativeT>(s->st_blocks));
fields->SetValue(offset + 6, gsl::narrow_cast<NativeT>(s->st_blksize));
// Using the noop `narrow_cast` since this overflows.
fields->SetValue(offset + 7, gsl::narrow_cast<NativeT>(s->st_ino));
fields->SetValue(offset + 8, gsl::narrow_cast<NativeT>(s->st_size));
fields->SetValue(offset + 9, gsl::narrow_cast<NativeT>(s->st_blocks));
#else
fields->SetValue(offset + 6, 0);
// This overflows on Windows for NativeT == double
// Using the noop `narrow_cast` since this overflows.
fields->SetValue(offset + 7, gsl::narrow_cast<NativeT>(s->st_ino));
fields->SetValue(offset + 8, gsl::narrow<NativeT>(s->st_size));
fields->SetValue(offset + 8, gsl::narrow_cast<NativeT>(s->st_size));
fields->SetValue(offset + 9, 0);
#endif

Expand Down
22 changes: 19 additions & 3 deletions test/known_issues/test-fs-stat-ino-overflow-on-windows.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ const fs = require('fs');
const promiseFs = require('fs').promises;
const path = require('path');
const tmpdir = require('../common/tmpdir');
const { isDate } = require('util').types;

tmpdir.refresh();

Expand All @@ -23,8 +22,25 @@ function getFilename() {
}

function verifyStats(bigintStats, numStats) {
assert.ok(Number.isSafeInteger(numStats.ino));
assert.strictEqual(bigintStats.ino, BigInt(numStats.ino));
const keys = [
'dev', 'mode', 'nlink', 'uid',
'gid', 'rdev', 'ino', 'size',
];
if (!common.isWindows) {
keys.push('blocks', 'blksize');
}
for (const key of keys) {
const nVal = numStats[key];
const bVal = bigintStats[key];
assert.ok(
Number.isSafeInteger(nVal),
`numStats.${key}: ${nVal} is not a safe integer`
);
assert.strictEqual(
bigintStats[key], BigInt(numStats[key]),
`bigintStats.${key}: ${bVal} is not equal to numStats.${key}: ${nVal}`
);
}
}

{
Expand Down
106 changes: 106 additions & 0 deletions test/parallel/test-fs-stat-ino-overflow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
'use strict';

const common = require('../common');
const assert = require('assert');

const fs = require('fs');
const promiseFs = require('fs').promises;
const path = require('path');
const tmpdir = require('../common/tmpdir');

tmpdir.refresh();

let testIndex = 0;

function getFilename() {
const filename = path.join(tmpdir.path, `test-file-${++testIndex}`);
fs.writeFileSync(filename, 'test');
return filename;
}

function verifyStats(bigintStats, numStats) {
const keys = [
'dev', 'mode', 'nlink', 'uid', 'gid', 'rdev', 'size',
];
if (!common.isWindows) {
keys.push('blocks', 'blksize', 'ino');
}
for (const key of keys) {
const nVal = numStats[key];
const bVal = bigintStats[key];
assert.strictEqual(
bigintStats[key], BigInt(numStats[key]),
`bigintStats.${key}: ${bVal} is not equal to numStats.${key}: ${nVal}`
);
assert.ok(
Number.isSafeInteger(nVal),
`numStats.${key}: ${nVal} is not a safe integer`
);
}
}

{
const filename = getFilename();
const bigintStats = fs.statSync(filename, { bigint: true });
const numStats = fs.statSync(filename);
verifyStats(bigintStats, numStats);
}

{
const filename = __filename;
const bigintStats = fs.statSync(filename, { bigint: true });
const numStats = fs.statSync(filename);
verifyStats(bigintStats, numStats);
}

{
const filename = __dirname;
const bigintStats = fs.statSync(filename, { bigint: true });
const numStats = fs.statSync(filename);
verifyStats(bigintStats, numStats);
}

{
const filename = getFilename();
const fd = fs.openSync(filename, 'r');
const bigintStats = fs.fstatSync(fd, { bigint: true });
const numStats = fs.fstatSync(fd);
verifyStats(bigintStats, numStats);
fs.closeSync(fd);
}

{
const filename = getFilename();
fs.stat(filename, { bigint: true }, (err, bigintStats) => {
fs.stat(filename, (err, numStats) => {
verifyStats(bigintStats, numStats);
});
});
}

{
const filename = getFilename();
const fd = fs.openSync(filename, 'r');
fs.fstat(fd, { bigint: true }, (err, bigintStats) => {
fs.fstat(fd, (err, numStats) => {
verifyStats(bigintStats, numStats);
fs.closeSync(fd);
});
});
}

(async function() {
const filename = getFilename();
const bigintStats = await promiseFs.stat(filename, { bigint: true });
const numStats = await promiseFs.stat(filename);
verifyStats(bigintStats, numStats);
})();

(async function() {
const filename = getFilename();
const handle = await promiseFs.open(filename, 'r');
const bigintStats = await handle.stat({ bigint: true });
const numStats = await handle.stat();
verifyStats(bigintStats, numStats);
await handle.close();
})();

0 comments on commit 5e69527

Please sign in to comment.