Summary
Under the fs-routing setup (fs-routing-clamp --prefix /tmp %{ imfs-grate %}), ~33 coreutils
tests fail at their first ln -s with /bin/ln: creating symbolic link 'X': File exists — even
though the symlink is being created in a freshly mktemp -d directory. The same tests pass on
the bare wasm runtime.
Reproduction
./run_default_tests.sh --grate fs-routing-clamp ls/dangle
+ bin/mktemp -d --tmp=/tmp cu-dangle.XXXXXXXXXX
++ t_=/tmp/cu-dangle.lLVWZhdjsm
++ cd /tmp/cu-dangle.lLVWZhdjsm
+ ln -s no-such-file dangle
/bin/ln: creating symbolic link `dangle': File exists
+ framework_failure
Root cause
imfs-grate/src/main.rs registers handlers for open, mkdir, unlink, link, rename, chdir, getcwd,
stat, etc., but not for SYS_SYMLINK or SYS_SYMLINKAT (GNU ln -s uses symlinkat).
Because symlinkat is unregistered, it falls through the imfs grate to RawPOSIX, which:
- operates on the real host filesystem, not the in-memory FS, and
- resolves the relative path dangle against RawPOSIX's stale CWD (the test's cd into the mktemp
dir was consumed by imfs's chdir_handler and never reached RawPOSIX).
So the very first test that runs symlink(target, "dangle") creates /dangle on the host FS; it
persists, and every subsequent test that creates a symlink of the same name fails with EEXIST.
The imfs-side mktemp dir and the host-side symlink live in two disjoint namespaces.
Affected tests (~33)
chmod/thru-dangling, chown/deref, cp/cp-HL, cp/deref-slink, cp/link-no-deref, cp/no-deref-link1,
cp/no-deref-link2, cp/no-deref-link3, cp/r-vs-symlink, cp/same-file, cp/slink-2-slink,
cp/symlink-slash, cp/thru-dangling, cp/abuse, cp/cp-deref, du/deref, du/deref-args, du/no-deref,
du/trailing-slash, ls/dangle, ls/file-type, ls/follow-slink, ls/inode, ls/no-arg,
ls/symlink-slash, mkdir/p-thru-slink, mv/into-self-4, ln/sf-1, ln/hard-to-sym, ln/misc,
ln/target-1, misc/stat-slash, misc/truncate-dangling-symlink, touch/dangling-symlink,
touch/no-dereference, touch/trailing-slash.
Suggested fix
Implement symlink_handler and symlinkat_handler in imfs-grate/src/handlers.rs and register them
in main.rs. The in-memory FS already has a Lnk node type (imfs/mod.rs, used internally for
./..), so this is mostly: resolve the new path relative to the cage CWD via
normalize_path_for_cage, reject EEXIST if it resolves, then create a Lnk node storing the
(un-resolved) target string. Pairs with Issue 3 (readlink).
Summary
Under the fs-routing setup (fs-routing-clamp --prefix /tmp %{ imfs-grate %}), ~33 coreutils
tests fail at their first ln -s with /bin/ln: creating symbolic link 'X': File exists — even
though the symlink is being created in a freshly mktemp -d directory. The same tests pass on
the bare wasm runtime.
Reproduction
Root cause
imfs-grate/src/main.rs registers handlers for open, mkdir, unlink, link, rename, chdir, getcwd,
stat, etc., but not for SYS_SYMLINK or SYS_SYMLINKAT (GNU ln -s uses symlinkat).
Because symlinkat is unregistered, it falls through the imfs grate to RawPOSIX, which:
dir was consumed by imfs's chdir_handler and never reached RawPOSIX).
So the very first test that runs symlink(target, "dangle") creates /dangle on the host FS; it
persists, and every subsequent test that creates a symlink of the same name fails with EEXIST.
The imfs-side mktemp dir and the host-side symlink live in two disjoint namespaces.
Affected tests (~33)
chmod/thru-dangling, chown/deref, cp/cp-HL, cp/deref-slink, cp/link-no-deref, cp/no-deref-link1,
cp/no-deref-link2, cp/no-deref-link3, cp/r-vs-symlink, cp/same-file, cp/slink-2-slink,
cp/symlink-slash, cp/thru-dangling, cp/abuse, cp/cp-deref, du/deref, du/deref-args, du/no-deref,
du/trailing-slash, ls/dangle, ls/file-type, ls/follow-slink, ls/inode, ls/no-arg,
ls/symlink-slash, mkdir/p-thru-slink, mv/into-self-4, ln/sf-1, ln/hard-to-sym, ln/misc,
ln/target-1, misc/stat-slash, misc/truncate-dangling-symlink, touch/dangling-symlink,
touch/no-dereference, touch/trailing-slash.
Suggested fix
Implement symlink_handler and symlinkat_handler in imfs-grate/src/handlers.rs and register them
in main.rs. The in-memory FS already has a Lnk node type (imfs/mod.rs, used internally for
./..), so this is mostly: resolve the new path relative to the cage CWD via
normalize_path_for_cage, reject EEXIST if it resolves, then create a Lnk node storing the
(un-resolved) target string. Pairs with Issue 3 (readlink).