Skip to content

Commit c4bee19

Browse files
committed
cleanup logic
1 parent 9cf9e97 commit c4bee19

File tree

5 files changed

+74
-2
lines changed

5 files changed

+74
-2
lines changed

ext/node/polyfills/fs.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ import {
111111
} from "ext:core/ops";
112112
import {
113113
getRid,
114+
hasFd,
114115
registerFd,
115116
unregisterFd,
116117
} from "ext:deno_node/internal/fs/fd_map.ts";
@@ -2215,7 +2216,11 @@ async function _writeFileGetOpenInfo(
22152216
flag: string = "w",
22162217
): Promise<{ rid: number; openedFd: number | null }> {
22172218
if (typeof pathOrRid === "number") {
2218-
return { rid: getRid(pathOrRid), openedFd: null };
2219+
// If fd is not yet mapped, getRid will dup it (creating a new rid).
2220+
// Track that so the caller can clean up the dup'd rid.
2221+
const wasMapped = hasFd(pathOrRid);
2222+
const rid = getRid(pathOrRid);
2223+
return { rid, openedFd: wasMapped ? null : pathOrRid };
22192224
}
22202225
try {
22212226
const { rid, fd } = await op_node_open(
@@ -2238,7 +2243,11 @@ function _writeFileGetOpenInfoSync(
22382243
flag: string = "w",
22392244
): { rid: number; openedFd: number | null } {
22402245
if (typeof pathOrRid === "number") {
2241-
return { rid: getRid(pathOrRid), openedFd: null };
2246+
// If fd is not yet mapped, getRid will dup it (creating a new rid).
2247+
// Track that so the caller can clean up the dup'd rid.
2248+
const wasMapped = hasFd(pathOrRid);
2249+
const rid = getRid(pathOrRid);
2250+
return { rid, openedFd: wasMapped ? null : pathOrRid };
22422251
}
22432252
try {
22442253
const { rid, fd } = op_node_open_sync(

ext/node/polyfills/internal/fs/fd_map.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ export function getRid(fd: number): number {
6060
return fd;
6161
}
6262

63+
export function hasFd(fd: number): boolean {
64+
return MapPrototypeGet(fdMap, fd) !== undefined;
65+
}
66+
6367
export function unregisterFd(fd: number): void {
6468
MapPrototypeDelete(fdMap, fd);
6569
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"args": "run --allow-read --allow-write main.ts",
3+
"output": "main.out"
4+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
sync: sync write via fdsync overwrite
2+
async: async write via fdasync overwrite
3+
path: via path
4+
multi: write 0write 1write 2write 3write 4write 5write 6write 7write 8write 9
5+
ok
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { closeSync, openSync, readFileSync, writeFileSync } from "node:fs";
2+
import { writeFile } from "node:fs/promises";
3+
4+
const tmp = Deno.makeTempDirSync();
5+
6+
// Test 1: writeFileSync with a numeric fd cleans up properly
7+
{
8+
const path = `${tmp}/sync.txt`;
9+
Deno.writeTextFileSync(path, "");
10+
const fd = openSync(path, "w");
11+
writeFileSync(fd, "sync write via fd");
12+
// fd should still be usable after writeFileSync (not closed)
13+
writeFileSync(fd, "sync overwrite");
14+
closeSync(fd);
15+
console.log("sync:", readFileSync(path, "utf8"));
16+
}
17+
18+
// Test 2: writeFile (async) with a numeric fd cleans up properly
19+
{
20+
const path = `${tmp}/async.txt`;
21+
Deno.writeTextFileSync(path, "");
22+
const fd = openSync(path, "w");
23+
await writeFile(fd, "async write via fd");
24+
// fd should still be usable after writeFile
25+
await writeFile(fd, "async overwrite");
26+
closeSync(fd);
27+
console.log("async:", readFileSync(path, "utf8"));
28+
}
29+
30+
// Test 3: writeFileSync with a path (string) still works
31+
{
32+
const path = `${tmp}/path.txt`;
33+
writeFileSync(path, "via path");
34+
console.log("path:", readFileSync(path, "utf8"));
35+
}
36+
37+
// Test 4: multiple writeFileSync calls with same fd don't leak
38+
{
39+
const path = `${tmp}/multi.txt`;
40+
Deno.writeTextFileSync(path, "");
41+
const fd = openSync(path, "w");
42+
for (let i = 0; i < 10; i++) {
43+
writeFileSync(fd, `write ${i}`);
44+
}
45+
closeSync(fd);
46+
console.log("multi:", readFileSync(path, "utf8"));
47+
}
48+
49+
Deno.removeSync(tmp, { recursive: true });
50+
console.log("ok");

0 commit comments

Comments
 (0)