aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2020-08-27 14:46:52 -0700
committerPaul Eggert2020-08-27 14:49:38 -0700
commit0bbc84630f12e848e19c39dce01f3d14559bf70b (patch)
tree8c2e252c0ea6ef65667f4df46c468ef2f0b50bc6 /src
parent1153b238aef5a48bbecd5a58cd6a14dae9ec1d2f (diff)
downloademacs-0bbc84630f12e848e19c39dce01f3d14559bf70b.tar.gz
emacs-0bbc84630f12e848e19c39dce01f3d14559bf70b.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/fileio.c38
1 files changed, 13 insertions, 25 deletions
diff --git a/src/fileio.c b/src/fileio.c
index b70dff1c22c..47e5e46a003 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;
831 bool is_escaped = 0; 830 bool is_escaped = 0;
832#endif /* DOS_NT */ 831#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;
@@ -1183,9 +1183,7 @@ the root directory. */)
1183 newdir = SSDATA (hdir); 1183 newdir = SSDATA (hdir);
1184 newdirlim = newdir + SBYTES (hdir); 1184 newdirlim = newdir + SBYTES (hdir);
1185 } 1185 }
1186#ifdef DOS_NT
1187 collapse_newdir = false; 1186 collapse_newdir = false;
1188#endif
1189 } 1187 }
1190 else /* ~user/filename */ 1188 else /* ~user/filename */
1191 { 1189 {
@@ -1205,9 +1203,7 @@ the root directory. */)
1205 1203
1206 while (*++nm && !IS_DIRECTORY_SEP (*nm)) 1204 while (*++nm && !IS_DIRECTORY_SEP (*nm))
1207 continue; 1205 continue;
1208#ifdef DOS_NT
1209 collapse_newdir = false; 1206 collapse_newdir = false;
1210#endif
1211 } 1207 }
1212 1208
1213 /* If we don't find a user of that name, leave the name 1209 /* If we don't find a user of that name, leave the name
@@ -1374,12 +1370,7 @@ the root directory. */)
1374 } 1370 }
1375#endif /* DOS_NT */ 1371#endif /* DOS_NT */
1376 1372
1377 /* Ignore any slash at the end of newdir, unless newdir is
1378 just "/" or "//". */
1379 length = newdirlim - newdir; 1373 length = newdirlim - newdir;
1380 while (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1])
1381 && ! (length == 2 && IS_DIRECTORY_SEP (newdir[0])))
1382 length--;
1383 1374
1384 /* Now concatenate the directory and name to new space in the stack frame. */ 1375 /* Now concatenate the directory and name to new space in the stack frame. */
1385 tlen = length + file_name_as_directory_slop + (nmlim - nm) + 1; 1376 tlen = length + file_name_as_directory_slop + (nmlim - nm) + 1;
@@ -1398,25 +1389,22 @@ the root directory. */)
1398 1389
1399 if (newdir) 1390 if (newdir)
1400 { 1391 {
1401 if (IS_DIRECTORY_SEP (nm[0])) 1392 if (!collapse_newdir)
1402 { 1393 {
1403#ifdef DOS_NT 1394 /* With ~ or ~user, leave NEWDIR as-is to avoid transforming
1404 /* If newdir is effectively "C:/", then the drive letter will have 1395 it from a symlink (or a regular file!) into a directory. */
1405 been stripped and newdir will be "/". Concatenating with an 1396 memcpy (target, newdir, length);
1406 absolute directory in nm produces "//", which will then be 1397 nbytes = length;
1407 incorrectly treated as a network share. Ignore newdir in
1408 this case (keeping the drive letter). */
1409 if (!(drive && nm[0] && IS_DIRECTORY_SEP (newdir[0])
1410 && newdir[1] == '\0'))
1411#endif
1412 {
1413 memcpy (target, newdir, length);
1414 target[length] = 0;
1415 nbytes = length;
1416 }
1417 } 1398 }
1418 else 1399 else
1419 nbytes = file_name_as_directory (target, newdir, length, multibyte); 1400 nbytes = file_name_as_directory (target, newdir, length, multibyte);
1401
1402 /* If TARGET ends in a directory separator, omit leading
1403 directory separators from NM so that concatenating a TARGET "/"
1404 to an NM "/foo" does not result in the incorrect "//foo". */
1405 if (nbytes && IS_DIRECTORY_SEP (target[nbytes - 1]))
1406 while (IS_DIRECTORY_SEP (nm[0]))
1407 nm++;
1420 } 1408 }
1421 1409
1422 memcpy (target + nbytes, nm, nmlim - nm + 1); 1410 memcpy (target + nbytes, nm, nmlim - nm + 1);