From abb31e7327e50cf2874ae9095eb147ed753862a3 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sat, 4 May 2019 22:22:12 +0200 Subject: rdsquashfs: add ability to unpack only a sub tree of the file system Signed-off-by: David Oberhollenzer --- unpack/rdsquashfs.c | 20 +++++- unpack/restore_fstree.c | 171 +++++++++++++++++++++++++----------------------- 2 files changed, 107 insertions(+), 84 deletions(-) diff --git a/unpack/rdsquashfs.c b/unpack/rdsquashfs.c index ec14e0e..4b3a573 100644 --- a/unpack/rdsquashfs.c +++ b/unpack/rdsquashfs.c @@ -12,6 +12,7 @@ static struct option long_opts[] = { { "list", required_argument, NULL, 'l' }, { "cat", required_argument, NULL, 'c' }, { "unpack-root", required_argument, NULL, 'u' }, + { "unpack-path", required_argument, NULL, 'p' }, { "no-dev", no_argument, NULL, 'D' }, { "no-sock", no_argument, NULL, 'S' }, { "no-fifo", no_argument, NULL, 'F' }, @@ -23,7 +24,7 @@ static struct option long_opts[] = { { "version", no_argument, NULL, 'V' }, }; -static const char *short_opts = "l:c:u:DSFLCOEhV"; +static const char *short_opts = "l:c:u:p:DSFLCOEhV"; static const char *help_string = "Usage: %s [OPTIONS] \n" @@ -37,6 +38,8 @@ static const char *help_string = " image, dump its contents to stdout.\n" " --unpack-root Unpack the contents of the filesystem into the\n" " specified path.\n" +" --unpack-path If specified, unpack this sub directory from the\n" +" image instead of the filesystem root.\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" @@ -157,6 +160,9 @@ int main(int argc, char **argv) op = OP_UNPACK; unpack_root = optarg; break; + case 'p': + cmdpath = get_path(cmdpath, optarg); + break; case 'h': printf(help_string, __progname); status = EXIT_SUCCESS; @@ -255,6 +261,16 @@ int main(int argc, char **argv) } break; case OP_UNPACK: + if (cmdpath == NULL) { + n = fs.root; + } else { + n = find_node(fs.root, cmdpath); + if (n == NULL) { + perror(cmdpath); + goto out_fs; + } + } + if (super.fragment_entry_count > 0 && super.fragment_table_start < super.bytes_used && !(super.flags & SQFS_FLAG_NO_FRAGMENTS)) { @@ -263,7 +279,7 @@ int main(int argc, char **argv) goto out_fs; } - if (restore_fstree(unpack_root, fs.root, cmp, super.block_size, + if (restore_fstree(unpack_root, n, cmp, super.block_size, frag, fd, unpack_flags)) { goto out_fs; } diff --git a/unpack/restore_fstree.c b/unpack/restore_fstree.c index 5a20c5f..270b25a 100644 --- a/unpack/restore_fstree.c +++ b/unpack/restore_fstree.c @@ -1,103 +1,99 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */ #include "rdsquashfs.h" -static int restore_directory(int dirfd, tree_node_t *n, compressor_t *cmp, - size_t block_size, frag_reader_t *frag, - int sqfsfd, int flags) +static int create_node(int dirfd, tree_node_t *n, compressor_t *cmp, + size_t block_size, frag_reader_t *frag, + int sqfsfd, int flags) { int fd; - for (n = n->data.dir->children; n != NULL; n = n->next) { - switch (n->mode & S_IFMT) { - case S_IFDIR: - if (mkdirat(dirfd, n->name, 0755) && - errno != EEXIST) { - fprintf(stderr, "mkdir %s: %s\n", - n->name, strerror(errno)); - return -1; - } + switch (n->mode & S_IFMT) { + case S_IFDIR: + if (mkdirat(dirfd, n->name, 0755) && errno != EEXIST) { + fprintf(stderr, "mkdir %s: %s\n", + n->name, strerror(errno)); + return -1; + } - fd = openat(dirfd, n->name, O_RDONLY | O_DIRECTORY); - if (fd < 0) { - fprintf(stderr, "open dir %s: %s\n", - n->name, strerror(errno)); - return -1; - } + fd = openat(dirfd, n->name, O_RDONLY | O_DIRECTORY); + if (fd < 0) { + fprintf(stderr, "open dir %s: %s\n", + n->name, strerror(errno)); + return -1; + } - if (restore_directory(fd, n, cmp, block_size, - frag, sqfsfd, flags)) { + for (n = n->data.dir->children; n != NULL; n = n->next) { + if (create_node(fd, n, cmp, block_size, frag, sqfsfd, + flags)) { close(fd); return -1; } + } - close(fd); - break; - case S_IFLNK: - if (symlinkat(n->data.slink_target, dirfd, n->name)) { - fprintf(stderr, "ln -s %s %s: %s\n", - n->data.slink_target, n->name, - strerror(errno)); - return -1; - } - break; - case S_IFSOCK: - case S_IFIFO: - if (mknodat(dirfd, n->name, - (n->mode & S_IFMT) | 0700, 0)) { - fprintf(stderr, "creating %s: %s\n", - n->name, strerror(errno)); - return -1; - } - break; - case S_IFBLK: - case S_IFCHR: - if (mknodat(dirfd, n->name, (n->mode & S_IFMT), - n->data.devno)) { - fprintf(stderr, "creating device %s: %s\n", - n->name, strerror(errno)); - return -1; - } - break; - case S_IFREG: - fd = openat(dirfd, n->name, - O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) { - fprintf(stderr, "creating %s: %s\n", - n->name, strerror(errno)); - return -1; - } - - if (extract_file(n->data.file, cmp, block_size, - frag, sqfsfd, fd)) { - close(fd); - return -1; - } + close(fd); + break; + case S_IFLNK: + if (symlinkat(n->data.slink_target, dirfd, n->name)) { + fprintf(stderr, "ln -s %s %s: %s\n", + n->data.slink_target, n->name, + strerror(errno)); + return -1; + } + break; + case S_IFSOCK: + case S_IFIFO: + if (mknodat(dirfd, n->name, (n->mode & S_IFMT) | 0700, 0)) { + fprintf(stderr, "creating %s: %s\n", + n->name, strerror(errno)); + return -1; + } + break; + case S_IFBLK: + case S_IFCHR: + if (mknodat(dirfd, n->name, (n->mode & S_IFMT), + n->data.devno)) { + fprintf(stderr, "creating device %s: %s\n", + n->name, strerror(errno)); + return -1; + } + break; + case S_IFREG: + fd = openat(dirfd, n->name, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) { + fprintf(stderr, "creating %s: %s\n", + n->name, strerror(errno)); + return -1; + } + if (extract_file(n->data.file, cmp, block_size, + frag, sqfsfd, fd)) { close(fd); - break; - default: - break; + return -1; } - if (flags & UNPACK_CHOWN) { - if (fchownat(dirfd, n->name, n->uid, n->gid, - AT_SYMLINK_NOFOLLOW)) { - fprintf(stderr, "chown %s: %s\n", - n->name, strerror(errno)); - return -1; - } - } + close(fd); + break; + default: + break; + } - if (flags & UNPACK_CHMOD) { - if (fchmodat(dirfd, n->name, n->mode, - AT_SYMLINK_NOFOLLOW)) { - fprintf(stderr, "chmod %s: %s\n", - n->name, strerror(errno)); - return -1; - } + if (flags & UNPACK_CHOWN) { + if (fchownat(dirfd, n->name, n->uid, n->gid, + AT_SYMLINK_NOFOLLOW)) { + fprintf(stderr, "chown %s: %s\n", + n->name, strerror(errno)); + return -1; } } + if (flags & UNPACK_CHMOD) { + if (fchmodat(dirfd, n->name, n->mode, + AT_SYMLINK_NOFOLLOW)) { + fprintf(stderr, "chmod %s: %s\n", + n->name, strerror(errno)); + return -1; + } + } return 0; } @@ -105,6 +101,7 @@ int restore_fstree(const char *rootdir, tree_node_t *root, compressor_t *cmp, size_t block_size, frag_reader_t *frag, int sqfsfd, int flags) { + tree_node_t *n; int dirfd; if (mkdir_p(rootdir)) @@ -116,8 +113,18 @@ int restore_fstree(const char *rootdir, tree_node_t *root, compressor_t *cmp, return -1; } - if (restore_directory(dirfd, root, cmp, block_size, frag, - sqfsfd, flags)) { + if (S_ISDIR(root->mode)) { + for (n = root->data.dir->children; n != NULL; n = n->next) { + if (create_node(dirfd, n, cmp, block_size, frag, + sqfsfd, flags)) { + close(dirfd); + return -1; + } + } + return 0; + } + + if (create_node(dirfd, root, cmp, block_size, frag, sqfsfd, flags)) { close(dirfd); return -1; } -- cgit v1.2.3