emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

. and ..


From: Luc Teirlinck
Subject: . and ..
Date: Wed, 17 Mar 2004 18:03:22 -0600 (CST)

There was a bug report on gnu.emacs.bug, about a week ago, regarding
the way emacs handles . and .. in file names.  A copy of the report is
attached at the bottom.  The bug(?) does not seem to have been "fixed"
in the meantime and, given reactions to similar bug reports in the
past, I would guess that this is because it is not considered a bug.

Below, I give a variation on the original bug report hoping to convince
people that one way or the other there _is_ a problem.

emacs -q
M-x ielm

ELISP> default-directory
"~/"
ELISP> (make-directory "foo/bar" t)
nil
ELISP> (make-symbolic-link "foo/bar" "bar") 
nil
ELISP> (file-truename "~/bar/../myfile")
"/home/teirllm/myfile"
;; I can understand why one could consider this return value a
;; "feature" instead of a bug (although to people used to programming C
;; or POSIX shells it is very unexpected and confusing).
ELISP> (file-truename "/home/teirllm/bar/../myfile")
"/home/teirllm/foo/myfile"
;; I _definitely_ understand how one can consider this return value to
;; be "correct".  But _both_ this one _and_ the previous one?
ELISP> (find-file-noselect "/home/teirllm/bar/../myfile")
#<buffer myfile>
ELISP> (set-buffer "myfile")
#<buffer myfile>
ELISP> (buffer-file-name)
"/home/teirllm/myfile"
ELISP> (find-file-noselect (file-truename "/home/teirllm/bar/../myfile"))
#<buffer myfile<2>>
ELISP> (set-buffer "myfile<2>")
#<buffer myfile<2>>
ELISP> (buffer-file-name)
"/home/teirllm/foo/myfile"
ELISP> 

Note that "/home/teirllm/bar/../myfile" and
(file-truename "/home/teirllm/bar/../myfile") refer to different files.

>From (elisp)Truenames:

The "truename" of a file is the name that you get by following symbolic
links at all levels until none remain, then simplifying away `.' and
`..' appearing as name components.  This results in a sort of canonical
name for the file.

Except, above it leads to a _different_ file.  Note that according to
the above description "/home/teirllm/foo/myfile" would seem to be the
"correct" answer.  C and POSIX shells agree with that, but
`expand-file-name' disagrees.

It seems hard to consider _everything_ above to be "features".

C and the shell handle . and .. as part of file name _resolution_.
They consistently treat "/home/teirllm/bar/../myfile" as a
*non-simplifiable* file name *until* they resolve the name left to
right.  There is no processing to be done until we arrive at
"/home/teirllm/bar" which is a symlink and has to be replaced with
"home/teirllm/foo/bar" giving "/home/teirllm/foo/bar/../myfile".  The
next thing to process is .. giving "/home/teirllm/foo/myfile".

Quite often, but not always, Emacs sees things differently from the
way C, the shell and other programs do.  Namely it first "simplifies"
the .. away, giving "/home/teirllm/myfile" and then nothing remains to
simplify, so this is the final result of resolution.

I believe we have to decide whether we want to systematically treat
. and .. in the same way C and POSIX shells treat them, or
systematically in the second, (part-time) Emacs way.  If we want to do
the first, only `file-truename' should handle . and .., and definitely
_not_ `expand-file-name', as is currently the case.  If we want to do
the second, then any function that does any part of file name
resolution should first call `expand-file-name' (or handle . and
.. itself), before doing any other part of file name resolution
(_except_ handling environment variables, ~ and the Emacs /~ and //
conventions, which are Emacs and command line features that have to be
handled before even starting file name resolution proper).  The second
solution would create even more confusion for C and shell programmers,
but at least would be consistent.

Both solutions represent incompatible changes, but the present
situation is self-incompatible: "/home/teirllm/bar/../myfile" seems to
refer to "/home/teirllm/myfile" and to "/home/teirllm/foo/myfile",
each pretty much about fifty percent of the time.  

I personally would prefer the first solution, namely, be 100%
consistent with C and POSIX shells.

Copy of original report:

From: Trey Smith <address@hidden>
Subject: bug with parent directories and symlinks
Newsgroups: gnu.emacs.bug
To: address@hidden
Date: Wed, 3 Mar 2004 17:11:04 -0500

This bug report concerns emacs version 21.2.1 on linux.

The problem relates to handling of parent directories in the presence
of
symlinks.  The following section explains how to replicate the
problem.

----------------------------------------------------------------------
Setup steps:

  cd /tmp
  mkdir -p foo/bar
  ln -s foo/bar bar
  echo 'this is my file' > foo/myfile
  cd bar

At this point we are in the "/tmp/foo/bar" directory, and there is a
file "/tmp/foo/myfile" which includes some text.  If we run emacs and
execute

  (find-file "../myfile")

Emacs will open "/tmp/myfile" instead of "/tmp/foo/myfile" as it
should.
----------------------------------------------------------------------

This problem is particularly annoying when compiling C code under
emacs,
because the compiler sometimes outputs header filenames in errors
using
a relative path that includes "..", and attempting to jump to the file
containing the error fails.

The suggested fix is to not calculate ".." internally in emacs, but
instead to use the filesystem.  In the above example, opening
"/tmp/bar/../myfile" from the shell correctly yields
"/tmp/foo/myfile".
Opening "/tmp/bar/../myfile" from emacs incorrectly yields
"/tmp/myfile".

-Trey




reply via email to

[Prev in Thread] Current Thread [Next in Thread]