diff options
-rw-r--r-- | bin/Makemodule.am | 3 | ||||
-rw-r--r-- | bin/tar2sqfs/options.c (renamed from bin/tar2sqfs.c) | 330 | ||||
-rw-r--r-- | bin/tar2sqfs/process_tarball.c | 272 | ||||
-rw-r--r-- | bin/tar2sqfs/tar2sqfs.c | 46 | ||||
-rw-r--r-- | bin/tar2sqfs/tar2sqfs.h | 37 |
5 files changed, 364 insertions, 324 deletions
diff --git a/bin/Makemodule.am b/bin/Makemodule.am index 3e32308..2328d5c 100644 --- a/bin/Makemodule.am +++ b/bin/Makemodule.am @@ -4,7 +4,8 @@ sqfs2tar_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) sqfs2tar_LDADD = libcommon.a libutil.a libsquashfs.la libtar.a libcompat.a sqfs2tar_LDADD += libfstree.a $(LZO_LIBS) $(PTHREAD_LIBS) -tar2sqfs_SOURCES = bin/tar2sqfs.c +tar2sqfs_SOURCES = bin/tar2sqfs/tar2sqfs.c bin/tar2sqfs/tar2sqfs.h +tar2sqfs_SOURCES += bin/tar2sqfs/options.c bin/tar2sqfs/process_tarball.c tar2sqfs_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) tar2sqfs_LDADD = libcommon.a libsquashfs.la libtar.a tar2sqfs_LDADD += libfstree.a libcompat.a libfstree.a $(LZO_LIBS) diff --git a/bin/tar2sqfs.c b/bin/tar2sqfs/options.c index bdd36e1..b5aa3ba 100644 --- a/bin/tar2sqfs.c +++ b/bin/tar2sqfs/options.c @@ -1,23 +1,4 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * tar2sqfs.c - * - * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> - */ -#include "config.h" -#include "common.h" -#include "compat.h" -#include "tar.h" - -#include <stdlib.h> -#include <getopt.h> -#include <string.h> -#include <stdio.h> -#include <fcntl.h> - -#ifdef _WIN32 -#include <io.h> -#endif +#include "tar2sqfs.h" static struct option long_opts[] = { { "root-becomes", required_argument, NULL, 'r' }, @@ -100,15 +81,13 @@ static const char *usagestr = "\txzcat rootfs.tar.xz | tar2sqfs rootfs.sqfs\n" "\n"; -static bool dont_skip = false; -static bool keep_time = true; -static bool no_tail_pack = false; -static sqfs_writer_cfg_t cfg; -static sqfs_writer_t sqfs; -static FILE *input_file = NULL; -static char *root_becomes = NULL; +bool dont_skip = false; +bool keep_time = true; +bool no_tail_pack = false; +sqfs_writer_cfg_t cfg; +char *root_becomes = NULL; -static void process_args(int argc, char **argv) +void process_args(int argc, char **argv) { bool have_compressor; int i, ret; @@ -247,298 +226,3 @@ fail_arg: fputs("Try `tar2sqfs --help' for more information.\n", stderr); exit(EXIT_FAILURE); } - -static int write_file(tar_header_decoded_t *hdr, file_info_t *fi, - sqfs_u64 filesize) -{ - sqfs_file_t *file; - int flags; - int ret; - - file = sqfs_get_stdin_file(input_file, hdr->sparse, filesize); - if (file == NULL) { - perror("packing files"); - return -1; - } - - flags = 0; - if (no_tail_pack && filesize > cfg.block_size) - flags |= SQFS_BLK_DONT_FRAGMENT; - - ret = write_data_from_file(hdr->name, sqfs.data, - (sqfs_inode_generic_t **)&fi->user_ptr, - file, flags); - sqfs_destroy(file); - - if (ret) - return -1; - - return skip_padding(input_file, hdr->sparse == NULL ? - filesize : hdr->record_size); -} - -static int copy_xattr(tree_node_t *node, const tar_header_decoded_t *hdr) -{ - tar_xattr_t *xattr; - int ret; - - ret = sqfs_xattr_writer_begin(sqfs.xwr); - if (ret) { - sqfs_perror(hdr->name, "beginning xattr block", ret); - return -1; - } - - for (xattr = hdr->xattr; xattr != NULL; xattr = xattr->next) { - if (sqfs_get_xattr_prefix_id(xattr->key) < 0) { - fprintf(stderr, "%s: squashfs does not " - "support xattr prefix of %s\n", - dont_skip ? "ERROR" : "WARNING", - xattr->key); - - if (dont_skip) - return -1; - continue; - } - - ret = sqfs_xattr_writer_add(sqfs.xwr, xattr->key, xattr->value, - xattr->value_len); - if (ret) { - sqfs_perror(hdr->name, "storing xattr key-value pair", - ret); - return -1; - } - } - - ret = sqfs_xattr_writer_end(sqfs.xwr, &node->xattr_idx); - if (ret) { - sqfs_perror(hdr->name, "completing xattr block", ret); - return -1; - } - - return 0; -} - -static int create_node_and_repack_data(tar_header_decoded_t *hdr) -{ - tree_node_t *node; - - if (hdr->is_hard_link) { - node = fstree_add_hard_link(&sqfs.fs, hdr->name, - hdr->link_target); - if (node == NULL) - goto fail_errno; - - if (!cfg.quiet) { - printf("Hard link %s -> %s\n", hdr->name, - hdr->link_target); - } - return 0; - } - - if (!keep_time) { - hdr->sb.st_mtime = sqfs.fs.defaults.st_mtime; - } - - node = fstree_add_generic(&sqfs.fs, hdr->name, - &hdr->sb, hdr->link_target); - if (node == NULL) - goto fail_errno; - - if (!cfg.quiet) - printf("Packing %s\n", hdr->name); - - if (!cfg.no_xattr) { - if (copy_xattr(node, hdr)) - return -1; - } - - if (S_ISREG(hdr->sb.st_mode)) { - if (write_file(hdr, &node->data.file, hdr->sb.st_size)) - return -1; - } - - return 0; -fail_errno: - perror(hdr->name); - return -1; -} - -static int set_root_attribs(const tar_header_decoded_t *hdr) -{ - if (hdr->is_hard_link || !S_ISDIR(hdr->sb.st_mode)) { - fprintf(stderr, "'%s' is not a directory!\n", hdr->name); - return -1; - } - - sqfs.fs.root->uid = hdr->sb.st_uid; - sqfs.fs.root->gid = hdr->sb.st_gid; - sqfs.fs.root->mode = hdr->sb.st_mode; - - if (keep_time) - sqfs.fs.root->mod_time = hdr->sb.st_mtime; - - if (!cfg.no_xattr) { - if (copy_xattr(sqfs.fs.root, hdr)) - return -1; - } - - return 0; -} - -static int process_tar_ball(void) -{ - bool skip, is_root, is_prefixed; - tar_header_decoded_t hdr; - sqfs_u64 offset, count; - sparse_map_t *m; - size_t rootlen; - int ret; - - rootlen = root_becomes == NULL ? 0 : strlen(root_becomes); - - for (;;) { - ret = read_header(input_file, &hdr); - if (ret > 0) - break; - if (ret < 0) - return -1; - - if (hdr.mtime < 0) - hdr.mtime = 0; - - if ((sqfs_u64)hdr.mtime > 0x0FFFFFFFFUL) - hdr.mtime = 0x0FFFFFFFFUL; - - hdr.sb.st_mtime = hdr.mtime; - - skip = false; - is_root = false; - is_prefixed = true; - - if (hdr.name == NULL || canonicalize_name(hdr.name) != 0) { - fprintf(stderr, "skipping '%s' (invalid name)\n", - hdr.name); - skip = true; - } - - if (root_becomes != NULL) { - if (strncmp(hdr.name, root_becomes, rootlen) == 0) { - if (hdr.name[rootlen] == '\0') { - is_root = true; - } else if (hdr.name[rootlen] != '/') { - is_prefixed = false; - } - } else { - is_prefixed = false; - } - - if (is_prefixed && !is_root) { - memmove(hdr.name, hdr.name + rootlen + 1, - strlen(hdr.name + rootlen + 1) + 1); - } - - if (is_prefixed && hdr.name[0] == '\0') { - fputs("skipping entry with empty name\n", - stderr); - skip = true; - } - } else if (hdr.name[0] == '\0') { - is_root = true; - } - - if (!is_prefixed) { - clear_header(&hdr); - continue; - } - - if (is_root) { - if (set_root_attribs(&hdr)) - goto fail; - clear_header(&hdr); - continue; - } - - if (!skip && hdr.unknown_record) { - fprintf(stderr, "%s: unknown entry type\n", hdr.name); - skip = true; - } - - if (!skip && hdr.sparse != NULL) { - offset = hdr.sparse->offset; - count = 0; - - for (m = hdr.sparse; m != NULL; m = m->next) { - if (m->offset < offset) { - skip = true; - break; - } - offset = m->offset + m->count; - count += m->count; - } - - if (count != hdr.record_size) - skip = true; - - if (skip) { - fprintf(stderr, "%s: broken sparse " - "file layout\n", hdr.name); - } - } - - if (skip) { - if (dont_skip) - goto fail; - if (skip_entry(input_file, hdr.sb.st_size)) - goto fail; - - clear_header(&hdr); - continue; - } - - if (create_node_and_repack_data(&hdr)) - goto fail; - - clear_header(&hdr); - } - - return 0; -fail: - clear_header(&hdr); - return -1; -} - -int main(int argc, char **argv) -{ - int status = EXIT_FAILURE; - - process_args(argc, argv); - -#ifdef _WIN32 - _setmode(_fileno(stdin), _O_BINARY); - input_file = stdin; -#else - input_file = freopen(NULL, "rb", stdin); -#endif - - if (input_file == NULL) { - perror("changing stdin to binary mode"); - return EXIT_FAILURE; - } - - if (sqfs_writer_init(&sqfs, &cfg)) - return EXIT_FAILURE; - - if (process_tar_ball()) - goto out; - - if (fstree_post_process(&sqfs.fs)) - goto out; - - if (sqfs_writer_finish(&sqfs, &cfg)) - goto out; - - status = EXIT_SUCCESS; -out: - sqfs_writer_cleanup(&sqfs, status); - return status; -} diff --git a/bin/tar2sqfs/process_tarball.c b/bin/tar2sqfs/process_tarball.c new file mode 100644 index 0000000..3863014 --- /dev/null +++ b/bin/tar2sqfs/process_tarball.c @@ -0,0 +1,272 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * process_tarball.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "tar2sqfs.h" + +static int write_file(FILE *input_file, sqfs_writer_t *sqfs, + const tar_header_decoded_t *hdr, + file_info_t *fi, sqfs_u64 filesize) +{ + sqfs_file_t *file; + int flags; + int ret; + + file = sqfs_get_stdin_file(input_file, hdr->sparse, filesize); + if (file == NULL) { + perror("packing files"); + return -1; + } + + flags = 0; + if (no_tail_pack && filesize > cfg.block_size) + flags |= SQFS_BLK_DONT_FRAGMENT; + + ret = write_data_from_file(hdr->name, sqfs->data, + (sqfs_inode_generic_t **)&fi->user_ptr, + file, flags); + sqfs_destroy(file); + + if (ret) + return -1; + + return skip_padding(input_file, hdr->sparse == NULL ? + filesize : hdr->record_size); +} + +static int copy_xattr(sqfs_writer_t *sqfs, tree_node_t *node, + const tar_header_decoded_t *hdr) +{ + tar_xattr_t *xattr; + int ret; + + ret = sqfs_xattr_writer_begin(sqfs->xwr); + if (ret) { + sqfs_perror(hdr->name, "beginning xattr block", ret); + return -1; + } + + for (xattr = hdr->xattr; xattr != NULL; xattr = xattr->next) { + if (sqfs_get_xattr_prefix_id(xattr->key) < 0) { + fprintf(stderr, "%s: squashfs does not " + "support xattr prefix of %s\n", + dont_skip ? "ERROR" : "WARNING", + xattr->key); + + if (dont_skip) + return -1; + continue; + } + + ret = sqfs_xattr_writer_add(sqfs->xwr, xattr->key, xattr->value, + xattr->value_len); + if (ret) { + sqfs_perror(hdr->name, "storing xattr key-value pair", + ret); + return -1; + } + } + + ret = sqfs_xattr_writer_end(sqfs->xwr, &node->xattr_idx); + if (ret) { + sqfs_perror(hdr->name, "completing xattr block", ret); + return -1; + } + + return 0; +} + +static int create_node_and_repack_data(FILE *input_file, sqfs_writer_t *sqfs, + tar_header_decoded_t *hdr) +{ + tree_node_t *node; + + if (hdr->is_hard_link) { + node = fstree_add_hard_link(&sqfs->fs, hdr->name, + hdr->link_target); + if (node == NULL) + goto fail_errno; + + if (!cfg.quiet) { + printf("Hard link %s -> %s\n", hdr->name, + hdr->link_target); + } + return 0; + } + + if (!keep_time) { + hdr->sb.st_mtime = sqfs->fs.defaults.st_mtime; + } + + node = fstree_add_generic(&sqfs->fs, hdr->name, + &hdr->sb, hdr->link_target); + if (node == NULL) + goto fail_errno; + + if (!cfg.quiet) + printf("Packing %s\n", hdr->name); + + if (!cfg.no_xattr) { + if (copy_xattr(sqfs, node, hdr)) + return -1; + } + + if (S_ISREG(hdr->sb.st_mode)) { + if (write_file(input_file, sqfs, hdr, &node->data.file, + hdr->sb.st_size)) { + return -1; + } + } + + return 0; +fail_errno: + perror(hdr->name); + return -1; +} + +static int set_root_attribs(sqfs_writer_t *sqfs, + const tar_header_decoded_t *hdr) +{ + if (hdr->is_hard_link || !S_ISDIR(hdr->sb.st_mode)) { + fprintf(stderr, "'%s' is not a directory!\n", hdr->name); + return -1; + } + + sqfs->fs.root->uid = hdr->sb.st_uid; + sqfs->fs.root->gid = hdr->sb.st_gid; + sqfs->fs.root->mode = hdr->sb.st_mode; + + if (keep_time) + sqfs->fs.root->mod_time = hdr->sb.st_mtime; + + if (!cfg.no_xattr) { + if (copy_xattr(sqfs, sqfs->fs.root, hdr)) + return -1; + } + + return 0; +} + +int process_tarball(FILE *input_file, sqfs_writer_t *sqfs) +{ + bool skip, is_root, is_prefixed; + tar_header_decoded_t hdr; + sqfs_u64 offset, count; + sparse_map_t *m; + size_t rootlen; + int ret; + + rootlen = root_becomes == NULL ? 0 : strlen(root_becomes); + + for (;;) { + ret = read_header(input_file, &hdr); + if (ret > 0) + break; + if (ret < 0) + return -1; + + if (hdr.mtime < 0) + hdr.mtime = 0; + + if ((sqfs_u64)hdr.mtime > 0x0FFFFFFFFUL) + hdr.mtime = 0x0FFFFFFFFUL; + + hdr.sb.st_mtime = hdr.mtime; + + skip = false; + is_root = false; + is_prefixed = true; + + if (hdr.name == NULL || canonicalize_name(hdr.name) != 0) { + fprintf(stderr, "skipping '%s' (invalid name)\n", + hdr.name); + skip = true; + } + + if (root_becomes != NULL) { + if (strncmp(hdr.name, root_becomes, rootlen) == 0) { + if (hdr.name[rootlen] == '\0') { + is_root = true; + } else if (hdr.name[rootlen] != '/') { + is_prefixed = false; + } + } else { + is_prefixed = false; + } + + if (is_prefixed && !is_root) { + memmove(hdr.name, hdr.name + rootlen + 1, + strlen(hdr.name + rootlen + 1) + 1); + } + + if (is_prefixed && hdr.name[0] == '\0') { + fputs("skipping entry with empty name\n", + stderr); + skip = true; + } + } else if (hdr.name[0] == '\0') { + is_root = true; + } + + if (!is_prefixed) { + clear_header(&hdr); + continue; + } + + if (is_root) { + if (set_root_attribs(sqfs, &hdr)) + goto fail; + clear_header(&hdr); + continue; + } + + if (!skip && hdr.unknown_record) { + fprintf(stderr, "%s: unknown entry type\n", hdr.name); + skip = true; + } + + if (!skip && hdr.sparse != NULL) { + offset = hdr.sparse->offset; + count = 0; + + for (m = hdr.sparse; m != NULL; m = m->next) { + if (m->offset < offset) { + skip = true; + break; + } + offset = m->offset + m->count; + count += m->count; + } + + if (count != hdr.record_size) + skip = true; + + if (skip) { + fprintf(stderr, "%s: broken sparse " + "file layout\n", hdr.name); + } + } + + if (skip) { + if (dont_skip) + goto fail; + if (skip_entry(input_file, hdr.sb.st_size)) + goto fail; + + clear_header(&hdr); + continue; + } + + if (create_node_and_repack_data(input_file, sqfs, &hdr)) + goto fail; + + clear_header(&hdr); + } + + return 0; +fail: + clear_header(&hdr); + return -1; +} diff --git a/bin/tar2sqfs/tar2sqfs.c b/bin/tar2sqfs/tar2sqfs.c new file mode 100644 index 0000000..ae56e6b --- /dev/null +++ b/bin/tar2sqfs/tar2sqfs.c @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * tar2sqfs.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "tar2sqfs.h" + +int main(int argc, char **argv) +{ + int status = EXIT_FAILURE; + FILE *input_file = NULL; + sqfs_writer_t sqfs; + + process_args(argc, argv); + +#ifdef _WIN32 + _setmode(_fileno(stdin), _O_BINARY); + input_file = stdin; +#else + input_file = freopen(NULL, "rb", stdin); +#endif + + if (input_file == NULL) { + perror("changing stdin to binary mode"); + return EXIT_FAILURE; + } + + memset(&sqfs, 0, sizeof(sqfs)); + if (sqfs_writer_init(&sqfs, &cfg)) + return EXIT_FAILURE; + + if (process_tarball(input_file, &sqfs)) + goto out; + + if (fstree_post_process(&sqfs.fs)) + goto out; + + if (sqfs_writer_finish(&sqfs, &cfg)) + goto out; + + status = EXIT_SUCCESS; +out: + sqfs_writer_cleanup(&sqfs, status); + return status; +} diff --git a/bin/tar2sqfs/tar2sqfs.h b/bin/tar2sqfs/tar2sqfs.h new file mode 100644 index 0000000..a27a50b --- /dev/null +++ b/bin/tar2sqfs/tar2sqfs.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * tar2sqfs.h + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#ifndef TAR2SQFS_H +#define TAR2SQFS_H + +#include "config.h" +#include "common.h" +#include "compat.h" +#include "tar.h" + +#include <stdlib.h> +#include <getopt.h> +#include <string.h> +#include <stdio.h> +#include <fcntl.h> + +#ifdef _WIN32 +#include <io.h> +#endif + +/* options.c */ +extern bool dont_skip; +extern bool keep_time; +extern bool no_tail_pack; +extern sqfs_writer_cfg_t cfg; +extern char *root_becomes; + +void process_args(int argc, char **argv); + +/* process_tarball.c */ +int process_tarball(FILE *input_file, sqfs_writer_t *sqfs); + +#endif /* TAR2SQFS_H */ |