aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2020-09-03 20:16:33 +0300
committerEli Zaretskii2020-09-03 20:16:33 +0300
commita4e45a13b65c496a0c53b58992a4be2e3d923325 (patch)
tree6099898ab7c01152d43130432f4e2fccb7dac855 /src
parent8cb15183aa8faba4af52d7b87e5ee4dcd3b1104f (diff)
downloademacs-a4e45a13b65c496a0c53b58992a4be2e3d923325.tar.gz
emacs-a4e45a13b65c496a0c53b58992a4be2e3d923325.zip
Fix 'expand-file-name' for remote files
This reverts most of commit 14fb657ba82da346d36f05f88da26f1c5498b798 and its followup fixes, and instead fixes the original bugs in a different manner that doesn't affect any unrelated use cases. As part of this, the code which caused 'expand-file-name' to enforce a trailing slash on expanded directories is removed, as this kind of semantic processing is outside of 'expand-file-name's scope. * src/fileio.c (Fexpand_file_name): If expanding default_directory yields a remote file name, call its handlers. (Bug#26911) (Bug#34834) * doc/lispref/files.texi (File Name Expansion): Remove the requirement that expanding a directory name yields a directory name, i.e. that the expansion must end in a slash. * etc/NEWS: Remove the announcement of the changed behavior of 'expand-file-name' wrt trailing slashes. * test/src/fileio-tests.el (fileio-tests--HOME-trailing-slash) (fileio-tests--expand-file-name-trailing-slash): Remove tests. * test/lisp/net/tramp-tests.el (tramp-test05-expand-file-name): No need to expect different results in Emacs 28 and later.
Diffstat (limited to 'src')
-rw-r--r--src/fileio.c86
1 files changed, 30 insertions, 56 deletions
diff --git a/src/fileio.c b/src/fileio.c
index c91af36fdf6..1e4ca82e5f3 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -827,9 +827,9 @@ the root directory. */)
827 ptrdiff_t tlen; 827 ptrdiff_t tlen;
828#ifdef DOS_NT 828#ifdef DOS_NT
829 int drive = 0; 829 int drive = 0;
830 bool collapse_newdir = true;
830 bool is_escaped = 0; 831 bool is_escaped = 0;
831#endif /* DOS_NT */ 832#endif /* DOS_NT */
832 bool collapse_newdir = true;
833 ptrdiff_t length, nbytes; 833 ptrdiff_t length, nbytes;
834 Lisp_Object handler, result, handled_name; 834 Lisp_Object handler, result, handled_name;
835 bool multibyte; 835 bool multibyte;
@@ -947,6 +947,22 @@ the root directory. */)
947 ) 947 )
948 { 948 {
949 default_directory = Fexpand_file_name (default_directory, Qnil); 949 default_directory = Fexpand_file_name (default_directory, Qnil);
950
951 /* The above expansion might have produced a remote file name,
952 so give the handlers one last chance to DTRT. This can
953 happen when both NAME and DEFAULT-DIRECTORY arguments are
954 relative file names, and the buffer's default-directory is
955 remote. */
956 handler = Ffind_file_name_handler (default_directory,
957 Qexpand_file_name);
958 if (!NILP (handler))
959 {
960 handled_name = call3 (handler, Qexpand_file_name,
961 name, default_directory);
962 if (STRINGP (handled_name))
963 return handled_name;
964 error ("Invalid handler in `file-name-handler-alist'");
965 }
950 } 966 }
951 } 967 }
952 multibyte = STRING_MULTIBYTE (name); 968 multibyte = STRING_MULTIBYTE (name);
@@ -1065,7 +1081,7 @@ the root directory. */)
1065#endif /* WINDOWSNT */ 1081#endif /* WINDOWSNT */
1066#endif /* DOS_NT */ 1082#endif /* DOS_NT */
1067 1083
1068 /* If nm is absolute, look for "/./" or "/../" or "//" sequences; if 1084 /* If nm is absolute, look for `/./' or `/../' or `//''sequences; if
1069 none are found, we can probably return right away. We will avoid 1085 none are found, we can probably return right away. We will avoid
1070 allocating a new string if name is already fully expanded. */ 1086 allocating a new string if name is already fully expanded. */
1071 if ( 1087 if (
@@ -1183,7 +1199,9 @@ the root directory. */)
1183 newdir = SSDATA (hdir); 1199 newdir = SSDATA (hdir);
1184 newdirlim = newdir + SBYTES (hdir); 1200 newdirlim = newdir + SBYTES (hdir);
1185 } 1201 }
1202#ifdef DOS_NT
1186 collapse_newdir = false; 1203 collapse_newdir = false;
1204#endif
1187 } 1205 }
1188 else /* ~user/filename */ 1206 else /* ~user/filename */
1189 { 1207 {
@@ -1203,7 +1221,9 @@ the root directory. */)
1203 1221
1204 while (*++nm && !IS_DIRECTORY_SEP (*nm)) 1222 while (*++nm && !IS_DIRECTORY_SEP (*nm))
1205 continue; 1223 continue;
1224#ifdef DOS_NT
1206 collapse_newdir = false; 1225 collapse_newdir = false;
1226#endif
1207 } 1227 }
1208 1228
1209 /* If we don't find a user of that name, leave the name 1229 /* If we don't find a user of that name, leave the name
@@ -1370,15 +1390,12 @@ the root directory. */)
1370 } 1390 }
1371#endif /* DOS_NT */ 1391#endif /* DOS_NT */
1372 1392
1373 length = newdirlim - newdir;
1374
1375#ifdef DOS_NT
1376 /* Ignore any slash at the end of newdir, unless newdir is 1393 /* Ignore any slash at the end of newdir, unless newdir is
1377 just "/" or "//". */ 1394 just "/" or "//". */
1395 length = newdirlim - newdir;
1378 while (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1]) 1396 while (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1])
1379 && ! (length == 2 && IS_DIRECTORY_SEP (newdir[0]))) 1397 && ! (length == 2 && IS_DIRECTORY_SEP (newdir[0])))
1380 length--; 1398 length--;
1381#endif
1382 1399
1383 /* Now concatenate the directory and name to new space in the stack frame. */ 1400 /* Now concatenate the directory and name to new space in the stack frame. */
1384 tlen = length + file_name_as_directory_slop + (nmlim - nm) + 1; 1401 tlen = length + file_name_as_directory_slop + (nmlim - nm) + 1;
@@ -1392,16 +1409,12 @@ the root directory. */)
1392#else /* not DOS_NT */ 1409#else /* not DOS_NT */
1393 target = SAFE_ALLOCA (tlen); 1410 target = SAFE_ALLOCA (tlen);
1394#endif /* not DOS_NT */ 1411#endif /* not DOS_NT */
1412 *target = 0;
1395 nbytes = 0; 1413 nbytes = 0;
1396 1414
1397 if (newdir) 1415 if (newdir)
1398 { 1416 {
1399#ifndef DOS_NT 1417 if (nm[0] == 0 || IS_DIRECTORY_SEP (nm[0]))
1400 bool treat_as_absolute = !collapse_newdir;
1401#else
1402 bool treat_as_absolute = !nm[0] || IS_DIRECTORY_SEP (nm[0]);
1403#endif
1404 if (treat_as_absolute)
1405 { 1418 {
1406#ifdef DOS_NT 1419#ifdef DOS_NT
1407 /* If newdir is effectively "C:/", then the drive letter will have 1420 /* If newdir is effectively "C:/", then the drive letter will have
@@ -1413,23 +1426,13 @@ the root directory. */)
1413 && newdir[1] == '\0')) 1426 && newdir[1] == '\0'))
1414#endif 1427#endif
1415 { 1428 {
1416 /* With ~ or ~user, leave NEWDIR as-is to avoid transforming
1417 it from a symlink (or a regular file!) into a directory. */
1418 memcpy (target, newdir, length); 1429 memcpy (target, newdir, length);
1430 target[length] = 0;
1419 nbytes = length; 1431 nbytes = length;
1420 } 1432 }
1421 } 1433 }
1422 else 1434 else
1423 nbytes = file_name_as_directory (target, newdir, length, multibyte); 1435 nbytes = file_name_as_directory (target, newdir, length, multibyte);
1424
1425#ifndef DOS_NT
1426 /* If TARGET ends in a directory separator, omit leading
1427 directory separators from NM so that concatenating a TARGET "/"
1428 to an NM "/foo" does not result in the incorrect "//foo". */
1429 if (nbytes && IS_DIRECTORY_SEP (target[nbytes - 1]))
1430 while (IS_DIRECTORY_SEP (nm[0]))
1431 nm++;
1432#endif
1433 } 1436 }
1434 1437
1435 memcpy (target + nbytes, nm, nmlim - nm + 1); 1438 memcpy (target + nbytes, nm, nmlim - nm + 1);
@@ -1446,20 +1449,6 @@ the root directory. */)
1446 { 1449 {
1447 *o++ = *p++; 1450 *o++ = *p++;
1448 } 1451 }
1449#ifndef DOS_NT
1450 else if (p[1] == '.' && IS_DIRECTORY_SEP (p[2]))
1451 {
1452 /* Replace "/./" with "/". */
1453 p += 2;
1454 }
1455 else if (p[1] == '.' && !p[2])
1456 {
1457 /* At the end of the file name, replace "/." with "/".
1458 The trailing "/" is for symlinks. */
1459 *o++ = *p;
1460 p += 2;
1461 }
1462#else
1463 else if (p[1] == '.' 1452 else if (p[1] == '.'
1464 && (IS_DIRECTORY_SEP (p[2]) 1453 && (IS_DIRECTORY_SEP (p[2])
1465 || p[2] == 0)) 1454 || p[2] == 0))
@@ -1470,7 +1459,6 @@ the root directory. */)
1470 *o++ = *p; 1459 *o++ = *p;
1471 p += 2; 1460 p += 2;
1472 } 1461 }
1473#endif
1474 else if (p[1] == '.' && p[2] == '.' 1462 else if (p[1] == '.' && p[2] == '.'
1475 /* `/../' is the "superroot" on certain file systems. 1463 /* `/../' is the "superroot" on certain file systems.
1476 Turned off on DOS_NT systems because they have no 1464 Turned off on DOS_NT systems because they have no
@@ -1484,35 +1472,21 @@ the root directory. */)
1484#endif 1472#endif
1485 && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0)) 1473 && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0))
1486 { 1474 {
1487#ifndef DOS_NT 1475#ifdef WINDOWSNT
1488 while (o != target)
1489 {
1490 o--;
1491 if (IS_DIRECTORY_SEP (*o))
1492 {
1493 /* Keep "/" at the end of the name, for symlinks. */
1494 o += p[3] == 0;
1495
1496 break;
1497 }
1498 }
1499#else
1500# ifdef WINDOWSNT
1501 char *prev_o = o; 1476 char *prev_o = o;
1502# endif 1477#endif
1503 while (o != target && (--o, !IS_DIRECTORY_SEP (*o))) 1478 while (o != target && (--o, !IS_DIRECTORY_SEP (*o)))
1504 continue; 1479 continue;
1505# ifdef WINDOWSNT 1480#ifdef WINDOWSNT
1506 /* Don't go below server level in UNC filenames. */ 1481 /* Don't go below server level in UNC filenames. */
1507 if (o == target + 1 && IS_DIRECTORY_SEP (*o) 1482 if (o == target + 1 && IS_DIRECTORY_SEP (*o)
1508 && IS_DIRECTORY_SEP (*target)) 1483 && IS_DIRECTORY_SEP (*target))
1509 o = prev_o; 1484 o = prev_o;
1510 else 1485 else
1511# endif 1486#endif
1512 /* Keep initial / only if this is the whole name. */ 1487 /* Keep initial / only if this is the whole name. */
1513 if (o == target && IS_ANY_SEP (*o) && p[3] == 0) 1488 if (o == target && IS_ANY_SEP (*o) && p[3] == 0)
1514 ++o; 1489 ++o;
1515#endif
1516 p += 3; 1490 p += 3;
1517 } 1491 }
1518 else if (IS_DIRECTORY_SEP (p[1]) 1492 else if (IS_DIRECTORY_SEP (p[1])