aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2019-07-24 14:28:13 -0700
committerPaul Eggert2019-07-24 14:33:02 -0700
commita5063aa8b174db286a0e83b8ffdd4e65c521f733 (patch)
treedc439d78ecef638817f98cb7e43868fa2ab7b856 /src
parente089c3141a51bf70b91da21a01cdb4be0b63c08d (diff)
downloademacs-a5063aa8b174db286a0e83b8ffdd4e65c521f733.tar.gz
emacs-a5063aa8b174db286a0e83b8ffdd4e65c521f733.zip
Do not treat ~nosuchuser as an absolute file name
Derived from Ken Brown’s patch (Bug#36502#97). * doc/lispref/files.texi (Relative File Names): * etc/NEWS: Document this. * src/fileio.c (user_homedir): New function. (Fexpand_file_name, file_name_absolute_p): Use it. (search_embedded_absfilename): Simplify via file_name_absolute_p. * test/src/fileio-tests.el (fileio-tests--no-such-user): New test.
Diffstat (limited to 'src')
-rw-r--r--src/fileio.c121
1 files changed, 55 insertions, 66 deletions
diff --git a/src/fileio.c b/src/fileio.c
index e4269b96a37..d1a7f39ac95 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -744,6 +744,31 @@ file_name_absolute_no_tilde_p (Lisp_Object name)
744 return IS_ABSOLUTE_FILE_NAME (SSDATA (name)); 744 return IS_ABSOLUTE_FILE_NAME (SSDATA (name));
745} 745}
746 746
747/* Return the home directory of the user NAME, or a null pointer if
748 NAME is empty or the user does not exist or the user's home
749 directory is not an absolute file name. NAME is an array of bytes
750 that continues up to (but not including) the next NUL byte or
751 directory separator. The returned string lives in storage good
752 until the next call to this or similar functions. */
753static char *
754user_homedir (char const *name)
755{
756 ptrdiff_t length;
757 for (length = 0; name[length] && !IS_DIRECTORY_SEP (name[length]); length++)
758 continue;
759 if (length == 0)
760 return NULL;
761 USE_SAFE_ALLOCA;
762 char *p = SAFE_ALLOCA (length + 1);
763 memcpy (p, name, length);
764 p[length] = 0;
765 struct passwd *pw = getpwnam (p);
766 SAFE_FREE ();
767 if (!pw || (pw->pw_dir && !IS_ABSOLUTE_FILE_NAME (pw->pw_dir)))
768 return NULL;
769 return pw->pw_dir;
770}
771
747DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0, 772DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
748 doc: /* Convert filename NAME to absolute, and canonicalize it. 773 doc: /* Convert filename NAME to absolute, and canonicalize it.
749Second arg DEFAULT-DIRECTORY is directory to start with if NAME is relative 774Second arg DEFAULT-DIRECTORY is directory to start with if NAME is relative
@@ -788,7 +813,6 @@ the root directory. */)
788 char *target; 813 char *target;
789 814
790 ptrdiff_t tlen; 815 ptrdiff_t tlen;
791 struct passwd *pw;
792#ifdef DOS_NT 816#ifdef DOS_NT
793 int drive = 0; 817 int drive = 0;
794 bool collapse_newdir = true; 818 bool collapse_newdir = true;
@@ -1153,39 +1177,29 @@ the root directory. */)
1153 } 1177 }
1154 else /* ~user/filename */ 1178 else /* ~user/filename */
1155 { 1179 {
1156 char *o, *p; 1180 char *nmhome = user_homedir (nm + 1);
1157 for (p = nm; *p && !IS_DIRECTORY_SEP (*p); p++) 1181 if (nmhome)
1158 continue;
1159 o = SAFE_ALLOCA (p - nm + 1);
1160 memcpy (o, nm, p - nm);
1161 o[p - nm] = 0;
1162
1163 block_input ();
1164 pw = getpwnam (o + 1);
1165 unblock_input ();
1166 if (pw)
1167 { 1182 {
1168 Lisp_Object tem; 1183 ptrdiff_t nmhomelen = strlen (nmhome);
1169 1184 newdir = nmhome;
1170 newdir = pw->pw_dir; 1185 newdirlim = newdir + nmhomelen;
1171 /* `getpwnam' may return a unibyte string, which will 1186 if (multibyte)
1172 bite us when we expect the directory to be multibyte. */
1173 tem = make_unibyte_string (newdir, strlen (newdir));
1174 newdirlim = newdir + SBYTES (tem);
1175 if (multibyte && !STRING_MULTIBYTE (tem))
1176 { 1187 {
1177 hdir = DECODE_FILE (tem); 1188 AUTO_STRING_WITH_LEN (lisp_nmhome, nmhome, nmhomelen);
1189 hdir = DECODE_FILE (lisp_nmhome);
1178 newdir = SSDATA (hdir); 1190 newdir = SSDATA (hdir);
1179 newdirlim = newdir + SBYTES (hdir); 1191 newdirlim = newdir + SBYTES (hdir);
1180 } 1192 }
1181 nm = p; 1193
1194 while (*++nm && !IS_DIRECTORY_SEP (*nm))
1195 continue;
1182#ifdef DOS_NT 1196#ifdef DOS_NT
1183 collapse_newdir = false; 1197 collapse_newdir = false;
1184#endif 1198#endif
1185 } 1199 }
1186 1200
1187 /* If we don't find a user of that name, leave the name 1201 /* If we don't find a user of that name, leave the name
1188 unchanged; don't move nm forward to p. */ 1202 unchanged. */
1189 } 1203 }
1190 } 1204 }
1191 1205
@@ -1667,18 +1681,6 @@ See also the function `substitute-in-file-name'.")
1667} 1681}
1668#endif 1682#endif
1669 1683
1670bool
1671file_name_absolute_p (const char *filename)
1672{
1673 return
1674 (IS_DIRECTORY_SEP (*filename) || *filename == '~'
1675#ifdef DOS_NT
1676 || (IS_DRIVE (*filename) && IS_DEVICE_SEP (filename[1])
1677 && IS_DIRECTORY_SEP (filename[2]))
1678#endif
1679 );
1680}
1681
1682/* Put into BUF the concatenation of DIR and FILE, with an intervening 1684/* Put into BUF the concatenation of DIR and FILE, with an intervening
1683 directory separator if needed. Return a pointer to the NUL byte 1685 directory separator if needed. Return a pointer to the NUL byte
1684 at the end of the concatenated string. */ 1686 at the end of the concatenated string. */
@@ -1774,7 +1776,10 @@ get_homedir (void)
1774 return ahome; 1776 return ahome;
1775} 1777}
1776 1778
1777/* If /~ or // appears, discard everything through first slash. */ 1779/* If a directory separator followed by an absolute file name (e.g.,
1780 "//foo", "/~", "/~someuser") appears in NM, return the address of
1781 the absolute file name. Otherwise return NULL. ENDP is the
1782 address of the null byte at the end of NM. */
1778static char * 1783static char *
1779search_embedded_absfilename (char *nm, char *endp) 1784search_embedded_absfilename (char *nm, char *endp)
1780{ 1785{
@@ -1784,34 +1789,8 @@ search_embedded_absfilename (char *nm, char *endp)
1784 && !IS_DIRECTORY_SEP (p[1])); 1789 && !IS_DIRECTORY_SEP (p[1]));
1785#endif 1790#endif
1786 for (; p < endp; p++) 1791 for (; p < endp; p++)
1787 { 1792 if (IS_DIRECTORY_SEP (p[-1]) && file_name_absolute_p (p))
1788 if (IS_DIRECTORY_SEP (p[-1]) && file_name_absolute_p (p)) 1793 return p;
1789 {
1790 char *s;
1791 for (s = p; *s && !IS_DIRECTORY_SEP (*s); s++)
1792 continue;
1793 if (p[0] == '~' && s > p + 1) /* We've got "/~something/". */
1794 {
1795 USE_SAFE_ALLOCA;
1796 char *o = SAFE_ALLOCA (s - p + 1);
1797 struct passwd *pw;
1798 memcpy (o, p, s - p);
1799 o [s - p] = 0;
1800
1801 /* If we have ~user and `user' exists, discard
1802 everything up to ~. But if `user' does not exist, leave
1803 ~user alone, it might be a literal file name. */
1804 block_input ();
1805 pw = getpwnam (o + 1);
1806 unblock_input ();
1807 SAFE_FREE ();
1808 if (pw)
1809 return p;
1810 }
1811 else
1812 return p;
1813 }
1814 }
1815 return NULL; 1794 return NULL;
1816} 1795}
1817 1796
@@ -2696,13 +2675,23 @@ This happens for interactive use with M-x. */)
2696 2675
2697DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p, 2676DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p,
2698 1, 1, 0, 2677 1, 1, 0,
2699 doc: /* Return t if FILENAME is an absolute file name or starts with `~'. 2678 doc: /* Return t if FILENAME is an absolute file name.
2700On Unix, absolute file names start with `/'. */) 2679On Unix, absolute file names start with `/'. In Emacs, an absolute
2680file name can also start with an initial `~' or `~USER' component,
2681where USER is a valid login name. */)
2701 (Lisp_Object filename) 2682 (Lisp_Object filename)
2702{ 2683{
2703 CHECK_STRING (filename); 2684 CHECK_STRING (filename);
2704 return file_name_absolute_p (SSDATA (filename)) ? Qt : Qnil; 2685 return file_name_absolute_p (SSDATA (filename)) ? Qt : Qnil;
2705} 2686}
2687
2688bool
2689file_name_absolute_p (char const *filename)
2690{
2691 return (IS_ABSOLUTE_FILE_NAME (filename)
2692 || (filename[0] == '~'
2693 && (!filename[1] || user_homedir (&filename[1]))));
2694}
2706 2695
2707DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0, 2696DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0,
2708 doc: /* Return t if file FILENAME exists (whether or not you can read it). 2697 doc: /* Return t if file FILENAME exists (whether or not you can read it).