]> git.ipfire.org Git - thirdparty/tar.git/commitdiff
chdir_id refactoring
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 28 Oct 2025 02:40:47 +0000 (19:40 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 15 Nov 2025 23:10:48 +0000 (15:10 -0800)
This prepares for future changes that need directory IDs.
* src/common.h (struct chdir_id): New struct.
* src/extract.c (extract_dir): Use chdir_id to avoid duplicate stats.
* src/misc.c (struct wd): New member ID.
(grow_wd): New function, extracted from chdir_arg and that
also initializes id.err.
(chdir_arg): Use it.  Initialize id.err.
(chdir_id): New function.

src/common.h
src/extract.c
src/misc.c

index 24511aaa3fb3799445a09791021572a29873eb59..1d31659d92ba349b13217d77e73ecbe685144df2 100644 (file)
@@ -756,6 +756,7 @@ extern idx_t chdir_current;
 extern int chdir_fd;
 idx_t chdir_arg (char const *dir);
 void chdir_do (idx_t dir);
+struct chdir_id { int err; dev_t st_dev; ino_t st_ino; } chdir_id (void);
 idx_t chdir_count (void);
 
 void close_diag (char const *name);
index b3760ac91bd15d413a9ed7894949b27742148062..92c34b2a7c146f6403b843737d0093abc5eb1707 100644 (file)
@@ -1106,12 +1106,14 @@ extract_dir (char *file_name, char typeflag)
   /* Save 'root device' to avoid purging mount points. */
   if (one_file_system_option && root_device == 0)
     {
-      struct stat st;
-
-      if (fstatat (chdir_fd, ".", &st, 0) < 0)
-       stat_diag (".");
+      struct chdir_id id = chdir_id ();
+      if (id.err)
+       {
+         errno = id.err;
+         stat_diag (".");
+       }
       else
-       root_device = st.st_dev;
+       root_device = id.st_dev;
     }
 
   if (incremental_option)
index 187e45f574aafc35b3d1c3b6bcbe0c806ed671e5..dcc81ef6aac884ce8d39eaca0d64b3e79294e41c 100644 (file)
@@ -913,6 +913,11 @@ struct wd
      the working directory.  If zero, the directory needs to be opened
      to be used.  */
   int fd;
+
+  /* If ID.err is zero, the directory's identity;
+     if positive, a failure indication with errno = ID.err;
+     if negative, no attempt has been made yet to get the identity.  */
+  struct chdir_id id;
 };
 
 /* A vector of chdir targets.  wd[0] is the initial working directory.  */
@@ -943,23 +948,29 @@ chdir_count (void)
   return wd_count - !!wd_count;
 }
 
+/* Grow the WD table by at least one entry.  */
+static void
+grow_wd (void)
+{
+  wd = xpalloc (wd, &wd_alloc, wd_alloc ? 1 : 2, -1, sizeof *wd);
+
+  if (! wd_count)
+    {
+      wd[wd_count].name = ".";
+      wd[wd_count].abspath = NULL;
+      wd[wd_count].fd = AT_FDCWD;
+      wd[wd_count].id.err = -1;
+      wd_count++;
+    }
+}
+
 /* DIR is the operand of a -C option; add it to vector of chdir targets,
    and return the index of its location.  */
 idx_t
 chdir_arg (char const *dir)
 {
   if (wd_count == wd_alloc)
-    {
-      wd = xpalloc (wd, &wd_alloc, wd_alloc ? 1 : 2, -1, sizeof *wd);
-
-      if (! wd_count)
-       {
-         wd[wd_count].name = ".";
-         wd[wd_count].abspath = NULL;
-         wd[wd_count].fd = AT_FDCWD;
-         wd_count++;
-       }
-    }
+    grow_wd ();
 
   /* Optimize the common special case of the working directory,
      or the working directory as a prefix.  */
@@ -975,6 +986,7 @@ chdir_arg (char const *dir)
   wd[wd_count].name = dir;
   wd[wd_count].abspath = NULL;
   wd[wd_count].fd = 0;
+  wd[wd_count].id.err = -1;
   return wd_count++;
 }
 
@@ -1046,6 +1058,25 @@ chdir_do (idx_t i)
       chdir_fd = fd;
     }
 }
+
+/* Return the identity of the current directory.  */
+struct chdir_id
+chdir_id (void)
+{
+  if (!wd)
+    grow_wd ();
+
+  struct wd *curr = &wd[chdir_current];
+  if (curr->id.err < 0)
+    {
+      struct stat st;
+      curr->id = ((chdir_fd < 0 ? stat (".", &st) : fstat (chdir_fd, &st)) < 0
+                 ? (struct chdir_id) { .err = errno }
+                 : (struct chdir_id) { .st_dev = st.st_dev,
+                                       .st_ino = st.st_ino });
+    }
+  return curr->id;
+}
 \f
 const char *
 tar_dirname (void)