mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 11:08:37 +00:00
fix(windows): skip unreliable dev comparison in fs-safe openVerifiedLocalFile
On Windows, device IDs (dev) returned by handle.stat() and fs.lstat() may differ even for the same file, causing false-positive 'path-mismatch' errors when reading local media files. This fix introduces a statsMatch() helper that: - Always compares inode (ino) values - Skips device ID (dev) comparison on Windows where it's unreliable - Maintains full comparison on Unix platforms Fixes #25699
This commit is contained in:
committed by
Peter Steinberger
parent
3c95f89662
commit
7455ceecf8
@@ -40,6 +40,23 @@ const OPEN_READ_FLAGS = fsConstants.O_RDONLY | (SUPPORTS_NOFOLLOW ? fsConstants.
|
|||||||
|
|
||||||
const ensureTrailingSep = (value: string) => (value.endsWith(path.sep) ? value : value + path.sep);
|
const ensureTrailingSep = (value: string) => (value.endsWith(path.sep) ? value : value + path.sep);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare file stats for identity verification.
|
||||||
|
* On Windows, device IDs (dev) are unreliable and may differ between
|
||||||
|
* handle.stat() and fs.lstat() for the same file. We skip dev comparison
|
||||||
|
* on Windows and rely solely on inode (ino) matching.
|
||||||
|
*/
|
||||||
|
function statsMatch(stat1: Stats, stat2: Stats): boolean {
|
||||||
|
if (stat1.ino !== stat2.ino) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// On Windows, dev values are unreliable across different stat sources
|
||||||
|
if (process.platform !== "win32" && stat1.dev !== stat2.dev) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
async function openVerifiedLocalFile(filePath: string): Promise<SafeOpenResult> {
|
async function openVerifiedLocalFile(filePath: string): Promise<SafeOpenResult> {
|
||||||
let handle: FileHandle;
|
let handle: FileHandle;
|
||||||
try {
|
try {
|
||||||
@@ -62,13 +79,13 @@ async function openVerifiedLocalFile(filePath: string): Promise<SafeOpenResult>
|
|||||||
if (!stat.isFile()) {
|
if (!stat.isFile()) {
|
||||||
throw new SafeOpenError("not-file", "not a file");
|
throw new SafeOpenError("not-file", "not a file");
|
||||||
}
|
}
|
||||||
if (stat.ino !== lstat.ino || stat.dev !== lstat.dev) {
|
if (!statsMatch(stat, lstat)) {
|
||||||
throw new SafeOpenError("path-mismatch", "path changed during read");
|
throw new SafeOpenError("path-mismatch", "path changed during read");
|
||||||
}
|
}
|
||||||
|
|
||||||
const realPath = await fs.realpath(filePath);
|
const realPath = await fs.realpath(filePath);
|
||||||
const realStat = await fs.stat(realPath);
|
const realStat = await fs.stat(realPath);
|
||||||
if (stat.ino !== realStat.ino || stat.dev !== realStat.dev) {
|
if (!statsMatch(stat, realStat)) {
|
||||||
throw new SafeOpenError("path-mismatch", "path mismatch");
|
throw new SafeOpenError("path-mismatch", "path mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user