2026-04-12 02:28:05 +09:00
|
|
|
import { closeSync, fsyncSync, openSync, renameSync, unlinkSync, writeFileSync } from "node:fs"
|
2026-04-04 14:33:52 +09:00
|
|
|
|
|
|
|
|
export function writeFileAtomically(filePath: string, content: string): void {
|
2026-04-12 02:28:05 +09:00
|
|
|
const tempPath = `${filePath}.tmp`
|
|
|
|
|
writeFileSync(tempPath, content, "utf-8")
|
2026-04-04 14:33:52 +09:00
|
|
|
const tempFileDescriptor = openSync(tempPath, "r")
|
|
|
|
|
try {
|
|
|
|
|
fsyncSync(tempFileDescriptor)
|
|
|
|
|
} finally {
|
|
|
|
|
closeSync(tempFileDescriptor)
|
|
|
|
|
}
|
2026-04-12 02:28:05 +09:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-04 14:33:52 +09:00
|
|
|
}
|