mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-11 10:29:39 +08:00
Reject directory replacement after temporary file creation or staging, preserve unrelated files during cleanup, and retry settings edits observed before the final rename. Add three regression tests for the review findings.
53 lines
1.6 KiB
JavaScript
53 lines
1.6 KiB
JavaScript
'use strict';
|
|
|
|
const crypto = require('crypto');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
function writeFileAtomic(filePath, content, options = {}) {
|
|
const resolvedPath = path.resolve(filePath);
|
|
const parentDir = path.dirname(resolvedPath);
|
|
const tempPath = path.join(
|
|
parentDir,
|
|
`.${path.basename(resolvedPath)}.${process.pid}.${crypto.randomBytes(8).toString('hex')}.tmp`
|
|
);
|
|
const mode = options.mode || 0o600;
|
|
|
|
if (options.validateParent) options.validateParent();
|
|
fs.mkdirSync(parentDir, { recursive: true });
|
|
|
|
let descriptor;
|
|
try {
|
|
if (options.validateParent) options.validateParent();
|
|
descriptor = fs.openSync(tempPath, 'wx', mode);
|
|
if (options.validateParent) options.validateParent();
|
|
fs.writeFileSync(descriptor, content, { encoding: options.encoding || 'utf8' });
|
|
fs.fsyncSync(descriptor);
|
|
fs.closeSync(descriptor);
|
|
descriptor = undefined;
|
|
if (options.validateParent) options.validateParent();
|
|
if (options.beforeRename) options.beforeRename();
|
|
fs.renameSync(tempPath, resolvedPath);
|
|
} catch (error) {
|
|
if (descriptor !== undefined) {
|
|
fs.closeSync(descriptor);
|
|
}
|
|
// If the parent was replaced, this pathname may now name somebody else's
|
|
// file. Leave the private staging file in its original directory.
|
|
let parentUnchanged = true;
|
|
try {
|
|
if (options.validateParent) options.validateParent();
|
|
} catch (_error) {
|
|
parentUnchanged = false;
|
|
}
|
|
if (parentUnchanged) fs.rmSync(tempPath, { force: true });
|
|
throw error;
|
|
}
|
|
|
|
return resolvedPath;
|
|
}
|
|
|
|
module.exports = {
|
|
writeFileAtomic,
|
|
};
|