mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:20:43 +00:00
fix(infra): resolve opened file paths by identity
This commit is contained in:
@@ -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(() => {});
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user