Ticket #65569: patch-fstat.diff

File patch-fstat.diff, 11.9 KB (added by lemzwerg (Werner Lemberg), 2 years ago)
  • src/dired.c

    From b3ad638a60845f17938ff812efcf2b2edfbd8c57 Mon Sep 17 00:00:00 2001
    From: Paul Eggert <eggert@cs.ucla.edu>
    Date: Mon, 20 Jan 2020 01:08:42 -0800
    Subject: [PATCH] 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.
    ---
     src/dired.c    |  4 ++--
     src/fileio.c   | 39 ++++++++++++++++++++++++---------------
     src/filelock.c |  3 ++-
     src/lisp.h     |  2 ++
     src/lread.c    |  4 ++--
     src/sysdep.c   | 36 +++++++++++++++++++++++++++++++-----
     6 files changed, 63 insertions(+), 25 deletions(-)
    
    diff --git src/dired.c src/dired.c
    index 611477aa4e..f013a4cea0 100644
    file_attributes (int fd, char const *name, 
    937937  int err = EINVAL;
    938938
    939939#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);
    941941  if (namefd < 0)
    942942    err = errno;
    943943  else
    file_attributes (int fd, char const *name, 
    970970         information to be accurate.  */
    971971      w32_stat_get_owner_group = 1;
    972972#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;
    974974#ifdef WINDOWSNT
    975975      w32_stat_get_owner_group = 0;
    976976#endif
  • src/fileio.c

    diff --git src/fileio.c src/fileio.c
    index 34934dd6df..87a17eab42 100644
    barf_or_query_if_file_exists (Lisp_Object absname, bool known_to_exist, 
    19521952
    19531953  encoded_filename = ENCODE_FILE (absname);
    19541954
    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))
    19561959    {
    19571960      if (S_ISDIR (statbuf.st_mode))
    19581961        xsignal2 (Qfile_error,
    DEFUN ("rename-file", Frename_file, Srename_file, 2, 3, 
    25552558  bool dirp = !NILP (Fdirectory_name_p (file));
    25562559  if (!dirp)
    25572560    {
    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)
    25592564        report_file_error ("Renaming", list2 (file, newname));
    25602565      dirp = S_ISDIR (file_st.st_mode) != 0;
    25612566    }
    file_directory_p (Lisp_Object file) 
    29282933#else
    29292934# ifdef O_PATH
    29302935  /* 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);
    29322938  if (0 <= fd)
    29332939    {
    29342940      emacs_close (fd);
    file_directory_p (Lisp_Object file) 
    29392945  /* O_PATH is defined but evidently this Linux kernel predates 2.6.39.
    29402946     Fall back on generic POSIX code.  */
    29412947# endif
    2942   /* Use file_accessible_directory_p, as it avoids stat EOVERFLOW
     2948  /* Use file_accessible_directory_p, as it avoids fstatat EOVERFLOW
    29432949     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
    29452951     EOVERFLOW then FILE must have been a directory unless a race
    29462952     condition occurred (a problem hard to work around portably).  */
    29472953  if (file_accessible_directory_p (file))
    file_directory_p (Lisp_Object file) 
    29492955  if (errno != EACCES)
    29502956    return false;
    29512957  struct stat st;
    2952   if (stat (SSDATA (file), &st) != 0)
     2958  if (emacs_fstatat (AT_FDCWD, SSDATA (file), &st, 0) != 0)
    29532959    return errno == EOVERFLOW;
    29542960  if (S_ISDIR (st.st_mode))
    29552961    return true;
    DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0, 
    30803086  Vw32_get_true_file_attributes = Qt;
    30813087#endif
    30823088
    3083   int stat_result = stat (SSDATA (absname), &st);
     3089  int stat_result = emacs_fstatat (AT_FDCWD, SSDATA (absname), &st, 0);
    30843090
    30853091#ifdef WINDOWSNT
    30863092  Vw32_get_true_file_attributes = true_attributes;
    DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, 
    33403346  if (!NILP (handler))
    33413347    return call2 (handler, Qfile_modes, absname);
    33423348
    3343   if (stat (SSDATA (ENCODE_FILE (absname)), &st) != 0)
     3349  if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (absname)), &st, 0) != 0)
    33443350    return file_attribute_errno (absname, errno);
    33453351  return make_fixnum (st.st_mode & 07777);
    33463352}
    DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_ 
    34863492    return call3 (handler, Qfile_newer_than_file_p, absname1, absname2);
    34873493
    34883494  int err1;
    3489   if (stat (SSDATA (ENCODE_FILE (absname1)), &st1) == 0)
     3495  if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (absname1)), &st1, 0) == 0)
    34903496    err1 = 0;
    34913497  else
    34923498    {
    DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_ 
    34943500      if (err1 != EOVERFLOW)
    34953501        return file_attribute_errno (absname1, err1);
    34963502    }
    3497   if (stat (SSDATA (ENCODE_FILE (absname2)), &st2) != 0)
     3503  if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (absname2)), &st2, 0) != 0)
    34983504    {
    34993505      file_attribute_errno (absname2, errno);
    35003506      return Qt;
    because (1) it preserves some marker positions and (2) it puts less data 
    38803886          if (end_offset < 0)
    38813887            buffer_overflow ();
    38823888
    3883           /* The file size returned from stat may be zero, but data
     3889          /* The file size returned from fstat may be zero, but data
    38843890             may be readable nonetheless, for example when this is a
    38853891             file in the /proc filesystem.  */
    38863892          if (end_offset == 0)
    DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime, 
    56255631
    56265632  filename = ENCODE_FILE (BVAR (b, filename));
    56275633
    5628   mtime = (stat (SSDATA (filename), &st) == 0
     5634  mtime = (emacs_fstatat (AT_FDCWD, SSDATA (filename), &st, 0) == 0
    56295635           ? get_stat_mtime (&st)
    56305636           : time_error_value (errno));
    56315637  if (timespec_cmp (mtime, b->modtime) == 0
    DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime, 
    56895695        /* The handler can find the file name the same way we did.  */
    56905696        return call2 (handler, Qset_visited_file_modtime, Qnil);
    56915697
    5692       if (stat (SSDATA (ENCODE_FILE (filename)), &st) == 0)
     5698      if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (filename)), &st, 0)
     5699          == 0)
    56935700        {
    56945701          current_buffer->modtime = get_stat_mtime (&st);
    56955702          current_buffer->modtime_size = st.st_size;
    auto_save_1 (void) 
    57285735  /* Get visited file's mode to become the auto save file's mode.  */
    57295736  if (! NILP (BVAR (current_buffer, filename)))
    57305737    {
    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)
    57325741        /* But make sure we can overwrite it later!  */
    57335742        auto_save_mode_bits = (st.st_mode | 0600) & 0777;
    57345743      else if (modes = Ffile_modes (BVAR (current_buffer, filename)),
    57355744               FIXNUMP (modes))
    5736         /* Remote files don't cooperate with stat.  */
     5745        /* Remote files don't cooperate with fstatat.  */
    57375746        auto_save_mode_bits = (XFIXNUM (modes) | 0600) & 0777;
    57385747    }
    57395748
  • src/filelock.c

    diff --git src/filelock.c src/filelock.c
    index b28f16e9b5..73202f0b2c 100644
    rename_lock_file (char const *old, char const *new, bool force) 
    347347         potential race condition since some other process may create
    348348         NEW immediately after the existence check, but it's the best
    349349         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)
    351352        {
    352353          errno = EEXIST;
    353354          return -1;
  • src/lisp.h

    diff --git src/lisp.h src/lisp.h
    index 4bcd122844..0bd375658e 100644
    maybe_disable_address_randomization (int argc, char **argv) 
    46054605extern void init_random (void);
    46064606extern void emacs_backtrace (int);
    46074607extern AVOID emacs_abort (void) NO_INLINE;
     4608extern int emacs_fstatat (int, char const *, void *, int);
     4609extern int emacs_openat (int, char const *, int, int);
    46084610extern int emacs_open (const char *, int, int);
    46094611extern int emacs_pipe (int[2]);
    46104612extern int emacs_close (int);
  • src/lread.c

    diff --git src/lread.c src/lread.c
    index 4e9860d5dc..69dd73912b 100644
    DEFUN ("load", Fload, Sload, 1, 5, 0, 
    13531353             ignores suffix order due to load_prefer_newer.  */
    13541354          if (!load_prefer_newer && is_elc)
    13551355            {
    1356               result = stat (SSDATA (efound), &s1);
     1356              result = emacs_fstatat (AT_FDCWD, SSDATA (efound), &s1, 0);
    13571357              if (result == 0)
    13581358                {
    13591359                  SSET (efound, SBYTES (efound) - 1, 0);
    1360                   result = stat (SSDATA (efound), &s2);
     1360                  result = emacs_fstatat (AT_FDCWD, SSDATA (efound), &s2, 0);
    13611361                  SSET (efound, SBYTES (efound) - 1, 'c');
    13621362                }
    13631363
  • src/sysdep.c

    diff --git src/sysdep.c src/sysdep.c
    index c6344d8cec..e8e8bbfb50 100644
    get_current_dir_name_or_unreachable (void) 
    312312  if (pwd
    313313      && (pwdlen = strnlen (pwd, bufsize_max)) < bufsize_max
    314314      && IS_DIRECTORY_SEP (pwd[pwdlen && IS_DEVICE_SEP (pwd[1]) ? 2 : 0])
    315       && stat (pwd, &pwdstat) == 0
    316       && stat (".", &dotstat) == 0
     315      && emacs_fstatat (AT_FDCWD, pwd, &pwdstat, 0) == 0
     316      && emacs_fstatat (AT_FDCWD, ".", &dotstat, 0) == 0
    317317      && dotstat.st_ino == pwdstat.st_ino
    318318      && dotstat.st_dev == pwdstat.st_dev)
    319319    {
    emacs_abort (void) 
    24492449}
    24502450#endif
    24512451
    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.
    24532473   Use binary I/O on systems that care about text vs binary I/O.
    24542474   Arrange for subprograms to not inherit the file descriptor.
    24552475   Prefer a method that is multithread-safe, if available.
    emacs_abort (void) 
    24572477   Allow the user to quit.  */
    24582478
    24592479int
    2460 emacs_open (const char *file, int oflags, int mode)
     2480emacs_openat (int dirfd, char const *file, int oflags, int mode)
    24612481{
    24622482  int fd;
    24632483  if (! (oflags & O_TEXT))
    24642484    oflags |= O_BINARY;
    24652485  oflags |= O_CLOEXEC;
    2466   while ((fd = open (file, oflags, mode)) < 0 && errno == EINTR)
     2486  while ((fd = openat (dirfd, file, oflags, mode)) < 0 && errno == EINTR)
    24672487    maybe_quit ();
    24682488  return fd;
    24692489}
    24702490
     2491int
     2492emacs_open (char const *file, int oflags, int mode)
     2493{
     2494  return emacs_openat (AT_FDCWD, file, oflags, mode);
     2495}
     2496
    24712497/* Open FILE as a stream for Emacs use, with mode MODE.
    24722498   Act like emacs_open with respect to threads, signals, and quits.  */
    24732499