Re: Bug Emacs 21.3: write-file downcasing

From:

Juanma Barranquero

Subject:

Re: Bug Emacs 21.3: write-file downcasing

Date:

Fri, 07 Feb 2003 16:50:11 +0100

On Fri, 07 Feb 2003 17:23:12 +0200, "Eli Zaretskii" <address@hidden> wrote:
> What was the problem that caused the change in file-truename?
My e-mails to Jason were as follows:
> Hi.
>
> I'm investigating this:
>
> > 2001-11-08 address@hidden (Andrew Maguire) gnu.emacs.bug
> > (file-truename "C:/temp/a_file")
> > returns "C:/temp/a_file" if the file does not exist and
> > "c:/temp/a_file" if it does.
>
> I'm not convinced this is a bug :)
>
> If the file does not exist, the argument is returned unmodified.
>
> OTOH, if the file does exist, eventually normalize_filename (in w32.c)
> gets called, which returns the path and name exactly as it exists in
> the filesystem, but purposefully downcases the drive letter, according
> to this changelog entry:
>
> > 1996-07-03 Andrew Innes <address@hidden>
> >
> > * nt.c (normalize_filename): Always lower-case drive letters, even
> > on systems that preserve case in filenames.
>
> and this source code comment:
>
> > /* Always lower-case drive letters a-z, even if the filesystem
> > preserves case in filenames.
> > This is so filenames can be compared by string comparison
> > functions that are case-sensitive. Even case-preserving filesystems
> > do not distinguish case in drive letters. */
>
> If the return value of file-truename is used in comparisons, then
> perhaps the best answer would be unconditionally downcasing the drive
> letter (in the windows-specific part of the code) even if
> w32-long-file-name returns nil.
>
> OTOH, I'm not sure what's the canonical truename of a non-existent
> file. Doc about file-truename (in the Elisp reference) seems to assume
> the arg is the name of an existing file, but the function takes pains
> to returns a non-nil value even if the file does not exist...
Jason sent me the full user report, which said:
> (file-truename "C:/temp/a_file")
> returns "C:/temp/a_file" if the file does not exist
> and "c:/temp/a_file" if it does.
>
> This causes confusion if you do a find-file on C:/temp/a_file
> edit it and save it. Then do a find-file on c:/temp/a_file.
> You will get two different edits on the same file.
which I followed with:
> The problem is that currently there's no interface between the lisp
> level and the C functions that manipulate filenames, other than
> w32-short-file-name and w32-long-file-name, and both of these return
> nil if the file does not exist.
>
> So to be able to call normalize_filename on a non-existent filename,
> either normalize_filename is "upgraded" to be directly accesible from
> lisp, or it is made accesible through w32-{long|short}-file-name,
> perhaps by adding an additional parameter to those functions that, if
> set to t, would make them return their normalized argument if it does
> not exists as a file. That'd be backward-compatible. To support this
> idea, I don't understand why w32-long-file-name, which is somewhat
> similar in spirit to file-truename, does return nil for unexistent
> files while the later does return a "truename" even if non-existent!
>
> Barring that, the only other answer I can think of is making an ugly
> hack in the nt-specific code of file-truename to unconditionally downcase
> the drive letter.
>
> All in all, I think there's a lack of definition wrt which is the
> right behavior for w32 filenames. It is worse the reported "bug" that
> this one (assuming a_file exists and a_file2 doesn not)?
>
> ELISP> (file-truename "/temp/a_file")
> "c:/temp/a_file"
> ELISP> (file-truename "/temp/a_file2")
> "/temp/a_file2"
and then
> A posible answer, now that I've found untranslated-canonical-name does
> exactly what we needed...
>
> Index: files.el
> ===================================================================
> RCS file: /cvsroot/emacs/emacs/lisp/files.el,v
> retrieving revision 1.538
> diff -u -r1.538 files.el
> --- files.el 2001/11/21 12:00:32 1.538
> +++ files.el 2001/11/21 16:11:49
> @@ -618,7 +618,7 @@
> (setq newname filename)
> ;; If filename doesn't exist, newname will be nil.
> (setq newname (w32-long-file-name filename)))
> - (setq filename (or newname filename)))
> + (setq filename (or newname (untranslated-canonical-name filename))))
> (setq done t)))
>
> ;; If this file directly leads to a link, process that iteratively
and, finally:
> > A posible answer, now that I've found untranslated-canonical-name does
> > exactly what we needed...
>
> Except that untranslated-canonical-name calls expand-file-name, which
> produces:
>
> > ELISP> (file-truename "~")
> > "c:/usr/home"
> > ELISP>
>
> Oops.
>
> Although I'm still puzzled about *what* is the supposed behavior of
> file-truename wrt non-existent files...
/L/e/k/t/u