fix: guard case-only rename recovery

This commit is contained in:
vorotamoroz
2026-07-16 20:48:12 +09:00
parent 869a893c19
commit 918d3b5547
355 changed files with 403 additions and 355 deletions
@@ -97,6 +97,23 @@ export class FSAPIVaultAdapter implements IVaultAdapter<FSAPIFile> {
};
}
private async deletePathIfExists(path: string): Promise<void> {
const parts = path.split("/").filter((part) => part !== "");
const name = parts.pop();
if (!name) return;
try {
let currentHandle = this.rootHandle;
for (const part of parts) {
currentHandle = await currentHandle.getDirectoryHandle(part);
}
await currentHandle.removeEntry(name);
} catch (error) {
if ((error as { name?: unknown })?.name === "NotFoundError") return;
throw error;
}
}
async rename(file: FSAPIFile, newPath: string): Promise<void> {
const source = await file.handle.getFile();
const data = await source.arrayBuffer();
@@ -120,6 +137,13 @@ export class FSAPIVaultAdapter implements IVaultAdapter<FSAPIFile> {
file.stat = renamedFile.stat;
file.handle = renamedFile.handle;
} catch (error) {
try {
await this.deletePathIfExists(newPath);
} catch (cleanupError) {
throw new Error(
`Could not rename ${oldPath} to ${newPath}, or remove the incomplete target. A temporary copy remains at ${temporaryPath}. Rename error: ${String(error)}. Cleanup error: ${String(cleanupError)}`
);
}
try {
const restoredFile = await this.createBinary(oldPath, data);
file.path = restoredFile.path;