aboutsummaryrefslogtreecommitdiff
path: root/bin/rdsquashfs/src/fill_files.c
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-01-31 11:21:30 +0100
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-01-31 13:51:49 +0100
commitcdccc69c62579b0c13b35fad0728079652b8f3c9 (patch)
tree9fa54c710f73c5e08a9c8466e7a712eb63ee07ac /bin/rdsquashfs/src/fill_files.c
parent2182129c8f359c4fa1390eaba7a65b595ccd4182 (diff)
Move library source into src sub-directory
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'bin/rdsquashfs/src/fill_files.c')
-rw-r--r--bin/rdsquashfs/src/fill_files.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/bin/rdsquashfs/src/fill_files.c b/bin/rdsquashfs/src/fill_files.c
new file mode 100644
index 0000000..3104146
--- /dev/null
+++ b/bin/rdsquashfs/src/fill_files.c
@@ -0,0 +1,186 @@
+/* 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)
+{
+ struct file_ent *new;
+ size_t new_sz;
+ char *path;
+ int ret;
+
+ 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;
+ }
+
+ ret = sqfs_tree_node_get_path(node, &path);
+ if (ret != 0) {
+ sqfs_perror(NULL, "assembling file path", ret);
+ return -1;
+ }
+
+ if (canonicalize_name(path)) {
+ fprintf(stderr, "Invalid file path '%s'\n", path);
+ sqfs_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)
+ sqfs_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)
+{
+ int ret, openflags;
+ ostream_t *fp;
+ size_t i;
+
+ openflags = OSTREAM_OPEN_OVERWRITE;
+
+ if (flags & UNPACK_NO_SPARSE)
+ openflags |= OSTREAM_OPEN_SPARSE;
+
+ for (i = 0; i < num_files; ++i) {
+ fp = ostream_open_file(files[i].path, openflags);
+ if (fp == NULL)
+ return -1;
+
+ if (!(flags & UNPACK_QUIET))
+ printf("unpacking %s\n", files[i].path);
+
+ ret = sqfs_data_reader_dump(files[i].path, data, files[i].inode,
+ fp, block_size);
+ if (ret == 0)
+ ret = ostream_flush(fp);
+
+ sqfs_drop(fp);
+ if (ret)
+ return -1;
+ }
+
+ 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;
+}