From cdccc69c62579b0c13b35fad0728079652b8f3c9 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Tue, 31 Jan 2023 11:21:30 +0100 Subject: Move library source into src sub-directory Signed-off-by: David Oberhollenzer --- bin/sqfs2tar/Makemodule.am | 6 +- bin/sqfs2tar/options.c | 212 -------------------------------- bin/sqfs2tar/sqfs2tar.c | 274 ------------------------------------------ bin/sqfs2tar/sqfs2tar.h | 56 --------- bin/sqfs2tar/src/options.c | 212 ++++++++++++++++++++++++++++++++ bin/sqfs2tar/src/sqfs2tar.c | 274 ++++++++++++++++++++++++++++++++++++++++++ bin/sqfs2tar/src/sqfs2tar.h | 56 +++++++++ bin/sqfs2tar/src/write_tree.c | 209 ++++++++++++++++++++++++++++++++ bin/sqfs2tar/src/xattr.c | 91 ++++++++++++++ bin/sqfs2tar/write_tree.c | 209 -------------------------------- bin/sqfs2tar/xattr.c | 91 -------------- 11 files changed, 845 insertions(+), 845 deletions(-) delete mode 100644 bin/sqfs2tar/options.c delete mode 100644 bin/sqfs2tar/sqfs2tar.c delete mode 100644 bin/sqfs2tar/sqfs2tar.h create mode 100644 bin/sqfs2tar/src/options.c create mode 100644 bin/sqfs2tar/src/sqfs2tar.c create mode 100644 bin/sqfs2tar/src/sqfs2tar.h create mode 100644 bin/sqfs2tar/src/write_tree.c create mode 100644 bin/sqfs2tar/src/xattr.c delete mode 100644 bin/sqfs2tar/write_tree.c delete mode 100644 bin/sqfs2tar/xattr.c (limited to 'bin/sqfs2tar') diff --git a/bin/sqfs2tar/Makemodule.am b/bin/sqfs2tar/Makemodule.am index 05cee5b..2e6c411 100644 --- a/bin/sqfs2tar/Makemodule.am +++ b/bin/sqfs2tar/Makemodule.am @@ -1,6 +1,6 @@ -sqfs2tar_SOURCES = bin/sqfs2tar/sqfs2tar.c bin/sqfs2tar/sqfs2tar.h -sqfs2tar_SOURCES += bin/sqfs2tar/options.c bin/sqfs2tar/write_tree.c -sqfs2tar_SOURCES += bin/sqfs2tar/xattr.c +sqfs2tar_SOURCES = bin/sqfs2tar/src/sqfs2tar.c bin/sqfs2tar/src/sqfs2tar.h \ + bin/sqfs2tar/src/options.c bin/sqfs2tar/src/write_tree.c \ + bin/sqfs2tar/src/xattr.c sqfs2tar_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) sqfs2tar_LDADD = libcommon.a libutil.a libsquashfs.la libtar.a sqfs2tar_LDADD += libio.a libxfrm.a libcompat.a libfstree.a diff --git a/bin/sqfs2tar/options.c b/bin/sqfs2tar/options.c deleted file mode 100644 index ba1588d..0000000 --- a/bin/sqfs2tar/options.c +++ /dev/null @@ -1,212 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * options.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#include "sqfs2tar.h" - -static struct option long_opts[] = { - { "compressor", required_argument, NULL, 'c' }, - { "subdir", required_argument, NULL, 'd' }, - { "keep-as-dir", no_argument, NULL, 'k' }, - { "root-becomes", required_argument, NULL, 'r' }, - { "no-skip", no_argument, NULL, 's' }, - { "no-xattr", no_argument, NULL, 'X' }, - { "no-hard-links", no_argument, NULL, 'L' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0 }, -}; - -static const char *short_opts = "c:d:kr:sXLhV"; - -static const char *usagestr = -"Usage: sqfs2tar [OPTIONS...] \n" -"\n" -"Read an input squashfs archive and turn it into a tar archive, written\n" -"to stdout.\n" -"\n" -"Possible options:\n" -"\n" -" --compressor, -c If set, stream compress the resulting tarball.\n" -" By default, the tarball is uncompressed.\n" -"\n" -" --subdir, -d Unpack the given sub directory instead of the\n" -" filesystem root. Can be specified more than\n" -" once to select multiple directories. If only\n" -" one is specified, it becomes the new root of\n" -" node of the archive file system tree.\n" -"\n" -" --root-becomes, -r Turn the root inode into a directory with the\n" -" specified name. Everything else will be stored\n" -" inside this directory. The special value '.' is\n" -" allowed to prefix all tar paths with './' and\n" -" add an entry named '.' for the root inode.\n" -" If this option isn't used, all meta data stored\n" -" in the root inode IS LOST!\n" -"\n" -" --keep-as-dir, -k If --subdir is used only once, don't make the\n" -" subdir the archive root, instead keep it as\n" -" prefix for all unpacked files.\n" -" Using --subdir more than once implies\n" -" --keep-as-dir.\n" -" --no-xattr, -X Do not copy extended attributes.\n" -" --no-hard-links, -L Do not generate hard links. Produce duplicate\n" -" entries instead.\n" -"\n" -" --no-skip, -s Abort if a file cannot be stored in a tar\n" -" archive. By default, it is simply skipped\n" -" and a warning is written to stderr.\n" -"\n" -" --help, -h Print help text and exit.\n" -" --version, -V Print version information and exit.\n" -"\n" -"Supported tar compression formats:\n"; - -bool dont_skip = false; -bool keep_as_dir = false; -bool no_xattr = false; -bool no_links = false; - -char *root_becomes = NULL; -char **subdirs = NULL; -size_t num_subdirs = 0; -static size_t max_subdirs = 0; -int compressor = 0; - -const char *filename = NULL; - -void process_args(int argc, char **argv) -{ - size_t idx, new_count; - const char *name; - int i, ret; - char **new; - - for (;;) { - i = getopt_long(argc, argv, short_opts, long_opts, NULL); - if (i == -1) - break; - - switch (i) { - case 'c': - compressor = xfrm_compressor_id_from_name(optarg); - if (compressor <= 0) { - fprintf(stderr, "unknown compressor '%s'.\n", - optarg); - goto fail; - } - break; - case 'd': - if (num_subdirs == max_subdirs) { - new_count = max_subdirs ? max_subdirs * 2 : 16; - new = realloc(subdirs, - new_count * sizeof(subdirs[0])); - if (new == NULL) - goto fail_errno; - - max_subdirs = new_count; - subdirs = new; - } - - subdirs[num_subdirs] = strdup(optarg); - if (subdirs[num_subdirs] == NULL) - goto fail_errno; - - if (canonicalize_name(subdirs[num_subdirs])) { - perror(optarg); - goto fail; - } - - ++num_subdirs; - break; - case 'r': - free(root_becomes); - root_becomes = strdup(optarg); - if (root_becomes == NULL) - goto fail_errno; - - if (strcmp(root_becomes, "./") == 0) - root_becomes[1] = '\0'; - - if (strcmp(root_becomes, ".") == 0) - break; - - if (canonicalize_name(root_becomes) != 0 || - strlen(root_becomes) == 0) { - fprintf(stderr, - "Invalid root directory '%s'.\n", - optarg); - goto fail_arg; - } - break; - case 'k': - keep_as_dir = true; - break; - case 's': - dont_skip = true; - break; - case 'X': - no_xattr = true; - break; - case 'L': - no_links = true; - break; - case 'h': - fputs(usagestr, stdout); - - i = XFRM_COMPRESSOR_MIN; - - while (i <= XFRM_COMPRESSOR_MAX) { - name = xfrm_compressor_name_from_id(i); - if (name != NULL) - printf("\t%s\n", name); - ++i; - } - - fputc('\n', stdout); - goto out_success; - case 'V': - print_version("sqfs2tar"); - goto out_success; - default: - goto fail_arg; - } - } - - if (optind >= argc) { - fputs("Missing argument: squashfs image\n", stderr); - goto fail_arg; - } - - filename = argv[optind++]; - - if (optind < argc) { - fputs("Unknown extra arguments\n", stderr); - goto fail_arg; - } - - if (num_subdirs > 1) - keep_as_dir = true; - - return; -fail_errno: - perror("parsing options"); - goto fail; -fail_arg: - fputs("Try `sqfs2tar --help' for more information.\n", stderr); - goto fail; -fail: - ret = EXIT_FAILURE; - goto out_exit; -out_success: - ret = EXIT_SUCCESS; - goto out_exit; -out_exit: - for (idx = 0; idx < num_subdirs; ++idx) - free(subdirs[idx]); - free(root_becomes); - free(subdirs); - exit(ret); -} diff --git a/bin/sqfs2tar/sqfs2tar.c b/bin/sqfs2tar/sqfs2tar.c deleted file mode 100644 index 43f9e78..0000000 --- a/bin/sqfs2tar/sqfs2tar.c +++ /dev/null @@ -1,274 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * sqfs2tar.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#include "sqfs2tar.h" - -sqfs_xattr_reader_t *xr; -sqfs_data_reader_t *data; -sqfs_super_t super; -ostream_t *out_file = NULL; - -static sqfs_file_t *file; - -char *assemble_tar_path(char *name, bool is_dir) -{ - size_t len, new_len; - char *temp; - (void)is_dir; - - if (root_becomes == NULL && !is_dir) - return name; - - new_len = strlen(name); - if (root_becomes != NULL) - new_len += strlen(root_becomes) + 1; - if (is_dir) - new_len += 1; - - temp = realloc(name, new_len + 1); - if (temp == NULL) { - perror("assembling tar entry filename"); - free(name); - return NULL; - } - - name = temp; - - if (root_becomes != NULL) { - len = strlen(root_becomes); - - memmove(name + len + 1, name, strlen(name) + 1); - memcpy(name, root_becomes, len); - name[len] = '/'; - } - - if (is_dir) { - len = strlen(name); - - if (len == 0 || name[len - 1] != '/') { - name[len++] = '/'; - name[len] = '\0'; - } - } - - return name; -} - -static int terminate_archive(void) -{ - char buffer[1024]; - - memset(buffer, '\0', sizeof(buffer)); - - return ostream_append(out_file, buffer, sizeof(buffer)); -} - -static sqfs_tree_node_t *tree_merge(sqfs_tree_node_t *lhs, - sqfs_tree_node_t *rhs) -{ - sqfs_tree_node_t *head = NULL, **next_ptr = &head; - sqfs_tree_node_t *it, *l, *r; - int diff; - - while (lhs->children != NULL && rhs->children != NULL) { - diff = strcmp((const char *)lhs->children->name, - (const char *)rhs->children->name); - - if (diff < 0) { - it = lhs->children; - lhs->children = lhs->children->next; - } else if (diff > 0) { - it = rhs->children; - rhs->children = rhs->children->next; - } else { - l = lhs->children; - lhs->children = lhs->children->next; - - r = rhs->children; - rhs->children = rhs->children->next; - - it = tree_merge(l, r); - } - - *next_ptr = it; - next_ptr = &it->next; - } - - it = (lhs->children != NULL ? lhs->children : rhs->children); - *next_ptr = it; - - sqfs_dir_tree_destroy(rhs); - lhs->children = head; - return lhs; -} - -int main(int argc, char **argv) -{ - sqfs_tree_node_t *root = NULL, *subtree = NULL; - int flags, ret, status = EXIT_FAILURE; - sqfs_compressor_t *cmp = NULL; - sqfs_id_table_t *idtbl = NULL; - sqfs_dir_reader_t *dr = NULL; - sqfs_compressor_config_t cfg; - size_t i; - - process_args(argc, argv); - - out_file = ostream_open_stdout(); - if (out_file == NULL) { - perror("changing stdout to binary mode"); - goto out; - } - - if (compressor > 0) { - xfrm_stream_t *xfrm = compressor_stream_create(compressor,NULL); - ostream_t *strm; - - if (xfrm == NULL) - goto out; - - strm = ostream_xfrm_create(out_file, xfrm); - sqfs_drop(out_file); - sqfs_drop(xfrm); - out_file = strm; - - if (out_file == NULL) - goto out; - } - - file = sqfs_open_file(filename, SQFS_FILE_OPEN_READ_ONLY); - if (file == NULL) { - perror(filename); - goto out; - } - - ret = sqfs_super_read(&super, file); - if (ret) { - sqfs_perror(filename, "reading super block", ret); - goto out; - } - - sqfs_compressor_config_init(&cfg, super.compression_id, - super.block_size, - SQFS_COMP_FLAG_UNCOMPRESS); - - ret = sqfs_compressor_create(&cfg, &cmp); - -#ifdef WITH_LZO - if (super.compression_id == SQFS_COMP_LZO && ret != 0) - ret = lzo_compressor_create(&cfg, &cmp); -#endif - - if (ret != 0) { - sqfs_perror(filename, "creating compressor", ret); - goto out; - } - - idtbl = sqfs_id_table_create(0); - - if (idtbl == NULL) { - perror("creating ID table"); - goto out; - } - - ret = sqfs_id_table_read(idtbl, file, &super, cmp); - if (ret) { - sqfs_perror(filename, "loading ID table", ret); - goto out; - } - - data = sqfs_data_reader_create(file, super.block_size, cmp, 0); - if (data == NULL) { - sqfs_perror(filename, "creating data reader", - SQFS_ERROR_ALLOC); - goto out; - } - - ret = sqfs_data_reader_load_fragment_table(data, &super); - if (ret) { - sqfs_perror(filename, "loading fragment table", ret); - goto out; - } - - dr = sqfs_dir_reader_create(&super, cmp, file, 0); - if (dr == NULL) { - sqfs_perror(filename, "creating dir reader", - SQFS_ERROR_ALLOC); - goto out; - } - - if (!no_xattr && !(super.flags & SQFS_FLAG_NO_XATTRS)) { - xr = sqfs_xattr_reader_create(0); - if (xr == NULL) { - sqfs_perror(filename, "creating xattr reader", - SQFS_ERROR_ALLOC); - goto out; - } - - ret = sqfs_xattr_reader_load(xr, &super, file, cmp); - if (ret) { - sqfs_perror(filename, "loading xattr table", ret); - goto out; - } - } - - if (num_subdirs == 0) { - ret = sqfs_dir_reader_get_full_hierarchy(dr, idtbl, NULL, - 0, &root); - if (ret) { - sqfs_perror(filename, "loading filesystem tree", ret); - goto out; - } - } else { - flags = 0; - - if (keep_as_dir || num_subdirs > 1) - flags = SQFS_TREE_STORE_PARENTS; - - for (i = 0; i < num_subdirs; ++i) { - ret = sqfs_dir_reader_get_full_hierarchy(dr, idtbl, - subdirs[i], - flags, - &subtree); - if (ret) { - sqfs_perror(subdirs[i], "loading filesystem " - "tree", ret); - goto out; - } - - if (root == NULL) { - root = subtree; - } else { - root = tree_merge(root, subtree); - } - } - } - - if (write_tree(root)) - goto out; - - if (terminate_archive()) - goto out; - - if (ostream_flush(out_file)) - goto out; - - status = EXIT_SUCCESS; -out: - sqfs_dir_tree_destroy(root); - sqfs_drop(xr); - sqfs_drop(dr); - sqfs_drop(data); - sqfs_drop(idtbl); - sqfs_drop(cmp); - sqfs_drop(file); - sqfs_drop(out_file); - for (i = 0; i < num_subdirs; ++i) - free(subdirs[i]); - free(subdirs); - free(root_becomes); - return status; -} diff --git a/bin/sqfs2tar/sqfs2tar.h b/bin/sqfs2tar/sqfs2tar.h deleted file mode 100644 index 4bf5428..0000000 --- a/bin/sqfs2tar/sqfs2tar.h +++ /dev/null @@ -1,56 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * sqfs2tar.h - * - * Copyright (C) 2019 David Oberhollenzer - */ -#ifndef SQFS2TAR_H -#define SQFS2TAR_H - -#include "config.h" -#include "common.h" - -#include "util/util.h" -#include "tar/tar.h" -#include "xfrm/compress.h" -#include "io/xfrm.h" - -#include -#include -#include -#include -#include -#include -#include - -/* options.c */ -extern bool dont_skip; -extern bool keep_as_dir; -extern bool no_xattr; -extern bool no_links; - -extern char *root_becomes; -extern char **subdirs; -extern size_t num_subdirs; -extern int compressor; - -extern const char *filename; - -void process_args(int argc, char **argv); - -/* tar2sqfs.c */ -extern sqfs_xattr_reader_t *xr; -extern sqfs_data_reader_t *data; -extern sqfs_super_t super; -extern ostream_t *out_file; - -char *assemble_tar_path(char *name, bool is_dir); - -/* xattr.c */ -int get_xattrs(const char *name, const sqfs_inode_generic_t *inode, - tar_xattr_t **out); - -/* write_tree.c */ -int write_tree(const sqfs_tree_node_t *n); - -#endif /* SQFS2TAR_H */ diff --git a/bin/sqfs2tar/src/options.c b/bin/sqfs2tar/src/options.c new file mode 100644 index 0000000..ba1588d --- /dev/null +++ b/bin/sqfs2tar/src/options.c @@ -0,0 +1,212 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * options.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#include "sqfs2tar.h" + +static struct option long_opts[] = { + { "compressor", required_argument, NULL, 'c' }, + { "subdir", required_argument, NULL, 'd' }, + { "keep-as-dir", no_argument, NULL, 'k' }, + { "root-becomes", required_argument, NULL, 'r' }, + { "no-skip", no_argument, NULL, 's' }, + { "no-xattr", no_argument, NULL, 'X' }, + { "no-hard-links", no_argument, NULL, 'L' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 }, +}; + +static const char *short_opts = "c:d:kr:sXLhV"; + +static const char *usagestr = +"Usage: sqfs2tar [OPTIONS...] \n" +"\n" +"Read an input squashfs archive and turn it into a tar archive, written\n" +"to stdout.\n" +"\n" +"Possible options:\n" +"\n" +" --compressor, -c If set, stream compress the resulting tarball.\n" +" By default, the tarball is uncompressed.\n" +"\n" +" --subdir, -d Unpack the given sub directory instead of the\n" +" filesystem root. Can be specified more than\n" +" once to select multiple directories. If only\n" +" one is specified, it becomes the new root of\n" +" node of the archive file system tree.\n" +"\n" +" --root-becomes, -r Turn the root inode into a directory with the\n" +" specified name. Everything else will be stored\n" +" inside this directory. The special value '.' is\n" +" allowed to prefix all tar paths with './' and\n" +" add an entry named '.' for the root inode.\n" +" If this option isn't used, all meta data stored\n" +" in the root inode IS LOST!\n" +"\n" +" --keep-as-dir, -k If --subdir is used only once, don't make the\n" +" subdir the archive root, instead keep it as\n" +" prefix for all unpacked files.\n" +" Using --subdir more than once implies\n" +" --keep-as-dir.\n" +" --no-xattr, -X Do not copy extended attributes.\n" +" --no-hard-links, -L Do not generate hard links. Produce duplicate\n" +" entries instead.\n" +"\n" +" --no-skip, -s Abort if a file cannot be stored in a tar\n" +" archive. By default, it is simply skipped\n" +" and a warning is written to stderr.\n" +"\n" +" --help, -h Print help text and exit.\n" +" --version, -V Print version information and exit.\n" +"\n" +"Supported tar compression formats:\n"; + +bool dont_skip = false; +bool keep_as_dir = false; +bool no_xattr = false; +bool no_links = false; + +char *root_becomes = NULL; +char **subdirs = NULL; +size_t num_subdirs = 0; +static size_t max_subdirs = 0; +int compressor = 0; + +const char *filename = NULL; + +void process_args(int argc, char **argv) +{ + size_t idx, new_count; + const char *name; + int i, ret; + char **new; + + for (;;) { + i = getopt_long(argc, argv, short_opts, long_opts, NULL); + if (i == -1) + break; + + switch (i) { + case 'c': + compressor = xfrm_compressor_id_from_name(optarg); + if (compressor <= 0) { + fprintf(stderr, "unknown compressor '%s'.\n", + optarg); + goto fail; + } + break; + case 'd': + if (num_subdirs == max_subdirs) { + new_count = max_subdirs ? max_subdirs * 2 : 16; + new = realloc(subdirs, + new_count * sizeof(subdirs[0])); + if (new == NULL) + goto fail_errno; + + max_subdirs = new_count; + subdirs = new; + } + + subdirs[num_subdirs] = strdup(optarg); + if (subdirs[num_subdirs] == NULL) + goto fail_errno; + + if (canonicalize_name(subdirs[num_subdirs])) { + perror(optarg); + goto fail; + } + + ++num_subdirs; + break; + case 'r': + free(root_becomes); + root_becomes = strdup(optarg); + if (root_becomes == NULL) + goto fail_errno; + + if (strcmp(root_becomes, "./") == 0) + root_becomes[1] = '\0'; + + if (strcmp(root_becomes, ".") == 0) + break; + + if (canonicalize_name(root_becomes) != 0 || + strlen(root_becomes) == 0) { + fprintf(stderr, + "Invalid root directory '%s'.\n", + optarg); + goto fail_arg; + } + break; + case 'k': + keep_as_dir = true; + break; + case 's': + dont_skip = true; + break; + case 'X': + no_xattr = true; + break; + case 'L': + no_links = true; + break; + case 'h': + fputs(usagestr, stdout); + + i = XFRM_COMPRESSOR_MIN; + + while (i <= XFRM_COMPRESSOR_MAX) { + name = xfrm_compressor_name_from_id(i); + if (name != NULL) + printf("\t%s\n", name); + ++i; + } + + fputc('\n', stdout); + goto out_success; + case 'V': + print_version("sqfs2tar"); + goto out_success; + default: + goto fail_arg; + } + } + + if (optind >= argc) { + fputs("Missing argument: squashfs image\n", stderr); + goto fail_arg; + } + + filename = argv[optind++]; + + if (optind < argc) { + fputs("Unknown extra arguments\n", stderr); + goto fail_arg; + } + + if (num_subdirs > 1) + keep_as_dir = true; + + return; +fail_errno: + perror("parsing options"); + goto fail; +fail_arg: + fputs("Try `sqfs2tar --help' for more information.\n", stderr); + goto fail; +fail: + ret = EXIT_FAILURE; + goto out_exit; +out_success: + ret = EXIT_SUCCESS; + goto out_exit; +out_exit: + for (idx = 0; idx < num_subdirs; ++idx) + free(subdirs[idx]); + free(root_becomes); + free(subdirs); + exit(ret); +} diff --git a/bin/sqfs2tar/src/sqfs2tar.c b/bin/sqfs2tar/src/sqfs2tar.c new file mode 100644 index 0000000..43f9e78 --- /dev/null +++ b/bin/sqfs2tar/src/sqfs2tar.c @@ -0,0 +1,274 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * sqfs2tar.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#include "sqfs2tar.h" + +sqfs_xattr_reader_t *xr; +sqfs_data_reader_t *data; +sqfs_super_t super; +ostream_t *out_file = NULL; + +static sqfs_file_t *file; + +char *assemble_tar_path(char *name, bool is_dir) +{ + size_t len, new_len; + char *temp; + (void)is_dir; + + if (root_becomes == NULL && !is_dir) + return name; + + new_len = strlen(name); + if (root_becomes != NULL) + new_len += strlen(root_becomes) + 1; + if (is_dir) + new_len += 1; + + temp = realloc(name, new_len + 1); + if (temp == NULL) { + perror("assembling tar entry filename"); + free(name); + return NULL; + } + + name = temp; + + if (root_becomes != NULL) { + len = strlen(root_becomes); + + memmove(name + len + 1, name, strlen(name) + 1); + memcpy(name, root_becomes, len); + name[len] = '/'; + } + + if (is_dir) { + len = strlen(name); + + if (len == 0 || name[len - 1] != '/') { + name[len++] = '/'; + name[len] = '\0'; + } + } + + return name; +} + +static int terminate_archive(void) +{ + char buffer[1024]; + + memset(buffer, '\0', sizeof(buffer)); + + return ostream_append(out_file, buffer, sizeof(buffer)); +} + +static sqfs_tree_node_t *tree_merge(sqfs_tree_node_t *lhs, + sqfs_tree_node_t *rhs) +{ + sqfs_tree_node_t *head = NULL, **next_ptr = &head; + sqfs_tree_node_t *it, *l, *r; + int diff; + + while (lhs->children != NULL && rhs->children != NULL) { + diff = strcmp((const char *)lhs->children->name, + (const char *)rhs->children->name); + + if (diff < 0) { + it = lhs->children; + lhs->children = lhs->children->next; + } else if (diff > 0) { + it = rhs->children; + rhs->children = rhs->children->next; + } else { + l = lhs->children; + lhs->children = lhs->children->next; + + r = rhs->children; + rhs->children = rhs->children->next; + + it = tree_merge(l, r); + } + + *next_ptr = it; + next_ptr = &it->next; + } + + it = (lhs->children != NULL ? lhs->children : rhs->children); + *next_ptr = it; + + sqfs_dir_tree_destroy(rhs); + lhs->children = head; + return lhs; +} + +int main(int argc, char **argv) +{ + sqfs_tree_node_t *root = NULL, *subtree = NULL; + int flags, ret, status = EXIT_FAILURE; + sqfs_compressor_t *cmp = NULL; + sqfs_id_table_t *idtbl = NULL; + sqfs_dir_reader_t *dr = NULL; + sqfs_compressor_config_t cfg; + size_t i; + + process_args(argc, argv); + + out_file = ostream_open_stdout(); + if (out_file == NULL) { + perror("changing stdout to binary mode"); + goto out; + } + + if (compressor > 0) { + xfrm_stream_t *xfrm = compressor_stream_create(compressor,NULL); + ostream_t *strm; + + if (xfrm == NULL) + goto out; + + strm = ostream_xfrm_create(out_file, xfrm); + sqfs_drop(out_file); + sqfs_drop(xfrm); + out_file = strm; + + if (out_file == NULL) + goto out; + } + + file = sqfs_open_file(filename, SQFS_FILE_OPEN_READ_ONLY); + if (file == NULL) { + perror(filename); + goto out; + } + + ret = sqfs_super_read(&super, file); + if (ret) { + sqfs_perror(filename, "reading super block", ret); + goto out; + } + + sqfs_compressor_config_init(&cfg, super.compression_id, + super.block_size, + SQFS_COMP_FLAG_UNCOMPRESS); + + ret = sqfs_compressor_create(&cfg, &cmp); + +#ifdef WITH_LZO + if (super.compression_id == SQFS_COMP_LZO && ret != 0) + ret = lzo_compressor_create(&cfg, &cmp); +#endif + + if (ret != 0) { + sqfs_perror(filename, "creating compressor", ret); + goto out; + } + + idtbl = sqfs_id_table_create(0); + + if (idtbl == NULL) { + perror("creating ID table"); + goto out; + } + + ret = sqfs_id_table_read(idtbl, file, &super, cmp); + if (ret) { + sqfs_perror(filename, "loading ID table", ret); + goto out; + } + + data = sqfs_data_reader_create(file, super.block_size, cmp, 0); + if (data == NULL) { + sqfs_perror(filename, "creating data reader", + SQFS_ERROR_ALLOC); + goto out; + } + + ret = sqfs_data_reader_load_fragment_table(data, &super); + if (ret) { + sqfs_perror(filename, "loading fragment table", ret); + goto out; + } + + dr = sqfs_dir_reader_create(&super, cmp, file, 0); + if (dr == NULL) { + sqfs_perror(filename, "creating dir reader", + SQFS_ERROR_ALLOC); + goto out; + } + + if (!no_xattr && !(super.flags & SQFS_FLAG_NO_XATTRS)) { + xr = sqfs_xattr_reader_create(0); + if (xr == NULL) { + sqfs_perror(filename, "creating xattr reader", + SQFS_ERROR_ALLOC); + goto out; + } + + ret = sqfs_xattr_reader_load(xr, &super, file, cmp); + if (ret) { + sqfs_perror(filename, "loading xattr table", ret); + goto out; + } + } + + if (num_subdirs == 0) { + ret = sqfs_dir_reader_get_full_hierarchy(dr, idtbl, NULL, + 0, &root); + if (ret) { + sqfs_perror(filename, "loading filesystem tree", ret); + goto out; + } + } else { + flags = 0; + + if (keep_as_dir || num_subdirs > 1) + flags = SQFS_TREE_STORE_PARENTS; + + for (i = 0; i < num_subdirs; ++i) { + ret = sqfs_dir_reader_get_full_hierarchy(dr, idtbl, + subdirs[i], + flags, + &subtree); + if (ret) { + sqfs_perror(subdirs[i], "loading filesystem " + "tree", ret); + goto out; + } + + if (root == NULL) { + root = subtree; + } else { + root = tree_merge(root, subtree); + } + } + } + + if (write_tree(root)) + goto out; + + if (terminate_archive()) + goto out; + + if (ostream_flush(out_file)) + goto out; + + status = EXIT_SUCCESS; +out: + sqfs_dir_tree_destroy(root); + sqfs_drop(xr); + sqfs_drop(dr); + sqfs_drop(data); + sqfs_drop(idtbl); + sqfs_drop(cmp); + sqfs_drop(file); + sqfs_drop(out_file); + for (i = 0; i < num_subdirs; ++i) + free(subdirs[i]); + free(subdirs); + free(root_becomes); + return status; +} diff --git a/bin/sqfs2tar/src/sqfs2tar.h b/bin/sqfs2tar/src/sqfs2tar.h new file mode 100644 index 0000000..4bf5428 --- /dev/null +++ b/bin/sqfs2tar/src/sqfs2tar.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * sqfs2tar.h + * + * Copyright (C) 2019 David Oberhollenzer + */ +#ifndef SQFS2TAR_H +#define SQFS2TAR_H + +#include "config.h" +#include "common.h" + +#include "util/util.h" +#include "tar/tar.h" +#include "xfrm/compress.h" +#include "io/xfrm.h" + +#include +#include +#include +#include +#include +#include +#include + +/* options.c */ +extern bool dont_skip; +extern bool keep_as_dir; +extern bool no_xattr; +extern bool no_links; + +extern char *root_becomes; +extern char **subdirs; +extern size_t num_subdirs; +extern int compressor; + +extern const char *filename; + +void process_args(int argc, char **argv); + +/* tar2sqfs.c */ +extern sqfs_xattr_reader_t *xr; +extern sqfs_data_reader_t *data; +extern sqfs_super_t super; +extern ostream_t *out_file; + +char *assemble_tar_path(char *name, bool is_dir); + +/* xattr.c */ +int get_xattrs(const char *name, const sqfs_inode_generic_t *inode, + tar_xattr_t **out); + +/* write_tree.c */ +int write_tree(const sqfs_tree_node_t *n); + +#endif /* SQFS2TAR_H */ diff --git a/bin/sqfs2tar/src/write_tree.c b/bin/sqfs2tar/src/write_tree.c new file mode 100644 index 0000000..354ec21 --- /dev/null +++ b/bin/sqfs2tar/src/write_tree.c @@ -0,0 +1,209 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * write_tree.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#include "sqfs2tar.h" + +static sqfs_hard_link_t *links = NULL; +static unsigned int record_counter; + +static sqfs_hard_link_t *find_hard_link(const char *name, sqfs_u32 inum) +{ + sqfs_hard_link_t *lnk = NULL; + + for (lnk = links; lnk != NULL; lnk = lnk->next) { + if (lnk->inode_number == inum) { + if (strcmp(name, lnk->target) == 0) + lnk = NULL; + break; + } + } + + return lnk; +} + +static void inode_stat(const sqfs_tree_node_t *node, struct stat *sb) +{ + memset(sb, 0, sizeof(*sb)); + + sb->st_mode = node->inode->base.mode; + sb->st_uid = node->uid; + sb->st_gid = node->gid; + sb->st_mtime = node->inode->base.mod_time; + + switch (node->inode->base.type) { + case SQFS_INODE_BDEV: + case SQFS_INODE_CDEV: + sb->st_rdev = node->inode->data.dev.devno; + break; + case SQFS_INODE_EXT_BDEV: + case SQFS_INODE_EXT_CDEV: + sb->st_rdev = node->inode->data.dev_ext.devno; + break; + case SQFS_INODE_SLINK: + sb->st_size = node->inode->data.slink.target_size; + break; + case SQFS_INODE_EXT_SLINK: + sb->st_size = node->inode->data.slink_ext.target_size; + break; + case SQFS_INODE_FILE: + sb->st_size = node->inode->data.file.file_size; + break; + case SQFS_INODE_EXT_FILE: + sb->st_size = node->inode->data.file_ext.file_size; + break; + case SQFS_INODE_DIR: + sb->st_size = node->inode->data.dir.size; + break; + case SQFS_INODE_EXT_DIR: + sb->st_size = node->inode->data.dir_ext.size; + break; + default: + break; + } +} + +static int write_tree_dfs(const sqfs_tree_node_t *n) +{ + sqfs_hard_link_t *lnk = NULL; + tar_xattr_t *xattr = NULL; + char *name, *target; + struct stat sb; + size_t len; + int ret; + + inode_stat(n, &sb); + + if (n->parent == NULL) { + if (root_becomes == NULL) + goto skip_hdr; + + len = strlen(root_becomes); + name = malloc(len + 2); + if (name == NULL) { + perror("creating root directory"); + return -1; + } + + memcpy(name, root_becomes, len); + name[len] = '/'; + name[len + 1] = '\0'; + } else { + if (!is_filename_sane((const char *)n->name, false)) { + fprintf(stderr, "Found a file named '%s', skipping.\n", + n->name); + if (dont_skip) { + fputs("Not allowed to skip files, aborting!\n", + stderr); + return -1; + } + return 0; + } + + ret = sqfs_tree_node_get_path(n, &name); + if (ret != 0) { + sqfs_perror(NULL, "resolving tree node path", ret); + return -1; + } + + if (canonicalize_name(name)) + goto out_skip; + + name = assemble_tar_path(name, S_ISDIR(sb.st_mode)); + if (name == NULL) + return -1; + + lnk = find_hard_link(name, n->inode->base.inode_number); + if (lnk != NULL) { + ret = write_hard_link(out_file, &sb, name, lnk->target, + record_counter++); + sqfs_free(name); + return ret; + } + } + + if (!no_xattr) { + if (get_xattrs(name, n->inode, &xattr)) { + sqfs_free(name); + return -1; + } + } + + target = S_ISLNK(sb.st_mode) ? (char *)n->inode->extra : NULL; + ret = write_tar_header(out_file, &sb, name, target, xattr, + record_counter++); + free_xattr_list(xattr); + + if (ret > 0) + goto out_skip; + + if (ret < 0) { + sqfs_free(name); + return -1; + } + + if (S_ISREG(sb.st_mode)) { + if (sqfs_data_reader_dump(name, data, n->inode, out_file, + super.block_size)) { + sqfs_free(name); + return -1; + } + + if (padd_file(out_file, sb.st_size)) { + sqfs_free(name); + return -1; + } + } + + sqfs_free(name); +skip_hdr: + for (n = n->children; n != NULL; n = n->next) { + if (write_tree_dfs(n)) + return -1; + } + return 0; +out_skip: + if (dont_skip) { + fputs("Not allowed to skip files, aborting!\n", stderr); + ret = -1; + } else { + fprintf(stderr, "Skipping %s\n", name); + ret = 0; + } + sqfs_free(name); + return ret; +} + +int write_tree(const sqfs_tree_node_t *n) +{ + sqfs_hard_link_t *lnk; + int status = -1; + + if (!no_links) { + int ret = sqfs_tree_find_hard_links(n, &links); + if (ret) { + sqfs_perror(NULL, "detecting hard links in " + "file system tree", ret); + return -1; + } + + for (lnk = links; lnk != NULL; lnk = lnk->next) { + lnk->target = assemble_tar_path(lnk->target, false); + + if (lnk->target == NULL) + goto out_links; + } + } + + status = write_tree_dfs(n); +out_links: + while (links != NULL) { + lnk = links; + links = links->next; + sqfs_free(lnk->target); + free(lnk); + } + return status; +} diff --git a/bin/sqfs2tar/src/xattr.c b/bin/sqfs2tar/src/xattr.c new file mode 100644 index 0000000..abec4fb --- /dev/null +++ b/bin/sqfs2tar/src/xattr.c @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * xattr.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#include "sqfs2tar.h" + +static tar_xattr_t *mkxattr(const sqfs_xattr_entry_t *key, + const sqfs_xattr_value_t *value) +{ + tar_xattr_t *ent; + + ent = calloc(1, sizeof(*ent) + strlen((const char *)key->key) + + value->size + 2); + + if (ent == NULL) { + perror("creating xattr entry"); + return NULL; + } + + ent->key = ent->data; + ent->value = (sqfs_u8 *)ent->key + strlen((const char *)key->key) + 1; + ent->value_len = value->size; + + strcpy(ent->key, (const char *)key->key); + memcpy(ent->value, value->value, value->size + 1); + return ent; +} + +int get_xattrs(const char *name, const sqfs_inode_generic_t *inode, + tar_xattr_t **out) +{ + tar_xattr_t *list = NULL, *ent; + sqfs_xattr_value_t *value; + sqfs_xattr_entry_t *key; + sqfs_xattr_id_t desc; + sqfs_u32 index; + size_t i; + int ret; + + if (xr == NULL) + return 0; + + sqfs_inode_get_xattr_index(inode, &index); + if (index == 0xFFFFFFFF) + return 0; + + ret = sqfs_xattr_reader_get_desc(xr, index, &desc); + if (ret) { + sqfs_perror(name, "resolving xattr index", ret); + return -1; + } + + ret = sqfs_xattr_reader_seek_kv(xr, &desc); + if (ret) { + sqfs_perror(name, "locating xattr key-value pairs", ret); + return -1; + } + + for (i = 0; i < desc.count; ++i) { + ret = sqfs_xattr_reader_read_key(xr, &key); + if (ret) { + sqfs_perror(name, "reading xattr key", ret); + goto fail; + } + + ret = sqfs_xattr_reader_read_value(xr, key, &value); + if (ret) { + sqfs_perror(name, "reading xattr value", ret); + sqfs_free(key); + goto fail; + } + + ent = mkxattr(key, value); + sqfs_free(key); + sqfs_free(value); + + if (ent == NULL) + goto fail; + + ent->next = list; + list = ent; + } + + *out = list; + return 0; +fail: + free_xattr_list(list); + return -1; +} diff --git a/bin/sqfs2tar/write_tree.c b/bin/sqfs2tar/write_tree.c deleted file mode 100644 index 354ec21..0000000 --- a/bin/sqfs2tar/write_tree.c +++ /dev/null @@ -1,209 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * write_tree.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#include "sqfs2tar.h" - -static sqfs_hard_link_t *links = NULL; -static unsigned int record_counter; - -static sqfs_hard_link_t *find_hard_link(const char *name, sqfs_u32 inum) -{ - sqfs_hard_link_t *lnk = NULL; - - for (lnk = links; lnk != NULL; lnk = lnk->next) { - if (lnk->inode_number == inum) { - if (strcmp(name, lnk->target) == 0) - lnk = NULL; - break; - } - } - - return lnk; -} - -static void inode_stat(const sqfs_tree_node_t *node, struct stat *sb) -{ - memset(sb, 0, sizeof(*sb)); - - sb->st_mode = node->inode->base.mode; - sb->st_uid = node->uid; - sb->st_gid = node->gid; - sb->st_mtime = node->inode->base.mod_time; - - switch (node->inode->base.type) { - case SQFS_INODE_BDEV: - case SQFS_INODE_CDEV: - sb->st_rdev = node->inode->data.dev.devno; - break; - case SQFS_INODE_EXT_BDEV: - case SQFS_INODE_EXT_CDEV: - sb->st_rdev = node->inode->data.dev_ext.devno; - break; - case SQFS_INODE_SLINK: - sb->st_size = node->inode->data.slink.target_size; - break; - case SQFS_INODE_EXT_SLINK: - sb->st_size = node->inode->data.slink_ext.target_size; - break; - case SQFS_INODE_FILE: - sb->st_size = node->inode->data.file.file_size; - break; - case SQFS_INODE_EXT_FILE: - sb->st_size = node->inode->data.file_ext.file_size; - break; - case SQFS_INODE_DIR: - sb->st_size = node->inode->data.dir.size; - break; - case SQFS_INODE_EXT_DIR: - sb->st_size = node->inode->data.dir_ext.size; - break; - default: - break; - } -} - -static int write_tree_dfs(const sqfs_tree_node_t *n) -{ - sqfs_hard_link_t *lnk = NULL; - tar_xattr_t *xattr = NULL; - char *name, *target; - struct stat sb; - size_t len; - int ret; - - inode_stat(n, &sb); - - if (n->parent == NULL) { - if (root_becomes == NULL) - goto skip_hdr; - - len = strlen(root_becomes); - name = malloc(len + 2); - if (name == NULL) { - perror("creating root directory"); - return -1; - } - - memcpy(name, root_becomes, len); - name[len] = '/'; - name[len + 1] = '\0'; - } else { - if (!is_filename_sane((const char *)n->name, false)) { - fprintf(stderr, "Found a file named '%s', skipping.\n", - n->name); - if (dont_skip) { - fputs("Not allowed to skip files, aborting!\n", - stderr); - return -1; - } - return 0; - } - - ret = sqfs_tree_node_get_path(n, &name); - if (ret != 0) { - sqfs_perror(NULL, "resolving tree node path", ret); - return -1; - } - - if (canonicalize_name(name)) - goto out_skip; - - name = assemble_tar_path(name, S_ISDIR(sb.st_mode)); - if (name == NULL) - return -1; - - lnk = find_hard_link(name, n->inode->base.inode_number); - if (lnk != NULL) { - ret = write_hard_link(out_file, &sb, name, lnk->target, - record_counter++); - sqfs_free(name); - return ret; - } - } - - if (!no_xattr) { - if (get_xattrs(name, n->inode, &xattr)) { - sqfs_free(name); - return -1; - } - } - - target = S_ISLNK(sb.st_mode) ? (char *)n->inode->extra : NULL; - ret = write_tar_header(out_file, &sb, name, target, xattr, - record_counter++); - free_xattr_list(xattr); - - if (ret > 0) - goto out_skip; - - if (ret < 0) { - sqfs_free(name); - return -1; - } - - if (S_ISREG(sb.st_mode)) { - if (sqfs_data_reader_dump(name, data, n->inode, out_file, - super.block_size)) { - sqfs_free(name); - return -1; - } - - if (padd_file(out_file, sb.st_size)) { - sqfs_free(name); - return -1; - } - } - - sqfs_free(name); -skip_hdr: - for (n = n->children; n != NULL; n = n->next) { - if (write_tree_dfs(n)) - return -1; - } - return 0; -out_skip: - if (dont_skip) { - fputs("Not allowed to skip files, aborting!\n", stderr); - ret = -1; - } else { - fprintf(stderr, "Skipping %s\n", name); - ret = 0; - } - sqfs_free(name); - return ret; -} - -int write_tree(const sqfs_tree_node_t *n) -{ - sqfs_hard_link_t *lnk; - int status = -1; - - if (!no_links) { - int ret = sqfs_tree_find_hard_links(n, &links); - if (ret) { - sqfs_perror(NULL, "detecting hard links in " - "file system tree", ret); - return -1; - } - - for (lnk = links; lnk != NULL; lnk = lnk->next) { - lnk->target = assemble_tar_path(lnk->target, false); - - if (lnk->target == NULL) - goto out_links; - } - } - - status = write_tree_dfs(n); -out_links: - while (links != NULL) { - lnk = links; - links = links->next; - sqfs_free(lnk->target); - free(lnk); - } - return status; -} diff --git a/bin/sqfs2tar/xattr.c b/bin/sqfs2tar/xattr.c deleted file mode 100644 index abec4fb..0000000 --- a/bin/sqfs2tar/xattr.c +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * xattr.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#include "sqfs2tar.h" - -static tar_xattr_t *mkxattr(const sqfs_xattr_entry_t *key, - const sqfs_xattr_value_t *value) -{ - tar_xattr_t *ent; - - ent = calloc(1, sizeof(*ent) + strlen((const char *)key->key) + - value->size + 2); - - if (ent == NULL) { - perror("creating xattr entry"); - return NULL; - } - - ent->key = ent->data; - ent->value = (sqfs_u8 *)ent->key + strlen((const char *)key->key) + 1; - ent->value_len = value->size; - - strcpy(ent->key, (const char *)key->key); - memcpy(ent->value, value->value, value->size + 1); - return ent; -} - -int get_xattrs(const char *name, const sqfs_inode_generic_t *inode, - tar_xattr_t **out) -{ - tar_xattr_t *list = NULL, *ent; - sqfs_xattr_value_t *value; - sqfs_xattr_entry_t *key; - sqfs_xattr_id_t desc; - sqfs_u32 index; - size_t i; - int ret; - - if (xr == NULL) - return 0; - - sqfs_inode_get_xattr_index(inode, &index); - if (index == 0xFFFFFFFF) - return 0; - - ret = sqfs_xattr_reader_get_desc(xr, index, &desc); - if (ret) { - sqfs_perror(name, "resolving xattr index", ret); - return -1; - } - - ret = sqfs_xattr_reader_seek_kv(xr, &desc); - if (ret) { - sqfs_perror(name, "locating xattr key-value pairs", ret); - return -1; - } - - for (i = 0; i < desc.count; ++i) { - ret = sqfs_xattr_reader_read_key(xr, &key); - if (ret) { - sqfs_perror(name, "reading xattr key", ret); - goto fail; - } - - ret = sqfs_xattr_reader_read_value(xr, key, &value); - if (ret) { - sqfs_perror(name, "reading xattr value", ret); - sqfs_free(key); - goto fail; - } - - ent = mkxattr(key, value); - sqfs_free(key); - sqfs_free(value); - - if (ent == NULL) - goto fail; - - ent->next = list; - list = ent; - } - - *out = list; - return 0; -fail: - free_xattr_list(list); - return -1; -} -- cgit v1.2.3