[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
realpath edge cases
From: |
Assaf Gordon |
Subject: |
realpath edge cases |
Date: |
Sun, 25 Jun 2017 00:02:53 +0000 |
User-agent: |
Mutt/1.5.23 (2014-03-12) |
Hello all,
I've encountered two interesting (?) edge-cases with realpath.
Perhaps they warrent a change in documentation (or even
error-checking code).
First,
Running 'realpath' in a deleted (unlinked) directory leads to confusing
error messages. Example:
# In terminal 1
mkdir /tmp/a
cd /tmp/a
# In another terminal
rmdir /tmp/a
# back in terminal 1
$ realpath /foo
/foo
$ realpath foo
realpath: foo: No such file or directory
$ realpath ../foo
realpath: ../foo: No such file or directory
$ realpath -m foo
realpath: foo: No such file or directory
I'd say this error message is confusing, because naively 'realpath' does
not require the last component to exist, and with '-m' it doesn't
require any component to exist. Yet the error message hints that
something that should exist doesn't.
The reason for the error message is this flow:
src/realpath.c:process_path()
src/realpath.c:realpath_canon()
gnulib/lib/canonicalize.c:canonicalize_filename_mode()
gnulib/lib/xgetcwd.c:xgetcwd()
Then xgetcwd fails (because the directory was deleted),
but despite the 'x' prefix, it only dies on ENOMEM,
not on ENOENT. It returns NULL, and the rest of the program
fails, but errno remains at ENOENT.
Not sure what would be a good gnulib fix without breaking
existing code that uses 'canonicalize_filename_mode'.
Of course, it is always recommended not to run programs
in a deleted directory... many programs will fail with confusing
errors.
Second,
`realpath --help` shows:
--relative-to=FILE print the resolved path relative to FILE
--relative-base=FILE print absolute paths unless paths below FILE
This hints (to a naive person like me :) ) that realpath will calculate
relative path to any file. But in fact, it assumes that the FILE
argument is always a directory, and with 'realpath -e' it indeeds
verifies it's a directory.
Example:
$ mkdir /tmp/b
$ cd /tmp/b
$ touch 1
$ realpath --relative-to=/tmp/b/1 2
../2
$ realpath -e --relative-to=/tmp/b/1 2
realpath: /tmp/b/1: Not a directory
One could argue it doesn't matter since 'realpath'
is mainly used to construct path strings in script.
But the resulting concatenated string is not a valid path:
$ touch /tmp/b/1/../2
touch: cannot touch '/tmp/b/1/../2': Not a directory
That is, if someone writes a shell script like:
base=/foo/bar/file.txt
rel=$(realpath --relative-to="$base" another.txt)
There might be assumption that "$base/$rel" should always work,
but it only works correctly if '$base' is a directory, despite
realpath not returning error message.
I assume that checking if the argument to --relative-{to,base}
is actually a directory when not using 'realpath -e' is not
acceptable as it will break existing behaviour.
So perhaps just update the usage text? (patch attached).
If not, then add a new 'gotcha' ?
regards,
- assaf
0001-realpath-improve-usage-description-for-relative-to-b.patch
Description: Text Data
- realpath edge cases,
Assaf Gordon <=