aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--COPYING.md5
-rw-r--r--extras/Makemodule.am5
-rw-r--r--extras/extract_one.c177
-rw-r--r--licenses/0BSD.txt10
5 files changed, 196 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 05afa84..df055d5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,6 +44,7 @@ Doxyfile
tests/*.sh
/mknastyfs
/mk42sqfs
+/extract_one
/list_files
/sqfsbrowse
/xattr_benchmark
diff --git a/COPYING.md b/COPYING.md
index 19f8c5d..d4e73b0 100644
--- a/COPYING.md
+++ b/COPYING.md
@@ -44,7 +44,7 @@ Although the existing squashfs-tools and the Linux kernel implementation have
been used for testing, the source code in this package is neither based on,
nor derived from either of them.
-## Documentation and the Build System
+## Documentation, examples and the Build System
The auto-tools based build system has in large parts been hacked together by
copy & pasting from various tutorials and other projects (mostly util-linux,
@@ -61,6 +61,9 @@ If you use those as a basis for writing about SquashFS or this package, please
cite your sources and mark verbatim quotations as such. I won't be angry if you
don't, but a thesis supervisor, reviewer or fellow Wikipedian might be.
+The `extras/extract_one.c` example file is licensed under the **0BSD license**,
+a copy of which can be found in `licenses/0BSD.txt`
+
# Binary Packages with 3rd Party Libraries
If this file is included in a binary release package, additional 3rd party
diff --git a/extras/Makemodule.am b/extras/Makemodule.am
index d3b80f2..9ebe037 100644
--- a/extras/Makemodule.am
+++ b/extras/Makemodule.am
@@ -7,6 +7,9 @@ mk42sqfs_LDADD = libsquashfs.la
list_files_SOURCES = extras/list_files.c
list_files_LDADD = libsquashfs.la
+extract_one_SOURCES = extras/extract_one.c
+extract_one_LDADD = libsquashfs.la
+
if WITH_READLINE
sqfsbrowse_SOURCES = extras/browse.c
sqfsbrowse_CFLAGS = $(AM_CFLAGS) $(READLINE_CFLAGS)
@@ -15,4 +18,4 @@ sqfsbrowse_LDADD = libsquashfs.la $(READLINE_LIBS)
noinst_PROGRAMS += sqfsbrowse
endif
-noinst_PROGRAMS += mknastyfs mk42sqfs list_files
+noinst_PROGRAMS += mknastyfs mk42sqfs list_files extract_one
diff --git a/extras/extract_one.c b/extras/extract_one.c
new file mode 100644
index 0000000..fcd8124
--- /dev/null
+++ b/extras/extract_one.c
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: 0BSD */
+/*
+ * extract_one.c
+ *
+ * Copyright (C) 2021 Luca Boccassi <luca.boccassi@microsoft.com>
+ */
+
+#include "sqfs/compressor.h"
+#include "sqfs/data_reader.h"
+#include "sqfs/dir_reader.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>
+
+int main(int argc, char **argv)
+{
+ sqfs_xattr_reader_t *xattr = 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_compressor_config_t cfg;
+ sqfs_super_t super;
+ sqfs_u64 file_size;
+ int status = EXIT_FAILURE, ret;
+
+ if (argc != 3) {
+ fputs("Usage: extract_one <squashfs-file> <source-file-path>\n", stderr);
+ return EXIT_FAILURE;
+ }
+
+ file = sqfs_open_file(argv[1], SQFS_FILE_OPEN_READ_ONLY);
+ if (file == NULL) {
+ perror(argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ ret = sqfs_super_read(&super, file);
+ if (ret) {
+ fprintf(stderr, "%s: error reading super block.\n", argv[1]);
+ goto out;
+ }
+
+ sqfs_compressor_config_init(&cfg, super.compression_id,
+ super.block_size,
+ SQFS_COMP_FLAG_UNCOMPRESS);
+
+ ret = sqfs_compressor_create(&cfg, &cmp);
+ if (ret != 0) {
+ fprintf(stderr, "%s: error creating compressor: %d.\n", argv[1], ret);
+ 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);
+ goto out;
+ }
+
+ ret = sqfs_id_table_read(idtbl, file, &super, cmp);
+ if (ret) {
+ fprintf(stderr, "%s: error loading ID table: %d.\n", argv[1], ret);
+ goto out;
+ }
+
+ dirrd = sqfs_dir_reader_create(&super, cmp, file, 0);
+ if (dirrd == NULL) {
+ fprintf(stderr, "%s: error creating dir reader: %d.\n", argv[1], SQFS_ERROR_ALLOC);
+ goto out;
+ }
+
+ data = sqfs_data_reader_create(file, super.block_size, cmp, 0);
+ if (data == NULL) {
+ fprintf(stderr, "%s: error creating data reader: %d.\n", argv[1], SQFS_ERROR_ALLOC);
+ goto out;
+ }
+
+ ret = sqfs_data_reader_load_fragment_table(data, &super);
+ if (ret) {
+ fprintf(stderr, "%s: error loading fragment table: %d.\n", argv[1], ret);
+ 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);
+ 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);
+
+ output = p = malloc(file_size);
+ if (output == NULL) {
+ fprintf(stderr, "malloc failed: %d\n", errno);
+ 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;
+
+ ret = sqfs_data_reader_get_fragment(data, n->inode, &chunk_size, &chunk);
+ if (ret) {
+ fprintf(stderr, "reading fragment block: %d\n", ret);
+ goto out;
+ }
+
+ memcpy(p, chunk, chunk_size);
+ free(chunk);
+ }
+
+ /* 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_destroy(data);
+ sqfs_destroy(dirrd);
+ sqfs_destroy(idtbl);
+ sqfs_destroy(xattr);
+ sqfs_destroy(cmp);
+ sqfs_destroy(file);
+ free(output);
+
+ return status;
+}
diff --git a/licenses/0BSD.txt b/licenses/0BSD.txt
new file mode 100644
index 0000000..ac85e0e
--- /dev/null
+++ b/licenses/0BSD.txt
@@ -0,0 +1,10 @@
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.