Skip to content

Commit a7f6a86

Browse files
committed
vfs: reject operations on closed ZipProvider handles
1 parent 9aa70ae commit a7f6a86

2 files changed

Lines changed: 38 additions & 3 deletions

File tree

lib/internal/vfs/providers/ziparchive.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const {
2323
const { VirtualProvider } = require('internal/vfs/provider');
2424
const { VirtualFileHandle } = require('internal/vfs/file_handle');
2525
const {
26+
createEBADF,
2627
createEEXIST,
2728
createEISDIR,
2829
createEINVAL,
@@ -136,10 +137,15 @@ class ZipFileHandle extends VirtualFileHandle {
136137
if (isAppend(flags)) this.position = this.#size;
137138
}
138139

139-
#checkReadable() {
140+
#checkClosed(syscall) {
141+
if (this.closed) throw createEBADF(syscall);
142+
}
143+
#checkReadable(syscall = 'read') {
144+
this.#checkClosed(syscall);
140145
if (!isReadableFlag(this.flags)) throw createEISDIR('read', this.path);
141146
}
142-
#checkWritable() {
147+
#checkWritable(syscall = 'write') {
148+
this.#checkClosed(syscall);
143149
if (!isWritableFlag(this.flags)) throw createEISDIR('write', this.path);
144150
}
145151
#ensureCapacity(size) {
@@ -223,6 +229,7 @@ class ZipFileHandle extends VirtualFileHandle {
223229
}
224230

225231
#doStat() {
232+
this.#checkClosed('fstat');
226233
return createFileStats(this.#size, { mode: this.mode });
227234
}
228235
async stat(options) {
@@ -233,7 +240,7 @@ class ZipFileHandle extends VirtualFileHandle {
233240
}
234241

235242
#doTruncate(len) {
236-
this.#checkWritable();
243+
this.#checkWritable('ftruncate');
237244
this.#ensureCapacity(len);
238245
this.#size = len;
239246
this.#dirty = true;
@@ -246,12 +253,14 @@ class ZipFileHandle extends VirtualFileHandle {
246253
}
247254

248255
async close() {
256+
if (this.closed) return;
249257
if (this.#dirty && isWritableFlag(this.flags)) {
250258
await this.#source.add(this.#name, this.#buffer.subarray(0, this.#size), { mode: this.mode });
251259
}
252260
await super.close();
253261
}
254262
closeSync() {
263+
if (this.closed) return;
255264
if (this.#dirty && isWritableFlag(this.flags)) {
256265
this.#source.addSync(this.#name, this.#buffer.subarray(0, this.#size), { mode: this.mode });
257266
}

test/parallel/test-vfs-zip-provider-handle.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,32 @@ function buildArchiveSync(entries, comment) {
443443
await zip.close();
444444
})().then(common.mustCall());
445445

446+
// --- operations on closed handles fail with EBADF -------------------------
447+
(async () => {
448+
const archive = await buildArchive([await zlib.ZipEntry.create('a.txt', Buffer.from('x'))]);
449+
const provider = new vfs.ZipProvider(new zlib.ZipBuffer(archive));
450+
451+
const handle = await provider.open('/a.txt', 'r+');
452+
await handle.close();
453+
await assert.rejects(handle.read(Buffer.alloc(1), 0, 1, 0), { code: 'EBADF' });
454+
await assert.rejects(handle.write(Buffer.from('x'), 0, 1, 0), { code: 'EBADF' });
455+
await assert.rejects(handle.readFile(), { code: 'EBADF' });
456+
await assert.rejects(handle.writeFile('x'), { code: 'EBADF' });
457+
await assert.rejects(handle.stat(), { code: 'EBADF' });
458+
await assert.rejects(handle.truncate(), { code: 'EBADF' });
459+
await handle.close(); // Closing an already-closed handle is a no-op.
460+
461+
const syncHandle = provider.openSync('/a.txt', 'r+');
462+
syncHandle.closeSync();
463+
assert.throws(() => syncHandle.readSync(Buffer.alloc(1), 0, 1, 0), { code: 'EBADF' });
464+
assert.throws(() => syncHandle.writeSync(Buffer.from('x'), 0, 1, 0), { code: 'EBADF' });
465+
assert.throws(() => syncHandle.readFileSync(), { code: 'EBADF' });
466+
assert.throws(() => syncHandle.writeFileSync('x'), { code: 'EBADF' });
467+
assert.throws(() => syncHandle.statSync(), { code: 'EBADF' });
468+
assert.throws(() => syncHandle.truncateSync(), { code: 'EBADF' });
469+
syncHandle.closeSync();
470+
})().then(common.mustCall());
471+
446472
// --- numeric open flags are normalized like node:fs (O_* constants) --------
447473
(async () => {
448474
const { O_RDONLY, O_WRONLY, O_CREAT, O_TRUNC } = fs.constants;

0 commit comments

Comments
 (0)