|
1 | 1 | 'use strict'; |
2 | 2 |
|
3 | | -// Most platforms don't allow reads or writes >= 2 GB. |
4 | | -// See https://github.com/libuv/libuv/pull/1501. |
5 | | -const kIoMaxLength = 2 ** 31 - 1; |
6 | | - |
7 | | -// Note: This is different from kReadFileBufferLength used for non-promisified |
8 | | -// fs.readFile. |
9 | | -const kReadFileMaxChunkSize = 2 ** 14; |
10 | | -const kWriteFileMaxChunkSize = 2 ** 14; |
11 | | - |
12 | | -// 2 ** 32 - 1 |
13 | | -const kMaxUserId = 4294967295; |
14 | | - |
15 | 3 | const { |
16 | 4 | Error, |
17 | 5 | MathMax, |
@@ -44,6 +32,13 @@ const { |
44 | 32 | const { isArrayBufferView } = require('internal/util/types'); |
45 | 33 | const { rimrafPromises } = require('internal/fs/rimraf'); |
46 | 34 | const { |
| 35 | + constants: { |
| 36 | + kIoMaxLength, |
| 37 | + kMaxUserId, |
| 38 | + kReadFileBufferLength, |
| 39 | + kReadFileUnknownBufferLength, |
| 40 | + kWriteFileMaxChunkSize, |
| 41 | + }, |
47 | 42 | copyObject, |
48 | 43 | getDirents, |
49 | 44 | getOptions, |
@@ -296,24 +291,46 @@ async function readFileHandle(filehandle, options) { |
296 | 291 | if (size > kIoMaxLength) |
297 | 292 | throw new ERR_FS_FILE_TOO_LARGE(size); |
298 | 293 |
|
299 | | - const chunks = []; |
300 | | - const chunkSize = size === 0 ? |
301 | | - kReadFileMaxChunkSize : |
302 | | - MathMin(size, kReadFileMaxChunkSize); |
303 | 294 | let endOfFile = false; |
| 295 | + let totalRead = 0; |
| 296 | + const noSize = size === 0; |
| 297 | + const buffers = []; |
| 298 | + const fullBuffer = noSize ? undefined : Buffer.allocUnsafeSlow(size); |
304 | 299 | do { |
305 | 300 | if (signal && signal.aborted) { |
306 | 301 | throw lazyDOMException('The operation was aborted', 'AbortError'); |
307 | 302 | } |
308 | | - const buf = Buffer.alloc(chunkSize); |
309 | | - const { bytesRead, buffer } = |
310 | | - await read(filehandle, buf, 0, chunkSize, -1); |
311 | | - endOfFile = bytesRead === 0; |
312 | | - if (bytesRead > 0) |
313 | | - chunks.push(buffer.slice(0, bytesRead)); |
| 303 | + let buffer; |
| 304 | + let offset; |
| 305 | + let length; |
| 306 | + if (noSize) { |
| 307 | + buffer = Buffer.allocUnsafeSlow(kReadFileUnknownBufferLength); |
| 308 | + offset = 0; |
| 309 | + length = kReadFileUnknownBufferLength; |
| 310 | + } else { |
| 311 | + buffer = fullBuffer; |
| 312 | + offset = totalRead; |
| 313 | + length = MathMin(size - totalRead, kReadFileBufferLength); |
| 314 | + } |
| 315 | + |
| 316 | + const bytesRead = (await binding.read(filehandle.fd, buffer, offset, |
| 317 | + length, -1, kUsePromises)) || 0; |
| 318 | + totalRead += bytesRead; |
| 319 | + endOfFile = bytesRead === 0 || totalRead === size; |
| 320 | + if (noSize && bytesRead > 0) { |
| 321 | + const isBufferFull = bytesRead === kReadFileUnknownBufferLength; |
| 322 | + const chunkBuffer = isBufferFull ? buffer : buffer.slice(0, bytesRead); |
| 323 | + ArrayPrototypePush(buffers, chunkBuffer); |
| 324 | + } |
314 | 325 | } while (!endOfFile); |
315 | 326 |
|
316 | | - const result = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks); |
| 327 | + let result; |
| 328 | + if (size > 0) { |
| 329 | + result = totalRead === size ? fullBuffer : fullBuffer.slice(0, totalRead); |
| 330 | + } else { |
| 331 | + result = buffers.length === 1 ? buffers[0] : Buffer.concat(buffers, |
| 332 | + totalRead); |
| 333 | + } |
317 | 334 |
|
318 | 335 | return options.encoding ? result.toString(options.encoding) : result; |
319 | 336 | } |
|
0 commit comments