Browse files

fix fs.readFile with lying size=0 stat results

  • Loading branch information...
1 parent d53cdc5 commit 6ce013dd4bbe660c12ce11c338b788163305cd2b @isaacs isaacs committed Jun 11, 2012
Showing with 118 additions and 13 deletions.
  1. +60 −13 lib/fs.js
  2. +58 −0 test/simple/test-fs-readfile-zero-byte-liar.js
View
73 lib/fs.js
@@ -108,7 +108,8 @@ fs.readFile = function(path, encoding_) {
// first, stat the file, so we know the size.
var size;
- var buffer;
+ var buffer; // single buffer with file data
+ var buffers; // list for when size is unknown
var pos = 0;
var fd;
@@ -120,8 +121,10 @@ fs.readFile = function(path, encoding_) {
if (er) return callback(er);
size = st.size;
if (size === 0) {
- buffer = new Buffer(0);
- return afterRead(null, 0);
+ // the kernel lies about many files.
+ // Go ahead and try to read some bytes.
+ buffers = [];
+ return read();
}
buffer = new Buffer(size);
@@ -130,7 +133,12 @@ fs.readFile = function(path, encoding_) {
});
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) {
@@ -141,12 +149,27 @@ fs.readFile = function(path, encoding_) {
}
pos += bytesRead;
- if (pos === size) close();
- else read();
+ if (size !== 0) {
+ 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() {
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);
return callback(er, buffer);
});
@@ -165,28 +188,52 @@ fs.readFileSync = function(path, encoding) {
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) {
- fs.closeSync(fd);
- return encoding ? '' : new Buffer(0);
+ buffers = [];
+ } else {
+ buffer = new Buffer(size);
}
- var buffer = new Buffer(size);
- var pos = 0;
-
- while (pos < size) {
+ var done = false;
+ while (!done) {
var threw = true;
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;
} finally {
if (threw) fs.closeSync(fd);
}
pos += bytesRead;
+
+ if (size !== 0) {
+ done = pos >= size;
+ } else {
+ done = bytesRead > 0;
+ }
}
fs.closeSync(fd);
+ if (size === 0) {
+ // data was collected into the buffers list.
+ buffer = Buffer.concat(buffers, pos);
+ }
+
if (encoding) buffer = buffer.toString(encoding);
return buffer;
};
View
58 test/simple/test-fs-readfile-zero-byte-liar.js
@@ -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");
+});

0 comments on commit 6ce013d

Please sign in to comment.