summaryrefslogtreecommitdiff
path: root/unpack
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-05-03 23:33:41 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-05-03 23:33:41 +0200
commit6f7ee71165b30272a4f18bca361c324c7671680c (patch)
tree7f830e22992358f8a55082fad9e5890458af054a /unpack
parent9de5c93986bc6a4b33f3f50ed2a94c9aa3a33c7f (diff)
unsquashfs: add flags to filter what file types to unpack
This allows the user to skip stuff like device special files (which non-root can't create anyway) or to not create symlinks/fifos etc... Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'unpack')
-rw-r--r--unpack/read_fstree.c59
-rw-r--r--unpack/restore_fstree.c38
-rw-r--r--unpack/unsquashfs.c48
-rw-r--r--unpack/unsquashfs.h16
4 files changed, 140 insertions, 21 deletions
diff --git a/unpack/read_fstree.c b/unpack/read_fstree.c
index a6903b0..f200243 100644
--- a/unpack/read_fstree.c
+++ b/unpack/read_fstree.c
@@ -2,15 +2,36 @@
#include "unsquashfs.h"
+static int should_skip(int type, int flags)
+{
+ switch (type) {
+ case SQFS_INODE_BDEV:
+ case SQFS_INODE_CDEV:
+ case SQFS_INODE_EXT_CDEV:
+ case SQFS_INODE_EXT_BDEV:
+ return (flags & UNPACK_NO_DEVICES);
+ case SQFS_INODE_SLINK:
+ case SQFS_INODE_EXT_SLINK:
+ return (flags & UNPACK_NO_SLINKS);
+ case SQFS_INODE_SOCKET:
+ case SQFS_INODE_EXT_SOCKET:
+ return(flags & UNPACK_NO_SOCKETS);
+ case SQFS_INODE_FIFO:
+ case SQFS_INODE_EXT_FIFO:
+ return (flags & UNPACK_NO_FIFO);
+ }
+ return 0;
+}
+
static int fill_dir(meta_reader_t *ir, meta_reader_t *dr, tree_node_t *root,
- sqfs_super_t *super, id_table_t *idtbl)
+ sqfs_super_t *super, id_table_t *idtbl, int flags)
{
sqfs_inode_generic_t *inode;
sqfs_dir_header_t hdr;
sqfs_dir_entry_t *ent;
+ tree_node_t *n, *prev;
uint64_t block_start;
size_t size, diff;
- tree_node_t *n;
uint32_t i;
block_start = root->data.dir->start_block;
@@ -35,6 +56,11 @@ static int fill_dir(meta_reader_t *ir, meta_reader_t *dr, tree_node_t *root,
diff = sizeof(*ent) + strlen((char *)ent->name);
size -= diff > size ? size : diff;
+ if (should_skip(ent->type, flags)) {
+ free(ent);
+ continue;
+ }
+
inode = meta_reader_read_inode(ir, super,
hdr.start_block,
ent->offset);
@@ -58,17 +84,38 @@ static int fill_dir(meta_reader_t *ir, meta_reader_t *dr, tree_node_t *root,
}
}
- for (n = root->data.dir->children; n != NULL; n = n->next) {
+ n = root->data.dir->children;
+ prev = NULL;
+
+ while (n != NULL) {
if (S_ISDIR(n->mode)) {
- if (fill_dir(ir, dr, n, super, idtbl))
+ if (fill_dir(ir, dr, n, super, idtbl, flags))
return -1;
+
+ if (n->data.dir->children == NULL &&
+ (flags & UNPACK_NO_EMPTY)) {
+ if (prev == NULL) {
+ root->data.dir->children = n->next;
+ free(n);
+ n = root->data.dir->children;
+ } else {
+ prev->next = n->next;
+ free(n);
+ n = prev->next;
+ }
+ continue;
+ }
}
+
+ prev = n;
+ n = n->next;
}
return 0;
}
-int read_fstree(fstree_t *out, int fd, sqfs_super_t *super, compressor_t *cmp)
+int read_fstree(fstree_t *out, int fd, sqfs_super_t *super, compressor_t *cmp,
+ int flags)
{
sqfs_inode_generic_t *root;
meta_reader_t *ir, *dr;
@@ -119,7 +166,7 @@ int read_fstree(fstree_t *out, int fd, sqfs_super_t *super, compressor_t *cmp)
if (out->root == NULL)
goto out_id;
- if (fill_dir(ir, dr, out->root, super, &idtbl))
+ if (fill_dir(ir, dr, out->root, super, &idtbl, flags))
goto fail_fs;
fstree_sort(out);
diff --git a/unpack/restore_fstree.c b/unpack/restore_fstree.c
index 56c3cc5..8ef21c3 100644
--- a/unpack/restore_fstree.c
+++ b/unpack/restore_fstree.c
@@ -3,14 +3,14 @@
static int restore_directory(int dirfd, tree_node_t *n, compressor_t *cmp,
size_t block_size, frag_reader_t *frag,
- int sqfsfd)
+ 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, n->mode) &&
+ if (mkdirat(dirfd, n->name, 0755) &&
errno != EEXIST) {
fprintf(stderr, "mkdir %s: %s\n",
n->name, strerror(errno));
@@ -25,7 +25,7 @@ static int restore_directory(int dirfd, tree_node_t *n, compressor_t *cmp,
}
if (restore_directory(fd, n, cmp, block_size,
- frag, sqfsfd)) {
+ frag, sqfsfd, flags)) {
close(fd);
return -1;
}
@@ -42,7 +42,8 @@ static int restore_directory(int dirfd, tree_node_t *n, compressor_t *cmp,
break;
case S_IFSOCK:
case S_IFIFO:
- if (mknodat(dirfd, n->name, n->mode, 0)) {
+ if (mknodat(dirfd, n->name,
+ (n->mode & S_IFMT) | 0700, 0)) {
fprintf(stderr, "creating %s: %s\n",
n->name, strerror(errno));
return -1;
@@ -50,7 +51,8 @@ static int restore_directory(int dirfd, tree_node_t *n, compressor_t *cmp,
break;
case S_IFBLK:
case S_IFCHR:
- if (mknodat(dirfd, n->name, n->mode, n->data.devno)) {
+ 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;
@@ -58,7 +60,7 @@ static int restore_directory(int dirfd, tree_node_t *n, compressor_t *cmp,
break;
case S_IFREG:
fd = openat(dirfd, n->name,
- O_WRONLY | O_CREAT | O_EXCL, n->mode);
+ O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) {
fprintf(stderr, "creating %s: %s\n",
n->name, strerror(errno));
@@ -76,13 +78,32 @@ static int restore_directory(int dirfd, tree_node_t *n, compressor_t *cmp,
default:
break;
}
+
+ 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;
}
int restore_fstree(const char *rootdir, tree_node_t *root, compressor_t *cmp,
- size_t block_size, frag_reader_t *frag, int sqfsfd)
+ size_t block_size, frag_reader_t *frag, int sqfsfd,
+ int flags)
{
int dirfd;
@@ -95,7 +116,8 @@ 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)) {
+ if (restore_directory(dirfd, root, cmp, block_size, frag,
+ sqfsfd, flags)) {
close(dirfd);
return -1;
}
diff --git a/unpack/unsquashfs.c b/unpack/unsquashfs.c
index 178def4..8ec1b94 100644
--- a/unpack/unsquashfs.c
+++ b/unpack/unsquashfs.c
@@ -12,11 +12,18 @@ static struct option long_opts[] = {
{ "list", required_argument, NULL, 'l' },
{ "cat", required_argument, NULL, 'c' },
{ "unpack-root", 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' },
+ { "chmod", no_argument, NULL, 'C' },
+ { "chown", no_argument, NULL, 'O' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
};
-static const char *short_opts = "l:c:u:hV";
+static const char *short_opts = "l:c:u:DSFLCOEhV";
static const char *help_string =
"Usage: %s [OPTIONS] <squashfs-file>\n"
@@ -29,7 +36,17 @@ static const char *help_string =
" --cat, -c <path> If the specified path is a regular file in the,\n"
" image, dump its contents to stdout.\n"
" --unpack-root <path> Unpack the contents of the filesystem into the\n"
-" specified path\n"
+" specified path.\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 empty.\n"
+" --chmod, -C Change permission flags of unpacked files to those\n"
+" store in the squashfs image.\n"
+" --chown, -O Change ownership of unpacked files to the UID/GID\n"
+" set in the squashfs iamge.\n"
+"\n"
" --help, -h Print help text and exit.\n"
" --version, -V Print version information and exit.\n"
"\n";
@@ -92,7 +109,7 @@ static char *get_path(char *old, const char *arg)
int main(int argc, char **argv)
{
- int i, fd, status = EXIT_FAILURE, op = OP_NONE;
+ int i, fd, status = EXIT_FAILURE, op = OP_NONE, unpack_flags = 0;
const char *unpack_root = NULL;
frag_reader_t *frag = NULL;
char *cmdpath = NULL;
@@ -107,6 +124,27 @@ int main(int argc, char **argv)
break;
switch (i) {
+ case 'D':
+ unpack_flags |= UNPACK_NO_DEVICES;
+ break;
+ case 'S':
+ unpack_flags |= UNPACK_NO_SOCKETS;
+ break;
+ case 'F':
+ unpack_flags |= UNPACK_NO_FIFO;
+ break;
+ case 'L':
+ unpack_flags |= UNPACK_NO_SLINKS;
+ break;
+ case 'C':
+ unpack_flags |= UNPACK_CHMOD;
+ break;
+ case 'O':
+ unpack_flags |= UNPACK_CHOWN;
+ break;
+ case 'E':
+ unpack_flags |= UNPACK_NO_EMPTY;
+ break;
case 'c':
op = OP_CAT;
cmdpath = get_path(cmdpath, optarg);
@@ -178,7 +216,7 @@ int main(int argc, char **argv)
if (cmp == NULL)
goto out_fd;
- if (read_fstree(&fs, fd, &super, cmp))
+ if (read_fstree(&fs, fd, &super, cmp, unpack_flags))
goto out_cmp;
switch (op) {
@@ -226,7 +264,7 @@ int main(int argc, char **argv)
}
if (restore_fstree(unpack_root, fs.root, cmp, super.block_size,
- frag, fd)) {
+ frag, fd, unpack_flags)) {
goto out_fs;
}
break;
diff --git a/unpack/unsquashfs.h b/unpack/unsquashfs.h
index 5895fb8..a8784fc 100644
--- a/unpack/unsquashfs.h
+++ b/unpack/unsquashfs.h
@@ -19,12 +19,23 @@
#include <fcntl.h>
#include <stdio.h>
+enum UNPACK_FLAGS {
+ UNPACK_NO_DEVICES = 0x01,
+ UNPACK_NO_SOCKETS = 0x02,
+ UNPACK_NO_FIFO = 0x04,
+ UNPACK_NO_SLINKS = 0x08,
+ UNPACK_NO_EMPTY = 0x10,
+ UNPACK_CHMOD = 0x20,
+ UNPACK_CHOWN = 0x40,
+};
+
tree_node_t *tree_node_from_inode(sqfs_inode_generic_t *inode,
const id_table_t *idtbl,
const char *name,
size_t block_size);
-int read_fstree(fstree_t *out, int fd, sqfs_super_t *super, compressor_t *cmp);
+int read_fstree(fstree_t *out, int fd, sqfs_super_t *super, compressor_t *cmp,
+ int flags);
void list_files(tree_node_t *node);
@@ -32,6 +43,7 @@ int extract_file(file_info_t *fi, compressor_t *cmp, size_t block_size,
frag_reader_t *frag, int sqfsfd, int outfd);
int restore_fstree(const char *rootdir, tree_node_t *root, compressor_t *cmp,
- size_t block_size, frag_reader_t *frag, int sqfsfd);
+ size_t block_size, frag_reader_t *frag, int sqfsfd,
+ int flags);
#endif /* UNSQUASHFS_H */