mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-16 13:15:36 +02:00
fix(fs): retry bounded Windows atomic rename sharing failures
This commit is contained in:
@@ -4,6 +4,30 @@ const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function renameAtomic(tempPath, resolvedPath, options) {
|
||||
const deadline = performance.now() + 750;
|
||||
let attempts = 0;
|
||||
let sleeper;
|
||||
while (true) {
|
||||
// A sharing violation may outlast the original validation. Recheck both
|
||||
// the parent and destination ownership before every publication attempt.
|
||||
if (options.validateParent) options.validateParent();
|
||||
if (options.beforeRename) options.beforeRename();
|
||||
try {
|
||||
fs.renameSync(tempPath, resolvedPath);
|
||||
return;
|
||||
} catch (error) {
|
||||
attempts++;
|
||||
const remaining = deadline - performance.now();
|
||||
if (process.platform !== 'win32'
|
||||
|| !['EPERM', 'EACCES', 'EBUSY'].includes(error.code)
|
||||
|| attempts >= 21 || remaining <= 0) throw error;
|
||||
sleeper ||= new Int32Array(new SharedArrayBuffer(4));
|
||||
Atomics.wait(sleeper, 0, 0, Math.min(25, remaining));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeFileAtomic(filePath, content, options = {}) {
|
||||
const resolvedPath = path.resolve(filePath);
|
||||
const parentDir = path.dirname(resolvedPath);
|
||||
@@ -25,9 +49,7 @@ function writeFileAtomic(filePath, content, options = {}) {
|
||||
fs.fsyncSync(descriptor);
|
||||
fs.closeSync(descriptor);
|
||||
descriptor = undefined;
|
||||
if (options.validateParent) options.validateParent();
|
||||
if (options.beforeRename) options.beforeRename();
|
||||
fs.renameSync(tempPath, resolvedPath);
|
||||
renameAtomic(tempPath, resolvedPath, options);
|
||||
} catch (error) {
|
||||
if (descriptor !== undefined) {
|
||||
fs.closeSync(descriptor);
|
||||
|
||||
Reference in New Issue
Block a user