mirror of
https://github.com/morluto/rea.git
synced 2026-11-14 02:32:54 +00:00
fix(reference): preserve raw symlink target identity
Read link targets as bytes before strict UTF-8 admission. Retain malformed targets as unreadable with source hex; preserve literal replacement characters and valid BOM-prefixed targets. Fixes #6765
This commit is contained in:
1 parent
51e5938776
commit
7ba05210fe
3 files changed
+81
-4
No files matched your search
@@ -377,9 +377,12 @@ const readSymlinkTarget = async (
|
||||
absolute: string,
|
||||
path: string,
|
||||
): Promise<ReferenceSourceEntry> => {
|
||||
let rawTarget: string;
|
||||
let rawTarget: Buffer;
|
||||
try {
|
||||
rawTarget = await readlink(absolute);
|
||||
// Keep the symlink's source bytes until UTF-8 validity is known. The
|
||||
// default string encoding can alias an invalid target with a real U+FFFD
|
||||
// sibling during the subsequent path lookup.
|
||||
rawTarget = await readlink(absolute, { encoding: "buffer" });
|
||||
} catch (cause: unknown) {
|
||||
// POSIX readlink reports EINVAL when the observed link became a non-link.
|
||||
// Keep this classification at the syscall, rather than hiding EINVAL from
|
||||
@@ -388,7 +391,21 @@ const readSymlinkTarget = async (
|
||||
return changedSymlink(path);
|
||||
throw cause;
|
||||
}
|
||||
const lexicalTarget = resolve(dirname(absolute), rawTarget);
|
||||
let target: string;
|
||||
try {
|
||||
target = new TextDecoder("utf-8", {
|
||||
fatal: true,
|
||||
ignoreBOM: true,
|
||||
}).decode(rawTarget);
|
||||
} catch {
|
||||
return entryFailure(
|
||||
path,
|
||||
"symlink",
|
||||
"unsupported",
|
||||
`Symlink target is not valid UTF-8 (raw target bytes: ${rawTarget.toString("hex")})`,
|
||||
);
|
||||
}
|
||||
const lexicalTarget = resolve(dirname(absolute), target);
|
||||
if (!isPathWithinRoot(root, lexicalTarget))
|
||||
return {
|
||||
status: "read",
|
||||
|
||||
Reference in new issue
Block a user