Skip to content

Commit a6511bf

Browse files
committed
fix: Guard file openings
1 parent 686e62b commit a6511bf

File tree

11 files changed

+30
-8
lines changed

11 files changed

+30
-8
lines changed

src/files/gzip.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { assert, assertObjectMatch } from '@std/assert'
22
import { parseGzip } from './gzip.ts'
33
import { BIDSFileDeno } from './deno.ts'
4+
import { testAsyncFileAccess } from './access.test.ts'
45

56
Deno.test('parseGzip', async (t) => {
67
await t.step('parses anonymized file', async () => {
@@ -40,3 +41,5 @@ Deno.test('parseGzip', async (t) => {
4041
assert(!gzip)
4142
})
4243
})
44+
45+
testAsyncFileAccess('Test file access errors for parseGzip', parseGzip)

src/files/gzip.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
import type { Gzip } from '@bids/schema/context'
66
import type { BIDSFile } from '../types/filetree.ts'
7+
import { readBytes } from './access.ts'
78

89
/**
910
* Parse a gzip header from a file
@@ -19,7 +20,7 @@ export async function parseGzip(
1920
file: BIDSFile,
2021
maxBytes: number = 512,
2122
): Promise<Gzip | undefined> {
22-
const buf = await file.readBytes(maxBytes)
23+
const buf = await readBytes(file, maxBytes)
2324
const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength)
2425
if (view.byteLength < 2 || view.getUint16(0, false) !== 0x1f8b) return undefined
2526

src/files/json.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { type assert, assertObjectMatch } from '@std/assert'
22
import type { BIDSFile } from '../types/filetree.ts'
33
import type { FileIgnoreRules } from './ignore.ts'
4+
import { testAsyncFileAccess } from './access.test.ts'
45

56
import { loadJSON } from './json.ts'
67

@@ -61,3 +62,5 @@ Deno.test('Test JSON error conditions', async (t) => {
6162
assertObjectMatch(error, { code: 'JSON_INVALID' })
6263
})
6364
})
65+
66+
testAsyncFileAccess('Test file access errors for loadJSON', loadJSON)

src/files/json.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import type { BIDSFile } from '../types/filetree.ts'
2+
import { readBytes } from './access.ts'
23

34
async function readJSONText(file: BIDSFile): Promise<string> {
45
// Read JSON text from a file
56
// JSON must be encoded in UTF-8 without a byte order mark (BOM)
67
const decoder = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true })
78
// Streaming TextDecoders are buggy in Deno and Chrome, so read the
89
// entire file into memory before decoding and parsing
9-
const data = await file.readBytes(file.size)
10+
const data = await readBytes(file, file.size)
1011
try {
1112
const text = decoder.decode(data)
1213
if (text.startsWith('\uFEFF')) {

src/files/nifti.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { assert, assertEquals, assertObjectMatch } from '@std/assert'
22
import { FileIgnoreRules } from './ignore.ts'
33
import { BIDSFileDeno } from './deno.ts'
4+
import { testAsyncFileAccess } from './access.test.ts'
45

56
import { axisCodes, loadHeader } from './nifti.ts'
67

@@ -96,3 +97,5 @@ Deno.test('Test extracting axis codes', async (t) => {
9697
assertEquals(axisCodes(affine), ['A', 'S', 'R'])
9798
})
9899
})
100+
101+
testAsyncFileAccess('Test file access errors for loadHeader', loadHeader)

src/files/nifti.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { isCompressed, isNIFTI1, isNIFTI2, NIFTI1, NIFTI2 } from '@mango/nifti'
22
import type { BIDSFile } from '../types/filetree.ts'
33
import { logger } from '../utils/logger.ts'
44
import type { NiftiHeader } from '@bids/schema/context'
5+
import { readBytes } from './access.ts'
56

67
async function extract(buffer: Uint8Array, nbytes: number): Promise<Uint8Array<ArrayBuffer>> {
78
// The fflate decompression that is used in nifti-reader does not like
@@ -32,8 +33,8 @@ async function extract(buffer: Uint8Array, nbytes: number): Promise<Uint8Array<A
3233
}
3334

3435
export async function loadHeader(file: BIDSFile): Promise<NiftiHeader> {
36+
const buf = await readBytes(file, 1024)
3537
try {
36-
const buf = await file.readBytes(1024)
3738
const data = isCompressed(buf.buffer) ? await extract(buf, 540) : buf.slice(0, 540)
3839
let header
3940
if (isNIFTI1(data.buffer)) {

src/files/tiff.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { assert, assertObjectMatch } from '@std/assert'
22
import { parseTIFF } from './tiff.ts'
33
import { BIDSFileDeno } from './deno.ts'
4+
import { testAsyncFileAccess } from './access.test.ts'
45

56
Deno.test('parseTIFF', async (t) => {
67
await t.step('parse example file as TIFF', async () => {
@@ -53,3 +54,5 @@ Deno.test('parseTIFF', async (t) => {
5354
})
5455
})
5556
})
57+
58+
testAsyncFileAccess('Test file access errors for parseTIFF', parseTIFF)

src/files/tiff.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import type { Ome, Tiff } from '@bids/schema/context'
66
import * as XML from '@libs/xml'
77
import type { BIDSFile } from '../types/filetree.ts'
8+
import { readBytes } from './access.ts'
89

910
function getImageDescription(
1011
dataview: DataView<ArrayBuffer>,
@@ -44,7 +45,7 @@ export async function parseTIFF(
4445
file: BIDSFile,
4546
OME: boolean,
4647
): Promise<{ tiff?: Tiff; ome?: Ome }> {
47-
const buf = await file.readBytes(4096)
48+
const buf = await readBytes(file, 4096)
4849
const dataview = new DataView(buf.buffer, buf.byteOffset, buf.byteLength)
4950
const magic = dataview.getUint16(0, true)
5051
const littleEndian = magic === 0x4949

src/files/tsv.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { pathToFile } from './filetree.ts'
99
import { loadTSV, loadTSVGZ } from './tsv.ts'
1010
import { streamFromString } from '../tests/utils.ts'
1111
import { ColumnsMap } from '../types/columns.ts'
12+
import { testAsyncFileAccess } from './access.test.ts'
1213

1314
function compressedStreamFromString(str: string): ReadableStream<Uint8Array<ArrayBuffer>> {
1415
return streamFromString(str).pipeThrough(new CompressionStream('gzip')) as ReadableStream<
@@ -292,3 +293,5 @@ Deno.test('TSVGZ loading', async (t) => {
292293
assertEquals(map.c, ['3', '6', '9'])
293294
})
294295
})
296+
297+
testAsyncFileAccess('Test file access errors for loadTSV', loadTSV)

src/files/tsv.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { ColumnsMap } from '../types/columns.ts'
77
import type { BIDSFile } from '../types/filetree.ts'
88
import { filememoizeAsync } from '../utils/memoize.ts'
99
import { createUTF8Stream } from './streams.ts'
10+
import { openStream } from './access.ts'
1011

1112
async function loadColumns(
1213
reader: ReadableStreamDefaultReader<string>,
@@ -55,7 +56,7 @@ export async function loadTSVGZ(
5556
headers: string[],
5657
maxRows: number = -1,
5758
): Promise<ColumnsMap> {
58-
const reader = file.stream
59+
const reader = openStream(file)
5960
.pipeThrough(new DecompressionStream('gzip'))
6061
.pipeThrough(createUTF8Stream())
6162
.pipeThrough(new TextLineStream())
@@ -75,7 +76,7 @@ export async function loadTSVGZ(
7576
}
7677

7778
async function _loadTSV(file: BIDSFile, maxRows: number = -1): Promise<ColumnsMap> {
78-
const reader = file.stream
79+
const reader = openStream(file)
7980
.pipeThrough(createUTF8Stream())
8081
.pipeThrough(new TextLineStream())
8182
.getReader()

0 commit comments

Comments
 (0)