diff --git a/packages/shim-deno/src/deno/stable/classes/FsFile.ts b/packages/shim-deno/src/deno/stable/classes/FsFile.ts index 2ff885d..9e34a12 100644 --- a/packages/shim-deno/src/deno/stable/classes/FsFile.ts +++ b/packages/shim-deno/src/deno/stable/classes/FsFile.ts @@ -12,6 +12,8 @@ import { read } from "../functions/read.js"; import { readSync } from "../functions/readSync.js"; import { write } from "../functions/write.js"; import { writeSync } from "../functions/writeSync.js"; +import { seek } from "../functions/seek.js"; +import { seekSync } from "../functions/seekSync.js"; (Symbol as any).dispose ??= Symbol("Symbol.dispose"); (Symbol as any).asyncDispose ??= Symbol("Symbol.asyncDispose"); @@ -51,12 +53,12 @@ export class FsFile implements Deno.FsFile { return readSync(this.rid, p); } - seek(_offset: number, _whence: Deno.SeekMode): Promise { - throw new Error("Method not implemented."); + async seek(offset: number, whence: Deno.SeekMode): Promise { + return await seek(this.rid, offset, whence); } - seekSync(_offset: number, _whence: Deno.SeekMode): number { - throw new Error("Method not implemented."); + seekSync(offset: number, whence: Deno.SeekMode): number { + return seekSync(this.rid, offset, whence); } async stat(): Promise { diff --git a/packages/shim-deno/src/deno/stable/functions/close.ts b/packages/shim-deno/src/deno/stable/functions/close.ts index b8576f6..c1fbf2d 100644 --- a/packages/shim-deno/src/deno/stable/functions/close.ts +++ b/packages/shim-deno/src/deno/stable/functions/close.ts @@ -2,4 +2,9 @@ import * as fs from "fs"; -export const close: typeof Deno.close = fs.closeSync; +import { positions } from "./seekSync.ts"; + +export const close: typeof Deno.close = function close(fd) { + fs.closeSync(fd); + positions.delete(fd); +}; diff --git a/packages/shim-deno/src/deno/stable/functions/open.ts b/packages/shim-deno/src/deno/stable/functions/open.ts index d3c92c0..def2e61 100644 --- a/packages/shim-deno/src/deno/stable/functions/open.ts +++ b/packages/shim-deno/src/deno/stable/functions/open.ts @@ -4,6 +4,7 @@ import { open as _open } from "fs"; import { promisify } from "util"; import { File } from "../classes/FsFile.js"; +import { positions } from "../functions/seekSync.js"; import { getFsFlag } from "../../internal/fs_flags.js"; import mapError from "../../internal/errorMap.js"; @@ -25,6 +26,7 @@ export const open: typeof Deno.open = async function open( }); try { const fd = await nodeOpen(path, flagMode, mode); + positions.set(fd, 0); return new File(fd); } catch (err) { throw mapError(err); diff --git a/packages/shim-deno/src/deno/stable/functions/openSync.ts b/packages/shim-deno/src/deno/stable/functions/openSync.ts index 1a3d091..f80fb80 100644 --- a/packages/shim-deno/src/deno/stable/functions/openSync.ts +++ b/packages/shim-deno/src/deno/stable/functions/openSync.ts @@ -3,6 +3,7 @@ import { openSync as nodeOpenSync } from "fs"; import { File } from "../classes/FsFile.js"; +import { positions } from "../functions/seekSync.js"; import { getFsFlag } from "../../internal/fs_flags.js"; import mapError from "../../internal/errorMap.js"; @@ -22,6 +23,7 @@ export const openSync: typeof Deno.openSync = function openSync( }); try { const fd = nodeOpenSync(path, flagMode, mode); + positions.set(fd, 0); return new File(fd); } catch (err) { throw mapError(err); diff --git a/packages/shim-deno/src/deno/stable/functions/read.ts b/packages/shim-deno/src/deno/stable/functions/read.ts index f638fe8..7aad158 100644 --- a/packages/shim-deno/src/deno/stable/functions/read.ts +++ b/packages/shim-deno/src/deno/stable/functions/read.ts @@ -3,6 +3,8 @@ import { promisify } from "util"; import { read as nodeRead } from "fs"; +import { positions } from "./seekSync.js"; + const _read = promisify(nodeRead); export const read: typeof Deno.read = async function read(rid, buffer) { @@ -13,7 +15,11 @@ export const read: typeof Deno.read = async function read(rid, buffer) { return 0; } - const { bytesRead } = await _read(rid, buffer, 0, buffer.length, null); + const position = positions.get(rid) ?? null; + const { bytesRead } = await _read(rid, buffer, 0, buffer.length, position); + if (position !== null) { + positions.set(rid, position + bytesRead); + } // node returns 0 on EOF, Deno expects null return bytesRead === 0 ? null : bytesRead; }; diff --git a/packages/shim-deno/src/deno/stable/functions/readSync.ts b/packages/shim-deno/src/deno/stable/functions/readSync.ts index a1eb820..764dd8b 100644 --- a/packages/shim-deno/src/deno/stable/functions/readSync.ts +++ b/packages/shim-deno/src/deno/stable/functions/readSync.ts @@ -2,8 +2,14 @@ import * as fs from "fs"; +import { positions } from "./seekSync.js"; + export const readSync: typeof Deno.readSync = (fd, buffer) => { - const bytesRead = fs.readSync(fd, buffer); + const position = positions.get(fd) ?? null; + const bytesRead = fs.readSync(fd, buffer, { position }); + if (position !== null) { + positions.set(fd, position + bytesRead); + } // node returns 0 on EOF, Deno expects null return bytesRead === 0 ? null : bytesRead; }; diff --git a/packages/shim-deno/src/deno/stable/functions/seek.ts b/packages/shim-deno/src/deno/stable/functions/seek.ts new file mode 100644 index 0000000..a27a2fe --- /dev/null +++ b/packages/shim-deno/src/deno/stable/functions/seek.ts @@ -0,0 +1,30 @@ +/// + +import { fstat } from "fs"; +import { promisify } from "util"; + +import { positions } from "./seekSync.js"; + +const nodeFstat = promisify(fstat); + +export const seek: typeof Deno.seek = async function (fd, offset, whence) { + let p = positions.get(fd); + if (p == null) { + throw new Error("Bad file descriptor"); + } + switch (whence) { + case Deno.SeekMode.Start: + p = Number(offset); + break; + case Deno.SeekMode.Current: + p += Number(offset); + break; + case Deno.SeekMode.End: + p = (await nodeFstat(fd)).size + Number(offset); + break; + default: + throw new TypeError(`Invalid seek mode: ${whence}`); + } + positions.set(fd, p!); + return p!; +}; diff --git a/packages/shim-deno/src/deno/stable/functions/seekSync.ts b/packages/shim-deno/src/deno/stable/functions/seekSync.ts new file mode 100644 index 0000000..277ff7b --- /dev/null +++ b/packages/shim-deno/src/deno/stable/functions/seekSync.ts @@ -0,0 +1,27 @@ +/// + +import { fstatSync } from "fs"; + +export const positions = new Map(); + +export const seekSync: typeof Deno.seekSync = function (fd, offset, whence) { + let p = positions.get(fd); + if (p == null) { + throw new Error("Bad file descriptor"); + } + switch (whence) { + case Deno.SeekMode.Start: + p = Number(offset); + break; + case Deno.SeekMode.Current: + p += Number(offset); + break; + case Deno.SeekMode.End: + p = fstatSync(fd).size + Number(offset); + break; + default: + throw new TypeError(`Invalid seek mode: ${whence}`); + } + positions.set(fd, p!); + return p!; +}; diff --git a/packages/shim-deno/tools/run_tests.mjs b/packages/shim-deno/tools/run_tests.mjs index 89c9403..0085f8c 100644 --- a/packages/shim-deno/tools/run_tests.mjs +++ b/packages/shim-deno/tools/run_tests.mjs @@ -51,14 +51,6 @@ const testsToSkip = new Set([ "openNotFound", // includes full path in node.js "openModeWriteRead", // not implemented "readFileIsDirectoryErrorCode", // todo(https://github.com/denoland/deno/issues/18629): re-enable - "seekStart", // not implemented - "seekSyncStart", // not implemented - "seekCurrent", // not implemented - "seekStartBigInt", // not implemented - "seekSyncCurrent", // not implemented - "seekEnd", // not implemented - "seekSyncEnd", // not implemented - "seekMode", // not implemented // mkdir_test "mkdirMode", // depends on Deno.umask