diff options
| author | Richard M. Stallman | 1994-07-05 20:23:13 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1994-07-05 20:23:13 +0000 |
| commit | 05ef1cdab942719e44c830dfd19b915702972e0e (patch) | |
| tree | d43bf078a8837f02c531c0502f17f362f843fe0d | |
| parent | 30dc01ea24f61c5f0a2561b8a36c2e259811d6e1 (diff) | |
| download | emacs-05ef1cdab942719e44c830dfd19b915702972e0e.tar.gz emacs-05ef1cdab942719e44c830dfd19b915702972e0e.zip | |
(file-truename): Use iteration when possible.
Avoid recalculating the same truename twice in one invocation.
Error check for infinite link loop.
(debugger): Make it a risky-local-variable.
| -rw-r--r-- | lisp/files.el | 97 |
1 files changed, 64 insertions, 33 deletions
diff --git a/lisp/files.el b/lisp/files.el index 66f3ac21721..5cf294ab54c 100644 --- a/lisp/files.el +++ b/lisp/files.el | |||
| @@ -329,11 +329,18 @@ accessible." | |||
| 329 | (funcall handler 'file-local-copy file) | 329 | (funcall handler 'file-local-copy file) |
| 330 | nil))) | 330 | nil))) |
| 331 | 331 | ||
| 332 | (defun file-truename (filename) | 332 | (defun file-truename (filename &optional counter prev-dirs) |
| 333 | "Return the truename of FILENAME, which should be absolute. | 333 | "Return the truename of FILENAME, which should be absolute. |
| 334 | The truename of a file name is found by chasing symbolic links | 334 | The truename of a file name is found by chasing symbolic links |
| 335 | both at the level of the file and at the level of the directories | 335 | both at the level of the file and at the level of the directories |
| 336 | containing it, until no links are left at any level." | 336 | containing it, until no links are left at any level. |
| 337 | |||
| 338 | The arguments COUNTER and PREV-DIRS are used only in recursive calls. | ||
| 339 | Do not specify them in other calls." | ||
| 340 | ;; COUNTER can be a cons cell whose car is the count of how many more links | ||
| 341 | ;; to chase before getting an error. | ||
| 342 | ;; PREV-DIRS can be a cons cell whose car is an alist | ||
| 343 | ;; of truenames we've just recently computed. | ||
| 337 | (if (or (string= filename "~") | 344 | (if (or (string= filename "~") |
| 338 | (and (string= (substring filename 0 1) "~") | 345 | (and (string= (substring filename 0 1) "~") |
| 339 | (string-match "~[^/]*" filename))) | 346 | (string-match "~[^/]*" filename))) |
| @@ -341,37 +348,60 @@ containing it, until no links are left at any level." | |||
| 341 | (setq filename (expand-file-name filename)) | 348 | (setq filename (expand-file-name filename)) |
| 342 | (if (string= filename "") | 349 | (if (string= filename "") |
| 343 | (setq filename "/")))) | 350 | (setq filename "/")))) |
| 344 | (let ((handler (find-file-name-handler filename 'file-truename))) | 351 | (or counter (setq counter (list 100))) |
| 345 | ;; For file name that has a special handler, call handler. | 352 | (or prev-dirs (setq prev-dirs (list nil))) |
| 346 | ;; This is so that ange-ftp can save time by doing a no-op. | 353 | (let (done) |
| 347 | (if handler | 354 | ;; If this file directly leads to a link, process that iteratively |
| 348 | (funcall handler 'file-truename filename) | 355 | ;; so that we don't use lots of stack. |
| 349 | (let ((dir (file-name-directory filename)) | 356 | (while (not done) |
| 350 | target dirfile) | 357 | (setcar counter (1- (car counter))) |
| 351 | ;; Get the truename of the directory. | 358 | (if (< (car counter) 0) |
| 352 | (setq dirfile (directory-file-name dir)) | 359 | (error "Apparent cycle of symbolic links for %s" filename)) |
| 353 | ;; If these are equal, we have the (or a) root directory. | 360 | (let ((handler (find-file-name-handler filename 'file-truename))) |
| 354 | (or (string= dir dirfile) | 361 | ;; For file name that has a special handler, call handler. |
| 355 | (setq dir (file-name-as-directory (file-truename dirfile)))) | 362 | ;; This is so that ange-ftp can save time by doing a no-op. |
| 356 | (if (equal ".." (file-name-nondirectory filename)) | 363 | (if handler |
| 357 | (directory-file-name (file-name-directory (directory-file-name dir))) | 364 | (setq filename (funcall handler 'file-truename filename) |
| 358 | (if (equal "." (file-name-nondirectory filename)) | 365 | done t) |
| 359 | (directory-file-name dir) | 366 | (let ((dir (file-name-directory filename)) |
| 360 | ;; Put it back on the file name. | 367 | target dirfile) |
| 361 | (setq filename (concat dir (file-name-nondirectory filename))) | 368 | ;; Get the truename of the directory. |
| 362 | ;; Is the file name the name of a link? | 369 | (setq dirfile (directory-file-name dir)) |
| 363 | (setq target (file-symlink-p filename)) | 370 | ;; If these are equal, we have the (or a) root directory. |
| 364 | (if target | 371 | (or (string= dir dirfile) |
| 365 | ;; Yes => chase that link, then start all over | 372 | ;; If this is the same dir we last got the truename for, |
| 366 | ;; since the link may point to a directory name that uses links. | 373 | ;; save time--don't recalculate. |
| 367 | ;; We can't safely use expand-file-name here | 374 | (if (assoc dir (car prev-dirs)) |
| 368 | ;; since target might look like foo/../bar where foo | 375 | (setq dir (cdr (assoc dir (car prev-dirs)))) |
| 369 | ;; is itself a link. Instead, we handle . and .. above. | 376 | (let ((old dir) |
| 370 | (if (file-name-absolute-p target) | 377 | (new (file-name-as-directory (file-truename dirfile counter prev-dirs)))) |
| 371 | (file-truename target) | 378 | (setcar prev-dirs (cons (cons old new) (car prev-dirs))) |
| 372 | (file-truename (concat dir target))) | 379 | (setq dir new)))) |
| 373 | ;; No, we are done! | 380 | (if (equal ".." (file-name-nondirectory filename)) |
| 374 | filename))))))) | 381 | (setq filename |
| 382 | (directory-file-name (file-name-directory (directory-file-name dir))) | ||
| 383 | done t) | ||
| 384 | (if (equal "." (file-name-nondirectory filename)) | ||
| 385 | (setq filename (directory-file-name dir) | ||
| 386 | done t) | ||
| 387 | ;; Put it back on the file name. | ||
| 388 | (setq filename (concat dir (file-name-nondirectory filename))) | ||
| 389 | ;; Is the file name the name of a link? | ||
| 390 | (setq target (file-symlink-p filename)) | ||
| 391 | (if target | ||
| 392 | ;; Yes => chase that link, then start all over | ||
| 393 | ;; since the link may point to a directory name that uses links. | ||
| 394 | ;; We can't safely use expand-file-name here | ||
| 395 | ;; since target might look like foo/../bar where foo | ||
| 396 | ;; is itself a link. Instead, we handle . and .. above. | ||
| 397 | (setq filename | ||
| 398 | (if (file-name-absolute-p target) | ||
| 399 | target | ||
| 400 | (concat dir target)) | ||
| 401 | done nil) | ||
| 402 | ;; No, we are done! | ||
| 403 | (setq done t)))))))) | ||
| 404 | filename)) | ||
| 375 | 405 | ||
| 376 | (defun file-chase-links (filename) | 406 | (defun file-chase-links (filename) |
| 377 | "Chase links in FILENAME until a name that is not a link. | 407 | "Chase links in FILENAME until a name that is not a link. |
| @@ -1105,6 +1135,7 @@ If `enable-local-variables' is nil, this function does not check for a | |||
| 1105 | "Variables to be ignored in a file's local variable spec.") | 1135 | "Variables to be ignored in a file's local variable spec.") |
| 1106 | 1136 | ||
| 1107 | ;; Get confirmation before setting these variables as locals in a file. | 1137 | ;; Get confirmation before setting these variables as locals in a file. |
| 1138 | (put 'debugger 'risky-local-variable t) | ||
| 1108 | (put 'enable-local-eval 'risky-local-variable t) | 1139 | (put 'enable-local-eval 'risky-local-variable t) |
| 1109 | (put 'eval 'risky-local-variable t) | 1140 | (put 'eval 'risky-local-variable t) |
| 1110 | (put 'file-name-handler-alist 'risky-local-variable t) | 1141 | (put 'file-name-handler-alist 'risky-local-variable t) |