aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2018-11-13 09:29:14 -0800
committerPaul Eggert2018-11-13 09:32:50 -0800
commit900276502fbb4dcabdabc5d7d24b4bc5645f2cf3 (patch)
tree4d6c17f5b3cea0f4d5dfbc7243eb6495269a7e56
parentce1fb157e840fd292c3db4632831c4514a663890 (diff)
downloademacs-900276502fbb4dcabdabc5d7d24b4bc5645f2cf3.tar.gz
emacs-900276502fbb4dcabdabc5d7d24b4bc5645f2cf3.zip
Act like POSIX sh if $HOME is relative
POSIX says sh ~/foo should act like $HOME/foo even if $HOME is relative, so be consistent with that (Bug#33255). * admin/merge-gnulib (GNULIB_MODULES): Add dosname. * src/buffer.c (init_buffer): Use emacs_wd to get initial working directory with slash appended if needed. (default-directory): Say it must be absolute. * src/emacs.c (emacs_wd): New global variable. (init_cmdargs): Dir arg is now char const *. (main): Set emacs_wd. * src/emacs.c (main) [NS_IMPL_COCOA]: * src/fileio.c (Fexpand_file_name): Use get_homedir instead of egetenv ("HOME"). * src/fileio.c: Include dosname.h, for IS_ABSOLUTE_FILE_NAME. (splice_dir_file, get_homedir): New functions. * src/xrdb.c (gethomedir): Remove. All callers changed to use get_homedir and splice_dir_file. * test/src/fileio-tests.el (fileio-tests--relative-HOME): New test.
-rwxr-xr-xadmin/merge-gnulib2
-rw-r--r--src/buffer.c28
-rw-r--r--src/emacs.c20
-rw-r--r--src/fileio.c62
-rw-r--r--src/lisp.h3
-rw-r--r--src/xrdb.c54
-rw-r--r--test/src/fileio-tests.el8
7 files changed, 103 insertions, 74 deletions
diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index 575e3fa74a7..84dcb0b8752 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -30,7 +30,7 @@ GNULIB_MODULES='
30 careadlinkat close-stream 30 careadlinkat close-stream
31 count-leading-zeros count-one-bits count-trailing-zeros 31 count-leading-zeros count-one-bits count-trailing-zeros
32 crypto/md5-buffer crypto/sha1-buffer crypto/sha256-buffer crypto/sha512-buffer 32 crypto/md5-buffer crypto/sha1-buffer crypto/sha256-buffer crypto/sha512-buffer
33 d-type diffseq dtoastr dtotimespec dup2 33 d-type diffseq dosname dtoastr dtotimespec dup2
34 environ execinfo explicit_bzero faccessat 34 environ execinfo explicit_bzero faccessat
35 fcntl fcntl-h fdatasync fdopendir 35 fcntl fcntl-h fdatasync fdopendir
36 filemode filevercmp flexmember fpieee fstatat fsusage fsync 36 filemode filevercmp flexmember fpieee fstatat fsusage fsync
diff --git a/src/buffer.c b/src/buffer.c
index ac2de7d19f2..90ef886b229 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -5268,9 +5268,7 @@ init_buffer_once (void)
5268void 5268void
5269init_buffer (int initialized) 5269init_buffer (int initialized)
5270{ 5270{
5271 char *pwd;
5272 Lisp_Object temp; 5271 Lisp_Object temp;
5273 ptrdiff_t len;
5274 5272
5275#ifdef USE_MMAP_FOR_BUFFERS 5273#ifdef USE_MMAP_FOR_BUFFERS
5276 if (initialized) 5274 if (initialized)
@@ -5324,7 +5322,7 @@ init_buffer (int initialized)
5324 if (NILP (BVAR (&buffer_defaults, enable_multibyte_characters))) 5322 if (NILP (BVAR (&buffer_defaults, enable_multibyte_characters)))
5325 Fset_buffer_multibyte (Qnil); 5323 Fset_buffer_multibyte (Qnil);
5326 5324
5327 pwd = emacs_get_current_dir_name (); 5325 char const *pwd = emacs_wd;
5328 5326
5329 if (!pwd) 5327 if (!pwd)
5330 { 5328 {
@@ -5336,22 +5334,16 @@ init_buffer (int initialized)
5336 { 5334 {
5337 /* Maybe this should really use some standard subroutine 5335 /* Maybe this should really use some standard subroutine
5338 whose definition is filename syntax dependent. */ 5336 whose definition is filename syntax dependent. */
5339 len = strlen (pwd); 5337 ptrdiff_t len = strlen (pwd);
5340 if (!(IS_DIRECTORY_SEP (pwd[len - 1]))) 5338 bool add_slash = ! IS_DIRECTORY_SEP (pwd[len - 1]);
5341 {
5342 /* Grow buffer to add directory separator and '\0'. */
5343 pwd = realloc (pwd, len + 2);
5344 if (!pwd)
5345 fatal ("get_current_dir_name: %s\n", strerror (errno));
5346 pwd[len] = DIRECTORY_SEP;
5347 pwd[len + 1] = '\0';
5348 len++;
5349 }
5350 5339
5351 /* At this moment, we still don't know how to decode the directory 5340 /* At this moment, we still don't know how to decode the directory
5352 name. So, we keep the bytes in unibyte form so that file I/O 5341 name. So, we keep the bytes in unibyte form so that file I/O
5353 routines correctly get the original bytes. */ 5342 routines correctly get the original bytes. */
5354 bset_directory (current_buffer, make_unibyte_string (pwd, len)); 5343 Lisp_Object dirname = make_unibyte_string (pwd, len + add_slash);
5344 if (add_slash)
5345 SSET (dirname, len, DIRECTORY_SEP);
5346 bset_directory (current_buffer, dirname);
5355 5347
5356 /* Add /: to the front of the name 5348 /* Add /: to the front of the name
5357 if it would otherwise be treated as magic. */ 5349 if it would otherwise be treated as magic. */
@@ -5372,8 +5364,6 @@ init_buffer (int initialized)
5372 5364
5373 temp = get_minibuffer (0); 5365 temp = get_minibuffer (0);
5374 bset_directory (XBUFFER (temp), BVAR (current_buffer, directory)); 5366 bset_directory (XBUFFER (temp), BVAR (current_buffer, directory));
5375
5376 free (pwd);
5377} 5367}
5378 5368
5379/* Similar to defvar_lisp but define a variable whose value is the 5369/* Similar to defvar_lisp but define a variable whose value is the
@@ -5706,8 +5696,8 @@ visual lines rather than logical lines. See the documentation of
5706 DEFVAR_PER_BUFFER ("default-directory", &BVAR (current_buffer, directory), 5696 DEFVAR_PER_BUFFER ("default-directory", &BVAR (current_buffer, directory),
5707 Qstringp, 5697 Qstringp,
5708 doc: /* Name of default directory of current buffer. 5698 doc: /* Name of default directory of current buffer.
5709It should be a directory name (as opposed to a directory file-name). 5699It should be an absolute directory name; on GNU and Unix systems,
5710On GNU and Unix systems, directory names end in a slash `/'. 5700these names start with `/' or `~' and end with `/'.
5711To interactively change the default directory, use command `cd'. */); 5701To interactively change the default directory, use command `cd'. */);
5712 5702
5713 DEFVAR_PER_BUFFER ("auto-fill-function", &BVAR (current_buffer, auto_fill_function), 5703 DEFVAR_PER_BUFFER ("auto-fill-function", &BVAR (current_buffer, auto_fill_function),
diff --git a/src/emacs.c b/src/emacs.c
index 512174d562e..acb4959bfea 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -204,6 +204,9 @@ HANDLE w32_daemon_event;
204char **initial_argv; 204char **initial_argv;
205int initial_argc; 205int initial_argc;
206 206
207/* The name of the working directory, or NULL if this info is unavailable. */
208char const *emacs_wd;
209
207static void sort_args (int argc, char **argv); 210static void sort_args (int argc, char **argv);
208static void syms_of_emacs (void); 211static void syms_of_emacs (void);
209 212
@@ -406,7 +409,7 @@ terminate_due_to_signal (int sig, int backtrace_limit)
406/* Code for dealing with Lisp access to the Unix command line. */ 409/* Code for dealing with Lisp access to the Unix command line. */
407 410
408static void 411static void
409init_cmdargs (int argc, char **argv, int skip_args, char *original_pwd) 412init_cmdargs (int argc, char **argv, int skip_args, char const *original_pwd)
410{ 413{
411 int i; 414 int i;
412 Lisp_Object name, dir, handler; 415 Lisp_Object name, dir, handler;
@@ -694,7 +697,7 @@ main (int argc, char **argv)
694 char *ch_to_dir = 0; 697 char *ch_to_dir = 0;
695 698
696 /* If we use --chdir, this records the original directory. */ 699 /* If we use --chdir, this records the original directory. */
697 char *original_pwd = 0; 700 char const *original_pwd = 0;
698 701
699 /* Record (approximately) where the stack begins. */ 702 /* Record (approximately) where the stack begins. */
700 stack_bottom = (char *) &stack_bottom_variable; 703 stack_bottom = (char *) &stack_bottom_variable;
@@ -794,6 +797,8 @@ main (int argc, char **argv)
794 exit (0); 797 exit (0);
795 } 798 }
796 799
800 emacs_wd = emacs_get_current_dir_name ();
801
797 if (argmatch (argv, argc, "-chdir", "--chdir", 4, &ch_to_dir, &skip_args)) 802 if (argmatch (argv, argc, "-chdir", "--chdir", 4, &ch_to_dir, &skip_args))
798 { 803 {
799#ifdef WINDOWSNT 804#ifdef WINDOWSNT
@@ -804,13 +809,14 @@ main (int argc, char **argv)
804 filename_from_ansi (ch_to_dir, newdir); 809 filename_from_ansi (ch_to_dir, newdir);
805 ch_to_dir = newdir; 810 ch_to_dir = newdir;
806#endif 811#endif
807 original_pwd = emacs_get_current_dir_name ();
808 if (chdir (ch_to_dir) != 0) 812 if (chdir (ch_to_dir) != 0)
809 { 813 {
810 fprintf (stderr, "%s: Can't chdir to %s: %s\n", 814 fprintf (stderr, "%s: Can't chdir to %s: %s\n",
811 argv[0], ch_to_dir, strerror (errno)); 815 argv[0], ch_to_dir, strerror (errno));
812 exit (1); 816 exit (1);
813 } 817 }
818 original_pwd = emacs_wd;
819 emacs_wd = emacs_get_current_dir_name ();
814 } 820 }
815 821
816#if defined (HAVE_SETRLIMIT) && defined (RLIMIT_STACK) && !defined (CYGWIN) 822#if defined (HAVE_SETRLIMIT) && defined (RLIMIT_STACK) && !defined (CYGWIN)
@@ -1289,21 +1295,21 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1289 { 1295 {
1290#ifdef NS_IMPL_COCOA 1296#ifdef NS_IMPL_COCOA
1291 /* Started from GUI? */ 1297 /* Started from GUI? */
1292 /* FIXME: Do the right thing if getenv returns NULL, or if 1298 /* FIXME: Do the right thing if get_homedir returns "", or if
1293 chdir fails. */ 1299 chdir fails. */
1294 if (! inhibit_window_system && ! isatty (STDIN_FILENO) && ! ch_to_dir) 1300 if (! inhibit_window_system && ! isatty (STDIN_FILENO) && ! ch_to_dir)
1295 chdir (getenv ("HOME")); 1301 chdir (get_homedir ());
1296 if (skip_args < argc) 1302 if (skip_args < argc)
1297 { 1303 {
1298 if (!strncmp (argv[skip_args], "-psn", 4)) 1304 if (!strncmp (argv[skip_args], "-psn", 4))
1299 { 1305 {
1300 skip_args += 1; 1306 skip_args += 1;
1301 if (! ch_to_dir) chdir (getenv ("HOME")); 1307 if (! ch_to_dir) chdir (get_homedir ());
1302 } 1308 }
1303 else if (skip_args+1 < argc && !strncmp (argv[skip_args+1], "-psn", 4)) 1309 else if (skip_args+1 < argc && !strncmp (argv[skip_args+1], "-psn", 4))
1304 { 1310 {
1305 skip_args += 2; 1311 skip_args += 2;
1306 if (! ch_to_dir) chdir (getenv ("HOME")); 1312 if (! ch_to_dir) chdir (get_homedir ());
1307 } 1313 }
1308 } 1314 }
1309#endif /* COCOA */ 1315#endif /* COCOA */
diff --git a/src/fileio.c b/src/fileio.c
index 7fb865809f5..e178c39fc18 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -96,6 +96,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
96#include <acl.h> 96#include <acl.h>
97#include <allocator.h> 97#include <allocator.h>
98#include <careadlinkat.h> 98#include <careadlinkat.h>
99#include <dosname.h>
99#include <fsusage.h> 100#include <fsusage.h>
100#include <stat-time.h> 101#include <stat-time.h>
101#include <tempname.h> 102#include <tempname.h>
@@ -1093,8 +1094,7 @@ the root directory. */)
1093 { 1094 {
1094 Lisp_Object tem; 1095 Lisp_Object tem;
1095 1096
1096 if (!(newdir = egetenv ("HOME"))) 1097 newdir = get_homedir ();
1097 newdir = newdirlim = "";
1098 nm++; 1098 nm++;
1099#ifdef WINDOWSNT 1099#ifdef WINDOWSNT
1100 if (newdir[0]) 1100 if (newdir[0])
@@ -1109,7 +1109,7 @@ the root directory. */)
1109#endif 1109#endif
1110 tem = build_string (newdir); 1110 tem = build_string (newdir);
1111 newdirlim = newdir + SBYTES (tem); 1111 newdirlim = newdir + SBYTES (tem);
1112 /* `egetenv' may return a unibyte string, which will bite us 1112 /* get_homedir may return a unibyte string, which will bite us
1113 if we expect the directory to be multibyte. */ 1113 if we expect the directory to be multibyte. */
1114 if (multibyte && !STRING_MULTIBYTE (tem)) 1114 if (multibyte && !STRING_MULTIBYTE (tem))
1115 { 1115 {
@@ -1637,7 +1637,6 @@ See also the function `substitute-in-file-name'.")
1637} 1637}
1638#endif 1638#endif
1639 1639
1640/* If /~ or // appears, discard everything through first slash. */
1641static bool 1640static bool
1642file_name_absolute_p (const char *filename) 1641file_name_absolute_p (const char *filename)
1643{ 1642{
@@ -1650,6 +1649,61 @@ file_name_absolute_p (const char *filename)
1650 ); 1649 );
1651} 1650}
1652 1651
1652/* Put into BUF the concatenation of DIR and FILE, with an intervening
1653 directory separator if needed. Return a pointer to the null byte
1654 at the end of the concatenated string. */
1655char *
1656splice_dir_file (char *buf, char const *dir, char const *file)
1657{
1658 char *e = stpcpy (buf, dir);
1659 *e = DIRECTORY_SEP;
1660 e += ! (buf < e && IS_DIRECTORY_SEP (e[-1]));
1661 return stpcpy (e, file);
1662}
1663
1664/* Get the home directory, an absolute file name. Return the empty
1665 string on failure. The returned value does not survive garbage
1666 collection, calls to this function, or calls to the getpwnam class
1667 of functions. */
1668char const *
1669get_homedir (void)
1670{
1671 char const *home = egetenv ("HOME");
1672 if (!home)
1673 {
1674 static char const *userenv[] = {"LOGNAME", "USER"};
1675 struct passwd *pw = NULL;
1676 for (int i = 0; i < ARRAYELTS (userenv); i++)
1677 {
1678 char *user = egetenv (userenv[i]);
1679 if (user)
1680 {
1681 pw = getpwnam (user);
1682 if (pw)
1683 break;
1684 }
1685 }
1686 if (!pw)
1687 pw = getpwuid (getuid ());
1688 if (pw)
1689 home = pw->pw_dir;
1690 if (!home)
1691 return "";
1692 }
1693 if (IS_ABSOLUTE_FILE_NAME (home))
1694 return home;
1695 if (!emacs_wd)
1696 error ("$HOME is relative to unknown directory");
1697 static char *ahome;
1698 static ptrdiff_t ahomesize;
1699 ptrdiff_t ahomelenbound = strlen (emacs_wd) + 1 + strlen (home) + 1;
1700 if (ahomesize <= ahomelenbound)
1701 ahome = xpalloc (ahome, &ahomesize, ahomelenbound + 1 - ahomesize, -1, 1);
1702 splice_dir_file (ahome, emacs_wd, home);
1703 return ahome;
1704}
1705
1706/* If /~ or // appears, discard everything through first slash. */
1653static char * 1707static char *
1654search_embedded_absfilename (char *nm, char *endp) 1708search_embedded_absfilename (char *nm, char *endp)
1655{ 1709{
diff --git a/src/lisp.h b/src/lisp.h
index f8ffb33a641..7e7dba631f3 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4061,6 +4061,8 @@ extern void syms_of_marker (void);
4061 4061
4062/* Defined in fileio.c. */ 4062/* Defined in fileio.c. */
4063 4063
4064extern char *splice_dir_file (char *, char const *, char const *);
4065extern char const *get_homedir (void);
4064extern Lisp_Object expand_and_dir_to_file (Lisp_Object); 4066extern Lisp_Object expand_and_dir_to_file (Lisp_Object);
4065extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object, 4067extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object,
4066 Lisp_Object, Lisp_Object, Lisp_Object, 4068 Lisp_Object, Lisp_Object, Lisp_Object,
@@ -4185,6 +4187,7 @@ extern void syms_of_frame (void);
4185/* Defined in emacs.c. */ 4187/* Defined in emacs.c. */
4186extern char **initial_argv; 4188extern char **initial_argv;
4187extern int initial_argc; 4189extern int initial_argc;
4190extern char const *emacs_wd;
4188#if defined (HAVE_X_WINDOWS) || defined (HAVE_NS) 4191#if defined (HAVE_X_WINDOWS) || defined (HAVE_NS)
4189extern bool display_arg; 4192extern bool display_arg;
4190#endif 4193#endif
diff --git a/src/xrdb.c b/src/xrdb.c
index 4abf1ad84ed..87c2faf6598 100644
--- a/src/xrdb.c
+++ b/src/xrdb.c
@@ -202,35 +202,6 @@ magic_db (const char *string, ptrdiff_t string_len, const char *class,
202} 202}
203 203
204 204
205static char *
206gethomedir (void)
207{
208 struct passwd *pw;
209 char *ptr;
210 char *copy;
211
212 if ((ptr = getenv ("HOME")) == NULL)
213 {
214 if ((ptr = getenv ("LOGNAME")) != NULL
215 || (ptr = getenv ("USER")) != NULL)
216 pw = getpwnam (ptr);
217 else
218 pw = getpwuid (getuid ());
219
220 if (pw)
221 ptr = pw->pw_dir;
222 }
223
224 if (ptr == NULL)
225 return xstrdup ("/");
226
227 ptrdiff_t len = strlen (ptr);
228 copy = xmalloc (len + 2);
229 strcpy (copy + len, "/");
230 return memcpy (copy, ptr, len);
231}
232
233
234/* Find the first element of SEARCH_PATH which exists and is readable, 205/* Find the first element of SEARCH_PATH which exists and is readable,
235 after expanding the %-escapes. Return 0 if we didn't find any, and 206 after expanding the %-escapes. Return 0 if we didn't find any, and
236 the path name of the one we found otherwise. */ 207 the path name of the one we found otherwise. */
@@ -316,12 +287,11 @@ get_user_app (const char *class)
316 if (! db) 287 if (! db)
317 { 288 {
318 /* Check in the home directory. This is a bit of a hack; let's 289 /* Check in the home directory. This is a bit of a hack; let's
319 hope one's home directory doesn't contain any %-escapes. */ 290 hope one's home directory doesn't contain ':' or '%'. */
320 char *home = gethomedir (); 291 char const *home = get_homedir ();
321 db = search_magic_path (home, class, "%L/%N"); 292 db = search_magic_path (home, class, "%L/%N");
322 if (! db) 293 if (! db)
323 db = search_magic_path (home, class, "%N"); 294 db = search_magic_path (home, class, "%N");
324 xfree (home);
325 } 295 }
326 296
327 return db; 297 return db;
@@ -346,10 +316,9 @@ get_user_db (Display *display)
346 else 316 else
347 { 317 {
348 /* Use ~/.Xdefaults. */ 318 /* Use ~/.Xdefaults. */
349 char *home = gethomedir (); 319 char const *home = get_homedir ();
350 ptrdiff_t homelen = strlen (home); 320 char *filename = xmalloc (strlen (home) + 1 + sizeof xdefaults);
351 char *filename = xrealloc (home, homelen + sizeof xdefaults); 321 splice_dir_file (filename, home, xdefaults);
352 strcpy (filename + homelen, xdefaults);
353 db = XrmGetFileDatabase (filename); 322 db = XrmGetFileDatabase (filename);
354 xfree (filename); 323 xfree (filename);
355 } 324 }
@@ -380,13 +349,12 @@ get_environ_db (void)
380 if (STRINGP (system_name)) 349 if (STRINGP (system_name))
381 { 350 {
382 /* Use ~/.Xdefaults-HOSTNAME. */ 351 /* Use ~/.Xdefaults-HOSTNAME. */
383 char *home = gethomedir (); 352 char const *home = get_homedir ();
384 ptrdiff_t homelen = strlen (home); 353 p = filename = xmalloc (strlen (home) + 1 + sizeof xdefaults
385 ptrdiff_t filenamesize = (homelen + sizeof xdefaults 354 + 1 + SBYTES (system_name));
386 + 1 + SBYTES (system_name)); 355 char *e = splice_dir_file (p, home, xdefaults);
387 p = filename = xrealloc (home, filenamesize); 356 *e++ = '/';
388 lispstpcpy (stpcpy (stpcpy (filename + homelen, xdefaults), "-"), 357 lispstpcpy (e, system_name);
389 system_name);
390 } 358 }
391 } 359 }
392 360
diff --git a/test/src/fileio-tests.el b/test/src/fileio-tests.el
index 5d12685fa19..b7b78bbda09 100644
--- a/test/src/fileio-tests.el
+++ b/test/src/fileio-tests.el
@@ -95,3 +95,11 @@ Also check that an encoding error can appear in a symlink."
95 (should (equal (file-name-as-directory "d:/abc/") "d:/abc/")) 95 (should (equal (file-name-as-directory "d:/abc/") "d:/abc/"))
96 (should (equal (file-name-as-directory "D:\\abc/") "d:/abc/")) 96 (should (equal (file-name-as-directory "D:\\abc/") "d:/abc/"))
97 (should (equal (file-name-as-directory "D:/abc//") "d:/abc//"))) 97 (should (equal (file-name-as-directory "D:/abc//") "d:/abc//")))
98
99(ert-deftest fileio-tests--relative-HOME ()
100 "Test that expand-file-name works even when HOME is relative."
101 (let ((old-home (getenv "HOME")))
102 (setenv "HOME" "a/b/c")
103 (should (equal (expand-file-name "~/foo")
104 (expand-file-name "a/b/c/foo")))
105 (setenv "HOME" old-home)))