diff --git a/lib/fs.js b/lib/fs.js index 910a714d67..be8c865a40 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -103,93 +103,88 @@ fs.readFile = function(path, encoding_) { var encoding = typeof(encoding_) === 'string' ? encoding_ : null; var callback = arguments[arguments.length - 1]; if (typeof(callback) !== 'function') callback = noop; - var readStream = fs.createReadStream(path); - var buffers = []; - var nread = 0; - var error; - - readStream.on('data', function(chunk) { - buffers.push(chunk); - nread += chunk.length; - }); - readStream.on('error', function(er) { - error = er; - readStream.destroy(); - if (!readStream.fd) { - readStream.emit('close'); - } + // first, stat the file, so we know the size. + var size; + var buffer; + var pos = 0; + var fd; + + fs.open(path, constants.O_RDONLY, 438 /*=0666*/, function(er, fd_) { + if (er) return callback(er); + fd = fd_; + + fs.fstat(fd, function(er, st) { + if (er) return callback(er); + size = st.size; + if (size === 0) { + buffer = new Buffer(0); + return afterRead(null, 0); + } + + buffer = new Buffer(size); + read(); + }); }); - readStream.on('close', function() { - if (error) { - return callback(error); - } + function read() { + fs.read(fd, buffer, pos, size - pos, pos, afterRead); + } - // copy all the buffers into one - var buffer; - switch (buffers.length) { - case 0: buffer = new Buffer(0); break; - case 1: buffer = buffers[0]; break; - default: // concat together - buffer = new Buffer(nread); - var n = 0; - buffers.forEach(function(b) { - var l = b.length; - b.copy(buffer, n, 0, l); - n += l; - }); - break; - } - if (encoding) { - try { - buffer = buffer.toString(encoding); - } catch (er) { + function afterRead(er, bytesRead) { + if (er) { + return fs.close(fd, function(er2) { return callback(er); - } + }); } - callback(null, buffer); - }); + + pos += bytesRead; + if (pos === size) close(); + else read(); + } + + function close() { + fs.close(fd, function(er) { + if (encoding) buffer = buffer.toString(encoding); + return callback(er, buffer); + }); + } }; fs.readFileSync = function(path, encoding) { var fd = fs.openSync(path, constants.O_RDONLY, 438 /*=0666*/); - var buffer = new Buffer(4048); - var buffers = []; - var nread = 0; - var lastRead = 0; + var size; + var threw = true; try { - do { - if (lastRead) { - buffer._bytesRead = lastRead; - nread += lastRead; - buffers.push(buffer); - } - var buffer = new Buffer(4048); - lastRead = fs.readSync(fd, buffer, 0, buffer.length, null); - } while (lastRead > 0); + size = fs.fstatSync(fd).size; + threw = false; } finally { + if (threw) fs.closeSync(fd); + } + + if (size === 0) { fs.closeSync(fd); + return encoding ? '' : new Buffer(0); } - if (buffers.length > 1) { - var offset = 0; - var i; - buffer = new Buffer(nread); - buffers.forEach(function(i) { - if (!i._bytesRead) return; - i.copy(buffer, offset, 0, i._bytesRead); - offset += i._bytesRead; - }); - } else if (buffers.length) { - // buffers has exactly 1 (possibly zero length) buffer, so this should - // be a shortcut - buffer = buffers[0].slice(0, buffers[0]._bytesRead); - } else { - buffer = new Buffer(0); + var buffer = new Buffer(size); + var pos = 0; + + while (pos < size) { + var threw = true; + try { + var bytesRead = fs.readSync(fd, buffer, pos, size - pos, pos); + threw = false; + } finally { + if (threw) fs.closeSync(fd); + } + + pos += bytesRead; } + fs.closeSync(fd); + if (encoding) buffer = buffer.toString(encoding); return buffer; }; diff --git a/test/simple/test-fs-sync-fd-leak.js b/test/simple/test-fs-sync-fd-leak.js index 469abf3abd..fe932c7dfa 100644 --- a/test/simple/test-fs-sync-fd-leak.js +++ b/test/simple/test-fs-sync-fd-leak.js @@ -38,6 +38,10 @@ fs.writeSync = function() { throw new Error('BAM'); }; +fs.fstatSync = function() { + throw new Error('BAM'); +}; + ensureThrows(function() { fs.readFileSync('dummy'); });