Repository navigation
readFile(fd) does not read the whole file (at least on Windows, possibly other platforms) #9671
Description
Activity
- changed the title
[-]readFile() and readFileSync() fail to read sparse file properly on Windows[/-][+]readFile() and readFileSync() fail to read sparse file on Windows[/+]on Nov 18, 2016 - addedfsIssues and PRs related to file-system APIs and the fs module.Issues and PRs related to file-system APIs and the fs module.windowsIssues and PRs related to the Windows platform.Issues and PRs related to the Windows platform.
on Nov 18, 2016 It seems sparseness is not the cause. This is also throws (Node.js 7.1.0 on Windows 7 x64):
var fs = require('fs'); var buffer = Buffer.alloc(8192); var path = 'test-read-file'; var fd = fs.openSync(path, 'w+'); console.log('created or truncated, file size is now: ' + fs.fstatSync(fd).size); console.log('writing 8192 bytes at offset ' + (0)); fs.writeSync(fd, Buffer.alloc(8192, 1), 0, 8192, 0); console.log('file size is now: ' + fs.fstatSync(fd).size + '\r\n'); console.log('reading 8192 bytes using readSync()...'); var bytesRead = fs.readSync(fd, buffer, 0, 8192, 0); if (bytesRead !== 8192) { throw new Error('readSync() read ' + bytesRead + ' bytes'); } else { console.log('readSync() read ' + bytesRead + ' bytes'); } console.log('\r\nreading entire file using readFileSync()...'); var result = fs.readFileSync(fd); if (result.length !== buffer.length) { throw new Error('readFileSync returned a buffer with length ' + result.length); } else { console.log('readFileSync returned a buffer with length ' + result.length); } fs.closeSync(fd); fs.unlinkSync(path); console.log('\r\nPASSED');
It seems the cause is this: after
writeSyncandreadSync, thereadFileSyncreads from their endfdposition. See how error message changes in this case:// ... console.log('reading 8191 bytes using readSync()...'); var bytesRead = fs.readSync(fd, buffer, 0, 8191, 0); if (bytesRead !== 8191) { throw new Error('readSync() read ' + bytesRead + ' bytes'); } else { console.log('readSync() read ' + bytesRead + ' bytes'); } // ...
Error: readFileSync returned a buffer with length 1Or in this case:
// ... console.log('reading 1 bytes using readSync()...'); var bytesRead = fs.readSync(fd, buffer, 0, 1, 0); if (bytesRead !== 1) { throw new Error('readSync() read ' + bytesRead + ' bytes'); } else { console.log('readSync() read ' + bytesRead + ' bytes'); } // ...
Error: readFileSync returned a buffer with length 8191While if you use path string instead of
fdin your initial code all is OK:// ... var result = fs.readFileSync('test-sparse-read-file'); // ...
created or truncated, sparse file size is now: 0 writing 1 byte at offset 8191 sparse file size is now: 8192 reading 8192 bytes using readSync()... readSync() read 8192 bytes reading entire file using readFileSync()... readFileSync returned a buffer with length 8192 PASSEDSo the bug seems to be this one:
readFile()andreadFileSync()don't rewindfdposition afterwriteSyncandreadSyncon the samefdon Windows, while they do rewind on Mac and Linux (I can't confirm the last though).Your script at #9671 (comment) passes on OS X, I don't have a Windows to try on.
The function used to read files is
fs.readSync(fd, buffer, pos, len), it calls http://man7.org/linux/man-pages/man2/pread.2.html, and it reads from a specific offset, and it does not change the file offset (per docs). In other words, no explicit "rewinding" of the fd is needed on Linux,readFilereads from explicit offsets, not the O/S maintained offset.I wonder, could uv's emulation of
preadfor Windows not be correct, somehow? Could you try some experiments withfs.read/fs.readSyncto see if they work incorrectly, bypassing thereadFilewrappers?@sam-github I'll try, but let's simplify it first. This throws with Node.js 7.1.0 on Windows 7 x64:
'use strict'; const assert = require('assert'); const fs = require('fs'); const filleLength = 2; const path = 'test-read-file'; const fd = fs.openSync(path, 'w+'); fs.writeSync(fd, Buffer.alloc(filleLength, 1), 0, filleLength, 0); assert.strictEqual(fs.readFileSync(fd).length, filleLength);
AssertionError: 0 === 2Does it throw on Linux or Mac?
Does not throw on unixen, as expected.
Please remove the complex ball of js code that is
readFile*from the picture, and replace that last line withassert.equal(filleLength, fs.readSync(fd, buf, 0, 10, 0), which I strongly suspect will not pass on Windows.So, if I get it right, with some corrections (
buf => Buffer.alloc(filleLength, 1)and10=>filleLength), this is the new test code:const assert = require('assert'); const fs = require('fs'); const filleLength = 2; const path = 'test-read-file'; const fd = fs.openSync(path, 'w+'); fs.writeSync(fd, Buffer.alloc(filleLength, 1), 0, filleLength, 0); assert.equal(filleLength, fs.readSync(fd, Buffer.alloc(filleLength, 1), 0, filleLength, 0));
It passes with Node.js 7.1.0 on Windows 7 x64. But this throws (nota bene
positionisnull, so it is current afterwriteSync):const assert = require('assert'); const fs = require('fs'); const filleLength = 2; const path = 'test-read-file'; const fd = fs.openSync(path, 'w+'); fs.writeSync(fd, Buffer.alloc(filleLength, 1), 0, filleLength, 0); assert.equal(filleLength, fs.readSync(fd, Buffer.alloc(filleLength, 1), 0, filleLength, null));
AssertionError: 2 == 0Does this last code throw on Linux or Mac? It should, if I get it right. So maybe we should return to previous one.
Reacted by Nikolai Vavilov/to @nodejs/platform-windows
and it does not change the file offset (per docs).
Are there any
fsfunctions that are supposed to increment file offset?It seems I've found the cause.
fs.readFileSynccallstryReadSync()at line 485.tryReadSync()callsfs.readSync()at line 456, but with wrong arguments.Compare
fs.readSync()signature at line 622:fs.readSync = function(fd, buffer, offset, length, position) {
and the call from
tryReadSync()at line 456bytesRead = fs.readSync(fd, buffer, pos, len);
so position is allways
undefined, ie current.Reacted by Joran Dirk Greef and Nicholas Sherlock@seishun
fs.read/write[Sync]update the file offset, they useread(2)andwrite(2).@vsemozhetbyt got time to PR a fix + regression test? It would be great if you did.
I'm afraid I have not the experience and knowledge required to edit the core and to make appropriate tests(
13 remaining items
- changed the title
[-]readFile() and readFileSync() fail to read sparse file on Windows[/-][+]readFile(fd) does not read the whole file (at least on Windows, possibly other platforms)[/+]on Jan 18, 2017 - added 5 commits that reference this issue
on Jan 18, 2017 Um how did this get closed?
- added a commit that references this issue
on Jun 6, 2017 - added a commit that references this issue
on Jun 21, 2017 This should remain open?
The provided test case no longer reproduces on master, so closing.
I wrote a small test that passes on Mac and Linux but throws on Windows:
Linux:
Windows:
The test shows that the problem does not appear to be with read() but only with readFileSync().
readFile() has the same issue.