emacs-diffs
[Top][All Lists]
Advanced

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

master 0bbc846: Fix recently-introduced expand-file-name bug


From: Paul Eggert
Subject: master 0bbc846: Fix recently-introduced expand-file-name bug
Date: Thu, 27 Aug 2020 17:49:44 -0400 (EDT)

branch: master
commit 0bbc84630f12e848e19c39dce01f3d14559bf70b
Author: Paul Eggert <eggert@cs.ucla.edu>
Commit: Paul Eggert <eggert@cs.ucla.edu>

    Fix recently-introduced expand-file-name bug
    
    The bug was that (expand-file-name "~") returned something
    like "/home/eggert/" instead of "/home/eggert".
    Problem     reported by Mattias Engdegård (Bug#26911#27).
    * src/fileio.c (Fexpand_file_name): When concatenating NEWDIR to
    NM, instead of stripping trailing slashes from NEWDIR (which can
    turn non-symlinks into symlinks), strip leading slashes from NM.
    This also simplifies the code by removing no-longer-needed DOS_NT
    special-casing.  Also, remove an unnecessary ‘target[length] = 0;’
    as that byte will be overwritten by the next memcpy anyway.
    * test/src/fileio-tests.el (fileio-tests--HOME-trailing-slash):
    New test.
---
 src/fileio.c             | 38 +++++++++++++-------------------------
 test/src/fileio-tests.el |  8 ++++++++
 2 files changed, 21 insertions(+), 25 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index b70dff1..47e5e46 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -827,9 +827,9 @@ the root directory.  */)
   ptrdiff_t tlen;
 #ifdef DOS_NT
   int drive = 0;
-  bool collapse_newdir = true;
   bool is_escaped = 0;
 #endif /* DOS_NT */
+  bool collapse_newdir = true;
   ptrdiff_t length, nbytes;
   Lisp_Object handler, result, handled_name;
   bool multibyte;
@@ -1183,9 +1183,7 @@ the root directory.  */)
              newdir = SSDATA (hdir);
              newdirlim = newdir + SBYTES (hdir);
            }
-#ifdef DOS_NT
          collapse_newdir = false;
-#endif
        }
       else                     /* ~user/filename */
        {
@@ -1205,9 +1203,7 @@ the root directory.  */)
 
              while (*++nm && !IS_DIRECTORY_SEP (*nm))
                continue;
-#ifdef DOS_NT
              collapse_newdir = false;
-#endif
            }
 
          /* If we don't find a user of that name, leave the name
@@ -1374,12 +1370,7 @@ the root directory.  */)
     }
 #endif /* DOS_NT */
 
-  /* Ignore any slash at the end of newdir, unless newdir is
-     just "/" or "//".  */
   length = newdirlim - newdir;
-  while (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1])
-        && ! (length == 2 && IS_DIRECTORY_SEP (newdir[0])))
-    length--;
 
   /* Now concatenate the directory and name to new space in the stack frame.  
*/
   tlen = length + file_name_as_directory_slop + (nmlim - nm) + 1;
@@ -1398,25 +1389,22 @@ the root directory.  */)
 
   if (newdir)
     {
-      if (IS_DIRECTORY_SEP (nm[0]))
+      if (!collapse_newdir)
        {
-#ifdef DOS_NT
-         /* If newdir is effectively "C:/", then the drive letter will have
-            been stripped and newdir will be "/".  Concatenating with an
-            absolute directory in nm produces "//", which will then be
-            incorrectly treated as a network share.  Ignore newdir in
-            this case (keeping the drive letter).  */
-         if (!(drive && nm[0] && IS_DIRECTORY_SEP (newdir[0])
-               && newdir[1] == '\0'))
-#endif
-           {
-             memcpy (target, newdir, length);
-             target[length] = 0;
-             nbytes = length;
-           }
+         /* With ~ or ~user, leave NEWDIR as-is to avoid transforming
+            it from a symlink (or a regular file!) into a directory.  */
+         memcpy (target, newdir, length);
+         nbytes = length;
        }
       else
        nbytes = file_name_as_directory (target, newdir, length, multibyte);
+
+      /* If TARGET ends in a directory separator, omit leading
+        directory separators from NM so that concatenating a TARGET "/"
+        to an NM "/foo" does not result in the incorrect "//foo".  */
+      if (nbytes && IS_DIRECTORY_SEP (target[nbytes - 1]))
+       while (IS_DIRECTORY_SEP (nm[0]))
+         nm++;
     }
 
   memcpy (target + nbytes, nm, nmlim - nm + 1);
diff --git a/test/src/fileio-tests.el b/test/src/fileio-tests.el
index 1516590..8b76912 100644
--- a/test/src/fileio-tests.el
+++ b/test/src/fileio-tests.el
@@ -108,6 +108,14 @@ Also check that an encoding error can appear in a symlink."
       (should (equal (expand-file-name "~/bar") "x:/foo/bar")))
     (setenv "HOME" old-home)))
 
+(ert-deftest fileio-tests--HOME-trailing-slash ()
+  "Test that expand-file-name of \"~\" respects trailing slash."
+  (let ((old-home (getenv "HOME")))
+    (dolist (home '("/a/b/c" "/a/b/c/"))
+      (setenv "HOME" home)
+      (should (equal (expand-file-name "~") (expand-file-name home))))
+    (setenv "HOME" old-home)))
+
 (ert-deftest fileio-tests--expand-file-name-trailing-slash ()
   (dolist (fooslashalias '("foo/" "foo//" "foo/." "foo//." "foo///././."
                            "foo/a/.."))



reply via email to

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