Cache parent directories

Although this might help (or hurt) performance, the main
motivation is to make it easier in future commits
to prevent tarballs from escaping the extraction directory.
* src/common.h: (BADFD): New constant.
(struct fdbase): New type.
* src/create.c (dump_file0): Use parent->fd instead of caching
it into a local, as the latter approach is now awkward.
* src/extract.c (extract_link): Don’t save errno unless needed.
* src/misc.c (safer_rmdir): New arg F.  All callers changed.
(maybe_backup_file): Construct full after_backup_name, now
that find_backup_file_name no longer does that for us.
(chdir_fd): Now static not extern, as other modules now use fdbase.
(fdbase_cache): New static var.
(fdbase_clear): New function.  Call it whenever removing
or renaming directories or symlinks to directories.
(fdbase_opendir): New static function.
(fdbase, fdbase1): New functions.  Call them whenever the
code formerly passed chdir_fd to a syscall.
This commit is contained in:
Paul Eggert
2025-11-15 15:10:48 -08:00
parent 382a47f2fd
commit bdd773d028
9 changed files with 372 additions and 130 deletions
+14 -7
View File
@@ -106,7 +106,10 @@ flush_deferred_unlinks (bool force)
else
fname = p->file_name;
if (unlinkat (chdir_fd, fname, AT_REMOVEDIR) < 0)
struct fdbase f = fdbase (fname);
if (f.fd != BADFD && unlinkat (f.fd, f.base, AT_REMOVEDIR) == 0)
fdbase_clear ();
else
{
switch (errno)
{
@@ -132,7 +135,10 @@ flush_deferred_unlinks (bool force)
}
else
{
if (unlinkat (chdir_fd, p->file_name, 0) < 0 && errno != ENOENT)
struct fdbase f = fdbase (p->file_name);
if (f.fd != BADFD && unlinkat (f.fd, f.base, 0) == 0)
fdbase_clear ();
else if (errno != ENOENT)
unlink_error (p->file_name);
}
dunlink_reclaim (p);
@@ -166,11 +172,12 @@ flush_deferred_unlinks (bool force)
else
fname = p->file_name;
if (unlinkat (chdir_fd, fname, AT_REMOVEDIR) < 0)
{
if (errno != ENOENT)
rmdir_error (fname);
}
struct fdbase f = fdbase (fname);
if (f.fd != BADFD && unlinkat (f.fd, f.base, AT_REMOVEDIR) == 0)
fdbase_clear ();
else if (errno != ENOENT)
rmdir_error (fname);
dunlink_reclaim (p);
p = next;
}