fix fs.readFile with lying size=0 stat results
This commit is contained in:
parent
d53cdc5378
commit
6ce013dd4b
73
lib/fs.js
73
lib/fs.js
@ -108,7 +108,8 @@ fs.readFile = function(path, encoding_) {
|
|||||||
|
|
||||||
// first, stat the file, so we know the size.
|
// first, stat the file, so we know the size.
|
||||||
var size;
|
var size;
|
||||||
var buffer;
|
var buffer; // single buffer with file data
|
||||||
|
var buffers; // list for when size is unknown
|
||||||
var pos = 0;
|
var pos = 0;
|
||||||
var fd;
|
var fd;
|
||||||
|
|
||||||
@ -120,8 +121,10 @@ fs.readFile = function(path, encoding_) {
|
|||||||
if (er) return callback(er);
|
if (er) return callback(er);
|
||||||
size = st.size;
|
size = st.size;
|
||||||
if (size === 0) {
|
if (size === 0) {
|
||||||
buffer = new Buffer(0);
|
// the kernel lies about many files.
|
||||||
return afterRead(null, 0);
|
// Go ahead and try to read some bytes.
|
||||||
|
buffers = [];
|
||||||
|
return read();
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = new Buffer(size);
|
buffer = new Buffer(size);
|
||||||
@ -130,7 +133,12 @@ fs.readFile = function(path, encoding_) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function read() {
|
function read() {
|
||||||
fs.read(fd, buffer, pos, size - pos, pos, afterRead);
|
if (size === 0) {
|
||||||
|
buffer = new Buffer(8192);
|
||||||
|
fs.read(fd, buffer, 0, 8192, pos, afterRead);
|
||||||
|
} else {
|
||||||
|
fs.read(fd, buffer, pos, size - pos, pos, afterRead);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function afterRead(er, bytesRead) {
|
function afterRead(er, bytesRead) {
|
||||||
@ -141,12 +149,27 @@ fs.readFile = function(path, encoding_) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pos += bytesRead;
|
pos += bytesRead;
|
||||||
if (pos === size) close();
|
if (size !== 0) {
|
||||||
else read();
|
if (pos === size) close();
|
||||||
|
else read();
|
||||||
|
} else {
|
||||||
|
// unknown size, just read until we don't get bytes.
|
||||||
|
if (bytesRead > 0) {
|
||||||
|
buffers.push(buffer.slice(0, bytesRead));
|
||||||
|
read();
|
||||||
|
} else {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
fs.close(fd, function(er) {
|
fs.close(fd, function(er) {
|
||||||
|
if (size === 0) {
|
||||||
|
// collected the data into the buffers list.
|
||||||
|
buffer = Buffer.concat(buffer.length, pos);
|
||||||
|
}
|
||||||
|
|
||||||
if (encoding) buffer = buffer.toString(encoding);
|
if (encoding) buffer = buffer.toString(encoding);
|
||||||
return callback(er, buffer);
|
return callback(er, buffer);
|
||||||
});
|
});
|
||||||
@ -165,28 +188,52 @@ fs.readFileSync = function(path, encoding) {
|
|||||||
if (threw) fs.closeSync(fd);
|
if (threw) fs.closeSync(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pos = 0;
|
||||||
|
var buffer; // single buffer with file data
|
||||||
|
var buffers; // list for when size is unknown
|
||||||
|
|
||||||
if (size === 0) {
|
if (size === 0) {
|
||||||
fs.closeSync(fd);
|
buffers = [];
|
||||||
return encoding ? '' : new Buffer(0);
|
} else {
|
||||||
|
buffer = new Buffer(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffer = new Buffer(size);
|
var done = false;
|
||||||
var pos = 0;
|
while (!done) {
|
||||||
|
|
||||||
while (pos < size) {
|
|
||||||
var threw = true;
|
var threw = true;
|
||||||
try {
|
try {
|
||||||
var bytesRead = fs.readSync(fd, buffer, pos, size - pos, pos);
|
if (size !== 0) {
|
||||||
|
var bytesRead = fs.readSync(fd, buffer, pos, size - pos, pos);
|
||||||
|
} else {
|
||||||
|
// the kernel lies about many files.
|
||||||
|
// Go ahead and try to read some bytes.
|
||||||
|
buffer = new Buffer(8192);
|
||||||
|
var bytesRead = fs.readSync(fd, buffer, 0, 8192, pos);
|
||||||
|
if (bytesRead) {
|
||||||
|
buffers.push(buffer.slice(0, bytesRead));
|
||||||
|
}
|
||||||
|
}
|
||||||
threw = false;
|
threw = false;
|
||||||
} finally {
|
} finally {
|
||||||
if (threw) fs.closeSync(fd);
|
if (threw) fs.closeSync(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
pos += bytesRead;
|
pos += bytesRead;
|
||||||
|
|
||||||
|
if (size !== 0) {
|
||||||
|
done = pos >= size;
|
||||||
|
} else {
|
||||||
|
done = bytesRead > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.closeSync(fd);
|
fs.closeSync(fd);
|
||||||
|
|
||||||
|
if (size === 0) {
|
||||||
|
// data was collected into the buffers list.
|
||||||
|
buffer = Buffer.concat(buffers, pos);
|
||||||
|
}
|
||||||
|
|
||||||
if (encoding) buffer = buffer.toString(encoding);
|
if (encoding) buffer = buffer.toString(encoding);
|
||||||
return buffer;
|
return buffer;
|
||||||
};
|
};
|
||||||
|
58
test/simple/test-fs-readfile-zero-byte-liar.js
Normal file
58
test/simple/test-fs-readfile-zero-byte-liar.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// Copyright Joyent, Inc. and other Node contributors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||||
|
// persons to whom the Software is furnished to do so, subject to the
|
||||||
|
// following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||||
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var assert = require('assert');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
var dataExpected = fs.readFileSync(__filename, 'utf8');
|
||||||
|
|
||||||
|
// sometimes stat returns size=0, but it's a lie.
|
||||||
|
fs._fstat = fs.fstat;
|
||||||
|
fs._fstatSync = fs.fstatSync;
|
||||||
|
|
||||||
|
fs.fstat = function(fd, cb) {
|
||||||
|
fs._fstat(fd, function(er, st) {
|
||||||
|
if (er) return cb(er);
|
||||||
|
st.size = 0;
|
||||||
|
return cb(er, st);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
fs.fstatSync = function(fd) {
|
||||||
|
var st = fs._fstatSync;
|
||||||
|
st.size = 0;
|
||||||
|
return st;
|
||||||
|
};
|
||||||
|
|
||||||
|
var d = fs.readFileSync(__filename, 'utf8');
|
||||||
|
assert.equal(d, dataExpected);
|
||||||
|
|
||||||
|
var called = false;
|
||||||
|
fs.readFile(__filename, 'utf8', function (er, d) {
|
||||||
|
assert.equal(d, dataExpected);
|
||||||
|
called = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('exit', function() {
|
||||||
|
assert(called);
|
||||||
|
console.log("ok");
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user