Importd: skip fifos and sockets (#41090)
This commit is contained in:
@@ -88,7 +88,7 @@ executables += [
|
||||
'sources' : files('import-generator.c'),
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-tar-extract.c'),
|
||||
'sources' : files('test-tar.c'),
|
||||
'type' : 'manual',
|
||||
},
|
||||
test_template + {
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "fd-util.h"
|
||||
#include "libarchive-util.h"
|
||||
#include "main-func.h"
|
||||
#include "tar-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
static int run(int argc, char **argv) {
|
||||
int r;
|
||||
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
if (argc != 3)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Need two arguments exactly: <input> <output>");
|
||||
|
||||
r = dlopen_libarchive();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
_cleanup_close_ int input_fd = open(argv[1], O_RDONLY | O_CLOEXEC);
|
||||
if (input_fd < 0)
|
||||
return log_error_errno(input_fd, "Cannot open %s: %m", argv[1]);
|
||||
|
||||
_cleanup_close_ int output_fd = open(argv[2], O_DIRECTORY | O_CLOEXEC);
|
||||
if (output_fd < 0)
|
||||
return log_error_errno(output_fd, "Cannot open %s: %m", argv[2]);
|
||||
|
||||
r = tar_x(input_fd, output_fd, /* flags= */ TAR_SELINUX);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "tar_x failed: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
||||
@@ -0,0 +1,58 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "libarchive-util.h"
|
||||
#include "main-func.h"
|
||||
#include "tar-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
static int run(int argc, char **argv) {
|
||||
int r;
|
||||
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
if (argc != 4)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Need three arguments exactly: -c <output> <input> | -x <input> <output>");
|
||||
|
||||
bool create;
|
||||
if (streq(argv[1], "-c"))
|
||||
create = true;
|
||||
else if (streq(argv[1], "-x"))
|
||||
create = false;
|
||||
else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown operation '%s'.", argv[1]);
|
||||
|
||||
r = dlopen_libarchive();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
int flags = create ? O_CREAT | O_WRONLY | O_TRUNC : O_RDONLY;
|
||||
_cleanup_close_ int fd1 = RET_NERRNO(open(argv[2], flags | O_CLOEXEC, 0666));
|
||||
if (fd1 < 0)
|
||||
return log_error_errno(fd1, "Cannot open %s: %m", argv[2]);
|
||||
|
||||
if (!create) {
|
||||
r = RET_NERRNO(mkdir(argv[3], 0777));
|
||||
if (r < 0 && r != -EEXIST)
|
||||
return log_error_errno(r, "Failed to mkdir %s: %m", argv[3]);
|
||||
}
|
||||
|
||||
_cleanup_close_ int fd2 = RET_NERRNO(open(argv[3], O_DIRECTORY | O_CLOEXEC));
|
||||
if (fd2 < 0)
|
||||
return log_error_errno(fd2, "Cannot open %s: %m", argv[3]);
|
||||
|
||||
if (create)
|
||||
r = tar_c(fd2, fd1, argv[2], /* flags= */ TAR_SELINUX);
|
||||
else
|
||||
r = tar_x(fd1, fd2, /* flags= */ TAR_SELINUX);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "tar %s failed: %m", argv[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
||||
+81
-30
@@ -472,9 +472,8 @@ static int archive_unpack_special_inode(
|
||||
return log_error_errno(errno, "Failed to fstat() '%s': %m", path);
|
||||
|
||||
if (((st.st_mode ^ filetype) & S_IFMT) != 0)
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(ENODEV),
|
||||
"Special node '%s' we just created is of a wrong type: %m", path);
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENODEV),
|
||||
"Special node '%s' we just created is of a wrong type: %m", path);
|
||||
|
||||
return TAKE_FD(fd);
|
||||
}
|
||||
@@ -552,7 +551,8 @@ static int archive_entry_read_acl(
|
||||
if (r == ARCHIVE_EOF)
|
||||
break;
|
||||
if (r != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unexpected error while iterating through ACLs.");
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||
"Unexpected error while iterating through ACLs.");
|
||||
|
||||
assert(rtype == type);
|
||||
|
||||
@@ -781,7 +781,8 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
|
||||
ar = sym_archive_read_open_fd(a, input_fd, 64 * 1024);
|
||||
if (ar != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to initialize archive context: %s", sym_archive_error_string(a));
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||
"Failed to initialize archive context: %s", sym_archive_error_string(a));
|
||||
|
||||
|
||||
OpenInode *open_inodes = NULL;
|
||||
@@ -811,14 +812,16 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
if (ar == ARCHIVE_EOF)
|
||||
break;
|
||||
if (!IN_SET(ar, ARCHIVE_OK, ARCHIVE_WARN))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse archive: %s", sym_archive_error_string(a));
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse archive: %s",
|
||||
sym_archive_error_string(a));
|
||||
|
||||
const char *p = NULL;
|
||||
r = archive_entry_pathname_safe(entry, &p);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Invalid path name in entry, refusing.");
|
||||
if (ar == ARCHIVE_WARN)
|
||||
log_warning("Non-critical error found while parsing '%s' from the archive, ignoring: %s", p ?: ".", sym_archive_error_string(a));
|
||||
log_warning("Non-critical error found while parsing '%s' from the archive, ignoring: %s",
|
||||
p ?: ".", sym_archive_error_string(a));
|
||||
|
||||
if (!p) {
|
||||
/* This is the root inode */
|
||||
@@ -838,7 +841,8 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (open_inodes[0].filetype != S_IFDIR)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Archives root inode is not a directory, refusing.");
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Archives root inode is not a directory, refusing.");
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -930,7 +934,9 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
"Invalid hardlink path name '%s' in entry, refusing.", target);
|
||||
|
||||
_cleanup_close_ int target_fd = -EBADF;
|
||||
r = chaseat(tree_fd, target, CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT|CHASE_NOFOLLOW, /* ret_path= */ NULL, &target_fd);
|
||||
r = chaseat(tree_fd, target,
|
||||
CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT|CHASE_NOFOLLOW,
|
||||
/* ret_path= */ NULL, &target_fd);
|
||||
if (r < 0)
|
||||
return log_error_errno(
|
||||
r,
|
||||
@@ -942,9 +948,9 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
|
||||
/* Refuse hardlinking directories early. */
|
||||
if (!inode_type_can_hardlink(verify_st.st_mode))
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(EBADF),
|
||||
"Refusing to hardlink inode '%s' of type '%s': %m", target, inode_type_to_string(verify_st.st_mode));
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADF),
|
||||
"Refusing to hardlink inode '%s' of type '%s': %m",
|
||||
target, inode_type_to_string(verify_st.st_mode));
|
||||
|
||||
if (linkat(target_fd, "", parent_fd, e, AT_EMPTY_PATH) < 0) {
|
||||
if (errno != ENOENT)
|
||||
@@ -959,16 +965,16 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
|
||||
_cleanup_close_ int target_parent_fd = -EBADF;
|
||||
_cleanup_free_ char *target_filename = NULL;
|
||||
r = chaseat(tree_fd, target, CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_EXTRACT_FILENAME|CHASE_NOFOLLOW, &target_filename, &target_parent_fd);
|
||||
r = chaseat(tree_fd, target,
|
||||
CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_EXTRACT_FILENAME|CHASE_NOFOLLOW,
|
||||
&target_filename, &target_parent_fd);
|
||||
if (r < 0)
|
||||
return log_error_errno(
|
||||
r,
|
||||
"Failed to find inode '%s' which shall be hardlinked as '%s': %m", target, j);
|
||||
return log_error_errno(r, "Failed to find inode '%s' which shall be hardlinked as '%s': %m",
|
||||
target, j);
|
||||
|
||||
if (linkat(target_parent_fd, target_filename, parent_fd, e, /* flags= */ 0) < 0)
|
||||
return log_error_errno(
|
||||
errno,
|
||||
"Failed to hardlink inode '%s' as '%s': %m", target, j);
|
||||
return log_error_errno(errno, "Failed to hardlink inode '%s' as '%s': %m",
|
||||
target, j);
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -1006,7 +1012,8 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
const char *w = startswith(e, ".wh.");
|
||||
if (w) {
|
||||
if (!filename_is_valid(w))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Invalid whiteout file entry '%s', refusing.", e);
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Invalid whiteout file entry '%s', refusing.", e);
|
||||
|
||||
r = archive_unpack_whiteout(a, entry, parent_fd, empty_to_root(parent_path), w, j);
|
||||
if (r < 0)
|
||||
@@ -1044,9 +1051,9 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
break;
|
||||
|
||||
default:
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||
"Unexpected file type %i of '%s', refusing.", (int) filetype, j);
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||
"Unexpected file type %i of '%s', refusing.",
|
||||
(int) filetype, j);
|
||||
}
|
||||
} else {
|
||||
/* This is some intermediary node in the path that we haven't opened yet. Create it with default attributes */
|
||||
@@ -1123,6 +1130,36 @@ struct make_archive_data {
|
||||
int have_unique_mount_id;
|
||||
};
|
||||
|
||||
static int filter_item(
|
||||
int inode_fd,
|
||||
const struct statx *sx,
|
||||
const char *path) {
|
||||
mode_t m;
|
||||
int r;
|
||||
|
||||
assert(inode_fd >= 0);
|
||||
assert(sx);
|
||||
assert(path);
|
||||
|
||||
if (FLAGS_SET(sx->stx_mask, STATX_TYPE))
|
||||
m = sx->stx_mode;
|
||||
else {
|
||||
struct stat st;
|
||||
r = RET_NERRNO(fstat(inode_fd, &st));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to stat '%s': %m", path);
|
||||
m = st.st_mode;
|
||||
}
|
||||
|
||||
/* Filter out sockets, fifos, and weird misc fds such as eventfds() that have no inode type. */
|
||||
if (IN_SET(m & S_IFMT, S_IFSOCK, S_IFIFO, 0)) {
|
||||
log_debug("Skipping '%s' (%s).", path, inode_type_to_string(m) ?: "unknown");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int hardlink_lookup(
|
||||
struct make_archive_data *d,
|
||||
int inode_fd,
|
||||
@@ -1380,7 +1417,13 @@ static int archive_item(
|
||||
assert(inode_fd >= 0);
|
||||
assert(sx);
|
||||
|
||||
log_debug("Archiving %s\n", path);
|
||||
r = filter_item(inode_fd, sx, path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
|
||||
log_debug("Archiving '%s'...", path);
|
||||
|
||||
_cleanup_(archive_entry_freep) struct archive_entry *entry = NULL;
|
||||
entry = sym_archive_entry_new();
|
||||
@@ -1397,7 +1440,8 @@ static int archive_item(
|
||||
sym_archive_entry_set_hardlink(entry, hardlink);
|
||||
|
||||
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));
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||
"Failed to write archive entry header: %s", sym_archive_error_string(d->archive));
|
||||
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
}
|
||||
@@ -1525,7 +1569,9 @@ static int archive_item(
|
||||
}
|
||||
|
||||
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));
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||
"Failed to write archive entry header: %s",
|
||||
sym_archive_error_string(d->archive));
|
||||
|
||||
if (S_ISREG(sx->stx_mode)) {
|
||||
assert(data_fd >= 0);
|
||||
@@ -1543,7 +1589,9 @@ static int archive_item(
|
||||
la_ssize_t k;
|
||||
k = sym_archive_write_data(d->archive, buffer, l);
|
||||
if (k < 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to write archive data: %s", sym_archive_error_string(d->archive));
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||
"Failed to write archive data: %s",
|
||||
sym_archive_error_string(d->archive));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1574,11 +1622,13 @@ int tar_c(int tree_fd, int output_fd, const char *filename, TarFlags flags) {
|
||||
else
|
||||
r = sym_archive_write_set_format_pax(a);
|
||||
if (r != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to set libarchive output format: %s", sym_archive_error_string(a));
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||
"Failed to set libarchive output format: %s", sym_archive_error_string(a));
|
||||
|
||||
r = sym_archive_write_open_fd(a, output_fd);
|
||||
if (r != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to set libarchive output file: %s", sym_archive_error_string(a));
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||
"Failed to set libarchive output file: %s", sym_archive_error_string(a));
|
||||
|
||||
_cleanup_(make_archive_data_done) struct make_archive_data data = {
|
||||
.archive = a,
|
||||
@@ -1599,7 +1649,8 @@ int tar_c(int tree_fd, int output_fd, const char *filename, TarFlags flags) {
|
||||
|
||||
r = sym_archive_write_close(a);
|
||||
if (r != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to finish writing archive: %s", sym_archive_error_string(a));
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||
"Unable to finish writing archive: %s", sym_archive_error_string(a));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user