An empty-string path operand resolves to the cwd, so every command reports Is a directory for ''.
$ sort ''
sort: read failed: : Is a directory # gsort '': "cannot read: '': No such file or directory"
$ cat ''
cat: : Is a directory # gcat '': "cannot open '' for reading: No such file..."
FS.resolve_path(cwd, "") returns the cwd, so the empty operand becomes a directory that exists, and the
command faithfully reports what the filesystem told it. The command is not at fault — the path layer is.
POSIX is explicit that an empty pathname resolves to nothing: it is ENOENT, never the current
directory. Every command taking a file operand inherits the wrong answer, and it is the kind of input
that shows up from an unquoted empty variable (sort "$f" with f unset), so it is reachable without
anyone typing ''.
The fix belongs in FS.resolve_path/2 — return {:error, :enoent} for an empty component rather than
collapsing to the base. Worth checking what resolve_path/2 does with the other degenerate inputs at the
same time (a bare /, repeated slashes, a trailing .), since they go through the same normalisation.
Note that cp/mv/ln/tee/touch/sed -i and the redirect path now route destination spellings
through FS.check_directory_spelling/3 (PR #75), so an empty destination may need the same treatment
as an empty source.
Pre-existing at origin/main (82ee9e5) — cat '' already misreports there, before any of the current
PRs. Deliberately deferred out of PR #72 and PR #74 because the fix is in the path layer and would have
conflicted with both.
Found by an independent verification pass while working #68 and #70.
An empty-string path operand resolves to the cwd, so every command reports
Is a directoryfor''.FS.resolve_path(cwd, "")returns the cwd, so the empty operand becomes a directory that exists, and thecommand faithfully reports what the filesystem told it. The command is not at fault — the path layer is.
POSIX is explicit that an empty pathname resolves to nothing: it is
ENOENT, never the currentdirectory. Every command taking a file operand inherits the wrong answer, and it is the kind of input
that shows up from an unquoted empty variable (
sort "$f"withfunset), so it is reachable withoutanyone typing
''.The fix belongs in
FS.resolve_path/2— return{:error, :enoent}for an empty component rather thancollapsing to the base. Worth checking what
resolve_path/2does with the other degenerate inputs at thesame time (a bare
/, repeated slashes, a trailing.), since they go through the same normalisation.Note that
cp/mv/ln/tee/touch/sed -iand the redirect path now route destination spellingsthrough
FS.check_directory_spelling/3(PR #75), so an empty destination may need the same treatmentas an empty source.
Pre-existing at
origin/main(82ee9e5) —cat ''already misreports there, before any of the currentPRs. Deliberately deferred out of PR #72 and PR #74 because the fix is in the path layer and would have
conflicted with both.
Found by an independent verification pass while working #68 and #70.