aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2020-08-26 13:25:35 -0700
committerPaul Eggert2020-08-26 13:27:56 -0700
commit14fb657ba82da346d36f05f88da26f1c5498b798 (patch)
treeca60dbe7a621ad7a5d00b1a28f489caf15e4896a /src
parentff864be694247e5f6c8732afcbaeb1c0a8a8a124 (diff)
downloademacs-14fb657ba82da346d36f05f88da26f1c5498b798.tar.gz
emacs-14fb657ba82da346d36f05f88da26f1c5498b798.zip
Fix expand-file-name symlink-to-dir bug
Problem reported by Yegor Timoshenko (Bug#26911), and I ran into it myself recently in normal-top-level. * doc/lispref/files.texi (File Name Expansion), etc/NEWS: Mention this. * src/fileio.c (Fexpand_file_name): Expand "/a/b/." to "/a/b/" not "/a/b", to avoid misinterpreting a symlink "/a/b". Similarly, expand "/a/b/c/.." to "/a/b/" not "/a/b". * test/lisp/net/tramp-tests.el (tramp-test05-expand-file-name): Adjust to match new behavior. (tramp-test05-expand-file-name-relative): This test now succeeds, at least on Fedora 31. * test/src/fileio-tests.el: (fileio-tests--expand-file-name-trailing-slash) New test.
Diffstat (limited to 'src')
-rw-r--r--src/fileio.c37
1 files changed, 22 insertions, 15 deletions
diff --git a/src/fileio.c b/src/fileio.c
index 37072d9b6bd..b70dff1c22c 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -1065,7 +1065,7 @@ the root directory. */)
1065#endif /* WINDOWSNT */ 1065#endif /* WINDOWSNT */
1066#endif /* DOS_NT */ 1066#endif /* DOS_NT */
1067 1067
1068 /* If nm is absolute, look for `/./' or `/../' or `//''sequences; if 1068 /* If nm is absolute, look for "/./" or "/../" or "//" sequences; if
1069 none are found, we can probably return right away. We will avoid 1069 none are found, we can probably return right away. We will avoid
1070 allocating a new string if name is already fully expanded. */ 1070 allocating a new string if name is already fully expanded. */
1071 if ( 1071 if (
@@ -1398,7 +1398,7 @@ the root directory. */)
1398 1398
1399 if (newdir) 1399 if (newdir)
1400 { 1400 {
1401 if (nm[0] == 0 || IS_DIRECTORY_SEP (nm[0])) 1401 if (IS_DIRECTORY_SEP (nm[0]))
1402 { 1402 {
1403#ifdef DOS_NT 1403#ifdef DOS_NT
1404 /* If newdir is effectively "C:/", then the drive letter will have 1404 /* If newdir is effectively "C:/", then the drive letter will have
@@ -1433,14 +1433,16 @@ the root directory. */)
1433 { 1433 {
1434 *o++ = *p++; 1434 *o++ = *p++;
1435 } 1435 }
1436 else if (p[1] == '.' 1436 else if (p[1] == '.' && IS_DIRECTORY_SEP (p[2]))
1437 && (IS_DIRECTORY_SEP (p[2])
1438 || p[2] == 0))
1439 { 1437 {
1440 /* If "/." is the entire filename, keep the "/". Otherwise, 1438 /* Replace "/./" with "/". */
1441 just delete the whole "/.". */ 1439 p += 2;
1442 if (o == target && p[2] == '\0') 1440 }
1443 *o++ = *p; 1441 else if (p[1] == '.' && !p[2])
1442 {
1443 /* At the end of the file name, replace "/." with "/".
1444 The trailing "/" is for symlinks. */
1445 *o++ = *p;
1444 p += 2; 1446 p += 2;
1445 } 1447 }
1446 else if (p[1] == '.' && p[2] == '.' 1448 else if (p[1] == '.' && p[2] == '.'
@@ -1459,18 +1461,23 @@ the root directory. */)
1459#ifdef WINDOWSNT 1461#ifdef WINDOWSNT
1460 char *prev_o = o; 1462 char *prev_o = o;
1461#endif 1463#endif
1462 while (o != target && (--o, !IS_DIRECTORY_SEP (*o))) 1464 while (o != target)
1463 continue; 1465 {
1466 o--;
1467 if (IS_DIRECTORY_SEP (*o))
1468 {
1469 /* Keep "/" at the end of the name, for symlinks. */
1470 o += p[3] == 0;
1471
1472 break;
1473 }
1474 }
1464#ifdef WINDOWSNT 1475#ifdef WINDOWSNT
1465 /* Don't go below server level in UNC filenames. */ 1476 /* Don't go below server level in UNC filenames. */
1466 if (o == target + 1 && IS_DIRECTORY_SEP (*o) 1477 if (o == target + 1 && IS_DIRECTORY_SEP (*o)
1467 && IS_DIRECTORY_SEP (*target)) 1478 && IS_DIRECTORY_SEP (*target))
1468 o = prev_o; 1479 o = prev_o;
1469 else
1470#endif 1480#endif
1471 /* Keep initial / only if this is the whole name. */
1472 if (o == target && IS_ANY_SEP (*o) && p[3] == 0)
1473 ++o;
1474 p += 3; 1481 p += 3;
1475 } 1482 }
1476 else if (IS_DIRECTORY_SEP (p[1]) 1483 else if (IS_DIRECTORY_SEP (p[1])