summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--unpack/rdsquashfs.c20
-rw-r--r--unpack/restore_fstree.c171
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] <squashfs-file>\n"
@@ -37,6 +38,8 @@ static const char *help_string =
" image, dump its contents to stdout.\n"
" --unpack-root <path> Unpack the contents of the filesystem into the\n"
" specified path.\n"
+" --unpack-path <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;
}