fix(infra): resolve opened file paths by identity

This commit is contained in:
Peter Steinberger
2026-04-14 22:48:43 +01:00
parent c6c222ba84
commit e7dfc88bfa
2 changed files with 56 additions and 3 deletions

View File

@@ -172,7 +172,7 @@ describe("fs-safe", () => {
const resolved = await resolveOpenedFileRealPathForHandle(handle, originalPath);
expect(resolved).toBe(movedPath);
await expect(fs.realpath(movedPath)).resolves.toBe(resolved);
await expect(handle.readFile({ encoding: "utf8" })).resolves.toBe("inside");
} finally {
await handle.close().catch(() => {});

View File

@@ -417,6 +417,7 @@ export async function resolveOpenedFileRealPathForHandle(
handle: FileHandle,
ioPath: string,
): Promise<string> {
const handleStat = await handle.stat();
const fdCandidates =
process.platform === "linux"
? [`/proc/self/fd/${handle.fd}`, `/dev/fd/${handle.fd}`]
@@ -425,22 +426,74 @@ export async function resolveOpenedFileRealPathForHandle(
: [`/dev/fd/${handle.fd}`];
for (const fdPath of fdCandidates) {
try {
return await fs.realpath(fdPath);
const fdRealPath = await fs.realpath(fdPath);
const fdRealStat = await fs.stat(fdRealPath);
if (sameFileIdentity(handleStat, fdRealStat)) {
return fdRealPath;
}
} catch {
// try next fd path
}
}
try {
return await fs.realpath(ioPath);
const ioRealPath = await fs.realpath(ioPath);
const ioRealStat = await fs.stat(ioRealPath);
if (sameFileIdentity(handleStat, ioRealStat)) {
return ioRealPath;
}
} catch (err) {
if (!isNotFoundPathError(err)) {
throw err;
}
}
const parentResolved = await resolveOpenedFileRealPathFromParent(handleStat, ioPath);
if (parentResolved) {
return parentResolved;
}
throw new SafeOpenError("path-mismatch", "unable to resolve opened file path");
}
async function resolveOpenedFileRealPathFromParent(
handleStat: Stats,
ioPath: string,
): Promise<string | null> {
let parentReal: string;
try {
parentReal = await fs.realpath(path.dirname(ioPath));
} catch (err) {
if (isNotFoundPathError(err)) {
return null;
}
throw err;
}
let entries: string[];
try {
entries = await fs.readdir(parentReal);
} catch (err) {
if (isNotFoundPathError(err)) {
return null;
}
throw err;
}
for (const entry of entries.toSorted()) {
const candidatePath = path.join(parentReal, entry);
try {
const candidateStat = await fs.lstat(candidatePath);
if (candidateStat.isFile() && sameFileIdentity(handleStat, candidateStat)) {
return await fs.realpath(candidatePath);
}
} catch (err) {
if (!isNotFoundPathError(err)) {
throw err;
}
}
}
return null;
}
export async function openWritableFileWithinRoot(params: {
rootDir: string;
relativePath: string;