aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorPaul Eggert2017-08-26 18:36:38 -0700
committerPaul Eggert2017-08-26 18:36:38 -0700
commite8001d4c27e1e33c83b9994aac4d5fc3feada2da (patch)
tree6910256d7cf7723aa1b3f7ab7779b91627ba52f6 /lisp
parent937d9d7f60460edb1d3f978151599fddcbba2214 (diff)
downloademacs-e8001d4c27e1e33c83b9994aac4d5fc3feada2da.tar.gz
emacs-e8001d4c27e1e33c83b9994aac4d5fc3feada2da.zip
Do not munge contents of local symbolic links
This lets Emacs deal with arbitrary local symlinks without mishandling their contents (Bug#28156). For example, (progn (shell-command "ln -fs '~' 'x'") (rename-file "x" "/tmp/x")) now consistently creates a symbolic link from '/tmp/x' to '~'. Formerly, it did that only if the working directory was on the same filesystem as /tmp; otherwise, it expanded the '~' to the user's home directory. * lisp/dired.el (dired-get-filename): Use files--name-absolute-system-p instead of rolling our own code. * lisp/files.el (files--name-absolute-system-p): New function. (file-truename, file-chase-links): Use it to avoid mishandling symlink contents that begin with ~. (copy-directory, move-file-to-trash): Use concat rather than expand-file-name, to avoid mishandling symlink contents that begin with ~. * src/fileio.c (Fmake_symbolic_link): Do not expand leading "~" in the target unless interactive. Strip leading "/:" if interactive. (emacs_readlinkat): Do not prepend "/:" to the link target if it starts with "/" and contains ":" before NUL. * test/src/fileio-tests.el (try-link): Rename from try-char, and accept a string instead of a char. All uses changed. (fileio-tests--symlink-failure): Also test leading ~, and "/:", to test the new behavior.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/dired.el5
-rw-r--r--lisp/files.el31
2 files changed, 22 insertions, 14 deletions
diff --git a/lisp/dired.el b/lisp/dired.el
index 0455f3d1378..ff62183f091 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -2332,10 +2332,7 @@ Otherwise, an error occurs in these cases."
2332 (if (and enable-multibyte-characters 2332 (if (and enable-multibyte-characters
2333 (not (multibyte-string-p file))) 2333 (not (multibyte-string-p file)))
2334 (setq file (string-to-multibyte file))))) 2334 (setq file (string-to-multibyte file)))))
2335 (and file (file-name-absolute-p file) 2335 (and file (files--name-absolute-system-p file)
2336 ;; A relative file name can start with ~.
2337 ;; Don't treat it as absolute in this context.
2338 (not (eq (aref file 0) ?~))
2339 (setq already-absolute t)) 2336 (setq already-absolute t))
2340 (cond 2337 (cond
2341 ((null file) 2338 ((null file)
diff --git a/lisp/files.el b/lisp/files.el
index ca3b055d7a6..872fc46e87a 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -1146,6 +1146,13 @@ accessible."
1146 (funcall handler 'file-local-copy file) 1146 (funcall handler 'file-local-copy file)
1147 nil))) 1147 nil)))
1148 1148
1149(defun files--name-absolute-system-p (file)
1150 "Return non-nil if FILE is an absolute name to the operating system.
1151This is like `file-name-absolute-p', except that it returns nil for
1152names beginning with `~'."
1153 (and (file-name-absolute-p file)
1154 (not (eq (aref file 0) ?~))))
1155
1149(defun file-truename (filename &optional counter prev-dirs) 1156(defun file-truename (filename &optional counter prev-dirs)
1150 "Return the truename of FILENAME. 1157 "Return the truename of FILENAME.
1151If FILENAME is not absolute, first expands it against `default-directory'. 1158If FILENAME is not absolute, first expands it against `default-directory'.
@@ -1247,9 +1254,9 @@ containing it, until no links are left at any level.
1247 ;; since target might look like foo/../bar where foo 1254 ;; since target might look like foo/../bar where foo
1248 ;; is itself a link. Instead, we handle . and .. above. 1255 ;; is itself a link. Instead, we handle . and .. above.
1249 (setq filename 1256 (setq filename
1250 (if (file-name-absolute-p target) 1257 (concat (if (files--name-absolute-system-p target)
1251 target 1258 "/:" dir)
1252 (concat dir target)) 1259 target)
1253 done nil) 1260 done nil)
1254 ;; No, we are done! 1261 ;; No, we are done!
1255 (setq done t)))))))) 1262 (setq done t))))))))
@@ -1284,7 +1291,10 @@ it means chase no more than that many links and then stop."
1284 (directory-file-name (file-name-directory newname)))) 1291 (directory-file-name (file-name-directory newname))))
1285 ;; Now find the parent of that dir. 1292 ;; Now find the parent of that dir.
1286 (setq newname (file-name-directory newname))) 1293 (setq newname (file-name-directory newname)))
1287 (setq newname (expand-file-name tem (file-name-directory newname))) 1294 (setq newname (concat (if (files--name-absolute-system-p tem)
1295 "/:"
1296 (file-name-directory newname))
1297 tem))
1288 (setq count (1+ count)))) 1298 (setq count (1+ count))))
1289 newname)) 1299 newname))
1290 1300
@@ -5504,10 +5514,10 @@ directly into NEWNAME instead."
5504 ;; If NEWNAME is an existing directory and COPY-CONTENTS 5514 ;; If NEWNAME is an existing directory and COPY-CONTENTS
5505 ;; is nil, copy into NEWNAME/[DIRECTORY-BASENAME]. 5515 ;; is nil, copy into NEWNAME/[DIRECTORY-BASENAME].
5506 ((not copy-contents) 5516 ((not copy-contents)
5507 (setq newname (expand-file-name 5517 (setq newname (concat
5518 (file-name-as-directory newname)
5508 (file-name-nondirectory 5519 (file-name-nondirectory
5509 (directory-file-name directory)) 5520 (directory-file-name directory))))
5510 newname))
5511 (and (file-exists-p newname) 5521 (and (file-exists-p newname)
5512 (not (file-directory-p newname)) 5522 (not (file-directory-p newname))
5513 (error "Cannot overwrite non-directory %s with a directory" 5523 (error "Cannot overwrite non-directory %s with a directory"
@@ -5519,7 +5529,8 @@ directly into NEWNAME instead."
5519 ;; We do not want to copy "." and "..". 5529 ;; We do not want to copy "." and "..".
5520 (directory-files directory 'full 5530 (directory-files directory 'full
5521 directory-files-no-dot-files-regexp)) 5531 directory-files-no-dot-files-regexp))
5522 (let ((target (expand-file-name (file-name-nondirectory file) newname)) 5532 (let ((target (concat (file-name-as-directory newname)
5533 (file-name-nondirectory file)))
5523 (filetype (car (file-attributes file)))) 5534 (filetype (car (file-attributes file))))
5524 (cond 5535 (cond
5525 ((eq filetype t) ; Directory but not a symlink. 5536 ((eq filetype t) ; Directory but not a symlink.
@@ -7149,8 +7160,8 @@ Otherwise, trash FILENAME using the freedesktop.org conventions,
7149 ;; If `trash-directory' is non-nil, move the file there. 7160 ;; If `trash-directory' is non-nil, move the file there.
7150 (let* ((trash-dir (expand-file-name trash-directory)) 7161 (let* ((trash-dir (expand-file-name trash-directory))
7151 (fn (directory-file-name (expand-file-name filename))) 7162 (fn (directory-file-name (expand-file-name filename)))
7152 (new-fn (expand-file-name (file-name-nondirectory fn) 7163 (new-fn (concat (file-name-as-directory trash-dir)
7153 trash-dir))) 7164 (file-name-nondirectory fn))))
7154 ;; We can't trash a parent directory of trash-directory. 7165 ;; We can't trash a parent directory of trash-directory.
7155 (if (string-prefix-p fn trash-dir) 7166 (if (string-prefix-p fn trash-dir)
7156 (error "Trash directory `%s' is a subdirectory of `%s'" 7167 (error "Trash directory `%s' is a subdirectory of `%s'"