bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] backupfile: new dir_fd args


From: Paul Eggert
Subject: [PATCH] backupfile: new dir_fd args
Date: Tue, 23 Oct 2018 19:11:34 -0700

New module opendirat with code taken from fts.
Use this module to let backupfile use a directory file descriptor.
* NEWS: Document the incompatible change.
* lib/backup-find.c (find_backup_file_name):
* lib/backup-rename.c (backup_file_rename):
New arg DIR_FD.
* lib/backupfile.c: Include stdint.h, for SIZE_MAX.
(SIZE_MAX): Remove.
Include opendirat.h rather than dirent--.h.
(check_extension): New args DIR_FD and BASE_MAX.  All callers changed.
(numbered_backup): New args DIR_FD and PNEW_FD.  All callers changed.
(backupfile_internal): New arg DIR_FD.  All callers changed.
* lib/fts.c: Include opendirat.h.
(opendirat): Move to opendirat.c.
* lib/opendirat.c, lib/opendirat.h, modules/opendirat: New files.
* modules/backupfile (Depends-on): Remove dirfd, opendir.
Add opendirat.
* modules/fts (Depends-on): Remove fdopendir, openat-safer.
Add opendirat.
---
 ChangeLog             | 23 ++++++++++++
 NEWS                  |  4 ++
 lib/backup-find.c     | 12 +++---
 lib/backup-internal.h |  2 +-
 lib/backup-rename.c   | 12 +++---
 lib/backupfile.c      | 86 ++++++++++++++++++++++++++-----------------
 lib/backupfile.h      | 19 +++++-----
 lib/fts.c             | 26 +------------
 lib/opendirat.c       | 54 +++++++++++++++++++++++++++
 lib/opendirat.h       |  2 +
 modules/backupfile    |  4 +-
 modules/fts           |  3 +-
 modules/opendirat     | 26 +++++++++++++
 13 files changed, 190 insertions(+), 83 deletions(-)
 create mode 100644 lib/opendirat.c
 create mode 100644 lib/opendirat.h
 create mode 100644 modules/opendirat

diff --git a/ChangeLog b/ChangeLog
index 7c3c17dff..c08de2869 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2018-10-23  Paul Eggert  <address@hidden>
+
+       backupfile: new dir_fd args
+       New module opendirat with code taken from fts.
+       Use this module to let backupfile use a directory file descriptor.
+       * NEWS: Document the incompatible change.
+       * lib/backup-find.c (find_backup_file_name):
+       * lib/backup-rename.c (backup_file_rename):
+       New arg DIR_FD.
+       * lib/backupfile.c: Include stdint.h, for SIZE_MAX.
+       (SIZE_MAX): Remove.
+       Include opendirat.h rather than dirent--.h.
+       (check_extension): New args DIR_FD and BASE_MAX.  All callers changed.
+       (numbered_backup): New args DIR_FD and PNEW_FD.  All callers changed.
+       (backupfile_internal): New arg DIR_FD.  All callers changed.
+       * lib/fts.c: Include opendirat.h.
+       (opendirat): Move to opendirat.c.
+       * lib/opendirat.c, lib/opendirat.h, modules/opendirat: New files.
+       * modules/backupfile (Depends-on): Remove dirfd, opendir.
+       Add opendirat.
+       * modules/fts (Depends-on): Remove fdopendir, openat-safer.
+       Add opendirat.
+
 2018-10-23  Bruno Haible  <address@hidden>
 
        localename: Simplify support for per-thread locales on Solaris 11.4.
diff --git a/NEWS b/NEWS
index cdcfb29dd..c28bbc7bc 100644
--- a/NEWS
+++ b/NEWS
@@ -44,6 +44,10 @@ User visible incompatible changes
 
 Date        Modules         Changes
 
+2018-10-23  backupfile      backup_file_rename and find_backup_file_name
+                            now take an additional directory file descriptor
+                            argument.  Pass AT_FDCWD to get the old behavior.
+
 2018-08-18  getpass         The include file is changed from "getpass.h" to
             getpass-gnu     <unistd.h>.
 
diff --git a/lib/backup-find.c b/lib/backup-find.c
index c39993975..477a018b2 100644
--- a/lib/backup-find.c
+++ b/lib/backup-find.c
@@ -24,14 +24,16 @@
 
 #include <stdlib.h>
 
-/* Return the name of a backup file for the existing file FILE,
-   allocated with malloc.  Report an error and exit if out of memory.
-   Do not call this function if backup_type == no_backups.  */
+/* Relative to DIR_FD, return the name of a backup file for the
+   existing file FILE, allocated with malloc.  Report an error and
+   exit if out of memory.  Do not call this function if
+   backup_type == no_backups.  */
 
 char *
-find_backup_file_name (char const *file, enum backup_type backup_type)
+find_backup_file_name (int dir_fd, char const *file,
+                       enum backup_type backup_type)
 {
-  char *result = backupfile_internal (file, backup_type, false);
+  char *result = backupfile_internal (dir_fd, file, backup_type, false);
   if (!result)
     xalloc_die ();
   return result;
diff --git a/lib/backup-internal.h b/lib/backup-internal.h
index 2401c07b0..17714b2d4 100644
--- a/lib/backup-internal.h
+++ b/lib/backup-internal.h
@@ -1,3 +1,3 @@
 #include "backupfile.h"
 #include <stdbool.h>
-extern char *backupfile_internal (char const *, enum backup_type, bool);
+extern char *backupfile_internal (int, char const *, enum backup_type, bool);
diff --git a/lib/backup-rename.c b/lib/backup-rename.c
index 292b7f2ff..a20332a68 100644
--- a/lib/backup-rename.c
+++ b/lib/backup-rename.c
@@ -19,13 +19,13 @@
 
 #include "backup-internal.h"
 
-/* Rename the existing file FILE to a backup name, allocated with
-   malloc, and return the backup name.  On failure return a null
-   pointer, setting errno.  Do not call this function if backup_type
-   == no_backups.  */
+/* Relative to DIR_FD, rename the existing file FILE to a backup name,
+   allocated with malloc, and return the backup name.  On failure
+   return a null pointer, setting errno.  Do not call this function if
+   backup_type == no_backups.  */
 
 char *
-backup_file_rename (char const *file, enum backup_type backup_type)
+backup_file_rename (int dir_fd, char const *file, enum backup_type backup_type)
 {
-  return backupfile_internal (file, backup_type, true);
+  return backupfile_internal (dir_fd, file, backup_type, true);
 }
diff --git a/lib/backupfile.c b/lib/backupfile.c
index 637be6c24..ee12f7124 100644
--- a/lib/backupfile.c
+++ b/lib/backupfile.c
@@ -29,6 +29,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -36,7 +37,7 @@
 
 #include <unistd.h>
 
-#include "dirent--.h"
+#include "opendirat.h"
 #ifndef _D_EXACT_NAMLEN
 # define _D_EXACT_NAMLEN(dp) strlen ((dp)->d_name)
 #endif
@@ -48,9 +49,6 @@
 #ifndef _POSIX_NAME_MAX
 # define _POSIX_NAME_MAX 14
 #endif
-#ifndef SIZE_MAX
-# define SIZE_MAX ((size_t) -1)
-#endif
 
 #if defined _XOPEN_NAME_MAX
 # define NAME_MAX_MINIMUM _XOPEN_NAME_MAX
@@ -92,10 +90,15 @@ set_simple_backup_suffix (char const *s)
 /* If FILE (which was of length FILELEN before an extension was
    appended to it) is too long, replace the extension with the single
    char E.  If the result is still too long, remove the char just
-   before E.  */
+   before E.
+
+   If DIR_FD is nonnegative, it is a file descriptor for FILE's parent.
+   *NAME_MAX is either 0, or the cached result of a previous call for
+   FILE's parent's _PC_NAME_MAX.  */
 
 static void
-check_extension (char *file, size_t filelen, char e)
+check_extension (char *file, size_t filelen, char e,
+                 int dir_fd, size_t *base_max)
 {
   char *base = last_component (file);
   size_t baselen = base_len (base);
@@ -104,22 +107,34 @@ check_extension (char *file, size_t filelen, char e)
   if (HAVE_DOS_FILE_NAMES || NAME_MAX_MINIMUM < baselen)
     {
       /* The new base name is long enough to require a pathconf check.  */
-      long name_max;
-
-      /* Temporarily modify the buffer into its parent directory name,
-         invoke pathconf on the directory, and then restore the buffer.  */
-      char tmp[sizeof "."];
-      memcpy (tmp, base, sizeof ".");
-      strcpy (base, ".");
-      errno = 0;
-      name_max = pathconf (file, _PC_NAME_MAX);
-      if (0 <= name_max || errno == 0)
+      if (*base_max == 0)
         {
-          long size = baselen_max = name_max;
-          if (name_max != size)
-            baselen_max = SIZE_MAX;
+          long name_max;
+          if (dir_fd < 0)
+            {
+              /* Temporarily modify the buffer into its parent
+                 directory name, invoke pathconf on the directory, and
+                 then restore the buffer.  */
+              char tmp[sizeof "."];
+              memcpy (tmp, base, sizeof ".");
+              strcpy (base, ".");
+              errno = 0;
+              name_max = pathconf (file, _PC_NAME_MAX);
+              name_max -= !errno;
+              memcpy (base, tmp, sizeof ".");
+            }
+          else
+            {
+              errno = 0;
+              name_max = fpathconf (dir_fd, _PC_NAME_MAX);
+              name_max -= !errno;
+            }
+
+          *base_max = (0 <= name_max && name_max <= SIZE_MAX ? name_max
+                       : name_max < -1 ? NAME_MAX_MINIMUM : SIZE_MAX);
         }
-      memcpy (base, tmp, sizeof ".");
+
+      baselen_max = *base_max;
     }
 
   if (HAVE_DOS_FILE_NAMES && baselen_max <= 12)
@@ -167,8 +182,9 @@ enum numbered_backup_result
     BACKUP_NOMEM
   };
 
-/* *BUFFER contains a file name.  Store into *BUFFER the next backup
-   name for the named file, with a version number greater than all the
+/* Relative to DIR_FD, *BUFFER contains a file name.
+   Store into *BUFFER the next backup name for the named file,
+   with a version number greater than all the
    existing numbered backups.  Reallocate *BUFFER as necessary; its
    initial allocated size is BUFFER_SIZE, which must be at least 4
    bytes longer than the file name to make room for the initially
@@ -180,11 +196,11 @@ enum numbered_backup_result
 
    *DIRPP is the destination directory.  If *DIRPP is null, open the
    destination directory and store the resulting stream into *DIRPP
-   without closing the stream.  */
+   and its file descriptor into *PNEW_FD without closing the stream.  */
 
 static enum numbered_backup_result
-numbered_backup (char **buffer, size_t buffer_size, size_t filelen,
-                 ptrdiff_t base_offset, DIR **dirpp)
+numbered_backup (int dir_fd, char **buffer, size_t buffer_size, size_t filelen,
+                 ptrdiff_t base_offset, DIR **dirpp, int *pnew_fd)
 {
   enum numbered_backup_result result = BACKUP_IS_NEW;
   DIR *dirp = *dirpp;
@@ -203,7 +219,7 @@ numbered_backup (char **buffer, size_t buffer_size, size_t 
filelen,
       char tmp[sizeof "."];
       memcpy (tmp, base, sizeof ".");
       strcpy (base, ".");
-      dirp = opendir (buf);
+      dirp = opendirat (dir_fd, buf, 0, pnew_fd);
       if (!dirp && errno == ENOMEM)
         result = BACKUP_NOMEM;
       memcpy (base, tmp, sizeof ".");
@@ -283,13 +299,15 @@ numbered_backup (char **buffer, size_t buffer_size, 
size_t filelen,
   return result;
 }
 
-/* Return the name of the new backup file for the existing file FILE,
-   allocated with malloc.  If RENAME, also rename FILE to the new name.
+/* Relative to DIR_FD, return the name of the new backup file for the
+   existing file FILE, allocated with malloc.
+   If RENAME, also rename FILE to the new name.
    On failure, return NULL and set errno.
    Do not call this function if backup_type == no_backups.  */
 
 char *
-backupfile_internal (char const *file, enum backup_type backup_type, bool 
rename)
+backupfile_internal (int dir_fd, char const *file,
+                     enum backup_type backup_type, bool rename)
 {
   ptrdiff_t base_offset = last_component (file) - file;
   size_t filelen = base_offset + strlen (file + base_offset);
@@ -311,6 +329,8 @@ backupfile_internal (char const *file, enum backup_type 
backup_type, bool rename
     return s;
 
   DIR *dirp = NULL;
+  int sdir = -1;
+  size_t base_max = 0;
   while (true)
     {
       memcpy (s, file, filelen + 1);
@@ -318,7 +338,8 @@ backupfile_internal (char const *file, enum backup_type 
backup_type, bool rename
       if (backup_type == simple_backups)
         memcpy (s + filelen, simple_backup_suffix, simple_backup_suffix_size);
       else
-        switch (numbered_backup (&s, ssize, filelen, base_offset, &dirp))
+        switch (numbered_backup (dir_fd, &s, ssize, filelen, base_offset,
+                                 &dirp, &sdir))
           {
           case BACKUP_IS_SAME_LENGTH:
             break;
@@ -330,11 +351,11 @@ backupfile_internal (char const *file, enum backup_type 
backup_type, bool rename
                 memcpy (s + filelen, simple_backup_suffix,
                         simple_backup_suffix_size);
               }
-            check_extension (s, filelen, '~');
+            check_extension (s, filelen, '~', sdir, &base_max);
             break;
 
           case BACKUP_IS_LONGER:
-            check_extension (s, filelen, '~');
+            check_extension (s, filelen, '~', sdir, &base_max);
             break;
 
           case BACKUP_NOMEM:
@@ -346,7 +367,6 @@ backupfile_internal (char const *file, enum backup_type 
backup_type, bool rename
       if (! rename)
         break;
 
-      int sdir = dirp ? dirfd (dirp) : -1;
       if (sdir < 0)
         {
           sdir = AT_FDCWD;
diff --git a/lib/backupfile.h b/lib/backupfile.h
index e22b0d067..538618ea6 100644
--- a/lib/backupfile.h
+++ b/lib/backupfile.h
@@ -17,11 +17,13 @@
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef BACKUPFILE_H_
-# define BACKUPFILE_H_
+#define BACKUPFILE_H_
 
-# ifdef __cplusplus
+#include <fcntl.h>
+
+#ifdef __cplusplus
 extern "C" {
-# endif
+#endif
 
 
 /* When to make backup files. */
@@ -41,21 +43,20 @@ enum backup_type
   numbered_backups
 };
 
-# define VALID_BACKUP_TYPE(Type)        \
+#define VALID_BACKUP_TYPE(Type) \
   ((unsigned int) (Type) <= numbered_backups)
 
 extern char const *simple_backup_suffix;
 
 void set_simple_backup_suffix (char const *);
-char *backup_file_rename (char const *, enum backup_type);
-char *find_backup_file_name (char const *, enum backup_type);
+char *backup_file_rename (int, char const *, enum backup_type);
+char *find_backup_file_name (int, char const *, enum backup_type);
 enum backup_type get_version (char const *context, char const *arg);
 enum backup_type xget_version (char const *context, char const *arg);
-void addext (char *, char const *, int);
 
 
-# ifdef __cplusplus
+#ifdef __cplusplus
 }
-# endif
+#endif
 
 #endif /* ! BACKUPFILE_H_ */
diff --git a/lib/fts.c b/lib/fts.c
index aaa6bb293..5e8e89532 100644
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -73,6 +73,7 @@ static char sccsid[] = "@(#)fts.c       8.6 (Berkeley) 
8/14/94";
 # include "fcntl--.h"
 # include "flexmember.h"
 # include "openat.h"
+# include "opendirat.h"
 # include "same-inode.h"
 #endif
 
@@ -294,31 +295,6 @@ fts_set_stat_required (FTSENT *p, bool required)
                            : FTS_NO_STAT_REQUIRED);
 }
 
-/* file-descriptor-relative opendir.  */
-/* FIXME: if others need this function, move it into lib/openat.c */
-static DIR *
-internal_function
-opendirat (int fd, char const *dir, int extra_flags, int *pdir_fd)
-{
-  int open_flags = (O_RDONLY | O_CLOEXEC | O_DIRECTORY | O_NOCTTY
-                    | O_NONBLOCK | extra_flags);
-  int new_fd = openat (fd, dir, open_flags);
-  DIR *dirp;
-
-  if (new_fd < 0)
-    return NULL;
-  dirp = fdopendir (new_fd);
-  if (dirp)
-    *pdir_fd = new_fd;
-  else
-    {
-      int saved_errno = errno;
-      close (new_fd);
-      errno = saved_errno;
-    }
-  return dirp;
-}
-
 /* Virtual fchdir.  Advance SP's working directory file descriptor,
    SP->fts_cwd_fd, to FD, and push the previous value onto the fd_ring.
    CHDIR_DOWN_ONE is true if FD corresponds to an entry in the directory
diff --git a/lib/opendirat.c b/lib/opendirat.c
new file mode 100644
index 000000000..19d114542
--- /dev/null
+++ b/lib/opendirat.c
@@ -0,0 +1,54 @@
+/* Open a directory relative to another directory.
+
+   Copyright 2006-2018 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+   Written by Jim Meyering and Paul Eggert.  */
+
+#include <config.h>
+
+#include <opendirat.h>
+
+#include <errno.h>
+#include <fcntl--.h>
+#include <unistd.h>
+
+/* Relative to DIR_FD, open the directory DIR, passing EXTRA_FLAGS to
+   the underlying openat call.  On success, store into *PNEW_FD the
+   underlying file descriptor of the newly opened directory and return
+   the directory stream.  On failure, return NULL and set errno.
+
+   On success, *PNEW_FD is at least 3, so this is a "safer" function.  */
+
+DIR *
+opendirat (int dir_fd, char const *dir, int extra_flags, int *pnew_fd)
+{
+  int open_flags = (O_RDONLY | O_CLOEXEC | O_DIRECTORY | O_NOCTTY
+                    | O_NONBLOCK | extra_flags);
+  int new_fd = openat (dir_fd, dir, open_flags);
+
+  if (new_fd < 0)
+    return NULL;
+  DIR *dirp = fdopendir (new_fd);
+  if (dirp)
+    *pnew_fd = new_fd;
+  else
+    {
+      int fdopendir_errno = errno;
+      close (new_fd);
+      errno = fdopendir_errno;
+    }
+  return dirp;
+}
diff --git a/lib/opendirat.h b/lib/opendirat.h
new file mode 100644
index 000000000..1edf5b57d
--- /dev/null
+++ b/lib/opendirat.h
@@ -0,0 +1,2 @@
+#include <dirent.h>
+DIR *opendirat (int, char const *, int, int *);
diff --git a/modules/backupfile b/modules/backupfile
index e9933fbc0..4ada3f561 100644
--- a/modules/backupfile
+++ b/modules/backupfile
@@ -13,14 +13,14 @@ argmatch
 closedir
 d-ino
 dirent-safer
-dirfd
 dirname-lgpl
 fcntl
 memcmp
-opendir
+opendirat
 renameatu
 readdir
 stdbool
+stdint
 
 configure.ac:
 gl_BACKUPFILE
diff --git a/modules/fts b/modules/fts
index ecbca70b5..3e09bcc91 100644
--- a/modules/fts
+++ b/modules/fts
@@ -15,7 +15,6 @@ d-type
 fchdir
 fcntl
 fcntl-h
-fdopendir
 flexmember
 fstat
 hash
@@ -23,8 +22,8 @@ i-ring
 lstat
 memmove
 openat-h
-openat-safer
 opendir
+opendirat
 readdir
 stdalign
 stdbool
diff --git a/modules/opendirat b/modules/opendirat
new file mode 100644
index 000000000..2e1798f63
--- /dev/null
+++ b/modules/opendirat
@@ -0,0 +1,26 @@
+Description:
+Open a directory relative to another directory.
+
+Files:
+lib/opendirat.c
+lib/opendirat.h
+
+Depends-on:
+dirent
+fcntl-h
+fdopendir
+openat-safer
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += opendirat.c
+
+Include:
+"opendirat.h"
+
+License:
+GPL
+
+Maintainer:
+all
-- 
2.17.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]