mirror of
https://git.savannah.gnu.org/git/tar.git
synced 2026-08-20 08:16:02 +00:00
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:
+54
-36
@@ -815,12 +815,15 @@ start_header (struct tar_stat_info *st)
|
||||
break;
|
||||
|
||||
case COMMAND_MTIME:
|
||||
if (!sys_exec_setmtime_script (set_mtime_command,
|
||||
chdir_fd,
|
||||
st->orig_file_name,
|
||||
set_mtime_format,
|
||||
&mtime))
|
||||
mtime = st->mtime;
|
||||
{
|
||||
struct fdbase f = fdbase (st->orig_file_name);
|
||||
if (f.fd == BADFD
|
||||
|| !sys_exec_setmtime_script (set_mtime_command,
|
||||
f.fd, f.base,
|
||||
set_mtime_format,
|
||||
&mtime))
|
||||
mtime = st->mtime;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1338,8 +1341,10 @@ create_archive (void)
|
||||
{
|
||||
if (! st.orig_file_name)
|
||||
{
|
||||
int fd = openat (chdir_fd, p->name,
|
||||
open_searchdir_flags);
|
||||
struct fdbase f = fdbase (p->name);
|
||||
int fd = (f.fd == BADFD ? -1
|
||||
: openat (f.fd, f.base,
|
||||
open_searchdir_flags));
|
||||
if (fd < 0)
|
||||
{
|
||||
file_removed_diag (p->name, !p->parent,
|
||||
@@ -1539,9 +1544,18 @@ subfile_open (struct tar_stat_info const *dir, char const *file, int flags)
|
||||
gettext ("");
|
||||
}
|
||||
|
||||
while ((fd = openat (dir ? dir->fd : chdir_fd, file, flags)) < 0
|
||||
&& open_failure_recover (dir))
|
||||
continue;
|
||||
do
|
||||
{
|
||||
if (dir)
|
||||
fd = openat (dir->fd, file, flags);
|
||||
else
|
||||
{
|
||||
struct fdbase f = fdbase (file);
|
||||
fd = f.fd == BADFD ? -1 : openat (f.fd, f.base, flags);
|
||||
}
|
||||
}
|
||||
while (fd < 0 && open_failure_recover (dir));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -1569,8 +1583,9 @@ restore_parent_fd (struct tar_stat_info const *st)
|
||||
|
||||
if (parentfd < 0)
|
||||
{
|
||||
int origfd = openat (chdir_fd, parent->orig_file_name,
|
||||
open_searchdir_flags);
|
||||
struct fdbase f = fdbase (parent->orig_file_name);
|
||||
int origfd = (f.fd == BADFD ? -1
|
||||
: openat (f.fd, f.base, open_searchdir_flags));
|
||||
if (0 <= origfd)
|
||||
{
|
||||
if (fstat (parentfd, &parentstat) < 0
|
||||
@@ -1605,7 +1620,6 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
bool is_dir;
|
||||
struct tar_stat_info const *parent = st->parent;
|
||||
bool top_level = ! parent;
|
||||
int parentfd = top_level ? chdir_fd : parent->fd;
|
||||
void (*diag) (char const *) = 0;
|
||||
|
||||
if (interactive_option && !confirm ("add", p))
|
||||
@@ -1618,12 +1632,15 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
if (!transform_name (&st->file_name, XFORM_REGFILE))
|
||||
return NULL;
|
||||
|
||||
if (parentfd < 0 && ! top_level)
|
||||
struct fdbase f = (top_level ? fdbase (name)
|
||||
: (struct fdbase) { .fd = parent->fd, .base = name });
|
||||
if (!top_level && parent->fd < 0)
|
||||
{
|
||||
errno = - parentfd;
|
||||
errno = - parent->fd;
|
||||
diag = open_diag;
|
||||
}
|
||||
else if (fstatat (parentfd, name, &st->stat, fstatat_flags) < 0)
|
||||
else if (f.fd == BADFD
|
||||
|| fstatat (f.fd, f.base, &st->stat, fstatat_flags) < 0)
|
||||
diag = stat_diag;
|
||||
else if (file_dumpable_p (&st->stat))
|
||||
{
|
||||
@@ -1695,9 +1712,9 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
bool ok;
|
||||
struct stat st2;
|
||||
|
||||
xattrs_acls_get (parentfd, name, st, !is_dir);
|
||||
xattrs_selinux_get (parentfd, name, st, fd);
|
||||
xattrs_xattrs_get (parentfd, name, st, fd);
|
||||
xattrs_acls_get (f.fd, f.base, st, !is_dir);
|
||||
xattrs_selinux_get (f.fd, f.base, st, fd);
|
||||
xattrs_xattrs_get (f.fd, f.base, st, fd);
|
||||
|
||||
if (is_dir)
|
||||
{
|
||||
@@ -1715,7 +1732,8 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
ok = dump_dir (st);
|
||||
|
||||
fd = st->fd;
|
||||
parentfd = top_level ? chdir_fd : parent->fd;
|
||||
f = (top_level ? fdbase (name)
|
||||
: (struct fdbase) { .fd = parent->fd, .base = name });
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1756,9 +1774,9 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
}
|
||||
else if (fd == 0)
|
||||
{
|
||||
if (parentfd < 0 && ! top_level)
|
||||
if (!top_level && parent->fd < 0)
|
||||
{
|
||||
errno = - parentfd;
|
||||
errno = - parent->fd;
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
@@ -1809,7 +1827,7 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
}
|
||||
else if (atime_preserve_option == replace_atime_preserve
|
||||
&& timespec_cmp (st->atime, get_stat_atime (&st2)) != 0
|
||||
&& set_file_atime (fd, parentfd, name, st->atime) < 0)
|
||||
&& set_file_atime (fd, f.fd, f.base, st->atime) < 0)
|
||||
utime_error (p);
|
||||
}
|
||||
|
||||
@@ -1821,7 +1839,7 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
}
|
||||
else if (S_ISLNK (st->stat.st_mode))
|
||||
{
|
||||
st->link_name = areadlinkat_with_size (parentfd, name, st->stat.st_size);
|
||||
st->link_name = areadlinkat_with_size (f.fd, f.base, st->stat.st_size);
|
||||
if (!st->link_name)
|
||||
{
|
||||
if (errno == ENOMEM)
|
||||
@@ -1835,8 +1853,8 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
< strlen (st->link_name))
|
||||
write_long_link (st);
|
||||
|
||||
xattrs_selinux_get (parentfd, name, st, 0);
|
||||
xattrs_xattrs_get (parentfd, name, st, 0);
|
||||
xattrs_selinux_get (f.fd, f.base, st, 0);
|
||||
xattrs_xattrs_get (f.fd, f.base, st, 0);
|
||||
|
||||
block_ordinal = current_block_ordinal ();
|
||||
st->stat.st_size = 0; /* force 0 size on symlink */
|
||||
@@ -1857,23 +1875,23 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
else if (S_ISCHR (st->stat.st_mode))
|
||||
{
|
||||
type = CHRTYPE;
|
||||
xattrs_acls_get (parentfd, name, st, true);
|
||||
xattrs_selinux_get (parentfd, name, st, 0);
|
||||
xattrs_xattrs_get (parentfd, name, st, 0);
|
||||
xattrs_acls_get (f.fd, f.base, st, true);
|
||||
xattrs_selinux_get (f.fd, f.base, st, 0);
|
||||
xattrs_xattrs_get (f.fd, f.base, st, 0);
|
||||
}
|
||||
else if (S_ISBLK (st->stat.st_mode))
|
||||
{
|
||||
type = BLKTYPE;
|
||||
xattrs_acls_get (parentfd, name, st, true);
|
||||
xattrs_selinux_get (parentfd, name, st, 0);
|
||||
xattrs_xattrs_get (parentfd, name, st, 0);
|
||||
xattrs_acls_get (f.fd, f.base, st, true);
|
||||
xattrs_selinux_get (f.fd, f.base, st, 0);
|
||||
xattrs_xattrs_get (f.fd, f.base, st, 0);
|
||||
}
|
||||
else if (S_ISFIFO (st->stat.st_mode))
|
||||
{
|
||||
type = FIFOTYPE;
|
||||
xattrs_acls_get (parentfd, name, st, true);
|
||||
xattrs_selinux_get (parentfd, name, st, 0);
|
||||
xattrs_xattrs_get (parentfd, name, st, 0);
|
||||
xattrs_acls_get (f.fd, f.base, st, true);
|
||||
xattrs_selinux_get (f.fd, f.base, st, 0);
|
||||
xattrs_xattrs_get (f.fd, f.base, st, 0);
|
||||
}
|
||||
else if (S_ISSOCK (st->stat.st_mode))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user