From: Paul Eggert Date: Tue, 28 Oct 2025 02:40:47 +0000 (-0700) Subject: chdir_id refactoring X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=56fb4a96ca43c247261b8c04dd65592f990f98ac;p=thirdparty%2Ftar.git chdir_id refactoring 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. --- diff --git a/src/common.h b/src/common.h index 24511aaa..1d31659d 100644 --- a/src/common.h +++ b/src/common.h @@ -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); diff --git a/src/extract.c b/src/extract.c index b3760ac9..92c34b2a 100644 --- a/src/extract.c +++ b/src/extract.c @@ -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) diff --git a/src/misc.c b/src/misc.c index 187e45f5..dcc81ef6 100644 --- a/src/misc.c +++ b/src/misc.c @@ -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; +} const char * tar_dirname (void)