Re: [19.25, efs 1.9] dired-handler-fn

sandy@ibm550.sissa.it
Mon, 18 Jul 1994 13:33:30 +0200


It just occured to me that maybe what is burning us when the
dired-handler-fn recurses are calls to file-truename.  I believe that
in GNU Emacs 19 this is not a fast function.  It is a lisp function in
files.el.  It does call find-file-name-handler, but if there is no
handler for file-truename it goes on to run lots of lisp (which
recursively calls itself!) with the file-name-handler-alist still
active.  This means lots of calls to find-file-name-handler.  Maybe if
file-truename has no handler, it should let-bind the
file-name-handler-alist to nil.  This would require packages that do
special file handling to be sure that they handle file-truename
directly, and not rely on side-effect handling via file-symlink-p,
etc.

In Lucid/X Emacs file-truename is in C, and so is fast.  However, it
doesn't check the file-name-handler-alist, so I need to overload it.
Will this be changing Lucid/X people?

Will file-truename be staying in lisp for GNU Emacs?  Noah?  Roland?
If it's getting called a lot, making it a subr. might be a good idea.

Try this version (slightly edited from files.el of 19.25):

(defun file-truename (filename)
  "Return the truename of FILENAME, which should be absolute.
The truename of a file name is found by chasing symbolic links
both at the level of the file and at the level of the directories
containing it, until no links are left at any level."
  (if (or (string= filename "~")
	  (and (string= (substring filename 0 1) "~")
	       (string-match "~[^/]*" filename)))
      (progn
	(setq filename (expand-file-name filename))
	(if (string= filename "")
	    (setq filename "/"))))
  (let ((handler (find-file-name-handler filename 'file-truename)))
    ;; For file name that has a special handler, call handler.
    ;; This is so that ange-ftp can save time by doing a no-op.
    (if handler
	(funcall handler 'file-truename filename)
      (let ((dir (file-name-directory filename))
	    target dirfile file-name-handler-alist)
	;; Get the truename of the directory.
	(setq dirfile (directory-file-name dir))
	;; If these are equal, we have the (or a) root directory.
	(or (string= dir dirfile)
	    (setq dir (file-name-as-directory (file-truename dirfile))))
	(if (equal ".." (file-name-nondirectory filename))
	    (directory-file-name (file-name-directory (directory-file-name dir)))
	  (if (equal "." (file-name-nondirectory filename))
	      (directory-file-name dir)
	    ;; Put it back on the file name.
	    (setq filename (concat dir (file-name-nondirectory filename)))
	    ;; Is the file name the name of a link?
	    (setq target (file-symlink-p filename))
	    (if target
		;; Yes => chase that link, then start all over
		;; since the link may point to a directory name that uses links.
		;; We can't safely use expand-file-name here
		;; since target might look like foo/../bar where foo
		;; is itself a link.  Instead, we handle . and .. above.
		(if (file-name-absolute-p target)
		    (file-truename target)
		  (file-truename (concat dir target)))
	      ;; No, we are done!
	      filename)))))))