mirror of https://github.com/garrytan/gstack.git
fix(browse): add random suffix to atomic-write temp filenames
writeSecureFileAtomic embedded only the pid in the staging filename, so two writes from the same process racing the same destination (the periodic checkpoint firing while a debounced checkpoint runs, both serialized but sharing a pid) could collide on the temp path and clobber each other's in-flight staging file before rename. Append 4 random bytes so every write gets a unique staging path. The destination still needs its own lock; this only guarantees each individual write is atomic. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
fd976e9b66
commit
53c2750cf1
|
|
@ -37,6 +37,7 @@
|
|||
*/
|
||||
|
||||
import { execFileSync } from 'child_process';
|
||||
import { randomBytes } from 'crypto';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
|
|
@ -139,16 +140,16 @@ export function writeSecureFile(
|
|||
*
|
||||
* Same-directory is load-bearing: a temp file on another filesystem would make
|
||||
* `rename` fall back to copy+unlink, which is NOT atomic. The temp name embeds
|
||||
* the pid so two daemons racing the same destination don't clobber each other's
|
||||
* temp file before their own rename (the destination itself still needs a lock
|
||||
* — this only guarantees each write is individually atomic).
|
||||
* the pid plus random bytes so racing writes never share a staging path (the
|
||||
* destination itself still needs a lock — this only guarantees each write is
|
||||
* individually atomic).
|
||||
*/
|
||||
export function writeSecureFileAtomic(
|
||||
filePath: string,
|
||||
data: string | NodeJS.ArrayBufferView,
|
||||
): void {
|
||||
const dir = path.dirname(filePath);
|
||||
const tmp = path.join(dir, `.${path.basename(filePath)}.${process.pid}.tmp`);
|
||||
const tmp = path.join(dir, `.${path.basename(filePath)}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`);
|
||||
let fd: number | null = null;
|
||||
try {
|
||||
fd = fs.openSync(tmp, 'w', 0o600);
|
||||
|
|
|
|||
Loading…
Reference in New Issue