| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e2f952f commit 77fedbd
12 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -81,6 +81,7 @@ const { | |||
| 81 | 81 | ||
| 82 | 82 | const { | |
| 83 | 83 | FSReqCallback, | |
| 84 | + ReadFileJob, | ||
| 84 | 85 | } = binding; | |
| 85 | 86 | const { toPathIfFileURL } = require('internal/url'); | |
| 86 | 87 | const { | |
@@ -98,6 +99,7 @@ const { | |||
| 98 | 99 | const { | |
| 99 | 100 | constants: { | |
| 100 | 101 | kIoMaxLength, | |
| 102 | + kReadFileBufferLength, | ||
| 101 | 103 | kMaxUserId, | |
| 102 | 104 | }, | |
| 103 | 105 | copyObject, | |
@@ -428,10 +430,70 @@ function readFile(path, options, callback) { | |||
| 428 | 430 | return; | |
| 429 | 431 | ||
| 430 | 432 | const flagsNumber = stringToFlags(options.flag, 'options.flag'); | |
| 433 | + path = getValidatedPath(path); | ||
| 434 | + if (options.buffer === undefined) { | ||
| 435 | + // Open + fstat + read + close in one thread pool round trip for files of | ||
| 436 | + // up to one chunk; larger files come back as an open fd + size and take | ||
| 437 | + // the chunked reader below (readFileAfterOneShot). `true`: a handed-back | ||
| 438 | + // fd will be closed through fs.close(), so track it as unmanaged. | ||
| 439 | + const job = new ReadFileJob(path, flagsNumber, kReadFileBufferLength, true); | ||
| 440 | + job.context = context; | ||
| 441 | + job.ondone = readFileAfterOneShot; | ||
| 442 | + const accessError = job.run(path); | ||
| 443 | + if (accessError !== undefined) { | ||
| 444 | + // Not scheduled: report it the way the request-based open() did. | ||
| 445 | + callback(accessError); | ||
| 446 | + } | ||
| 447 | + return; | ||
| 448 | + } | ||
| 431 | 449 | const req = new FSReqCallback(); | |
| 432 | 450 | req.context = context; | |
| 433 | 451 | req.oncomplete = readFileAfterOpen; | |
| 434 | - binding.open(getValidatedPath(path), flagsNumber, 0o666, req); | ||
| 452 | + binding.open(path, flagsNumber, 0o666, req); | ||
| 453 | + } | ||
| 454 | + | ||
| 455 | + function readFileAfterOneShot(err, buffer, fd, size, closeErr) { | ||
| 456 | + const context = this.context; | ||
| 457 | + if (err) { | ||
| 458 | + context.callback(err); | ||
| 459 | + return; | ||
| 460 | + } | ||
| 461 | + if (fd !== -1) { | ||
| 462 | + // (context.read() below performs the abort check for this case.) | ||
| 463 | + // Larger than one chunk: continue exactly like after open + fstat. | ||
| 464 | + context.fd = fd; | ||
| 465 | + context.size = size; | ||
| 466 | + if (size > kIoMaxLength) { | ||
| 467 | + return context.close(new ERR_FS_FILE_TOO_LARGE(size)); | ||
| 468 | + } | ||
| 469 | + try { | ||
| 470 | + context.prepare(); | ||
| 471 | + } catch (err) { | ||
| 472 | + return context.close(err); | ||
| 473 | + } | ||
| 474 | + context.read(); | ||
| 475 | + return; | ||
| 476 | + } | ||
| 477 | + if (closeErr) { | ||
| 478 | + context.callback(closeErr); | ||
| 479 | + return; | ||
| 480 | + } | ||
| 481 | + if (context.signal?.aborted) { | ||
| 482 | + // An abort that arrived while the read was in flight wins, as it did when | ||
| 483 | + // it was noticed between the open/fstat/read steps. | ||
| 484 | + context.callback(new AbortError(undefined, { cause: context.signal.reason })); | ||
| 485 | + return; | ||
| 486 | + } | ||
| 487 | + let result = buffer; | ||
| 488 | + if (context.encoding) { | ||
| 489 | + try { | ||
| 490 | + result = buffer.toString(context.encoding); | ||
| 491 | + } catch (err) { | ||
| 492 | + context.callback(err); | ||
| 493 | + return; | ||
| 494 | + } | ||
| 495 | + } | ||
| 496 | + context.callback(null, result); | ||
| 435 | 497 | } | |
| 436 | 498 | ||
| 437 | 499 | function tryStatSync(fd, isUserFd) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1211,26 +1211,32 @@ async function readFileHandleWithUserBuffer(filehandle, options, size) { | |||
| 1211 | 1211 | return encoding ? buffer.toString(encoding) : buffer.subarray(0, totalRead); | |
| 1212 | 1212 | } | |
| 1213 | 1213 | ||
| 1214 | - async function readFileHandle(filehandle, options) { | ||
| 1214 | + async function readFileHandle(filehandle, options, knownRegularFileSize) { | ||
| 1215 | 1215 | const signal = options?.signal; | |
| 1216 | 1216 | const encoding = options?.encoding; | |
| 1217 | 1217 | const decoder = encoding && new StringDecoder(encoding); | |
| 1218 | 1218 | ||
| 1219 | 1219 | checkAborted(signal); | |
| 1220 | 1220 | ||
| 1221 | - const statFields = await PromisePrototypeThen( | ||
| 1222 | - binding.fstat(filehandle.fd, false, kUsePromises), | ||
| 1223 | - undefined, | ||
| 1224 | - handleErrorFromBinding, | ||
| 1225 | - ); | ||
| 1226 | - | ||
| 1227 | - checkAborted(signal); | ||
| 1228 | - | ||
| 1229 | 1221 | let size = 0; | |
| 1230 | 1222 | let length = 0; | |
| 1231 | - if ((statFields[1/* mode */] & S_IFMT) === S_IFREG) { | ||
| 1232 | - size = statFields[8/* size */]; | ||
| 1223 | + if (knownRegularFileSize !== undefined) { | ||
| 1224 | + // Handed over by readFile() together with an already open fd. | ||
| 1225 | + size = knownRegularFileSize; | ||
| 1233 | 1226 | length = encoding ? MathMin(size, kReadFileBufferLength) : size; | |
| 1227 | + } else { | ||
| 1228 | + const statFields = await PromisePrototypeThen( | ||
| 1229 | + binding.fstat(filehandle.fd, false, kUsePromises), | ||
| 1230 | + undefined, | ||
| 1231 | + handleErrorFromBinding, | ||
| 1232 | + ); | ||
| 1233 | + | ||
| 1234 | + checkAborted(signal); | ||
| 1235 | + | ||
| 1236 | + if ((statFields[1/* mode */] & S_IFMT) === S_IFREG) { | ||
| 1237 | + size = statFields[8/* size */]; | ||
| 1238 | + length = encoding ? MathMin(size, kReadFileBufferLength) : size; | ||
| 1239 | + } | ||
| 1234 | 1240 | } | |
| 1235 | 1241 | if (length === 0) { | |
| 1236 | 1242 | length = kReadFileUnknownBufferLength; | |
@@ -2146,10 +2152,49 @@ async function readFile(path, options) { | |||
| 2146 | 2152 | ||
| 2147 | 2153 | checkAborted(options.signal); | |
| 2148 | 2154 | ||
| 2155 | + if (options.buffer === undefined && vfsState.handlers === null) { | ||
| 2156 | + // Open + fstat + read + close in one thread pool round trip for files of | ||
| 2157 | + // up to one chunk; larger files come back as an open fd + size and are | ||
| 2158 | + // read by readFileHandle() as before. | ||
| 2159 | + path = getValidatedPath(path); | ||
| 2160 | + const { 0: buffer, 1: fd, 2: size } = await readFileInOneRoundTrip(path, stringToFlags(flag)); | ||
| 2161 | + if (fd === -1) { | ||
| 2162 | + checkAborted(options.signal); // An abort during the read still wins. | ||
| 2163 | + return options.encoding ? buffer.toString(options.encoding) : buffer; | ||
| 2164 | + } | ||
| 2165 | + const filehandle = new FileHandle(new binding.FileHandle(fd)); | ||
| 2166 | + return handleFdClose(readFileHandle(filehandle, options, size), filehandle.close); | ||
| 2167 | + } | ||
| 2168 | + | ||
| 2149 | 2169 | const fd = await open(path, flag, 0o666); | |
| 2150 | 2170 | return handleFdClose(readFileHandle(fd, options), fd.close); | |
| 2151 | 2171 | } | |
| 2152 | 2172 | ||
| 2173 | + /** | ||
| 2174 | + * @param {string|Buffer} path Validated path | ||
| 2175 | + * @param {number} flagsNumber | ||
| 2176 | + * @returns {Promise<[Buffer|undefined, number, number|undefined]>} [buffer, -1] or [undefined, fd, size] | ||
| 2177 | + */ | ||
| 2178 | + function readFileInOneRoundTrip(path, flagsNumber) { | ||
| 2179 | + return new Promise((resolve, reject) => { | ||
| 2180 | + const job = new binding.ReadFileJob(path, flagsNumber, kReadFileBufferLength); | ||
| 2181 | + job.ondone = (err, buffer, fd, size, closeErr) => { | ||
| 2182 | + const error = err ?? closeErr; | ||
| 2183 | + if (error != null) { | ||
| 2184 | + ErrorCaptureStackTrace(error, readFileInOneRoundTrip); | ||
| 2185 | + reject(error); | ||
| 2186 | + } else { | ||
| 2187 | + resolve([buffer, fd, size]); | ||
| 2188 | + } | ||
| 2189 | + }; | ||
| 2190 | + const accessError = job.run(path); | ||
| 2191 | + if (accessError !== undefined) { | ||
| 2192 | + ErrorCaptureStackTrace(accessError, readFileInOneRoundTrip); | ||
| 2193 | + reject(accessError); | ||
| 2194 | + } | ||
| 2195 | + }); | ||
| 2196 | + } | ||
| 2197 | + | ||
| 2153 | 2198 | async function* _watch(filename, options = kEmptyObject) { | |
| 2154 | 2199 | const h = vfsState.handlers; | |
| 2155 | 2200 | if (h !== null) { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments