From 32d0ab6b96d8a43cb9720557952291b3b120ba8b Mon Sep 17 00:00:00 2001 From: Michael Ramos Date: Tue, 22 Sep 2026 18:39:37 -0700 Subject: [PATCH] Skip the directory durability barrier on Windows Windows cannot open a directory as a file handle, so syncDirectory() threw EPERM on every upload PUT and blob installation, making publication impossible there (#42). A directory fsync is a POSIX barrier with no Windows equivalent; on win32 the atomic rename is the strongest available guarantee, so the barrier is now skipped there explicitly instead of failing the operation. POSIX platforms are unchanged. Claude-Session: https://claude.ai/code/session_01EcbEctwH1oDTrYhqHe6n9g --- src/storage/verified-file.ts | 16 +++++++- .../verified-file-directory-sync.test.ts | 39 +++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 tests/storage/verified-file-directory-sync.test.ts diff --git a/src/storage/verified-file.ts b/src/storage/verified-file.ts index 38332f5f..38407abd 100644 --- a/src/storage/verified-file.ts +++ b/src/storage/verified-file.ts @@ -140,8 +140,20 @@ export function readableFileRange( }); } -/** Syncs a directory entry after an atomic installation or replacement. */ -export async function syncDirectory(directory: string): Promise { +/** + * Syncs a directory entry after an atomic installation or replacement. + * + * A directory fsync is a POSIX durability barrier. Windows cannot open a + * directory as a file handle, so the open or sync call throws EPERM there and + * no equivalent barrier exists. On Windows the rename itself is the strongest + * available guarantee, so the sync is skipped rather than failing every + * publication. + */ +export async function syncDirectory( + directory: string, + platform: NodeJS.Platform = process.platform, +): Promise { + if (platform === "win32") return; const handle = await open(directory, "r"); try { await handle.sync(); diff --git a/tests/storage/verified-file-directory-sync.test.ts b/tests/storage/verified-file-directory-sync.test.ts new file mode 100644 index 00000000..9264abe3 --- /dev/null +++ b/tests/storage/verified-file-directory-sync.test.ts @@ -0,0 +1,39 @@ +import {mkdtemp, rm} from "node:fs/promises"; +import {tmpdir} from "node:os"; +import {join} from "node:path"; + +import {afterEach, beforeEach, describe, expect, it} from "vitest"; + +import {syncDirectory} from "../../src/storage/verified-file.js"; + +describe("syncDirectory platform behavior", () => { + let directory = ""; + + beforeEach(async () => { + directory = await mkdtemp(join(tmpdir(), "artifact-server-sync-")); + }); + + afterEach(async () => { + await rm(directory, {force: true, recursive: true}); + }); + + it("syncs a real directory on POSIX platforms", async () => { + await expect(syncDirectory(directory, "linux")).resolves.toBeUndefined(); + }); + + it("skips the directory barrier on Windows instead of failing publication", async () => { + await expect(syncDirectory(directory, "win32")).resolves.toBeUndefined(); + }); + + it("still reports a missing directory on POSIX platforms", async () => { + await expect( + syncDirectory(join(directory, "absent"), "linux"), + ).rejects.toThrowError(/ENOENT/u); + }); + + it("does not touch the filesystem on Windows", async () => { + await expect( + syncDirectory(join(directory, "absent"), "win32"), + ).resolves.toBeUndefined(); + }); +});