aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2020-01-20 01:08:42 -0800
committerPaul Eggert2020-01-20 01:21:52 -0800
commitb3ad638a60845f17938ff812efcf2b2edfbd8c57 (patch)
treeda4d1f416f9e06fe7f3e3318dd7127a39d812bec /src
parent6cc1db8174bcbe4fabc3627505a7d945cae7029d (diff)
downloademacs-b3ad638a60845f17938ff812efcf2b2edfbd8c57.tar.gz
emacs-b3ad638a60845f17938ff812efcf2b2edfbd8c57.zip
Work better if stat etc. are interrupted
Quit or retry if fstat, lstat, stat or openat fail with EINTR. This should fix some bugs on platforms where accessing files via NFS can fail that way (Bug#9256). * src/dired.c (file_attributes): * src/fileio.c (file_directory_p) [O_PATH]: Use emacs_openat instead of openat. * src/dired.c (file_attributes): Use emacs_fstatat instead of fstatat. * src/fileio.c (barf_or_query_if_file_exists, Frename_file): * src/filelock.c (rename_lock_file): Use emacs_fstatat instead of lstat. * src/fileio.c (file_directory_p, Ffile_regular_p, Ffile_modes) (Ffile_newer_than_file_p, Fverify_visited_file_modtime) (Fset_visited_file_modtime, auto_save_1): * src/lread.c (Fload): * src/sysdep.c (get_current_dir_name_or_unreachable): Use emacs_fstatat instead of stat. * src/sysdep.c (emacs_fstatat, emacs_openat): New functions. (emacs_open): Redo in terms of emacs_open.
Diffstat (limited to 'src')
-rw-r--r--src/dired.c4
-rw-r--r--src/fileio.c39
-rw-r--r--src/filelock.c3
-rw-r--r--src/lisp.h2
-rw-r--r--src/lread.c4
-rw-r--r--src/sysdep.c36
6 files changed, 63 insertions, 25 deletions
diff --git a/src/dired.c b/src/dired.c
index 611477aa4ef..f013a4cea03 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -937,7 +937,7 @@ file_attributes (int fd, char const *name,
937 int err = EINVAL; 937 int err = EINVAL;
938 938
939#if defined O_PATH && !defined HAVE_CYGWIN_O_PATH_BUG 939#if defined O_PATH && !defined HAVE_CYGWIN_O_PATH_BUG
940 int namefd = openat (fd, name, O_PATH | O_CLOEXEC | O_NOFOLLOW); 940 int namefd = emacs_openat (fd, name, O_PATH | O_CLOEXEC | O_NOFOLLOW, 0);
941 if (namefd < 0) 941 if (namefd < 0)
942 err = errno; 942 err = errno;
943 else 943 else
@@ -970,7 +970,7 @@ file_attributes (int fd, char const *name,
970 information to be accurate. */ 970 information to be accurate. */
971 w32_stat_get_owner_group = 1; 971 w32_stat_get_owner_group = 1;
972#endif 972#endif
973 err = fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW) == 0 ? 0 : errno; 973 err = emacs_fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW) == 0 ? 0 : errno;
974#ifdef WINDOWSNT 974#ifdef WINDOWSNT
975 w32_stat_get_owner_group = 0; 975 w32_stat_get_owner_group = 0;
976#endif 976#endif
diff --git a/src/fileio.c b/src/fileio.c
index 34934dd6df6..87a17eab425 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -1952,7 +1952,10 @@ barf_or_query_if_file_exists (Lisp_Object absname, bool known_to_exist,
1952 1952
1953 encoded_filename = ENCODE_FILE (absname); 1953 encoded_filename = ENCODE_FILE (absname);
1954 1954
1955 if (! known_to_exist && lstat (SSDATA (encoded_filename), &statbuf) == 0) 1955 if (! known_to_exist
1956 && (emacs_fstatat (AT_FDCWD, SSDATA (encoded_filename),
1957 &statbuf, AT_SYMLINK_NOFOLLOW)
1958 == 0))
1956 { 1959 {
1957 if (S_ISDIR (statbuf.st_mode)) 1960 if (S_ISDIR (statbuf.st_mode))
1958 xsignal2 (Qfile_error, 1961 xsignal2 (Qfile_error,
@@ -2555,7 +2558,9 @@ This is what happens in interactive use with M-x. */)
2555 bool dirp = !NILP (Fdirectory_name_p (file)); 2558 bool dirp = !NILP (Fdirectory_name_p (file));
2556 if (!dirp) 2559 if (!dirp)
2557 { 2560 {
2558 if (lstat (SSDATA (encoded_file), &file_st) != 0) 2561 if (emacs_fstatat (AT_FDCWD, SSDATA (encoded_file),
2562 &file_st, AT_SYMLINK_NOFOLLOW)
2563 != 0)
2559 report_file_error ("Renaming", list2 (file, newname)); 2564 report_file_error ("Renaming", list2 (file, newname));
2560 dirp = S_ISDIR (file_st.st_mode) != 0; 2565 dirp = S_ISDIR (file_st.st_mode) != 0;
2561 } 2566 }
@@ -2928,7 +2933,8 @@ file_directory_p (Lisp_Object file)
2928#else 2933#else
2929# ifdef O_PATH 2934# ifdef O_PATH
2930 /* Use O_PATH if available, as it avoids races and EOVERFLOW issues. */ 2935 /* Use O_PATH if available, as it avoids races and EOVERFLOW issues. */
2931 int fd = openat (AT_FDCWD, SSDATA (file), O_PATH | O_CLOEXEC | O_DIRECTORY); 2936 int fd = emacs_openat (AT_FDCWD, SSDATA (file),
2937 O_PATH | O_CLOEXEC | O_DIRECTORY, 0);
2932 if (0 <= fd) 2938 if (0 <= fd)
2933 { 2939 {
2934 emacs_close (fd); 2940 emacs_close (fd);
@@ -2939,9 +2945,9 @@ file_directory_p (Lisp_Object file)
2939 /* O_PATH is defined but evidently this Linux kernel predates 2.6.39. 2945 /* O_PATH is defined but evidently this Linux kernel predates 2.6.39.
2940 Fall back on generic POSIX code. */ 2946 Fall back on generic POSIX code. */
2941# endif 2947# endif
2942 /* Use file_accessible_directory_p, as it avoids stat EOVERFLOW 2948 /* Use file_accessible_directory_p, as it avoids fstatat EOVERFLOW
2943 problems and could be cheaper. However, if it fails because FILE 2949 problems and could be cheaper. However, if it fails because FILE
2944 is inaccessible, fall back on stat; if the latter fails with 2950 is inaccessible, fall back on fstatat; if the latter fails with
2945 EOVERFLOW then FILE must have been a directory unless a race 2951 EOVERFLOW then FILE must have been a directory unless a race
2946 condition occurred (a problem hard to work around portably). */ 2952 condition occurred (a problem hard to work around portably). */
2947 if (file_accessible_directory_p (file)) 2953 if (file_accessible_directory_p (file))
@@ -2949,7 +2955,7 @@ file_directory_p (Lisp_Object file)
2949 if (errno != EACCES) 2955 if (errno != EACCES)
2950 return false; 2956 return false;
2951 struct stat st; 2957 struct stat st;
2952 if (stat (SSDATA (file), &st) != 0) 2958 if (emacs_fstatat (AT_FDCWD, SSDATA (file), &st, 0) != 0)
2953 return errno == EOVERFLOW; 2959 return errno == EOVERFLOW;
2954 if (S_ISDIR (st.st_mode)) 2960 if (S_ISDIR (st.st_mode))
2955 return true; 2961 return true;
@@ -3080,7 +3086,7 @@ See `file-symlink-p' to distinguish symlinks. */)
3080 Vw32_get_true_file_attributes = Qt; 3086 Vw32_get_true_file_attributes = Qt;
3081#endif 3087#endif
3082 3088
3083 int stat_result = stat (SSDATA (absname), &st); 3089 int stat_result = emacs_fstatat (AT_FDCWD, SSDATA (absname), &st, 0);
3084 3090
3085#ifdef WINDOWSNT 3091#ifdef WINDOWSNT
3086 Vw32_get_true_file_attributes = true_attributes; 3092 Vw32_get_true_file_attributes = true_attributes;
@@ -3340,7 +3346,7 @@ Return nil if FILENAME does not exist. */)
3340 if (!NILP (handler)) 3346 if (!NILP (handler))
3341 return call2 (handler, Qfile_modes, absname); 3347 return call2 (handler, Qfile_modes, absname);
3342 3348
3343 if (stat (SSDATA (ENCODE_FILE (absname)), &st) != 0) 3349 if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (absname)), &st, 0) != 0)
3344 return file_attribute_errno (absname, errno); 3350 return file_attribute_errno (absname, errno);
3345 return make_fixnum (st.st_mode & 07777); 3351 return make_fixnum (st.st_mode & 07777);
3346} 3352}
@@ -3486,7 +3492,7 @@ otherwise, if FILE2 does not exist, the answer is t. */)
3486 return call3 (handler, Qfile_newer_than_file_p, absname1, absname2); 3492 return call3 (handler, Qfile_newer_than_file_p, absname1, absname2);
3487 3493
3488 int err1; 3494 int err1;
3489 if (stat (SSDATA (ENCODE_FILE (absname1)), &st1) == 0) 3495 if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (absname1)), &st1, 0) == 0)
3490 err1 = 0; 3496 err1 = 0;
3491 else 3497 else
3492 { 3498 {
@@ -3494,7 +3500,7 @@ otherwise, if FILE2 does not exist, the answer is t. */)
3494 if (err1 != EOVERFLOW) 3500 if (err1 != EOVERFLOW)
3495 return file_attribute_errno (absname1, err1); 3501 return file_attribute_errno (absname1, err1);
3496 } 3502 }
3497 if (stat (SSDATA (ENCODE_FILE (absname2)), &st2) != 0) 3503 if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (absname2)), &st2, 0) != 0)
3498 { 3504 {
3499 file_attribute_errno (absname2, errno); 3505 file_attribute_errno (absname2, errno);
3500 return Qt; 3506 return Qt;
@@ -3880,7 +3886,7 @@ by calling `format-decode', which see. */)
3880 if (end_offset < 0) 3886 if (end_offset < 0)
3881 buffer_overflow (); 3887 buffer_overflow ();
3882 3888
3883 /* The file size returned from stat may be zero, but data 3889 /* The file size returned from fstat may be zero, but data
3884 may be readable nonetheless, for example when this is a 3890 may be readable nonetheless, for example when this is a
3885 file in the /proc filesystem. */ 3891 file in the /proc filesystem. */
3886 if (end_offset == 0) 3892 if (end_offset == 0)
@@ -5625,7 +5631,7 @@ See Info node `(elisp)Modification Time' for more details. */)
5625 5631
5626 filename = ENCODE_FILE (BVAR (b, filename)); 5632 filename = ENCODE_FILE (BVAR (b, filename));
5627 5633
5628 mtime = (stat (SSDATA (filename), &st) == 0 5634 mtime = (emacs_fstatat (AT_FDCWD, SSDATA (filename), &st, 0) == 0
5629 ? get_stat_mtime (&st) 5635 ? get_stat_mtime (&st)
5630 : time_error_value (errno)); 5636 : time_error_value (errno));
5631 if (timespec_cmp (mtime, b->modtime) == 0 5637 if (timespec_cmp (mtime, b->modtime) == 0
@@ -5689,7 +5695,8 @@ in `current-time' or an integer flag as returned by `visited-file-modtime'. */)
5689 /* The handler can find the file name the same way we did. */ 5695 /* The handler can find the file name the same way we did. */
5690 return call2 (handler, Qset_visited_file_modtime, Qnil); 5696 return call2 (handler, Qset_visited_file_modtime, Qnil);
5691 5697
5692 if (stat (SSDATA (ENCODE_FILE (filename)), &st) == 0) 5698 if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (filename)), &st, 0)
5699 == 0)
5693 { 5700 {
5694 current_buffer->modtime = get_stat_mtime (&st); 5701 current_buffer->modtime = get_stat_mtime (&st);
5695 current_buffer->modtime_size = st.st_size; 5702 current_buffer->modtime_size = st.st_size;
@@ -5728,12 +5735,14 @@ auto_save_1 (void)
5728 /* Get visited file's mode to become the auto save file's mode. */ 5735 /* Get visited file's mode to become the auto save file's mode. */
5729 if (! NILP (BVAR (current_buffer, filename))) 5736 if (! NILP (BVAR (current_buffer, filename)))
5730 { 5737 {
5731 if (stat (SSDATA (BVAR (current_buffer, filename)), &st) >= 0) 5738 if (emacs_fstatat (AT_FDCWD, SSDATA (BVAR (current_buffer, filename)),
5739 &st, 0)
5740 == 0)
5732 /* But make sure we can overwrite it later! */ 5741 /* But make sure we can overwrite it later! */
5733 auto_save_mode_bits = (st.st_mode | 0600) & 0777; 5742 auto_save_mode_bits = (st.st_mode | 0600) & 0777;
5734 else if (modes = Ffile_modes (BVAR (current_buffer, filename)), 5743 else if (modes = Ffile_modes (BVAR (current_buffer, filename)),
5735 FIXNUMP (modes)) 5744 FIXNUMP (modes))
5736 /* Remote files don't cooperate with stat. */ 5745 /* Remote files don't cooperate with fstatat. */
5737 auto_save_mode_bits = (XFIXNUM (modes) | 0600) & 0777; 5746 auto_save_mode_bits = (XFIXNUM (modes) | 0600) & 0777;
5738 } 5747 }
5739 5748
diff --git a/src/filelock.c b/src/filelock.c
index b28f16e9b5a..73202f0b2c4 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -347,7 +347,8 @@ rename_lock_file (char const *old, char const *new, bool force)
347 potential race condition since some other process may create 347 potential race condition since some other process may create
348 NEW immediately after the existence check, but it's the best 348 NEW immediately after the existence check, but it's the best
349 we can portably do here. */ 349 we can portably do here. */
350 if (lstat (new, &st) == 0 || errno == EOVERFLOW) 350 if (emacs_fstatat (AT_FDCWD, new, &st, AT_SYMLINK_NOFOLLOW) == 0
351 || errno == EOVERFLOW)
351 { 352 {
352 errno = EEXIST; 353 errno = EEXIST;
353 return -1; 354 return -1;
diff --git a/src/lisp.h b/src/lisp.h
index 4bcd1228443..0bd375658e2 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4605,6 +4605,8 @@ extern void seed_random (void *, ptrdiff_t);
4605extern void init_random (void); 4605extern void init_random (void);
4606extern void emacs_backtrace (int); 4606extern void emacs_backtrace (int);
4607extern AVOID emacs_abort (void) NO_INLINE; 4607extern AVOID emacs_abort (void) NO_INLINE;
4608extern int emacs_fstatat (int, char const *, void *, int);
4609extern int emacs_openat (int, char const *, int, int);
4608extern int emacs_open (const char *, int, int); 4610extern int emacs_open (const char *, int, int);
4609extern int emacs_pipe (int[2]); 4611extern int emacs_pipe (int[2]);
4610extern int emacs_close (int); 4612extern int emacs_close (int);
diff --git a/src/lread.c b/src/lread.c
index 4e9860d5dc8..69dd73912bc 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -1353,11 +1353,11 @@ Return t if the file exists and loads successfully. */)
1353 ignores suffix order due to load_prefer_newer. */ 1353 ignores suffix order due to load_prefer_newer. */
1354 if (!load_prefer_newer && is_elc) 1354 if (!load_prefer_newer && is_elc)
1355 { 1355 {
1356 result = stat (SSDATA (efound), &s1); 1356 result = emacs_fstatat (AT_FDCWD, SSDATA (efound), &s1, 0);
1357 if (result == 0) 1357 if (result == 0)
1358 { 1358 {
1359 SSET (efound, SBYTES (efound) - 1, 0); 1359 SSET (efound, SBYTES (efound) - 1, 0);
1360 result = stat (SSDATA (efound), &s2); 1360 result = emacs_fstatat (AT_FDCWD, SSDATA (efound), &s2, 0);
1361 SSET (efound, SBYTES (efound) - 1, 'c'); 1361 SSET (efound, SBYTES (efound) - 1, 'c');
1362 } 1362 }
1363 1363
diff --git a/src/sysdep.c b/src/sysdep.c
index c6344d8cec7..e8e8bbfb502 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -312,8 +312,8 @@ get_current_dir_name_or_unreachable (void)
312 if (pwd 312 if (pwd
313 && (pwdlen = strnlen (pwd, bufsize_max)) < bufsize_max 313 && (pwdlen = strnlen (pwd, bufsize_max)) < bufsize_max
314 && IS_DIRECTORY_SEP (pwd[pwdlen && IS_DEVICE_SEP (pwd[1]) ? 2 : 0]) 314 && IS_DIRECTORY_SEP (pwd[pwdlen && IS_DEVICE_SEP (pwd[1]) ? 2 : 0])
315 && stat (pwd, &pwdstat) == 0 315 && emacs_fstatat (AT_FDCWD, pwd, &pwdstat, 0) == 0
316 && stat (".", &dotstat) == 0 316 && emacs_fstatat (AT_FDCWD, ".", &dotstat, 0) == 0
317 && dotstat.st_ino == pwdstat.st_ino 317 && dotstat.st_ino == pwdstat.st_ino
318 && dotstat.st_dev == pwdstat.st_dev) 318 && dotstat.st_dev == pwdstat.st_dev)
319 { 319 {
@@ -2449,7 +2449,27 @@ emacs_abort (void)
2449} 2449}
2450#endif 2450#endif
2451 2451
2452/* Open FILE for Emacs use, using open flags OFLAG and mode MODE. 2452/* Assuming the directory DIRFD, store information about FILENAME into *ST,
2453 using FLAGS to control how the status is obtained.
2454 Do not fail merely because fetching info was interrupted by a signal.
2455 Allow the user to quit.
2456
2457 The type of ST is void * instead of struct stat * because the
2458 latter type would be problematic in lisp.h. Some platforms may
2459 play tricks like "#define stat stat64" in <sys/stat.h>, and lisp.h
2460 does not include <sys/stat.h>. */
2461
2462int
2463emacs_fstatat (int dirfd, char const *filename, void *st, int flags)
2464{
2465 int r;
2466 while ((r = fstatat (dirfd, filename, st, flags)) != 0 && errno == EINTR)
2467 maybe_quit ();
2468 return r;
2469}
2470
2471/* Assuming the directory DIRFD, open FILE for Emacs use,
2472 using open flags OFLAGS and mode MODE.
2453 Use binary I/O on systems that care about text vs binary I/O. 2473 Use binary I/O on systems that care about text vs binary I/O.
2454 Arrange for subprograms to not inherit the file descriptor. 2474 Arrange for subprograms to not inherit the file descriptor.
2455 Prefer a method that is multithread-safe, if available. 2475 Prefer a method that is multithread-safe, if available.
@@ -2457,17 +2477,23 @@ emacs_abort (void)
2457 Allow the user to quit. */ 2477 Allow the user to quit. */
2458 2478
2459int 2479int
2460emacs_open (const char *file, int oflags, int mode) 2480emacs_openat (int dirfd, char const *file, int oflags, int mode)
2461{ 2481{
2462 int fd; 2482 int fd;
2463 if (! (oflags & O_TEXT)) 2483 if (! (oflags & O_TEXT))
2464 oflags |= O_BINARY; 2484 oflags |= O_BINARY;
2465 oflags |= O_CLOEXEC; 2485 oflags |= O_CLOEXEC;
2466 while ((fd = open (file, oflags, mode)) < 0 && errno == EINTR) 2486 while ((fd = openat (dirfd, file, oflags, mode)) < 0 && errno == EINTR)
2467 maybe_quit (); 2487 maybe_quit ();
2468 return fd; 2488 return fd;
2469} 2489}
2470 2490
2491int
2492emacs_open (char const *file, int oflags, int mode)
2493{
2494 return emacs_openat (AT_FDCWD, file, oflags, mode);
2495}
2496
2471/* Open FILE as a stream for Emacs use, with mode MODE. 2497/* Open FILE as a stream for Emacs use, with mode MODE.
2472 Act like emacs_open with respect to threads, signals, and quits. */ 2498 Act like emacs_open with respect to threads, signals, and quits. */
2473 2499