Skip to content

Commit b1e4ac0

Browse files
Mert Can Altinmertcanaltin
authored andcommitted
fs: enable chunked reading for large files in readFileHandle
1 parent ee0a006 commit b1e4ac0

File tree

2 files changed

+36
-40
lines changed

2 files changed

+36
-40
lines changed

lib/internal/fs/promises.js

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ const {
3939
aggregateTwoErrors,
4040
codes: {
4141
ERR_ACCESS_DENIED,
42-
ERR_FS_FILE_TOO_LARGE,
4342
ERR_INVALID_ARG_VALUE,
4443
ERR_INVALID_STATE,
4544
ERR_METHOD_NOT_IMPLEMENTED,
@@ -49,7 +48,6 @@ const { isArrayBufferView } = require('internal/util/types');
4948

5049
const {
5150
constants: {
52-
kIoMaxLength,
5351
kMaxUserId,
5452
kReadFileBufferLength,
5553
kReadFileUnknownBufferLength,
@@ -521,17 +519,14 @@ async function readFileHandle(filehandle, options) {
521519

522520
let size = 0;
523521
let length = 0;
524-
if ((statFields[1/* mode */] & S_IFMT) === S_IFREG) {
525-
size = statFields[8/* size */];
522+
if ((statFields[1 /* mode */] & S_IFMT) === S_IFREG) {
523+
size = statFields[8 /* size */];
526524
length = encoding ? MathMin(size, kReadFileBufferLength) : size;
527525
}
528526
if (length === 0) {
529527
length = kReadFileUnknownBufferLength;
530528
}
531529

532-
if (size > kIoMaxLength)
533-
throw new ERR_FS_FILE_TOO_LARGE(size);
534-
535530
let totalRead = 0;
536531
const noSize = size === 0;
537532
let buffer = Buffer.allocUnsafeSlow(length);
@@ -554,9 +549,7 @@ async function readFileHandle(filehandle, options) {
554549
)) ?? 0;
555550
totalRead += bytesRead;
556551

557-
if (bytesRead === 0 ||
558-
totalRead === size ||
559-
(bytesRead !== buffer.length && !chunkedRead && !noSize)) {
552+
if (bytesRead === 0 || totalRead === size || (bytesRead !== buffer.length && !chunkedRead && !noSize)) {
560553
const singleRead = bytesRead === totalRead;
561554

562555
const bytesToCheck = chunkedRead ? totalRead : bytesRead;
@@ -579,9 +572,9 @@ async function readFileHandle(filehandle, options) {
579572
result += decoder.end(buffer);
580573
return result;
581574
}
582-
const readBuffer = bytesRead !== buffer.length ?
583-
buffer.subarray(0, bytesRead) :
584-
buffer;
575+
576+
const readBuffer = bytesRead !== buffer.length ? buffer.subarray(0, bytesRead) : buffer;
577+
585578
if (encoding) {
586579
result += decoder.write(readBuffer);
587580
} else if (size !== 0) {
@@ -590,6 +583,8 @@ async function readFileHandle(filehandle, options) {
590583
buffers ??= [];
591584
// Unknown file size requires chunks.
592585
ArrayPrototypePush(buffers, readBuffer);
586+
587+
// Create a new buffer (continue for large files)
593588
buffer = Buffer.allocUnsafeSlow(kReadFileUnknownBufferLength);
594589
}
595590
}

test/parallel/test-fs-promises-file-handle-readFile.js

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ const common = require('../common');
55
// The following tests validate base functionality for the fs.promises
66
// FileHandle.readFile method.
77

8-
const fs = require('fs');
8+
const fs = require('node:fs');
99
const {
1010
open,
1111
readFile,
1212
writeFile,
13-
truncate,
1413
} = fs.promises;
15-
const path = require('path');
14+
const path = require('node:path');
15+
const os = require('node:os');
1616
const tmpdir = require('../common/tmpdir');
1717
const tick = require('../common/tick');
18-
const assert = require('assert');
18+
const assert = require('node:assert');
1919
const tmpDir = tmpdir.path;
2020

2121
tmpdir.refresh();
@@ -35,6 +35,29 @@ async function validateReadFile() {
3535
await fileHandle.close();
3636
}
3737

38+
async function validateLargeFileSupport() {
39+
const LARGE_FILE_SIZE = 3 * 1024 * 1024 * 1024; // 3 GiB
40+
const FILE_PATH = path.join(os.tmpdir(), 'large-virtual-file.bin');
41+
42+
function createVirtualLargeFile() {
43+
return Buffer.alloc(LARGE_FILE_SIZE, 'A');
44+
}
45+
46+
const virtualFile = createVirtualLargeFile();
47+
48+
await writeFile(FILE_PATH, virtualFile);
49+
50+
const buffer = await readFile(FILE_PATH);
51+
52+
assert.strictEqual(
53+
buffer.length,
54+
LARGE_FILE_SIZE,
55+
`Expected file size to be ${LARGE_FILE_SIZE}, but got ${buffer.length}`
56+
);
57+
58+
await fs.promises.unlink(FILE_PATH);
59+
}
60+
3861
async function validateReadFileProc() {
3962
// Test to make sure reading a file under the /proc directory works. Adapted
4063
// from test-fs-read-file-sync-hostname.js.
@@ -100,32 +123,10 @@ async function doReadAndCancel() {
100123

101124
await fileHandle.close();
102125
}
103-
104-
// Validate file size is within range for reading
105-
{
106-
// Variable taken from https://github.com/nodejs/node/blob/1377163f3351/lib/internal/fs/promises.js#L5
107-
const kIoMaxLength = 2 ** 31 - 1;
108-
109-
if (!tmpdir.hasEnoughSpace(kIoMaxLength)) {
110-
// truncate() will fail with ENOSPC if there is not enough space.
111-
common.printSkipMessage(`Not enough space in ${tmpDir}`);
112-
} else {
113-
const newFile = path.resolve(tmpDir, 'dogs-running3.txt');
114-
await writeFile(newFile, Buffer.from('0'));
115-
await truncate(newFile, kIoMaxLength + 1);
116-
117-
const fileHandle = await open(newFile, 'r');
118-
119-
await assert.rejects(fileHandle.readFile(), {
120-
name: 'RangeError',
121-
code: 'ERR_FS_FILE_TOO_LARGE'
122-
});
123-
await fileHandle.close();
124-
}
125-
}
126126
}
127127

128128
validateReadFile()
129+
.then(validateLargeFileSupport)
129130
.then(validateReadFileProc)
130131
.then(doReadAndCancel)
131132
.then(common.mustCall());

0 commit comments

Comments
 (0)