Files
oh-my-opencode/src/shared/write-file-atomically.ts
T
YeonGyu-Kim 7735b2abd5 fix(shared): tolerate EPERM during fsync in writeFileAtomically
Replaces fsyncSync(tempFileDescriptor) with tolerantFsyncSync, allowing
EPERM/EACCES/ENOTSUP/EINVAL during fsync while still propagating real
errors. Adds an optional deps.fsyncSync injection point used solely by
the new EPERM tolerance regression tests.

Without this fix, plugin startup itself can fail on synced folders
because writeFileAtomically is used by config migrations and posthog
activity state — the same EPERM-on-fsync failure pattern reported for
team_create.
2026-05-08 14:09:17 +09:00

42 lines
1005 B
TypeScript

import {
closeSync,
type fsyncSync as FsyncSync,
openSync,
renameSync,
unlinkSync,
writeFileSync,
} from "node:fs"
import { tolerantFsyncSync } from "./tolerant-fsync"
export function writeFileAtomically(
filePath: string,
content: string,
deps: { fsyncSync?: typeof FsyncSync } = {},
): void {
const tempPath = `${filePath}.tmp`
writeFileSync(tempPath, content, "utf-8")
const tempFileDescriptor = openSync(tempPath, "r")
try {
tolerantFsyncSync(tempFileDescriptor, `writeFileAtomically:${filePath}`, deps.fsyncSync)
} finally {
closeSync(tempFileDescriptor)
}
try {
renameSync(tempPath, filePath)
} catch (error) {
const isWindows = process.platform === "win32"
const isPermissionError =
error instanceof Error &&
(error.message.includes("EPERM") || error.message.includes("EACCES"))
if (isWindows && isPermissionError) {
unlinkSync(filePath)
renameSync(tempPath, filePath)
} else {
throw error
}
}
}