aboutsummaryrefslogtreecommitdiff
path: root/extras/extract_one.c
diff options
context:
space:
mode:
Diffstat (limited to 'extras/extract_one.c')
-rw-r--r--extras/extract_one.c145
1 files changed, 76 insertions, 69 deletions
diff --git a/extras/extract_one.c b/extras/extract_one.c
index d0fe1b9..d0dbafd 100644
--- a/extras/extract_one.c
+++ b/extras/extract_one.c
@@ -8,35 +8,82 @@
#include "sqfs/compressor.h"
#include "sqfs/data_reader.h"
#include "sqfs/dir_reader.h"
+#include "sqfs/dir_entry.h"
#include "sqfs/error.h"
#include "sqfs/id_table.h"
#include "sqfs/io.h"
#include "sqfs/inode.h"
#include "sqfs/super.h"
-#include "sqfs/xattr_reader.h"
#include <string.h>
#include <stdlib.h>
-#include <errno.h>
#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
+
+static int find_file(sqfs_dir_iterator_t *it, const char *path,
+ sqfs_istream_t **out)
+{
+ const char *end = strchr(path, '/');
+ size_t len = end == NULL ? strlen(path) : (size_t)(end - path);
+
+ for (;;) {
+ sqfs_dir_entry_t *ent;
+ int ret;
+
+ ret = it->next(it, &ent);
+ if (ret < 0) {
+ fputs("error reading directory entry\n", stderr);
+ return -1;
+ }
+
+ if (ret > 0) {
+ fputs("entry not found\n", stderr);
+ return -1;
+ }
+
+ if (strncmp(ent->name, path, len) != 0 ||
+ ent->name[len] != '\0') {
+ free(ent);
+ continue;
+ }
+
+ if (end == NULL) {
+ ret = it->open_file_ro(it, out);
+ if (ret) {
+ fprintf(stderr, "%s: error opening file %d\n",
+ ent->name, ret);
+ }
+ } else {
+ sqfs_dir_iterator_t *sub;
+
+ ret = it->open_subdir(it, &sub);
+ if (ret != 0) {
+ fprintf(stderr, "%s: error opening subdir\n",
+ ent->name);
+ } else {
+ ret = find_file(sub, end + 1, out);
+ sqfs_drop(sub);
+ }
+ }
+
+ free(ent);
+ return ret;
+ }
+}
int main(int argc, char **argv)
{
- sqfs_xattr_reader_t *xattr = NULL;
+ sqfs_inode_generic_t *iroot = NULL;
sqfs_data_reader_t *data = NULL;
sqfs_dir_reader_t *dirrd = NULL;
sqfs_compressor_t *cmp = NULL;
sqfs_id_table_t *idtbl = NULL;
- sqfs_tree_node_t *n = NULL;
sqfs_file_t *file = NULL;
- sqfs_u8 *p, *output = NULL;
+ sqfs_dir_iterator_t *it = NULL;
sqfs_compressor_config_t cfg;
sqfs_super_t super;
- sqfs_u64 file_size;
int status = EXIT_FAILURE, ret;
+ sqfs_istream_t *is = NULL;
+ char buffer[512];
if (argc != 3) {
fputs("Usage: extract_one <squashfs-file> <source-file-path>\n", stderr);
@@ -56,8 +103,8 @@ int main(int argc, char **argv)
}
sqfs_compressor_config_init(&cfg, super.compression_id,
- super.block_size,
- SQFS_COMP_FLAG_UNCOMPRESS);
+ super.block_size,
+ SQFS_COMP_FLAG_UNCOMPRESS);
ret = sqfs_compressor_create(&cfg, &cmp);
if (ret != 0) {
@@ -65,20 +112,6 @@ int main(int argc, char **argv)
goto out;
}
- if (!(super.flags & SQFS_FLAG_NO_XATTRS)) {
- xattr = sqfs_xattr_reader_create(0);
- if (xattr == NULL) {
- fprintf(stderr, "%s: error creating xattr reader: %d.\n", argv[1], SQFS_ERROR_ALLOC);
- goto out;
- }
-
- ret = sqfs_xattr_reader_load(xattr, &super, file, cmp);
- if (ret) {
- fprintf(stderr, "%s: error loading xattr reader: %d.\n", argv[1], ret);
- goto out;
- }
- }
-
idtbl = sqfs_id_table_create(0);
if (idtbl == NULL) {
fprintf(stderr, "%s: error creating ID table: %d.\n", argv[1], ret);
@@ -109,69 +142,43 @@ int main(int argc, char **argv)
goto out;
}
- ret = sqfs_dir_reader_get_full_hierarchy(dirrd, idtbl, argv[2], 0, &n);
- if (ret) {
- fprintf(stderr, "%s: error reading filesystem hierarchy: %d.\n", argv[1], ret);
+ if (sqfs_dir_reader_get_root_inode(dirrd, &iroot)) {
+ fprintf(stderr, "%s: error reading root inode.\n", argv[1]);
goto out;
}
- if (!S_ISREG(n->inode->base.mode)) {
- fprintf(stderr, "/%s is not a file\n", argv[2]);
- goto out;
- }
-
- sqfs_inode_get_file_size(n->inode, &file_size);
+ ret = sqfs_dir_iterator_create(dirrd, idtbl, data, NULL, iroot, &it);
+ free(iroot);
- output = p = malloc(file_size);
- if (output == NULL) {
- fprintf(stderr, "malloc failed: %d\n", errno);
+ if (ret) {
+ fprintf(stderr, "%s: error creating root iterator.\n",
+ argv[2]);
goto out;
}
- for (size_t i = 0; i < sqfs_inode_get_file_block_count(n->inode); ++i) {
- size_t chunk_size, read = (file_size < super.block_size) ? file_size : super.block_size;
- sqfs_u8 *chunk;
-
- ret = sqfs_data_reader_get_block(data, n->inode, i, &chunk_size, &chunk);
- if (ret) {
- fprintf(stderr, "reading data block: %d\n", ret);
- goto out;
- }
-
- memcpy(p, chunk, chunk_size);
- p += chunk_size;
- free(chunk);
-
- file_size -= read;
- }
-
- if (file_size > 0) {
- size_t chunk_size;
- sqfs_u8 *chunk;
+ if (find_file(it, argv[2], &is))
+ goto out;
- ret = sqfs_data_reader_get_fragment(data, n->inode, &chunk_size, &chunk);
- if (ret) {
- fprintf(stderr, "reading fragment block: %d\n", ret);
+ for (;;) {
+ ret = sqfs_istream_read(is, buffer, sizeof(buffer));
+ if (ret < 0) {
+ fprintf(stderr, "%s: read error!\n", argv[2]);
goto out;
}
+ if (ret == 0)
+ break;
- memcpy(p, chunk, chunk_size);
- free(chunk);
+ fwrite(buffer, 1, ret, stdout);
}
- /* for example simplicity, assume this is a text file */
- fprintf(stdout, "%s\n", (char *)output);
-
status = EXIT_SUCCESS;
out:
- sqfs_dir_tree_destroy(n);
+ sqfs_drop(is);
+ sqfs_drop(it);
sqfs_drop(data);
sqfs_drop(dirrd);
sqfs_drop(idtbl);
- sqfs_drop(xattr);
sqfs_drop(cmp);
sqfs_drop(file);
- free(output);
-
return status;
}