I have found a difference in behavior between Tcl's [file normalize $path]
and the path resolution used by the calls in C, such as open()
and
realpath()
.
It revolves around the use of symbolic links immediately followed by ..
.
The setup: given this directory structure (notice that sidedir_link
is a link to a
different directory):
/tmp/fileA.txt
/tmp/sidedir/fileA.txt
/tmp/subdir/fileA.txt
/tmp/subdir/sidedir_link -> /tmp/sidedir
the current directory is /tmp/subdir
, and I have created the command
utils::realpath
to be a Tcl call to the C function realpath()
in
<stdlib.h>
.
Here's the transcript. The first two calls show how both resolve a symbolic
link. And the last two show the difference in behavior when dealing with
the ..
that immediately follows the symbolic link.
wish% file normalize sidedir_link/fileA.txt
/tmp/sidedir/fileA.txt
wish% ::utils::realpath sidedir_link/fileA.txt
/tmp/sidedir/fileA.txt
wish% file normalize sidedir_link/../fileA.txt
/tmp/subdir/fileA.txt
wish% ::utils::realpath sidedir_link/../fileA.txt
/tmp/fileA.txt
Note: The difference is /tmp/subdir/fileA.txt
versus /tmp/fileA.txt
.
Specifically, [file normalize $path]
appears to lexically resolve the ..
by removing the preceding portion of the path, whereas the C calls actually
resolve the symbolic link and then apply the ..
. If the symbolic link
were to /some/location/far/far/away
, the resolved path would be
/some/location/far/far/fileA.txt
.
I couldn't find any mention of this in the Tcl docs, the wiki, or in the bug tracking system.
So, is this a Tcl bug? A C-library bug? Expected behavior?
I'm using Tcl 8.4.9 and Redhat 6 (yes, a bit behind the times...)
Note: I can reproduce the same behavior in Tcl 8.6.1
The reason this is important is that the Tcl/Tk GUI is indicating that a file exists (because it uses the file
commands), but when the backend actually opens the file using the C-library call open()
, the run fails (because the path is different, and doesn't exist).