mirror of
https://git.savannah.gnu.org/git/tar.git
synced 2026-04-26 03:20:40 +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:
@@ -752,11 +752,17 @@ int deref_stat (char const *name, struct stat *buf);
|
||||
idx_t blocking_read (int fd, void *buf, idx_t count);
|
||||
idx_t blocking_write (int fd, void const *buf, idx_t count);
|
||||
|
||||
/* Not valid as the first argument to openat.
|
||||
It is a negative integer not equal to AT_FDCWD. */
|
||||
enum { BADFD = AT_FDCWD == -1 ? -2 : -1 };
|
||||
|
||||
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);
|
||||
struct fdbase { int fd; char const *base; } fdbase (char const *);
|
||||
struct fdbase fdbase1 (char const *);
|
||||
void fdbase_clear (void);
|
||||
idx_t chdir_count (void);
|
||||
|
||||
void close_diag (char const *name);
|
||||
|
||||
@@ -213,7 +213,9 @@ diff_file (void)
|
||||
}
|
||||
else
|
||||
{
|
||||
diff_handle = openat (chdir_fd, file_name, open_read_flags);
|
||||
struct fdbase f = fdbase (file_name);
|
||||
diff_handle = (f.fd == BADFD ? -1
|
||||
: openat (f.fd, f.base, open_read_flags));
|
||||
|
||||
if (diff_handle < 0)
|
||||
{
|
||||
@@ -232,8 +234,7 @@ diff_file (void)
|
||||
&& stat_data.st_size != 0)
|
||||
{
|
||||
struct timespec atime = get_stat_atime (&stat_data);
|
||||
if (set_file_atime (diff_handle, chdir_fd, file_name, atime)
|
||||
< 0)
|
||||
if (set_file_atime (diff_handle, f.fd, f.base, atime) < 0)
|
||||
utime_error (file_name);
|
||||
}
|
||||
|
||||
@@ -265,9 +266,9 @@ diff_symlink (void)
|
||||
char buf[1024];
|
||||
idx_t len = strlen (current_stat_info.link_name);
|
||||
char *linkbuf = len < sizeof buf ? buf : xmalloc (len + 1);
|
||||
|
||||
ssize_t status = readlinkat (chdir_fd, current_stat_info.file_name,
|
||||
linkbuf, len + 1);
|
||||
struct fdbase f = fdbase (current_stat_info.file_name);
|
||||
ssize_t status = (f.fd == BADFD ? -1
|
||||
: readlinkat (f.fd, f.base, linkbuf, len + 1));
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
@@ -426,7 +427,8 @@ diff_multivol (void)
|
||||
}
|
||||
|
||||
|
||||
int fd = openat (chdir_fd, current_stat_info.file_name, open_read_flags);
|
||||
struct fdbase f = fdbase (current_stat_info.file_name);
|
||||
int fd = f.fd == BADFD ? -1 : openat (f.fd, f.base, open_read_flags);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
|
||||
90
src/create.c
90
src/create.c
@@ -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))
|
||||
{
|
||||
|
||||
160
src/extract.c
160
src/extract.c
@@ -266,7 +266,8 @@ fd_i_chmod (int fd, char const *file, mode_t mode, int atflag)
|
||||
if (result == 0 || implemented (errno))
|
||||
return result;
|
||||
}
|
||||
return fchmodat (chdir_fd, file, mode, atflag);
|
||||
struct fdbase f = fdbase (file);
|
||||
return f.fd == BADFD ? -1 : fchmodat (f.fd, f.base, mode, atflag);
|
||||
}
|
||||
|
||||
/* A version of fd_i_chmod which gracefully handles several common error
|
||||
@@ -315,16 +316,18 @@ fd_chown (int fd, char const *file, uid_t uid, gid_t gid, int atflag)
|
||||
if (result == 0 || implemented (errno))
|
||||
return result;
|
||||
}
|
||||
return fchownat (chdir_fd, file, uid, gid, atflag);
|
||||
struct fdbase f = fdbase (file);
|
||||
return f.fd == BADFD ? -1 : fchownat (f.fd, f.base, uid, gid, atflag);
|
||||
}
|
||||
|
||||
/* Use fstat if possible, fstatat otherwise. */
|
||||
static int
|
||||
fd_stat (int fd, char const *file, struct stat *st, int atflag)
|
||||
{
|
||||
return (0 <= fd
|
||||
? fstat (fd, st)
|
||||
: fstatat (chdir_fd, file, st, atflag));
|
||||
if (0 <= fd)
|
||||
return fstat (fd, st);
|
||||
struct fdbase f = fdbase (file);
|
||||
return f.fd == BADFD ? -1 : fstatat (f.fd, f.base, st, atflag);
|
||||
}
|
||||
|
||||
/* Set the mode for FILE_NAME to MODE.
|
||||
@@ -421,7 +424,15 @@ set_stat (char const *file_name,
|
||||
ts[0].tv_nsec = UTIME_OMIT;
|
||||
ts[1] = st->mtime;
|
||||
|
||||
if (fdutimensat (fd, chdir_fd, file_name, ts, atflag) == 0)
|
||||
int r;
|
||||
if (0 <= fd)
|
||||
r = futimens (fd, ts);
|
||||
if (fd < 0 || (r < 0 && errno == ENOSYS))
|
||||
{
|
||||
struct fdbase f = fdbase (file_name);
|
||||
r = f.fd == BADFD ? -1 : utimensat (f.fd, f.base, ts, atflag);
|
||||
}
|
||||
if (r == 0)
|
||||
{
|
||||
if (incremental_option)
|
||||
check_time (file_name, ts[0]);
|
||||
@@ -546,9 +557,9 @@ delay_set_stat (char const *file_name, struct tar_stat_info const *st,
|
||||
if (data->interdir)
|
||||
{
|
||||
struct stat real_st;
|
||||
if (fstatat (chdir_fd, data->file_name,
|
||||
&real_st, data->atflag)
|
||||
< 0)
|
||||
struct fdbase f = fdbase (data->file_name);
|
||||
if (f.fd == BADFD
|
||||
|| fstatat (f.fd, f.base, &real_st, data->atflag) < 0)
|
||||
{
|
||||
stat_error (data->file_name);
|
||||
}
|
||||
@@ -660,7 +671,8 @@ repair_delayed_set_stat (char const *dir,
|
||||
for (data = delayed_set_stat_head; data; data = data->next)
|
||||
{
|
||||
struct stat st;
|
||||
if (fstatat (chdir_fd, data->file_name, &st, data->atflag) < 0)
|
||||
struct fdbase f = fdbase (data->file_name);
|
||||
if (f.fd == BADFD || fstatat (f.fd, f.base, &st, data->atflag) < 0)
|
||||
{
|
||||
stat_error (data->file_name);
|
||||
return;
|
||||
@@ -774,7 +786,8 @@ make_directories (char *file_name, bool *interdir_made)
|
||||
*cursor = '\0'; /* truncate the name there */
|
||||
desired_mode = MODE_RWX & ~ newdir_umask;
|
||||
mode = desired_mode | (we_are_root ? 0 : MODE_WXUSR);
|
||||
status = mkdirat (chdir_fd, file_name, mode);
|
||||
struct fdbase f = fdbase (file_name);
|
||||
status = f.fd == BADFD ? -1 : mkdirat (f.fd, f.base, mode);
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
@@ -817,7 +830,8 @@ make_directories (char *file_name, bool *interdir_made)
|
||||
process may have created it, so check whether it exists now. */
|
||||
*parent_end = '\0';
|
||||
struct stat st;
|
||||
int stat_status = fstatat (chdir_fd, file_name, &st, 0);
|
||||
struct fdbase f = fdbase (file_name);
|
||||
int stat_status = f.fd == BADFD ? -1 : fstatat (f.fd, f.base, &st, 0);
|
||||
if (! (stat_status < 0 || S_ISDIR (st.st_mode)))
|
||||
stat_status = -1;
|
||||
if (stat_status < 0)
|
||||
@@ -973,7 +987,8 @@ set_xattr (MAYBE_UNUSED char const *file_name,
|
||||
#ifdef HAVE_XATTRS
|
||||
if (xattrs_option && st->xattr_map.xm_size)
|
||||
{
|
||||
int r = mknodat (chdir_fd, file_name, mode | S_IFREG, 0);
|
||||
struct fdbase f = fdbase (file_name);
|
||||
int r = f.fd == BADFD ? -1 : mknodat (f.fd, f.base, mode | S_IFREG, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
xattrs_xattrs_set (st, file_name, typeflag, false);
|
||||
@@ -1017,7 +1032,8 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links)
|
||||
|
||||
if (check_for_renamed_directories)
|
||||
{
|
||||
if (fstatat (chdir_fd, data->file_name, &st, data->atflag) < 0)
|
||||
struct fdbase f = fdbase (data->file_name);
|
||||
if (f.fd == BADFD || fstatat (f.fd, f.base, &st, data->atflag) < 0)
|
||||
{
|
||||
stat_error (data->file_name);
|
||||
skip_this_one = 1;
|
||||
@@ -1066,8 +1082,9 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links)
|
||||
static bool
|
||||
is_directory_link (char const *file_name, struct stat *st)
|
||||
{
|
||||
return (issymlinkat (chdir_fd, file_name)
|
||||
&& fstatat (chdir_fd, file_name, st, 0) == 0
|
||||
struct fdbase f = fdbase (file_name);
|
||||
return (f.fd != BADFD && issymlinkat (f.fd, f.base)
|
||||
&& fstatat (f.fd, f.base, st, 0) == 0
|
||||
&& S_ISDIR (st->st_mode));
|
||||
}
|
||||
|
||||
@@ -1126,7 +1143,8 @@ extract_dir (char *file_name, char typeflag)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
status = mkdirat (chdir_fd, file_name, mode);
|
||||
struct fdbase f = fdbase (file_name);
|
||||
status = f.fd == BADFD ? -1 : mkdirat (f.fd, f.base, mode);
|
||||
if (status == 0)
|
||||
{
|
||||
current_mode = mode & ~ current_umask;
|
||||
@@ -1235,18 +1253,20 @@ open_output_file (char const *file_name, char typeflag, mode_t mode,
|
||||
}
|
||||
}
|
||||
|
||||
struct fdbase f = fdbase (file_name);
|
||||
|
||||
/* If O_NOFOLLOW is needed but does not work, check for a symlink
|
||||
separately. There's a race condition, but that cannot be avoided
|
||||
on hosts lacking O_NOFOLLOW. */
|
||||
if (! HAVE_WORKING_O_NOFOLLOW
|
||||
&& overwriting_old_files && ! dereference_option
|
||||
&& issymlinkat (chdir_fd, file_name))
|
||||
&& f.fd != BADFD && issymlinkat (f.fd, f.base))
|
||||
{
|
||||
errno = ELOOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = openat (chdir_fd, file_name, openflag, mode);
|
||||
fd = f.fd == BADFD ? -1 : openat (f.fd, f.base, openflag, mode);
|
||||
if (0 <= fd)
|
||||
{
|
||||
if (openflag & O_EXCL)
|
||||
@@ -1410,7 +1430,8 @@ find_delayed_link_source (char const *name)
|
||||
if (!delayed_link_table)
|
||||
return false;
|
||||
|
||||
if (fstatat (chdir_fd, name, &st, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
struct fdbase f = fdbase (name);
|
||||
if (f.fd == BADFD || fstatat (f.fd, f.base, &st, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
stat_error (name);
|
||||
@@ -1436,8 +1457,16 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made)
|
||||
int fd;
|
||||
struct stat st;
|
||||
|
||||
while ((fd = openat (chdir_fd, file_name, O_WRONLY | O_CREAT | O_EXCL, 0)) < 0)
|
||||
for (;;)
|
||||
{
|
||||
struct fdbase f = fdbase (file_name);
|
||||
if (f.fd != BADFD)
|
||||
{
|
||||
fd = openat (f.fd, f.base, O_WRONLY | O_CREAT | O_EXCL, 0);
|
||||
if (0 <= fd)
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno == EEXIST && find_delayed_link_source (file_name))
|
||||
{
|
||||
/* The placeholder file has already been created. This means
|
||||
@@ -1459,7 +1488,7 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made)
|
||||
open_error (file_name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fstat (fd, &st) < 0)
|
||||
{
|
||||
@@ -1536,15 +1565,23 @@ extract_link (char *file_name, MAYBE_UNUSED char typeflag)
|
||||
|
||||
do
|
||||
{
|
||||
struct stat st1, st2;
|
||||
int e;
|
||||
int status = linkat (chdir_fd, link_name, chdir_fd, file_name, 0);
|
||||
e = errno;
|
||||
struct stat st, st1;
|
||||
int status;
|
||||
|
||||
struct fdbase f = fdbase (file_name), f1;
|
||||
if (f.fd == BADFD)
|
||||
status = -1;
|
||||
else
|
||||
{
|
||||
f1 = fdbase1 (link_name);
|
||||
status = (f1.fd == BADFD ? -1
|
||||
: linkat (f1.fd, f1.base, f.fd, f.base, 0));
|
||||
}
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
if (delayed_link_table
|
||||
&& fstatat (chdir_fd, link_name, &st1, AT_SYMLINK_NOFOLLOW) == 0)
|
||||
&& fstatat (f1.fd, f1.base, &st1, AT_SYMLINK_NOFOLLOW) == 0)
|
||||
{
|
||||
struct delayed_link dl1;
|
||||
dl1.st_ino = st1.st_ino;
|
||||
@@ -1564,14 +1601,14 @@ extract_link (char *file_name, MAYBE_UNUSED char typeflag)
|
||||
|
||||
return true;
|
||||
}
|
||||
else if ((e == EEXIST && streq (link_name, file_name))
|
||||
|| ((fstatat (chdir_fd, link_name, &st1, AT_SYMLINK_NOFOLLOW)
|
||||
== 0)
|
||||
&& (fstatat (chdir_fd, file_name, &st2, AT_SYMLINK_NOFOLLOW)
|
||||
== 0)
|
||||
&& psame_inode (&st1, &st2)))
|
||||
return true;
|
||||
|
||||
int e = errno;
|
||||
if ((e == EEXIST && streq (link_name, file_name))
|
||||
|| (f.fd != BADFD && f1.fd != BADFD
|
||||
&& fstatat (f1.fd, f1.base, &st1, AT_SYMLINK_NOFOLLOW) == 0
|
||||
&& fstatat (f.fd, f.base, &st, AT_SYMLINK_NOFOLLOW) == 0
|
||||
&& psame_inode (&st1, &st)))
|
||||
return true;
|
||||
errno = e;
|
||||
}
|
||||
while ((rc = maybe_recoverable (file_name, false, &interdir_made))
|
||||
@@ -1597,7 +1634,10 @@ extract_symlink (char *file_name, MAYBE_UNUSED char typeflag)
|
||||
|| contains_dot_dot (current_stat_info.link_name)))
|
||||
return create_placeholder_file (file_name, true, &interdir_made);
|
||||
|
||||
while (symlinkat (current_stat_info.link_name, chdir_fd, file_name) < 0)
|
||||
for (struct fdbase f;
|
||||
((f = fdbase (file_name)).fd == BADFD
|
||||
|| symlinkat (current_stat_info.link_name, f.fd, f.base) < 0);
|
||||
)
|
||||
switch (maybe_recoverable (file_name, false, &interdir_made))
|
||||
{
|
||||
case RECOVER_OK:
|
||||
@@ -1636,8 +1676,10 @@ extract_node (char *file_name, char typeflag)
|
||||
mode_t mode = (current_stat_info.stat.st_mode & (MODE_RWX | S_IFBLK | S_IFCHR)
|
||||
& ~ (0 < same_owner_option ? S_IRWXG | S_IRWXO : 0));
|
||||
|
||||
while (mknodat (chdir_fd, file_name, mode, current_stat_info.stat.st_rdev)
|
||||
< 0)
|
||||
for (struct fdbase f;
|
||||
((f = fdbase (file_name)).fd == BADFD
|
||||
|| mknodat (f.fd, f.base, mode, current_stat_info.stat.st_rdev) < 0);
|
||||
)
|
||||
switch (maybe_recoverable (file_name, false, &interdir_made))
|
||||
{
|
||||
case RECOVER_OK:
|
||||
@@ -1666,7 +1708,10 @@ extract_fifo (char *file_name, char typeflag)
|
||||
mode_t mode = (current_stat_info.stat.st_mode & MODE_RWX
|
||||
& ~ (0 < same_owner_option ? S_IRWXG | S_IRWXO : 0));
|
||||
|
||||
while (mkfifoat (chdir_fd, file_name, mode) < 0)
|
||||
for (struct fdbase f;
|
||||
((f = fdbase (file_name)).fd == BADFD
|
||||
|| mkfifoat (f.fd, f.base, mode) < 0);
|
||||
)
|
||||
switch (maybe_recoverable (file_name, false, &interdir_made))
|
||||
{
|
||||
case RECOVER_OK:
|
||||
@@ -1882,7 +1927,7 @@ static void
|
||||
apply_delayed_link (struct delayed_link *ds)
|
||||
{
|
||||
struct string_list *sources = ds->sources;
|
||||
char const *valid_source = 0;
|
||||
char const *valid_source = NULL;
|
||||
|
||||
chdir_do (ds->change_dir);
|
||||
|
||||
@@ -1894,24 +1939,29 @@ apply_delayed_link (struct delayed_link *ds)
|
||||
/* Make sure the placeholder file is still there. If not,
|
||||
don't create a link, as the placeholder was probably
|
||||
removed by a later extraction. */
|
||||
if (fstatat (chdir_fd, source, &st, AT_SYMLINK_NOFOLLOW) == 0
|
||||
struct fdbase f = fdbase (source);
|
||||
if (f.fd != BADFD && fstatat (f.fd, f.base, &st, AT_SYMLINK_NOFOLLOW) == 0
|
||||
&& SAME_INODE (st, *ds)
|
||||
&& BIRTHTIME_EQ (get_stat_birthtime (&st), ds->birthtime))
|
||||
{
|
||||
/* Unlink the placeholder, then create a hard link if possible,
|
||||
a symbolic link otherwise. */
|
||||
if (unlinkat (chdir_fd, source, 0) < 0)
|
||||
struct fdbase f1;
|
||||
if (unlinkat (f.fd, f.base, 0) < 0)
|
||||
unlink_error (source);
|
||||
else if (valid_source
|
||||
&& (linkat (chdir_fd, valid_source, chdir_fd, source, 0)
|
||||
== 0))
|
||||
&& ((f1 = f.fd == BADFD ? f : fdbase1 (valid_source)).fd
|
||||
!= BADFD)
|
||||
&& linkat (f1.fd, f1.base, f.fd, f.base, 0) == 0)
|
||||
;
|
||||
else if (!ds->is_symlink)
|
||||
{
|
||||
if (linkat (chdir_fd, ds->target, chdir_fd, source, 0) < 0)
|
||||
f1 = f.fd == BADFD ? f : fdbase1 (ds->target);
|
||||
if (f1.fd == BADFD
|
||||
|| linkat (f1.fd, f1.base, f.fd, f.base, 0) < 0)
|
||||
link_error (ds->target, source);
|
||||
}
|
||||
else if (symlinkat (ds->target, chdir_fd, source) < 0)
|
||||
else if (symlinkat (ds->target, f.fd, f.base) < 0)
|
||||
symlink_error (ds->target, source);
|
||||
else
|
||||
{
|
||||
@@ -1996,9 +2046,14 @@ extract_finish (void)
|
||||
bool
|
||||
rename_directory (char *src, char *dst)
|
||||
{
|
||||
if (renameat (chdir_fd, src, chdir_fd, dst) == 0)
|
||||
fixup_delayed_set_stat (src, dst);
|
||||
else
|
||||
struct fdbase f1 = fdbase1 (src);
|
||||
struct fdbase f = f1.fd == BADFD ? f1 : fdbase (dst);
|
||||
if (f.fd != BADFD && renameat (f1.fd, f1.base, f.fd, f.base) == 0)
|
||||
{
|
||||
fdbase_clear ();
|
||||
fixup_delayed_set_stat (src, dst);
|
||||
}
|
||||
else if (f1.fd != BADFD)
|
||||
{
|
||||
int e = errno;
|
||||
|
||||
@@ -2007,8 +2062,13 @@ rename_directory (char *src, char *dst)
|
||||
case ENOENT:
|
||||
if (make_directories (dst, NULL) == 0)
|
||||
{
|
||||
if (renameat (chdir_fd, src, chdir_fd, dst) == 0)
|
||||
return true;
|
||||
f = fdbase (dst);
|
||||
if (f.fd != BADFD
|
||||
&& renameat (f1.fd, f1.base, f.fd, f.base) == 0)
|
||||
{
|
||||
fdbase_clear ();
|
||||
return true;
|
||||
}
|
||||
e = errno;
|
||||
}
|
||||
break;
|
||||
|
||||
175
src/misc.c
175
src/misc.c
@@ -656,21 +656,25 @@ must_be_dot_or_slash (char const *file_name)
|
||||
}
|
||||
}
|
||||
|
||||
/* Act like rmdir (FILE_NAME) relative to CHDIR_FD.
|
||||
/* Act like rmdir (FILENAME) relative to chdir_fd, i.e., like rmdir (F).
|
||||
However, reject attempts to remove a root directory
|
||||
even on systems that allow such a thing.
|
||||
Also, do not try to change the removed directory's status later. */
|
||||
static int
|
||||
safer_rmdir (const char *file_name)
|
||||
safer_rmdir (const char *file_name, struct fdbase f)
|
||||
{
|
||||
if (!file_name[slashlen (file_name)])
|
||||
if (f.fd == BADFD)
|
||||
return -1; /* Preserve errno. */
|
||||
|
||||
if (IS_ABSOLUTE_FILE_NAME (f.base))
|
||||
{
|
||||
errno = file_name[0] ? EBUSY : ENOENT;
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (unlinkat (chdir_fd, file_name, AT_REMOVEDIR) == 0)
|
||||
if (f.fd != BADFD && unlinkat (f.fd, f.base, AT_REMOVEDIR) == 0)
|
||||
{
|
||||
fdbase_clear ();
|
||||
remove_delayed_set_stat (file_name);
|
||||
return 0;
|
||||
}
|
||||
@@ -692,10 +696,15 @@ remove_any_file (const char *file_name, enum remove_option option)
|
||||
non-directory. */
|
||||
bool try_unlink_first = cannot_unlink_dir ();
|
||||
|
||||
struct fdbase f = fdbase (file_name);
|
||||
|
||||
if (try_unlink_first)
|
||||
{
|
||||
if (unlinkat (chdir_fd, file_name, 0) == 0)
|
||||
return 1;
|
||||
if (f.fd != BADFD && unlinkat (f.fd, f.base, 0) == 0)
|
||||
{
|
||||
fdbase_clear ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* POSIX 1003.1-2001 requires EPERM when attempting to unlink a
|
||||
directory without appropriate privileges, but many Linux
|
||||
@@ -704,13 +713,16 @@ remove_any_file (const char *file_name, enum remove_option option)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (safer_rmdir (file_name) == 0)
|
||||
if (safer_rmdir (file_name, f) == 0)
|
||||
return 1;
|
||||
|
||||
switch (errno)
|
||||
{
|
||||
case ENOTDIR:
|
||||
return !try_unlink_first && unlinkat (chdir_fd, file_name, 0) == 0;
|
||||
if (try_unlink_first || f.fd == BADFD || unlinkat (f.fd, f.base, 0) < 0)
|
||||
return 0;
|
||||
fdbase_clear ();
|
||||
return 1;
|
||||
|
||||
case 0:
|
||||
case EEXIST:
|
||||
@@ -751,7 +763,7 @@ remove_any_file (const char *file_name, enum remove_option option)
|
||||
}
|
||||
|
||||
free (directory);
|
||||
return safer_rmdir (file_name) == 0;
|
||||
return safer_rmdir (file_name, fdbase (file_name)) == 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -801,13 +813,27 @@ maybe_backup_file (const char *file_name, bool this_is_the_archive)
|
||||
&& (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode)))
|
||||
return true;
|
||||
|
||||
after_backup_name = find_backup_file_name (chdir_fd, file_name, backup_type);
|
||||
struct fdbase f = fdbase (file_name);
|
||||
if (f.fd == BADFD)
|
||||
{
|
||||
open_error (file_name);
|
||||
return false;
|
||||
}
|
||||
idx_t subdirlen = f.base - file_name;
|
||||
after_backup_name = find_backup_file_name (f.fd, f.base, backup_type);
|
||||
if (! after_backup_name)
|
||||
xalloc_die ();
|
||||
idx_t after_backup_namelen = strlen (after_backup_name);
|
||||
after_backup_name = xrealloc (after_backup_name,
|
||||
subdirlen + after_backup_namelen + 1);
|
||||
memmove (after_backup_name + subdirlen, after_backup_name,
|
||||
after_backup_namelen + 1);
|
||||
memcpy (after_backup_name, file_name, subdirlen);
|
||||
|
||||
if (renameat (chdir_fd, before_backup_name, chdir_fd, after_backup_name)
|
||||
== 0)
|
||||
if (renameat (f.fd, f.base, f.fd, &after_backup_name[subdirlen]) == 0)
|
||||
{
|
||||
if (S_ISLNK (file_stat.st_mode))
|
||||
fdbase_clear ();
|
||||
if (verbose_option)
|
||||
fprintf (stdlis, _("Renaming %s to %s\n"),
|
||||
quote_n (0, before_backup_name),
|
||||
@@ -833,8 +859,11 @@ undo_last_backup (void)
|
||||
{
|
||||
if (after_backup_name)
|
||||
{
|
||||
if (renameat (chdir_fd, after_backup_name, chdir_fd, before_backup_name)
|
||||
< 0)
|
||||
struct fdbase f = fdbase (before_backup_name);
|
||||
if (f.fd == BADFD
|
||||
|| (renameat (f.fd, &after_backup_name[f.base - before_backup_name],
|
||||
f.fd, f.base)
|
||||
< 0))
|
||||
{
|
||||
int e = errno;
|
||||
paxerror (e, _("%s: Cannot rename to %s"),
|
||||
@@ -855,7 +884,8 @@ undo_last_backup (void)
|
||||
int
|
||||
deref_stat (char const *name, struct stat *buf)
|
||||
{
|
||||
return fstatat (chdir_fd, name, buf, fstatat_flags);
|
||||
struct fdbase f = fdbase (name);
|
||||
return f.fd == BADFD ? -1 : fstatat (f.fd, f.base, buf, fstatat_flags);
|
||||
}
|
||||
|
||||
/* Read from FD into the buffer BUF with COUNT bytes. Attempt to fill
|
||||
@@ -1020,7 +1050,7 @@ idx_t chdir_current;
|
||||
similar locations for fstatat, etc. This is an open file
|
||||
descriptor, or AT_FDCWD if the working directory is current. It is
|
||||
valid until the next invocation of chdir_do. */
|
||||
int chdir_fd = AT_FDCWD;
|
||||
static int chdir_fd = AT_FDCWD;
|
||||
|
||||
/* Change to directory I, in a virtual way. This does not actually
|
||||
invoke chdir; it merely sets chdir_fd to an int suitable as the
|
||||
@@ -1100,6 +1130,113 @@ chdir_id (void)
|
||||
}
|
||||
return curr->id;
|
||||
}
|
||||
|
||||
/* Caches of recent calls to fdbase and fdbase1. */
|
||||
static struct fdbase_cache
|
||||
{
|
||||
/* Length of subdirectory name. If zero, no subdir is cached here:
|
||||
SUBDIR (if nonnull) is merely a buffer available for use later,
|
||||
and CHDIR_CURRENT and FD are irrelevant. */
|
||||
idx_t subdirlen;
|
||||
|
||||
/* Index of ancestor of this subdirectory. */
|
||||
idx_t chdir_current;
|
||||
|
||||
/* Buffer containing name of subdirectory relative to the ancestor. */
|
||||
char *subdir;
|
||||
|
||||
/* Number of bytes allocated for SUBDIR. */
|
||||
idx_t subdiralloc;
|
||||
|
||||
/* FD of subdirectory. */
|
||||
int fd;
|
||||
} fdbase_cache[2];
|
||||
|
||||
/* Clear the fdbase cache. Call this after any action that might
|
||||
invalidate the cache. Such actions include removing or renaming
|
||||
directories or symlinks to directories. Call this if in doubt,
|
||||
e.g., if it is not known whether a removed directory entry is a
|
||||
symlink to a directory. */
|
||||
void
|
||||
fdbase_clear (void)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
struct fdbase_cache *c = &fdbase_cache[i];
|
||||
if (c->subdirlen)
|
||||
{
|
||||
if (0 <= c->fd)
|
||||
close (c->fd);
|
||||
c->subdirlen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return an fd open to FILE_NAME's parent directory,
|
||||
along with the base name of FILE_NAME.
|
||||
Use the alternate cache if ALTERNATE, the main cache otherwise.
|
||||
If FILE_NAME is relative, it is relative to chdir_fd.
|
||||
Return AT_FDCWD if FILE_NAME is relative to the working directory.
|
||||
Return BADFD (setting errno) on failure. */
|
||||
static struct fdbase
|
||||
fdbase_opendir (char const *file_name, bool alternate)
|
||||
{
|
||||
char const *name = file_name;
|
||||
|
||||
/* Skip past leading "./"s,
|
||||
but not past the last "./" if that ends the name. */
|
||||
idx_t dslen = dotslashlen (name);
|
||||
if (dslen)
|
||||
{
|
||||
name += dslen;
|
||||
if (!*name)
|
||||
for (name--; *--name != '.'; )
|
||||
continue;
|
||||
}
|
||||
|
||||
/* For files immediately under CHDIR_FD, and for root directories,
|
||||
just use CHDIR_FD and NAME. */
|
||||
char const *base = last_component (name);
|
||||
idx_t subdirlen = base - name;
|
||||
if (!subdirlen | !*base)
|
||||
return (struct fdbase) { .fd = chdir_fd, .base = name };
|
||||
|
||||
struct fdbase_cache *c = &fdbase_cache[alternate];
|
||||
|
||||
if (! (c->chdir_current == chdir_current
|
||||
&& c->subdirlen == subdirlen
|
||||
&& memeq (c->subdir, name, subdirlen)))
|
||||
{
|
||||
if (c->subdirlen && 0 <= c->fd)
|
||||
close (c->fd);
|
||||
|
||||
c->chdir_current = chdir_current;
|
||||
if (c->subdiralloc <= subdirlen)
|
||||
c->subdir = xpalloc (c->subdir, &c->subdiralloc,
|
||||
subdirlen - c->subdiralloc + 1, -1, 1);
|
||||
char *p = mempcpy (c->subdir, name, subdirlen);
|
||||
*p = '\0';
|
||||
c->fd = openat (chdir_fd, c->subdir, open_searchdir_flags);
|
||||
c->subdirlen = c->fd < 0 ? 0 : subdirlen;
|
||||
if (BADFD != -1 && c->fd < 0)
|
||||
c->fd = BADFD;
|
||||
}
|
||||
|
||||
return (struct fdbase) { .fd = c->fd, .base = base };
|
||||
}
|
||||
|
||||
struct fdbase
|
||||
fdbase (char const *name)
|
||||
{
|
||||
return fdbase_opendir (name, false);
|
||||
}
|
||||
|
||||
struct fdbase
|
||||
fdbase1 (char const *name)
|
||||
{
|
||||
return fdbase_opendir (name, true);
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
tar_dirname (void)
|
||||
@@ -1353,7 +1490,9 @@ tar_savedir (const char *name, bool must_exist)
|
||||
{
|
||||
char *ret = NULL;
|
||||
DIR *dir = NULL;
|
||||
int fd = openat (chdir_fd, name, open_read_flags | O_DIRECTORY);
|
||||
struct fdbase f = fdbase (name);
|
||||
int fd = (f.fd == BADFD ? -1
|
||||
: openat (f.fd, f.base, open_read_flags | O_DIRECTORY));
|
||||
if (fd < 0)
|
||||
{
|
||||
if (!must_exist && errno == ENOENT)
|
||||
|
||||
@@ -1799,8 +1799,9 @@ collect_and_sort_names (void)
|
||||
}
|
||||
if (S_ISDIR (st.stat.st_mode))
|
||||
{
|
||||
int dir_fd = openat (chdir_fd, name->name,
|
||||
open_read_flags | O_DIRECTORY);
|
||||
struct fdbase f = fdbase (name->name);
|
||||
int dir_fd = (f.fd == BADFD ? -1
|
||||
: openat (f.fd, f.base, open_read_flags | O_DIRECTORY));
|
||||
if (dir_fd < 0)
|
||||
open_diag (name->name);
|
||||
else
|
||||
|
||||
21
src/unlink.c
21
src/unlink.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ static bool acting_as_filter;
|
||||
static void
|
||||
append_file (char *file_name)
|
||||
{
|
||||
int handle = openat (chdir_fd, file_name, O_RDONLY | O_BINARY);
|
||||
struct fdbase f = fdbase (file_name);
|
||||
int handle = f.fd == BADFD ? -1 : openat (f.fd, f.base, O_RDONLY | O_BINARY);
|
||||
|
||||
if (handle < 0)
|
||||
{
|
||||
|
||||
24
src/xattrs.c
24
src/xattrs.c
@@ -293,7 +293,8 @@ xattrs__acls_set (struct tar_stat_info const *st,
|
||||
/* No "default" IEEE 1003.1e ACL set for directory. At this moment,
|
||||
FILE_NAME may already have inherited default acls from parent
|
||||
directory; clean them up. */
|
||||
if (acl_delete_def_file_at (chdir_fd, file_name) < 0)
|
||||
struct fdbase f1 = fdbase (file_name);
|
||||
if (f1.fd == BADFD || acl_delete_def_file_at (f1.fd, f1.base) < 0)
|
||||
warnopt (WARN_XATTR_WRITE, errno,
|
||||
_("acl_delete_def_file_at: Cannot drop default POSIX ACLs "
|
||||
"for file '%s'"),
|
||||
@@ -309,7 +310,8 @@ xattrs__acls_set (struct tar_stat_info const *st,
|
||||
return;
|
||||
}
|
||||
|
||||
if (acl_set_file_at (chdir_fd, file_name, type, acl) < 0)
|
||||
struct fdbase f = fdbase (file_name);
|
||||
if (f.fd == BADFD || acl_set_file_at (f.fd, f.base, type, acl) < 0)
|
||||
/* warn even if filesystem does not support acls */
|
||||
warnopt (WARN_XATTR_WRITE, errno,
|
||||
_ ("acl_set_file_at: Cannot set POSIX ACLs for file '%s'"),
|
||||
@@ -599,13 +601,16 @@ xattrs__fd_set (char const *file_name, char typeflag,
|
||||
{
|
||||
const char *sysname = "setxattrat";
|
||||
int ret;
|
||||
struct fdbase f = fdbase (file_name);
|
||||
|
||||
if (typeflag != SYMTYPE)
|
||||
ret = setxattrat (chdir_fd, file_name, attr, ptr, len, 0);
|
||||
if (f.fd == BADFD)
|
||||
ret = -1;
|
||||
else if (typeflag != SYMTYPE)
|
||||
ret = setxattrat (f.fd, f.base, attr, ptr, len, 0);
|
||||
else
|
||||
{
|
||||
sysname = "lsetxattr";
|
||||
ret = lsetxattrat (chdir_fd, file_name, attr, ptr, len, 0);
|
||||
ret = lsetxattrat (f.fd, f.base, attr, ptr, len, 0);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
@@ -662,14 +667,17 @@ xattrs_selinux_set (MAYBE_UNUSED struct tar_stat_info const *st,
|
||||
if (!st->cntx_name)
|
||||
return;
|
||||
|
||||
if (typeflag != SYMTYPE)
|
||||
struct fdbase f = fdbase (file_name);
|
||||
if (f.fd == BADFD)
|
||||
ret = -1;
|
||||
else if (typeflag != SYMTYPE)
|
||||
{
|
||||
ret = setfileconat (chdir_fd, file_name, st->cntx_name);
|
||||
ret = setfileconat (f.fd, f.base, st->cntx_name);
|
||||
sysname = "setfileconat";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = lsetfileconat (chdir_fd, file_name, st->cntx_name);
|
||||
ret = lsetfileconat (f.fd, f.base, st->cntx_name);
|
||||
sysname = "lsetfileconat";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user