tar-util: add support for file flags
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#if HAVE_LIBARCHIVE
|
||||
static void *libarchive_dl = NULL;
|
||||
|
||||
DLSYM_PROTOTYPE(archive_entry_fflags) = NULL;
|
||||
DLSYM_PROTOTYPE(archive_entry_filetype) = NULL;
|
||||
DLSYM_PROTOTYPE(archive_entry_free) = NULL;
|
||||
DLSYM_PROTOTYPE(archive_entry_gid) = NULL;
|
||||
@@ -26,6 +27,7 @@ DLSYM_PROTOTYPE(archive_entry_pathname) = NULL;
|
||||
DLSYM_PROTOTYPE(archive_entry_rdevmajor) = NULL;
|
||||
DLSYM_PROTOTYPE(archive_entry_rdevminor) = NULL;
|
||||
DLSYM_PROTOTYPE(archive_entry_set_ctime) = NULL;
|
||||
DLSYM_PROTOTYPE(archive_entry_set_fflags) = NULL;
|
||||
DLSYM_PROTOTYPE(archive_entry_set_filetype) = NULL;
|
||||
DLSYM_PROTOTYPE(archive_entry_set_gid) = NULL;
|
||||
DLSYM_PROTOTYPE(archive_entry_set_hardlink) = NULL;
|
||||
@@ -74,6 +76,7 @@ int dlopen_libarchive(void) {
|
||||
&libarchive_dl,
|
||||
"libarchive.so.13",
|
||||
LOG_DEBUG,
|
||||
DLSYM_ARG(archive_entry_fflags),
|
||||
DLSYM_ARG(archive_entry_filetype),
|
||||
DLSYM_ARG(archive_entry_free),
|
||||
DLSYM_ARG(archive_entry_gid),
|
||||
@@ -93,6 +96,7 @@ int dlopen_libarchive(void) {
|
||||
DLSYM_ARG(archive_entry_rdevmajor),
|
||||
DLSYM_ARG(archive_entry_rdevminor),
|
||||
DLSYM_ARG(archive_entry_set_ctime),
|
||||
DLSYM_ARG(archive_entry_set_fflags),
|
||||
DLSYM_ARG(archive_entry_set_filetype),
|
||||
DLSYM_ARG(archive_entry_set_gid),
|
||||
DLSYM_ARG(archive_entry_set_hardlink),
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "dlfcn-util.h"
|
||||
|
||||
extern DLSYM_PROTOTYPE(archive_entry_fflags);
|
||||
extern DLSYM_PROTOTYPE(archive_entry_filetype);
|
||||
extern DLSYM_PROTOTYPE(archive_entry_free);
|
||||
extern DLSYM_PROTOTYPE(archive_entry_gid);
|
||||
@@ -22,6 +23,7 @@ extern DLSYM_PROTOTYPE(archive_entry_pathname);
|
||||
extern DLSYM_PROTOTYPE(archive_entry_rdevmajor);
|
||||
extern DLSYM_PROTOTYPE(archive_entry_rdevminor);
|
||||
extern DLSYM_PROTOTYPE(archive_entry_set_ctime);
|
||||
extern DLSYM_PROTOTYPE(archive_entry_set_fflags);
|
||||
extern DLSYM_PROTOTYPE(archive_entry_set_filetype);
|
||||
extern DLSYM_PROTOTYPE(archive_entry_set_gid);
|
||||
extern DLSYM_PROTOTYPE(archive_entry_set_hardlink);
|
||||
|
||||
+86
-4
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "chase.h"
|
||||
#include "chattr-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "hexdecoct.h"
|
||||
@@ -29,6 +30,15 @@
|
||||
|
||||
#define DEPTH_MAX 128U
|
||||
|
||||
/* We are a bit conservative with the flags we save/restore in tar files */
|
||||
#define CHATTR_TAR_FL \
|
||||
(FS_NOATIME_FL | \
|
||||
FS_NOCOW_FL | \
|
||||
FS_PROJINHERIT_FL | \
|
||||
FS_NODUMP_FL | \
|
||||
FS_SYNC_FL | \
|
||||
FS_DIRSYNC_FL)
|
||||
|
||||
typedef struct XAttr {
|
||||
char *name;
|
||||
struct iovec data;
|
||||
@@ -44,6 +54,7 @@ typedef struct OpenInode {
|
||||
struct timespec mtime;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
unsigned fflags;
|
||||
XAttr *xattr;
|
||||
size_t n_xattr;
|
||||
} OpenInode;
|
||||
@@ -105,6 +116,20 @@ static int open_inode_finalize(OpenInode *of) {
|
||||
RET_GATHER(r, log_error_errno(k, "Failed to adjust ownership/mode of '%s': %m", of->path));
|
||||
}
|
||||
|
||||
if ((of->fflags & ~CHATTR_EARLY_FL) != 0 && inode_type_can_chattr(of->filetype)) {
|
||||
k = chattr_full(of->fd,
|
||||
/* path= */ NULL,
|
||||
/* value= */ of->fflags,
|
||||
/* mask= */ of->fflags & ~CHATTR_EARLY_FL,
|
||||
/* ret_previous= */ NULL,
|
||||
/* ret_final= */ NULL,
|
||||
CHATTR_FALLBACK_BITWISE);
|
||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(k))
|
||||
log_warning_errno(k, "Failed to apply chattr of '%s', ignoring: %m", of->path);
|
||||
else if (k < 0)
|
||||
RET_GATHER(r, log_error_errno(k, "Failed to adjust chattr of '%s': %m", of->path));
|
||||
}
|
||||
|
||||
/* We also adjust the mtime only after leaving a dir, since it might otherwise change again
|
||||
* because we make modifications inside it */
|
||||
if (of->mtime.tv_nsec != UTIME_OMIT) {
|
||||
@@ -155,7 +180,8 @@ static int archive_unpack_regular(
|
||||
struct archive_entry *entry,
|
||||
int parent_fd,
|
||||
const char *filename,
|
||||
const char *path) {
|
||||
const char *path,
|
||||
unsigned fflags) {
|
||||
|
||||
int r;
|
||||
|
||||
@@ -170,6 +196,22 @@ static int archive_unpack_regular(
|
||||
if (fd < 0)
|
||||
return log_error_errno(fd, "Failed to create regular file '%s': %m", path);
|
||||
|
||||
if ((fflags & CHATTR_EARLY_FL) != 0) {
|
||||
r = chattr_full(fd,
|
||||
/* path= */ NULL,
|
||||
/* value= */ fflags,
|
||||
/* mask= */ fflags & CHATTR_EARLY_FL,
|
||||
/* ret_previous= */ NULL,
|
||||
/* ret_final= */ NULL,
|
||||
CHATTR_FALLBACK_BITWISE);
|
||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||
log_warning_errno(r, "Failed to apply chattr of '%s', ignoring: %m", path);
|
||||
else if (r < 0) {
|
||||
log_error_errno(r, "Failed to adjust chattr of '%s': %m", path);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
r = sym_archive_read_data_into_fd(a, fd);
|
||||
if (r != ARCHIVE_OK) {
|
||||
r = log_error_errno(
|
||||
@@ -210,7 +252,10 @@ static int archive_unpack_directory(
|
||||
struct archive_entry *entry,
|
||||
int parent_fd,
|
||||
const char *filename,
|
||||
const char *path) {
|
||||
const char *path,
|
||||
unsigned fflags) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(entry);
|
||||
@@ -226,6 +271,20 @@ static int archive_unpack_directory(
|
||||
if (fd < 0)
|
||||
return log_error_errno(fd, "Failed to create directory '%s': %m", path);
|
||||
|
||||
if ((fflags & CHATTR_EARLY_FL) != 0) {
|
||||
r = chattr_full(fd,
|
||||
/* path= */ NULL,
|
||||
/* value= */ fflags,
|
||||
/* mask= */ fflags & CHATTR_EARLY_FL,
|
||||
/* ret_previous= */ NULL,
|
||||
/* ret_final= */ NULL,
|
||||
CHATTR_FALLBACK_BITWISE);
|
||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||
log_warning_errno(r, "Failed to apply chattr of '%s', ignoring: %m", path);
|
||||
else if (r < 0)
|
||||
return log_error_errno(r, "Failed to adjust chattr of '%s': %m", path);
|
||||
}
|
||||
|
||||
return TAKE_FD(fd);
|
||||
}
|
||||
|
||||
@@ -334,6 +393,7 @@ static int archive_entry_read_stat(
|
||||
struct timespec *mtime,
|
||||
uid_t *uid,
|
||||
gid_t *gid,
|
||||
unsigned *fflags,
|
||||
XAttr **xa,
|
||||
size_t *n_xa,
|
||||
TarFlags flags) {
|
||||
@@ -361,6 +421,12 @@ static int archive_entry_read_stat(
|
||||
if (gid && sym_archive_entry_gid_is_set(entry))
|
||||
*gid = sym_archive_entry_gid(entry);
|
||||
|
||||
if (fflags) {
|
||||
unsigned long fs = 0, fc = 0;
|
||||
sym_archive_entry_fflags(entry, &fs, &fc);
|
||||
*fflags = (fs & ~fc) & CHATTR_TAR_FL;
|
||||
}
|
||||
|
||||
(void) sym_archive_entry_xattr_reset(entry);
|
||||
for (;;) {
|
||||
const char *name = NULL;
|
||||
@@ -476,6 +542,7 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
&open_inodes[0].mtime,
|
||||
&open_inodes[0].uid,
|
||||
&open_inodes[0].gid,
|
||||
&open_inodes[0].fflags,
|
||||
&open_inodes[0].xattr,
|
||||
&open_inodes[0].n_xattr,
|
||||
flags);
|
||||
@@ -546,6 +613,7 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
uid_t uid = UID_INVALID;
|
||||
gid_t gid = GID_INVALID;
|
||||
struct timespec mtime = { .tv_nsec = UTIME_OMIT };
|
||||
unsigned fflags = 0;
|
||||
XAttr *xa = NULL;
|
||||
size_t n_xa = 0;
|
||||
CLEANUP_ARRAY(xa, n_xa, xattr_done_many);
|
||||
@@ -620,6 +688,7 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
&mtime,
|
||||
&uid,
|
||||
&gid,
|
||||
&fflags,
|
||||
&xa,
|
||||
&n_xa,
|
||||
flags);
|
||||
@@ -629,11 +698,11 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
switch (filetype) {
|
||||
|
||||
case S_IFREG:
|
||||
fd = archive_unpack_regular(a, entry, parent_fd, e, j);
|
||||
fd = archive_unpack_regular(a, entry, parent_fd, e, j, fflags);
|
||||
break;
|
||||
|
||||
case S_IFDIR:
|
||||
fd = archive_unpack_directory(a, entry, parent_fd, e, j);
|
||||
fd = archive_unpack_directory(a, entry, parent_fd, e, j, fflags);
|
||||
break;
|
||||
|
||||
case S_IFLNK:
|
||||
@@ -678,6 +747,7 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
.mtime = mtime,
|
||||
.uid = uid,
|
||||
.gid = gid,
|
||||
.fflags = fflags,
|
||||
.xattr = TAKE_PTR(xa),
|
||||
.n_xattr = n_xa,
|
||||
};
|
||||
@@ -975,6 +1045,18 @@ static int archive_item(
|
||||
return r;
|
||||
}
|
||||
|
||||
if (inode_type_can_chattr(sx->stx_mode)) {
|
||||
unsigned f = 0;
|
||||
|
||||
r = read_attr_fd(data_fd >= 0 ? data_fd : inode_fd, &f);
|
||||
if (r < 0 && !ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||
return log_error_errno(r, "Failed to read file flags of '%s': %m", path);
|
||||
|
||||
f &= CHATTR_TAR_FL;
|
||||
if (f != 0)
|
||||
sym_archive_entry_set_fflags(entry, f, /* clear= */ 0);
|
||||
}
|
||||
|
||||
if (sym_archive_write_header(d->archive, entry) != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to write archive entry header: %s", sym_archive_error_string(d->archive));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user