diff --git a/src/application/RegularFileRead.ts b/src/application/RegularFileRead.ts index 6792a3b272..cdbadedc46 100644 --- a/src/application/RegularFileRead.ts +++ b/src/application/RegularFileRead.ts @@ -22,6 +22,8 @@ export interface RegularFileReadOptions { readonly signal?: AbortSignal | undefined; readonly symlinks?: "follow" | "reject"; readonly resources?: ArtifactResourceScope; + /** Runs on the opened file's own state before any byte is read; throw to refuse the read. */ + readonly admit?: (state: Stats) => void; } export class InvalidUtf8FileError extends TypeError { @@ -223,6 +225,7 @@ const readRegularFileContent = ( withRegularFile( path, async (handle, stats) => { + options.admit?.(stats); const bytes = await readBoundedFileBytes( handle, stats.size, diff --git a/src/application/environment/environmentExport.ts b/src/application/environment/environmentExport.ts index 298e8e931f..0a080c1ffb 100644 --- a/src/application/environment/environmentExport.ts +++ b/src/application/environment/environmentExport.ts @@ -208,11 +208,16 @@ const readInput = async ( ): Promise> => { let bytes: Buffer; try { - // Admit the whole read before materializing it; the bundle needs these exact bytes. - const refused = headroomRefusal(path, (await stat(path)).size); - if (refused !== undefined) return err(refused); - bytes = await readRegularFile(path); + // Admit the whole read against the opened file's own size, before materializing the + // exact bytes the bundle copies. + bytes = await readRegularFile(path, { + admit: (state) => { + const refused = headroomRefusal(path, state.size); + if (refused !== undefined) throw refused; + }, + }); } catch (cause: unknown) { + if (cause instanceof AnalysisResourceConstraintError) return err(cause); if (NOT_A_FILE_CODES.has(systemCode(cause) ?? "")) return err( inputError(