summaryrefslogtreecommitdiff
path: root/unpack
diff options
context:
space:
mode:
Diffstat (limited to 'unpack')
-rw-r--r--unpack/Makemodule.am9
-rw-r--r--unpack/describe.c125
-rw-r--r--unpack/dump_xattrs.c120
-rw-r--r--unpack/fill_files.c183
-rw-r--r--unpack/list_files.c156
-rw-r--r--unpack/options.c217
-rw-r--r--unpack/rdsquashfs.c175
-rw-r--r--unpack/rdsquashfs.h77
-rw-r--r--unpack/restore_fstree.c320
9 files changed, 0 insertions, 1382 deletions
diff --git a/unpack/Makemodule.am b/unpack/Makemodule.am
deleted file mode 100644
index 94aa0b2..0000000
--- a/unpack/Makemodule.am
+++ /dev/null
@@ -1,9 +0,0 @@
-rdsquashfs_SOURCES = unpack/rdsquashfs.c unpack/rdsquashfs.h
-rdsquashfs_SOURCES += unpack/list_files.c unpack/options.c
-rdsquashfs_SOURCES += unpack/restore_fstree.c unpack/describe.c
-rdsquashfs_SOURCES += unpack/fill_files.c unpack/dump_xattrs.c
-rdsquashfs_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS)
-rdsquashfs_LDADD = libcommon.a libcompat.a libsquashfs.la
-rdsquashfs_LDADD += libfstree.a $(LZO_LIBS) $(PTHREAD_LIBS)
-
-bin_PROGRAMS += rdsquashfs
diff --git a/unpack/describe.c b/unpack/describe.c
deleted file mode 100644
index d30f844..0000000
--- a/unpack/describe.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * describe.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "rdsquashfs.h"
-
-static int print_name(const sqfs_tree_node_t *n)
-{
- char *start, *ptr, *name = sqfs_tree_node_get_path(n);
- int ret;
-
- if (name == NULL) {
- perror("Recovering file path of tree node");
- return -1;
- }
-
- ret = canonicalize_name(name);
- assert(ret == 0);
-
- if (strchr(name, ' ') == NULL && strchr(name, '"') == NULL) {
- fputs(name, stdout);
- } else {
- fputc('"', stdout);
-
- ptr = strchr(name, '"');
-
- if (ptr != NULL) {
- start = name;
-
- do {
- fwrite(start, 1, ptr - start, stdout);
- fputs("\\\"", stdout);
- start = ptr + 1;
- ptr = strchr(start, '"');
- } while (ptr != NULL);
-
- fputs(start, stdout);
- } else {
- fputs(name, stdout);
- }
-
- fputc('"', stdout);
- }
-
- free(name);
- return 0;
-}
-
-static void print_perm(const sqfs_tree_node_t *n)
-{
- printf(" 0%o %d %d", n->inode->base.mode & (~S_IFMT), n->uid, n->gid);
-}
-
-static int print_simple(const char *type, const sqfs_tree_node_t *n,
- const char *extra)
-{
- printf("%s ", type);
- if (print_name(n))
- return -1;
- print_perm(n);
- if (extra != NULL)
- printf(" %s", extra);
- fputc('\n', stdout);
- return 0;
-}
-
-int describe_tree(const sqfs_tree_node_t *root, const char *unpack_root)
-{
- const sqfs_tree_node_t *n;
-
- switch (root->inode->base.mode & S_IFMT) {
- case S_IFSOCK:
- return print_simple("sock", root, NULL);
- case S_IFLNK:
- return print_simple("slink", root,
- (const char *)root->inode->extra);
- case S_IFIFO:
- return print_simple("pipe", root, NULL);
- case S_IFREG:
- if (unpack_root == NULL)
- return print_simple("file", root, NULL);
-
- fputs("file ", stdout);
- if (print_name(root))
- return -1;
- print_perm(root);
- printf(" %s/", unpack_root);
- if (print_name(root))
- return -1;
- fputc('\n', stdout);
- break;
- case S_IFCHR:
- case S_IFBLK: {
- char buffer[32];
- sqfs_u32 devno;
-
- if (root->inode->base.type == SQFS_INODE_EXT_BDEV ||
- root->inode->base.type == SQFS_INODE_EXT_CDEV) {
- devno = root->inode->data.dev_ext.devno;
- } else {
- devno = root->inode->data.dev.devno;
- }
-
- sprintf(buffer, "%c %d %d",
- S_ISCHR(root->inode->base.mode) ? 'c' : 'b',
- major(devno), minor(devno));
- return print_simple("nod", root, buffer);
- }
- case S_IFDIR:
- if (root->name[0] != '\0') {
- if (print_simple("dir", root, NULL))
- return -1;
- }
-
- for (n = root->children; n != NULL; n = n->next) {
- if (describe_tree(n, unpack_root))
- return -1;
- }
- break;
- }
-
- return 0;
-}
diff --git a/unpack/dump_xattrs.c b/unpack/dump_xattrs.c
deleted file mode 100644
index 93b0b01..0000000
--- a/unpack/dump_xattrs.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * dump_xattrs.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "rdsquashfs.h"
-
-static void print_hex(const sqfs_u8 *value, size_t len)
-{
- printf("0x");
-
- while (len--)
- printf("%02X", *(value++));
-}
-
-static bool is_printable(const sqfs_u8 *value, size_t len)
-{
- size_t utf8_cont = 0;
- sqfs_u8 x;
-
- while (len--) {
- x = *(value++);
-
- if (utf8_cont > 0) {
- if ((x & 0xC0) != 0x80)
- return false;
-
- --utf8_cont;
- } else {
- if (x < 0x80) {
- if (x < 0x20) {
- if (x >= 0x07 && x <= 0x0D)
- continue;
- if (x == 0x00)
- continue;
- return false;
- }
-
- if (x == 0x7F)
- return false;
- }
-
- if ((x & 0xE0) == 0xC0) {
- utf8_cont = 1;
- } else if ((x & 0xF0) == 0xE0) {
- utf8_cont = 2;
- } else if ((x & 0xF8) == 0xF0) {
- utf8_cont = 3;
- } else if ((x & 0xFC) == 0xF8) {
- utf8_cont = 4;
- } else if ((x & 0xFE) == 0xFC) {
- utf8_cont = 5;
- }
-
- if (utf8_cont > 0 && len < utf8_cont)
- return false;
- }
- }
-
- return true;
-}
-
-int dump_xattrs(sqfs_xattr_reader_t *xattr, const sqfs_inode_generic_t *inode)
-{
- sqfs_xattr_value_t *value;
- sqfs_xattr_entry_t *key;
- sqfs_xattr_id_t desc;
- sqfs_u32 index;
- size_t i;
-
- if (xattr == NULL)
- return 0;
-
- sqfs_inode_get_xattr_index(inode, &index);
-
- if (index == 0xFFFFFFFF)
- return 0;
-
- if (sqfs_xattr_reader_get_desc(xattr, index, &desc)) {
- fputs("Error resolving xattr index\n", stderr);
- return -1;
- }
-
- if (sqfs_xattr_reader_seek_kv(xattr, &desc)) {
- fputs("Error locating xattr key-value pairs\n", stderr);
- return -1;
- }
-
- for (i = 0; i < desc.count; ++i) {
- if (sqfs_xattr_reader_read_key(xattr, &key)) {
- fputs("Error reading xattr key\n", stderr);
- return -1;
- }
-
- if (sqfs_xattr_reader_read_value(xattr, key, &value)) {
- fputs("Error reading xattr value\n", stderr);
- free(key);
- return -1;
- }
-
- if (is_printable(key->key, key->size)) {
- printf("%s=", key->key);
- } else {
- print_hex(key->key, key->size);
- }
-
- if (is_printable(value->value, value->size)) {
- printf("%s\n", value->value);
- } else {
- print_hex(value->value, value->size);
- printf("\n");
- }
-
- free(key);
- free(value);
- }
-
- return 0;
-}
diff --git a/unpack/fill_files.c b/unpack/fill_files.c
deleted file mode 100644
index b75afbf..0000000
--- a/unpack/fill_files.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * fill_files.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-#include "rdsquashfs.h"
-
-static struct file_ent {
- char *path;
- const sqfs_inode_generic_t *inode;
-} *files = NULL;
-
-static size_t num_files = 0, max_files = 0;
-static size_t block_size = 0;
-
-static int compare_files(const void *l, const void *r)
-{
- sqfs_u32 lhs_frag_idx, lhs_frag_off, rhs_frag_idx, rhs_frag_off;
- sqfs_u64 lhs_size, rhs_size, lhs_start, rhs_start;
- const struct file_ent *lhs = l, *rhs = r;
-
- sqfs_inode_get_frag_location(lhs->inode, &lhs_frag_idx, &lhs_frag_off);
- sqfs_inode_get_file_block_start(lhs->inode, &lhs_start);
- sqfs_inode_get_file_size(lhs->inode, &lhs_size);
-
- sqfs_inode_get_frag_location(rhs->inode, &rhs_frag_idx, &rhs_frag_off);
- sqfs_inode_get_file_block_start(rhs->inode, &rhs_start);
- sqfs_inode_get_file_size(rhs->inode, &rhs_size);
-
- /* Files with fragments come first, ordered by ID.
- In case of tie, files without data blocks come first,
- and the others are ordered by start block. */
- if ((lhs_size % block_size) && (lhs_frag_off < block_size) &&
- (lhs_frag_idx != 0xFFFFFFFF)) {
- if ((rhs_size % block_size) && (rhs_frag_off < block_size) &&
- (rhs_frag_idx != 0xFFFFFFFF))
- return -1;
-
- if (lhs_frag_idx < rhs_frag_idx)
- return -1;
-
- if (lhs_frag_idx > rhs_frag_idx)
- return 1;
-
- if (lhs_size < block_size)
- return (rhs_size < block_size) ? 0 : -1;
-
- if (rhs_size < block_size)
- return 1;
-
- goto order_by_start;
- }
-
- if ((rhs_size % block_size) && (rhs_frag_off < block_size) &&
- (rhs_frag_idx != 0xFFFFFFFF))
- return 1;
-
- /* order the rest by start block */
-order_by_start:
- return lhs_start < rhs_start ? -1 : lhs_start > rhs_start ? 1 : 0;
-}
-
-static int add_file(const sqfs_tree_node_t *node)
-{
- size_t new_sz;
- char *path;
- void *new;
-
- if (num_files == max_files) {
- new_sz = max_files ? max_files * 2 : 256;
- new = realloc(files, sizeof(files[0]) * new_sz);
-
- if (new == NULL) {
- perror("expanding file list");
- return -1;
- }
-
- files = new;
- max_files = new_sz;
- }
-
- path = sqfs_tree_node_get_path(node);
- if (path == NULL) {
- perror("assembling file path");
- return -1;
- }
-
- if (canonicalize_name(path)) {
- fprintf(stderr, "Invalid file path '%s'\n", path);
- free(path);
- return -1;
- }
-
- files[num_files].path = path;
- files[num_files].inode = node->inode;
- num_files++;
- return 0;
-}
-
-static void clear_file_list(void)
-{
- size_t i;
-
- for (i = 0; i < num_files; ++i)
- free(files[i].path);
-
- free(files);
- files = NULL;
- num_files = 0;
- max_files = 0;
-}
-
-static int gen_file_list_dfs(const sqfs_tree_node_t *n)
-{
- if (!is_filename_sane((const char *)n->name, true)) {
- fprintf(stderr, "Found an entry named '%s', skipping.\n",
- n->name);
- return 0;
- }
-
- if (S_ISREG(n->inode->base.mode))
- return add_file(n);
-
- if (S_ISDIR(n->inode->base.mode)) {
- for (n = n->children; n != NULL; n = n->next) {
- if (gen_file_list_dfs(n))
- return -1;
- }
- }
-
- return 0;
-}
-
-static int fill_files(sqfs_data_reader_t *data, int flags)
-{
- size_t i;
- FILE *fp;
-
- for (i = 0; i < num_files; ++i) {
- fp = fopen(files[i].path, "wb");
- if (fp == NULL) {
- fprintf(stderr, "unpacking %s: %s\n",
- files[i].path, strerror(errno));
- return -1;
- }
-
- if (!(flags & UNPACK_QUIET))
- printf("unpacking %s\n", files[i].path);
-
- if (sqfs_data_reader_dump(files[i].path, data, files[i].inode,
- fp, block_size,
- (flags & UNPACK_NO_SPARSE) == 0)) {
- fclose(fp);
- return -1;
- }
-
- fflush(fp);
- fclose(fp);
- }
-
- return 0;
-}
-
-int fill_unpacked_files(size_t blk_sz, const sqfs_tree_node_t *root,
- sqfs_data_reader_t *data, int flags)
-{
- int status;
-
- block_size = blk_sz;
-
- if (gen_file_list_dfs(root)) {
- clear_file_list();
- return -1;
- }
-
- qsort(files, num_files, sizeof(files[0]), compare_files);
-
- status = fill_files(data, flags);
- clear_file_list();
- return status;
-}
diff --git a/unpack/list_files.c b/unpack/list_files.c
deleted file mode 100644
index 238ffec..0000000
--- a/unpack/list_files.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * list_files.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "rdsquashfs.h"
-
-static void mode_to_str(sqfs_u16 mode, char *p)
-{
- switch (mode & S_IFMT) {
- case S_IFDIR: *(p++) = 'd'; break;
- case S_IFCHR: *(p++) = 'c'; break;
- case S_IFBLK: *(p++) = 'b'; break;
- case S_IFREG: *(p++) = '-'; break;
- case S_IFLNK: *(p++) = 'l'; break;
- case S_IFSOCK: *(p++) = 's'; break;
- case S_IFIFO: *(p++) = 'p'; break;
- default: *(p++) = '?'; break;
- }
-
- *(p++) = (mode & S_IRUSR) ? 'r' : '-';
- *(p++) = (mode & S_IWUSR) ? 'w' : '-';
-
- switch (mode & (S_IXUSR | S_ISUID)) {
- case S_IXUSR | S_ISUID: *(p++) = 's'; break;
- case S_IXUSR: *(p++) = 'x'; break;
- case S_ISUID: *(p++) = 'S'; break;
- default: *(p++) = '-'; break;
- }
-
- *(p++) = (mode & S_IRGRP) ? 'r' : '-';
- *(p++) = (mode & S_IWGRP) ? 'w' : '-';
-
- switch (mode & (S_IXGRP | S_ISGID)) {
- case S_IXGRP | S_ISGID: *(p++) = 's'; break;
- case S_IXGRP: *(p++) = 'x'; break;
- case S_ISGID: *(p++) = 'S'; break;
- case 0: *(p++) = '-'; break;
- }
-
- *(p++) = (mode & S_IROTH) ? 'r' : '-';
- *(p++) = (mode & S_IWOTH) ? 'w' : '-';
-
- switch (mode & (S_IXOTH | S_ISVTX)) {
- case S_IXOTH | S_ISVTX: *(p++) = 't'; break;
- case S_IXOTH: *(p++) = 'x'; break;
- case S_ISVTX: *(p++) = 'T'; break;
- case 0: *(p++) = '-'; break;
- }
-
- *p = '\0';
-}
-
-static int count_int_chars(unsigned int i)
-{
- int count = 1;
-
- while (i > 10) {
- ++count;
- i /= 10;
- }
-
- return count;
-}
-
-static void print_node_size(const sqfs_tree_node_t *n, char *buffer)
-{
- switch (n->inode->base.mode & S_IFMT) {
- case S_IFLNK:
- print_size(strlen((const char *)n->inode->extra), buffer, true);
- break;
- case S_IFREG: {
- sqfs_u64 size;
- sqfs_inode_get_file_size(n->inode, &size);
- print_size(size, buffer, true);
- break;
- }
- case S_IFDIR:
- if (n->inode->base.type == SQFS_INODE_EXT_DIR) {
- print_size(n->inode->data.dir_ext.size, buffer, true);
- } else {
- print_size(n->inode->data.dir.size, buffer, true);
- }
- break;
- case S_IFBLK:
- case S_IFCHR: {
- sqfs_u32 devno;
-
- if (n->inode->base.type == SQFS_INODE_EXT_BDEV ||
- n->inode->base.type == SQFS_INODE_EXT_CDEV) {
- devno = n->inode->data.dev_ext.devno;
- } else {
- devno = n->inode->data.dev.devno;
- }
-
- sprintf(buffer, "%u:%u", major(devno), minor(devno));
- break;
- }
- default:
- buffer[0] = '0';
- buffer[1] = '\0';
- break;
- }
-}
-
-void list_files(const sqfs_tree_node_t *node)
-{
- int i, max_uid_chars = 0, max_gid_chars = 0, max_sz_chars = 0;
- char modestr[12], sizestr[32];
- const sqfs_tree_node_t *n;
-
- if (S_ISDIR(node->inode->base.mode)) {
- for (n = node->children; n != NULL; n = n->next) {
- i = count_int_chars(n->uid);
- max_uid_chars = i > max_uid_chars ? i : max_uid_chars;
-
- i = count_int_chars(n->gid);
- max_gid_chars = i > max_gid_chars ? i : max_gid_chars;
-
- print_node_size(n, sizestr);
- i = strlen(sizestr);
- max_sz_chars = i > max_sz_chars ? i : max_sz_chars;
- }
-
- for (n = node->children; n != NULL; n = n->next) {
- mode_to_str(n->inode->base.mode, modestr);
- print_node_size(n, sizestr);
-
- printf("%s %*u/%-*u %*s %s", modestr,
- max_uid_chars, n->uid,
- max_gid_chars, n->gid,
- max_sz_chars, sizestr,
- n->name);
-
- if (S_ISLNK(n->inode->base.mode)) {
- printf(" -> %s\n",
- (const char *)n->inode->extra);
- } else {
- fputc('\n', stdout);
- }
- }
- } else {
- mode_to_str(node->inode->base.mode, modestr);
- print_node_size(node, sizestr);
-
- printf("%s %u/%u %s %s", modestr,
- node->uid, node->gid, sizestr, node->name);
-
- if (S_ISLNK(node->inode->base.mode)) {
- printf(" -> %s\n", (const char *)node->inode->extra);
- } else {
- fputc('\n', stdout);
- }
- }
-}
diff --git a/unpack/options.c b/unpack/options.c
deleted file mode 100644
index cdd19e1..0000000
--- a/unpack/options.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * options.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "rdsquashfs.h"
-
-static struct option long_opts[] = {
- { "list", required_argument, NULL, 'l' },
- { "cat", required_argument, NULL, 'c' },
- { "xattr", required_argument, NULL, 'x' },
- { "unpack-root", required_argument, NULL, 'p' },
- { "unpack-path", required_argument, NULL, 'u' },
- { "no-dev", no_argument, NULL, 'D' },
- { "no-sock", no_argument, NULL, 'S' },
- { "no-fifo", no_argument, NULL, 'F' },
- { "no-slink", no_argument, NULL, 'L' },
- { "no-empty-dir", no_argument, NULL, 'E' },
- { "no-sparse", no_argument, NULL, 'Z' },
-#ifdef HAVE_SYS_XATTR_H
- { "set-xattr", no_argument, NULL, 'X' },
-#endif
- { "set-times", no_argument, NULL, 'T' },
- { "describe", no_argument, NULL, 'd' },
- { "chmod", no_argument, NULL, 'C' },
- { "chown", no_argument, NULL, 'O' },
- { "quiet", no_argument, NULL, 'q' },
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, 'V' },
- { NULL, 0, NULL, 0 },
-};
-
-static const char *short_opts =
- "l:c:u:p:x:DSFLCOEZTj:dqhV"
-#ifdef HAVE_SYS_XATTR_H
- "X"
-#endif
- ;
-
-static const char *help_string =
-"Usage: rdsquashfs [OPTIONS] <squashfs-file>\n"
-"\n"
-"View or extract the contents of a squashfs image.\n"
-"\n"
-"Possible options:\n"
-"\n"
-" --list, -l <path> Produce a directory listing for a given path in\n"
-" the squashfs image.\n"
-" --cat, -c <path> If the specified path is a regular file in the,\n"
-" image, dump its contents to stdout.\n"
-" --xattr, -x <path> Enumerate extended attributes associated with\n"
-" an inode that the given path resolves to.\n"
-" --unpack-path, -u <path> Unpack this sub directory from the image. To\n"
-" unpack everything, simply specify /.\n"
-" --describe, -d Produce a file listing from the image.\n"
-"\n"
-" --unpack-root, -p <path> If used with --unpack-path, this is where the\n"
-" data unpacked to. If used with --describe, this\n"
-" is used as a prefix for the input path of\n"
-" regular files.\n"
-"\n"
-" --no-dev, -D Do not unpack device special files.\n"
-" --no-sock, -S Do not unpack socket files.\n"
-" --no-fifo, -F Do not unpack named pipes.\n"
-" --no-slink, -L Do not unpack symbolic links.\n"
-" --no-empty-dir, -E Do not unpack directories that would end up\n"
-" empty after applying the above rules.\n"
-" --no-sparse, -Z Do not create sparse files, always write zero\n"
-" blocks to disk.\n"
-#ifdef HAVE_SYS_XATTR_H
-" --set-xattr, -X When unpacking files to disk, set the extended\n"
-" attributes from the squashfs image.\n"
-#endif
-" --set-times, -T When unpacking files to disk, set the create\n"
-" and modify timestamps from the squashfs image.\n"
-" --chmod, -C Change permission flags of unpacked files to\n"
-" those store in the squashfs image.\n"
-" --chown, -O Change ownership of unpacked files to the\n"
-" UID/GID set in the squashfs image.\n"
-" --quiet, -q Do not print out progress while unpacking.\n"
-"\n"
-" --help, -h Print help text and exit.\n"
-" --version, -V Print version information and exit.\n"
-"\n";
-
-static char *get_path(char *old, const char *arg)
-{
- char *path;
-
- free(old);
-
- path = strdup(arg);
- if (path == NULL) {
- perror("processing arguments");
- exit(EXIT_FAILURE);
- }
-
- if (canonicalize_name(path)) {
- fprintf(stderr, "Invalid path: %s\n", arg);
- free(path);
- exit(EXIT_FAILURE);
- }
-
- return path;
-}
-
-void process_command_line(options_t *opt, int argc, char **argv)
-{
- int i;
-
- opt->op = OP_NONE;
- opt->rdtree_flags = 0;
- opt->flags = 0;
- opt->cmdpath = NULL;
- opt->unpack_root = NULL;
- opt->image_name = NULL;
-
- for (;;) {
- i = getopt_long(argc, argv, short_opts, long_opts, NULL);
- if (i == -1)
- break;
-
- switch (i) {
- case 'D':
- opt->rdtree_flags |= SQFS_TREE_NO_DEVICES;
- break;
- case 'S':
- opt->rdtree_flags |= SQFS_TREE_NO_SOCKETS;
- break;
- case 'F':
- opt->rdtree_flags |= SQFS_TREE_NO_FIFO;
- break;
- case 'L':
- opt->rdtree_flags |= SQFS_TREE_NO_SLINKS;
- break;
- case 'E':
- opt->rdtree_flags |= SQFS_TREE_NO_EMPTY;
- break;
- case 'C':
- opt->flags |= UNPACK_CHMOD;
- break;
- case 'O':
- opt->flags |= UNPACK_CHOWN;
- break;
- case 'Z':
- opt->flags |= UNPACK_NO_SPARSE;
- break;
-#ifdef HAVE_SYS_XATTR_H
- case 'X':
- opt->flags |= UNPACK_SET_XATTR;
- break;
-#endif
- case 'T':
- opt->flags |= UNPACK_SET_TIMES;
- break;
- case 'c':
- opt->op = OP_CAT;
- opt->cmdpath = get_path(opt->cmdpath, optarg);
- break;
- case 'd':
- opt->op = OP_DESCRIBE;
- free(opt->cmdpath);
- opt->cmdpath = NULL;
- break;
- case 'x':
- opt->op = OP_RDATTR;
- opt->cmdpath = get_path(opt->cmdpath, optarg);
- break;
- case 'l':
- opt->op = OP_LS;
- opt->cmdpath = get_path(opt->cmdpath, optarg);
- break;
- case 'p':
- opt->unpack_root = optarg;
- break;
- case 'u':
- opt->op = OP_UNPACK;
- opt->cmdpath = get_path(opt->cmdpath, optarg);
- break;
- case 'q':
- opt->flags |= UNPACK_QUIET;
- break;
- case 'h':
- fputs(help_string, stdout);
- free(opt->cmdpath);
- exit(EXIT_SUCCESS);
- case 'V':
- print_version("rdsquashfs");
- free(opt->cmdpath);
- exit(EXIT_SUCCESS);
- default:
- goto fail_arg;
- }
- }
-
- if (opt->op == OP_NONE) {
- fputs("No operation specified\n", stderr);
- goto fail_arg;
- }
-
- if (opt->op == OP_LS || opt->op == OP_CAT || opt->op == OP_RDATTR) {
- opt->rdtree_flags |= SQFS_TREE_NO_RECURSE;
- }
-
- if (optind >= argc) {
- fputs("Missing image argument\n", stderr);
- goto fail_arg;
- }
-
- opt->image_name = argv[optind++];
- return;
-fail_arg:
- fputs("Try `rdsquashfs --help' for more information.\n", stderr);
- free(opt->cmdpath);
- exit(EXIT_FAILURE);
-}
diff --git a/unpack/rdsquashfs.c b/unpack/rdsquashfs.c
deleted file mode 100644
index fa2bbb4..0000000
--- a/unpack/rdsquashfs.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * rdsquashfs.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "rdsquashfs.h"
-
-int main(int argc, char **argv)
-{
- sqfs_xattr_reader_t *xattr = NULL;
- sqfs_compressor_config_t cfg;
- int status = EXIT_FAILURE;
- sqfs_data_reader_t *data;
- sqfs_dir_reader_t *dirrd;
- sqfs_compressor_t *cmp;
- sqfs_id_table_t *idtbl;
- sqfs_tree_node_t *n;
- sqfs_super_t super;
- sqfs_file_t *file;
- options_t opt;
- int ret;
-
- process_command_line(&opt, argc, argv);
-
- file = sqfs_open_file(opt.image_name, SQFS_FILE_OPEN_READ_ONLY);
- if (file == NULL) {
- perror(opt.image_name);
- goto out_cmd;
- }
-
- ret = sqfs_super_read(&super, file);
- if (ret) {
- sqfs_perror(opt.image_name, "reading super block", ret);
- goto out_file;
- }
-
- 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(opt.image_name, "creating compressor", ret);
- goto out_file;
- }
-
- if (!(super.flags & SQFS_FLAG_NO_XATTRS)) {
- xattr = sqfs_xattr_reader_create(0);
- if (xattr == NULL) {
- sqfs_perror(opt.image_name, "creating xattr reader",
- SQFS_ERROR_ALLOC);
- goto out_cmp;
- }
-
- ret = sqfs_xattr_reader_load(xattr, &super, file, cmp);
- if (ret) {
- sqfs_perror(opt.image_name, "loading xattr table",
- ret);
- goto out_xr;
- }
- }
-
- idtbl = sqfs_id_table_create(0);
- if (idtbl == NULL) {
- sqfs_perror(opt.image_name, "creating ID table",
- SQFS_ERROR_ALLOC);
- goto out_xr;
- }
-
- ret = sqfs_id_table_read(idtbl, file, &super, cmp);
- if (ret) {
- sqfs_perror(opt.image_name, "loading ID table", ret);
- goto out_id;
- }
-
- dirrd = sqfs_dir_reader_create(&super, cmp, file);
- if (dirrd == NULL) {
- sqfs_perror(opt.image_name, "creating dir reader",
- SQFS_ERROR_ALLOC);
- goto out_id;
- }
-
- data = sqfs_data_reader_create(file, super.block_size, cmp);
- if (data == NULL) {
- sqfs_perror(opt.image_name, "creating data reader",
- SQFS_ERROR_ALLOC);
- goto out_dr;
- }
-
- ret = sqfs_data_reader_load_fragment_table(data, &super);
- if (ret) {
- sqfs_perror(opt.image_name, "loading fragment table", ret);
- goto out_data;
- }
-
- ret = sqfs_dir_reader_get_full_hierarchy(dirrd, idtbl, opt.cmdpath,
- opt.rdtree_flags, &n);
- if (ret) {
- sqfs_perror(opt.image_name, "reading filesystem tree", ret);
- goto out_data;
- }
-
- switch (opt.op) {
- case OP_LS:
- list_files(n);
- break;
- case OP_CAT:
- if (!S_ISREG(n->inode->base.mode)) {
- fprintf(stderr, "/%s: not a regular file\n",
- opt.cmdpath);
- goto out;
- }
-
- if (sqfs_data_reader_dump(opt.cmdpath, data, n->inode,
- stdout, super.block_size, false)) {
- goto out;
- }
- break;
- case OP_UNPACK:
- if (opt.unpack_root != NULL) {
- if (mkdir_p(opt.unpack_root))
- goto out;
-
- if (chdir(opt.unpack_root)) {
- perror(opt.unpack_root);
- goto out;
- }
- }
-
- if (restore_fstree(n, opt.flags))
- goto out;
-
- if (fill_unpacked_files(super.block_size, n, data, opt.flags))
- goto out;
-
- if (update_tree_attribs(xattr, n, opt.flags))
- goto out;
- break;
- case OP_DESCRIBE:
- if (describe_tree(n, opt.unpack_root))
- goto out;
- break;
- case OP_RDATTR:
- if (dump_xattrs(xattr, n->inode))
- goto out;
- break;
- }
-
- status = EXIT_SUCCESS;
-out:
- sqfs_dir_tree_destroy(n);
-out_data:
- sqfs_destroy(data);
-out_dr:
- sqfs_destroy(dirrd);
-out_id:
- sqfs_destroy(idtbl);
-out_xr:
- if (xattr != NULL)
- sqfs_destroy(xattr);
-out_cmp:
- sqfs_destroy(cmp);
-out_file:
- sqfs_destroy(file);
-out_cmd:
- free(opt.cmdpath);
- return status;
-}
diff --git a/unpack/rdsquashfs.h b/unpack/rdsquashfs.h
deleted file mode 100644
index 17c0a85..0000000
--- a/unpack/rdsquashfs.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * rdsquashfs.h
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#ifndef RDSQUASHFS_H
-#define RDSQUASHFS_H
-
-#include "config.h"
-#include "common.h"
-#include "fstree.h"
-
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#endif
-#ifdef HAVE_SYS_XATTR_H
-#include <sys/xattr.h>
-
-#if defined(__APPLE__) && defined(__MACH__)
-#define lsetxattr(path, name, value, size, flags) \
- setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW)
-#endif
-#endif
-#include <string.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-
-enum UNPACK_FLAGS {
- UNPACK_CHMOD = 0x01,
- UNPACK_CHOWN = 0x02,
- UNPACK_QUIET = 0x04,
- UNPACK_NO_SPARSE = 0x08,
- UNPACK_SET_XATTR = 0x10,
- UNPACK_SET_TIMES = 0x20,
-};
-
-enum {
- OP_NONE = 0,
- OP_LS,
- OP_CAT,
- OP_UNPACK,
- OP_DESCRIBE,
- OP_RDATTR,
-};
-
-typedef struct {
- int op;
- int rdtree_flags;
- int flags;
- char *cmdpath;
- const char *unpack_root;
- const char *image_name;
-} options_t;
-
-void list_files(const sqfs_tree_node_t *node);
-
-int restore_fstree(sqfs_tree_node_t *root, int flags);
-
-int update_tree_attribs(sqfs_xattr_reader_t *xattr,
- const sqfs_tree_node_t *root, int flags);
-
-int fill_unpacked_files(size_t blk_sz, const sqfs_tree_node_t *root,
- sqfs_data_reader_t *data, int flags);
-
-int describe_tree(const sqfs_tree_node_t *root, const char *unpack_root);
-
-int dump_xattrs(sqfs_xattr_reader_t *xattr, const sqfs_inode_generic_t *inode);
-
-void process_command_line(options_t *opt, int argc, char **argv);
-
-#endif /* RDSQUASHFS_H */
diff --git a/unpack/restore_fstree.c b/unpack/restore_fstree.c
deleted file mode 100644
index 8f99439..0000000
--- a/unpack/restore_fstree.c
+++ /dev/null
@@ -1,320 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * restore_fstree.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "rdsquashfs.h"
-
-#ifdef _WIN32
-static int create_node(const sqfs_tree_node_t *n, const char *name)
-{
- WCHAR *wpath;
- HANDLE fh;
-
- wpath = path_to_windows(name);
- if (wpath == NULL)
- return -1;
-
- switch (n->inode->base.mode & S_IFMT) {
- case S_IFDIR:
- if (!CreateDirectoryW(wpath, NULL))
- goto fail;
- break;
- case S_IFREG:
- fh = CreateFileW(wpath, GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, CREATE_NEW, 0, NULL);
-
- if (fh == INVALID_HANDLE_VALUE)
- goto fail;
-
- CloseHandle(fh);
- break;
- default:
- break;
- }
-
- free(wpath);
- return 0;
-fail:
- fprintf(stderr, "Creating %s: %ld\n", name, GetLastError());
- free(wpath);
- return -1;
-}
-#else
-static int create_node(const sqfs_tree_node_t *n, const char *name)
-{
- sqfs_u32 devno;
- int fd;
-
- switch (n->inode->base.mode & S_IFMT) {
- case S_IFDIR:
- if (mkdir(name, 0755) && errno != EEXIST) {
- fprintf(stderr, "mkdir %s: %s\n",
- name, strerror(errno));
- return -1;
- }
- break;
- case S_IFLNK:
- if (symlink((const char *)n->inode->extra, name)) {
- fprintf(stderr, "ln -s %s %s: %s\n",
- (const char *)n->inode->extra, name,
- strerror(errno));
- return -1;
- }
- break;
- case S_IFSOCK:
- case S_IFIFO:
- if (mknod(name, (n->inode->base.mode & S_IFMT) | 0700, 0)) {
- fprintf(stderr, "creating %s: %s\n",
- name, strerror(errno));
- return -1;
- }
- break;
- case S_IFBLK:
- case S_IFCHR:
- if (n->inode->base.type == SQFS_INODE_EXT_BDEV ||
- n->inode->base.type == SQFS_INODE_EXT_CDEV) {
- devno = n->inode->data.dev_ext.devno;
- } else {
- devno = n->inode->data.dev.devno;
- }
-
- if (mknod(name, n->inode->base.mode & S_IFMT, devno)) {
- fprintf(stderr, "creating device %s: %s\n",
- name, strerror(errno));
- return -1;
- }
- break;
- case S_IFREG:
- fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0600);
-
- if (fd < 0) {
- fprintf(stderr, "creating %s: %s\n",
- name, strerror(errno));
- return -1;
- }
-
- close(fd);
- break;
- default:
- break;
- }
-
- return 0;
-}
-#endif
-
-static int create_node_dfs(const sqfs_tree_node_t *n, int flags)
-{
- const sqfs_tree_node_t *c;
- char *name;
- int ret;
-
- if (!is_filename_sane((const char *)n->name, true)) {
- fprintf(stderr, "Found an entry named '%s', skipping.\n",
- n->name);
- return 0;
- }
-
- name = sqfs_tree_node_get_path(n);
- if (name == NULL) {
- fprintf(stderr, "Constructing full path for '%s': %s\n",
- (const char *)n->name, strerror(errno));
- return -1;
- }
-
- ret = canonicalize_name(name);
- assert(ret == 0);
-
- if (!(flags & UNPACK_QUIET))
- printf("creating %s\n", name);
-
- ret = create_node(n, name);
- free(name);
- if (ret)
- return -1;
-
- if (S_ISDIR(n->inode->base.mode)) {
- for (c = n->children; c != NULL; c = c->next) {
- if (create_node_dfs(c, flags))
- return -1;
- }
- }
- return 0;
-}
-
-#ifdef HAVE_SYS_XATTR_H
-static int set_xattr(const char *path, sqfs_xattr_reader_t *xattr,
- const sqfs_tree_node_t *n)
-{
- sqfs_xattr_value_t *value;
- sqfs_xattr_entry_t *key;
- sqfs_xattr_id_t desc;
- sqfs_u32 index;
- size_t i;
- int ret;
-
- sqfs_inode_get_xattr_index(n->inode, &index);
-
- if (index == 0xFFFFFFFF)
- return 0;
-
- if (sqfs_xattr_reader_get_desc(xattr, index, &desc)) {
- fputs("Error resolving xattr index\n", stderr);
- return -1;
- }
-
- if (sqfs_xattr_reader_seek_kv(xattr, &desc)) {
- fputs("Error locating xattr key-value pairs\n", stderr);
- return -1;
- }
-
- for (i = 0; i < desc.count; ++i) {
- if (sqfs_xattr_reader_read_key(xattr, &key)) {
- fputs("Error reading xattr key\n", stderr);
- return -1;
- }
-
- if (sqfs_xattr_reader_read_value(xattr, key, &value)) {
- fputs("Error reading xattr value\n", stderr);
- free(key);
- return -1;
- }
-
- ret = lsetxattr(path, (const char *)key->key,
- value->value, value->size, 0);
- if (ret) {
- fprintf(stderr, "setting xattr '%s' on %s: %s\n",
- key->key, path, strerror(errno));
- }
-
- free(key);
- free(value);
- if (ret)
- return -1;
- }
-
- return 0;
-}
-#endif
-
-static int set_attribs(sqfs_xattr_reader_t *xattr,
- const sqfs_tree_node_t *n, int flags)
-{
- const sqfs_tree_node_t *c;
- char *path;
- int ret;
-
- if (!is_filename_sane((const char *)n->name, true))
- return 0;
-
- if (S_ISDIR(n->inode->base.mode)) {
- for (c = n->children; c != NULL; c = c->next) {
- if (set_attribs(xattr, c, flags))
- return -1;
- }
- }
-
- path = sqfs_tree_node_get_path(n);
- if (path == NULL) {
- fprintf(stderr, "Reconstructing full path: %s\n",
- strerror(errno));
- return -1;
- }
-
- ret = canonicalize_name(path);
- assert(ret == 0);
-
-#ifdef HAVE_SYS_XATTR_H
- if ((flags & UNPACK_SET_XATTR) && xattr != NULL) {
- if (set_xattr(path, xattr, n))
- goto fail;
- }
-#endif
-
-#ifndef _WIN32
- if (flags & UNPACK_SET_TIMES) {
- struct timespec times[2];
-
- memset(times, 0, sizeof(times));
- times[0].tv_sec = n->inode->base.mod_time;
- times[1].tv_sec = n->inode->base.mod_time;
-
- if (utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW)) {
- fprintf(stderr, "setting timestamp on %s: %s\n",
- path, strerror(errno));
- goto fail;
- }
- }
-#endif
- if (flags & UNPACK_CHOWN) {
- if (fchownat(AT_FDCWD, path, n->uid, n->gid,
- AT_SYMLINK_NOFOLLOW)) {
- fprintf(stderr, "chown %s: %s\n",
- path, strerror(errno));
- goto fail;
- }
- }
-
- if (flags & UNPACK_CHMOD && !S_ISLNK(n->inode->base.mode)) {
- if (fchmodat(AT_FDCWD, path,
- n->inode->base.mode & ~S_IFMT, 0)) {
- fprintf(stderr, "chmod %s: %s\n",
- path, strerror(errno));
- goto fail;
- }
- }
-
- free(path);
- return 0;
-fail:
- free(path);
- return -1;
-}
-
-int restore_fstree(sqfs_tree_node_t *root, int flags)
-{
- sqfs_tree_node_t *n, *old_parent;
-
- /* make sure fstree_get_path() stops at this node */
- old_parent = root->parent;
- root->parent = NULL;
-
- if (S_ISDIR(root->inode->base.mode)) {
- for (n = root->children; n != NULL; n = n->next) {
- if (create_node_dfs(n, flags))
- return -1;
- }
- } else {
- if (create_node_dfs(root, flags))
- return -1;
- }
-
- root->parent = old_parent;
- return 0;
-}
-
-int update_tree_attribs(sqfs_xattr_reader_t *xattr,
- const sqfs_tree_node_t *root, int flags)
-{
- const sqfs_tree_node_t *n;
-
- if ((flags & (UNPACK_CHOWN | UNPACK_CHMOD |
- UNPACK_SET_TIMES | UNPACK_SET_XATTR)) == 0) {
- return 0;
- }
-
- if (S_ISDIR(root->inode->base.mode)) {
- for (n = root->children; n != NULL; n = n->next) {
- if (set_attribs(xattr, n, flags))
- return -1;
- }
- } else {
- if (set_attribs(xattr, root, flags))
- return -1;
- }
-
- return 0;
-}