Files
orca/src/main/rolling-file-backup.ts
T
mirror 34fa2cd5ca
Skill update round trip / roundtrip (false, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, latest) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
source snapshot 2026-09-02
2026-09-02 02:03:16 +08:00

28 lines
1.0 KiB
TypeScript

import { randomUUID } from 'node:crypto'
import { lstatSync, rmSync } from 'node:fs'
import { copyFileWithWindowsRetry, renameFileWithWindowsRetry } from './codex-accounts/fs-utils'
export function writeRollingFileBackup(sourcePath: string, backupPath: string): void {
try {
if (lstatSync(backupPath).isSymbolicLink()) {
// Why: copyFile follows a destination symlink and can corrupt an
// unrelated dotfiles target before the primary atomic write begins.
throw new Error(`Refusing to overwrite symlinked backup: ${backupPath}`)
}
} catch (error) {
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
throw error
}
}
const tempPath = `${backupPath}.${process.pid}.${randomUUID()}.tmp`
try {
// Why: replacing the backup from a fresh inode cannot mutate another file
// through a hard link, and a failed rename leaves the prior backup intact.
copyFileWithWindowsRetry(sourcePath, tempPath)
renameFileWithWindowsRetry(tempPath, backupPath)
} finally {
rmSync(tempPath, { force: true })
}
}