aboutsummaryrefslogtreecommitdiff
path: root/include/sqfs
diff options
context:
space:
mode:
Diffstat (limited to 'include/sqfs')
-rw-r--r--include/sqfs/block_processor.h111
-rw-r--r--include/sqfs/compress.h71
-rw-r--r--include/sqfs/id_table.h48
-rw-r--r--include/sqfs/meta_reader.h52
-rw-r--r--include/sqfs/meta_writer.h87
-rw-r--r--include/sqfs/squashfs.h272
6 files changed, 641 insertions, 0 deletions
diff --git a/include/sqfs/block_processor.h b/include/sqfs/block_processor.h
new file mode 100644
index 0000000..18d8c4a
--- /dev/null
+++ b/include/sqfs/block_processor.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * block_processor.h
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#ifndef BLOCK_PROCESSOR_H
+#define BLOCK_PROCESSOR_H
+
+#include "config.h"
+#include "sqfs/compress.h"
+
+enum {
+ /* only calculate checksum, do NOT compress the data */
+ BLK_DONT_COMPRESS = 0x0001,
+
+ /* set by compressor worker if the block was actually compressed */
+ BLK_IS_COMPRESSED = 0x0002,
+
+ /* do not calculate block checksum */
+ BLK_DONT_CHECKSUM = 0x0004,
+
+ /* set by compressor worker if compression failed */
+ BLK_COMPRESS_ERROR = 0x0008,
+
+ /* first user setable block flag */
+ BLK_USER = 0x0080
+};
+
+typedef struct block_t {
+ /* used internally, ignored and overwritten when enqueueing blocks */
+ struct block_t *next;
+ uint32_t sequence_number;
+
+ /* Size of the data area */
+ uint32_t size;
+
+ /* checksum of the input data */
+ uint32_t checksum;
+
+ /* user settable file block index */
+ uint32_t index;
+
+ /* user pointer associated with the block */
+ void *user;
+
+ /* user settable flag field */
+ uint32_t flags;
+
+ /* raw data to be processed */
+ uint8_t data[];
+} block_t;
+
+typedef struct block_processor_t block_processor_t;
+
+/*
+ Gets called for each processed block. May be called from a different thread
+ than the one that calls enqueue, but only from one thread at a time.
+ Guaranteed to be called on blocks in the order that they are submitted
+ to enqueue.
+
+ A non-zero return value is interpreted as fatal error.
+ */
+typedef int (*block_cb)(void *user, block_t *blk);
+
+block_processor_t *block_processor_create(size_t max_block_size,
+ compressor_t *cmp,
+ unsigned int num_workers,
+ void *user,
+ block_cb callback);
+
+void block_processor_destroy(block_processor_t *proc);
+
+/*
+ Add a block to be processed. Returns non-zero on error and prints a message
+ to stderr.
+
+ The function takes over ownership of the submitted block. It is freed with
+ a after processing and calling the block callback.
+
+ Even on failure, the workers may still be running and
+ block_processor_finish must be called before cleaning up.
+*/
+int block_processor_enqueue(block_processor_t *proc, block_t *block);
+
+/*
+ Wait for the compressor workers to finish. Returns zero on success, non-zero
+ if an internal error occoured or one of the block callbacks returned a
+ non-zero value.
+ */
+int block_processor_finish(block_processor_t *proc);
+
+/*
+ Convenience function to create a block structure and optionally fill it with
+ content.
+
+ filename is used for printing error messages. If fd is a valid file
+ descriptor (>= 0), the function attempts to populate the payload data
+ from the input file.
+ */
+block_t *create_block(const char *filename, int fd, size_t size,
+ void *user, uint32_t flags);
+
+/*
+ Convenience function to process a data block. Returns 0 on success,
+ prints to stderr on failure.
+ */
+int process_block(block_t *block, compressor_t *cmp,
+ uint8_t *scratch, size_t scratch_size);
+
+#endif /* BLOCK_PROCESSOR_H */
diff --git a/include/sqfs/compress.h b/include/sqfs/compress.h
new file mode 100644
index 0000000..1dfba12
--- /dev/null
+++ b/include/sqfs/compress.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * compress.h
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#ifndef COMPRESS_H
+#define COMPRESS_H
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "squashfs.h"
+
+typedef struct compressor_t compressor_t;
+
+/* Encapsultes a compressor with a simple interface to compress or
+ uncompress/extract blocks of data. */
+struct compressor_t {
+ /* Write compressor options to the output file if necessary.
+ Returns the number of bytes written or -1 on failure.
+ Internally prints error messages to stderr. */
+ int (*write_options)(compressor_t *cmp, int fd);
+
+ /* Read compressor options to the input file.
+ Returns zero on success, -1 on failure.
+ Internally prints error messages to stderr. */
+ int (*read_options)(compressor_t *cmp, int fd);
+
+ /*
+ Compress or uncompress a chunk of data.
+
+ Returns the number of bytes written to the output buffer, -1 on
+ failure or 0 if the output buffer was too small.
+ The compressor also returns 0 if the compressed result ends
+ up larger than the original input.
+
+ Internally prints compressor specific error messages to stderr.
+ */
+ ssize_t (*do_block)(compressor_t *cmp, const uint8_t *in, size_t size,
+ uint8_t *out, size_t outsize);
+
+ /* create another compressor just like this one, i.e.
+ with the exact same settings */
+ compressor_t *(*create_copy)(compressor_t *cmp);
+
+ void (*destroy)(compressor_t *stream);
+};
+
+bool compressor_exists(E_SQFS_COMPRESSOR id);
+
+/* block_size is the configured block size for the SquashFS image. Needed
+ by some compressors to set internal defaults. */
+compressor_t *compressor_create(E_SQFS_COMPRESSOR id, bool compress,
+ size_t block_size, char *options);
+
+void compressor_print_help(E_SQFS_COMPRESSOR id);
+
+void compressor_print_available(void);
+
+E_SQFS_COMPRESSOR compressor_get_default(void);
+
+const char *compressor_name_from_id(E_SQFS_COMPRESSOR id);
+
+int compressor_id_from_name(const char *name, E_SQFS_COMPRESSOR *out);
+
+#endif /* COMPRESS_H */
diff --git a/include/sqfs/id_table.h b/include/sqfs/id_table.h
new file mode 100644
index 0000000..dcc8a18
--- /dev/null
+++ b/include/sqfs/id_table.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * id_table.h
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#ifndef ID_TABLE_H
+#define ID_TABLE_H
+
+#include "config.h"
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "compress.h"
+
+/* Encapsulates the ID table used by SquashFS */
+typedef struct {
+ /* Array of unique 32 bit IDs */
+ uint32_t *ids;
+
+ /* Number of 32 bit IDs stored in the array */
+ size_t num_ids;
+
+ /* Actual size of the array, i.e. maximum available */
+ size_t max_ids;
+} id_table_t;
+
+/* Returns 0 on success. Prints error message to stderr on failure. */
+int id_table_init(id_table_t *tbl);
+
+void id_table_cleanup(id_table_t *tbl);
+
+/* Resolve a 32 bit to a 16 bit table index.
+ Returns 0 on success. Internally prints errors to stderr. */
+int id_table_id_to_index(id_table_t *tbl, uint32_t id, uint16_t *out);
+
+/* Write an ID table to a SquashFS image.
+ Returns 0 on success. Internally prints error message to stderr. */
+int id_table_write(id_table_t *tbl, int outfd, sqfs_super_t *super,
+ compressor_t *cmp);
+
+/* Read an ID table from a SquashFS image.
+ Returns 0 on success. Internally prints error messages to stderr. */
+int id_table_read(id_table_t *tbl, int fd, sqfs_super_t *super,
+ compressor_t *cmp);
+
+#endif /* ID_TABLE_H */
diff --git a/include/sqfs/meta_reader.h b/include/sqfs/meta_reader.h
new file mode 100644
index 0000000..d5628af
--- /dev/null
+++ b/include/sqfs/meta_reader.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * meta_reader.h
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#ifndef META_READER_H
+#define META_READER_H
+
+#include "config.h"
+
+#include "compress.h"
+#include "squashfs.h"
+
+typedef struct meta_reader_t meta_reader_t;
+
+/* Create a meta data reader using a given compressor to extract data.
+ Internally prints error message to stderr on failure.
+
+ Start offset and limit can be specified to do bounds checking against
+ a subregion of the filesystem image.
+*/
+meta_reader_t *meta_reader_create(int fd, compressor_t *cmp,
+ uint64_t start, uint64_t limit);
+
+void meta_reader_destroy(meta_reader_t *m);
+
+/* Returns 0 on success. Internally prints to stderr on failure */
+int meta_reader_seek(meta_reader_t *m, uint64_t block_start,
+ size_t offset);
+
+void meta_reader_get_position(meta_reader_t *m, uint64_t *block_start,
+ size_t *offset);
+
+/* Returns 0 on success. Internally prints to stderr on failure */
+int meta_reader_read(meta_reader_t *m, void *data, size_t size);
+
+/* Inode can be freed with a single free() call.
+ The function internally prints error message to stderr on failure. */
+sqfs_inode_generic_t *meta_reader_read_inode(meta_reader_t *ir,
+ sqfs_super_t *super,
+ uint64_t block_start,
+ size_t offset);
+
+/* Returns 0 on success. Internally prints to stderr on failure */
+int meta_reader_read_dir_header(meta_reader_t *m, sqfs_dir_header_t *hdr);
+
+/* Entry can be freed with a single free() call.
+ The function internally prints to stderr on failure */
+sqfs_dir_entry_t *meta_reader_read_dir_ent(meta_reader_t *m);
+
+#endif /* META_READER_H */
diff --git a/include/sqfs/meta_writer.h b/include/sqfs/meta_writer.h
new file mode 100644
index 0000000..762cc38
--- /dev/null
+++ b/include/sqfs/meta_writer.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * meta_writer.h
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#ifndef META_WRITER_H
+#define META_WRITER_H
+
+#include "config.h"
+
+#include "compress.h"
+#include "squashfs.h"
+#include "id_table.h"
+#include "fstree.h"
+
+typedef struct {
+ tree_node_t *node;
+ uint32_t block;
+ uint32_t index;
+} idx_ref_t;
+
+typedef struct {
+ size_t num_nodes;
+ size_t max_nodes;
+ idx_ref_t idx_nodes[];
+} dir_index_t;
+
+typedef struct meta_writer_t meta_writer_t;
+
+/* Create a meta data reader using a given compressor to compress data.
+ Internally prints error message to stderr on failure.
+ If keep_in_mem is true, the blocks are collected in memory and must
+ be explicitly flushed to disk using meta_write_write_to_file.
+*/
+meta_writer_t *meta_writer_create(int fd, compressor_t *cmp, bool keep_in_mem);
+
+void meta_writer_destroy(meta_writer_t *m);
+
+/* Compress and flush the currently unfinished block to disk. Returns 0 on
+ success, internally prints error message to stderr on failure */
+int meta_writer_flush(meta_writer_t *m);
+
+/* Returns 0 on success. Prints error message to stderr on failure. */
+int meta_writer_append(meta_writer_t *m, const void *data, size_t size);
+
+/* Query the current block start position and offset within the block */
+void meta_writer_get_position(const meta_writer_t *m, uint64_t *block_start,
+ uint32_t *offset);
+
+/* Reset all internal state, including the current block start position. */
+void meta_writer_reset(meta_writer_t *m);
+
+/* If created with keep_in_mem true, write the collected blocks to disk.
+ Does not flush the current block. Writes error messages to stderr and
+ returns non-zero on failure. */
+int meta_write_write_to_file(meta_writer_t *m);
+
+/*
+ High level helper function that writes squashfs directory entries to
+ a meta data writer.
+
+ The dir_info_t structure is used to generate the listing and updated
+ accordingly (such as writing back the header position and total size).
+ A directory index is created on the fly and returned in *index.
+ A single free() call is sufficient.
+
+ Returns 0 on success. Prints error messages to stderr on failure.
+ */
+int meta_writer_write_dir(meta_writer_t *dm, dir_info_t *dir,
+ dir_index_t **index);
+
+/*
+ High level helper function to serialize a tree_node_t to a squashfs inode
+ and write it to a meta data writer.
+
+ The inode is written to `im`. If it is a directory node, the directory
+ contents are written to `dm` using meta_writer_write_dir. The given
+ id_table_t is used to store the uid and gid on the fly and write the
+ coresponding indices to the inode structure.
+
+ Returns 0 on success. Prints error messages to stderr on failure.
+ */
+int meta_writer_write_inode(fstree_t *fs, id_table_t *idtbl, meta_writer_t *im,
+ meta_writer_t *dm, tree_node_t *node);
+
+#endif /* META_WRITER_H */
diff --git a/include/sqfs/squashfs.h b/include/sqfs/squashfs.h
new file mode 100644
index 0000000..eb35fdd
--- /dev/null
+++ b/include/sqfs/squashfs.h
@@ -0,0 +1,272 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * squashfs.h
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#ifndef SQUASHFS_H
+#define SQUASHFS_H
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#define SQFS_MAGIC 0x73717368
+#define SQFS_VERSION_MAJOR 4
+#define SQFS_VERSION_MINOR 0
+#define SQFS_META_BLOCK_SIZE 8192
+#define SQFS_DEFAULT_BLOCK_SIZE 131072
+#define SQFS_DEVBLK_SIZE 4096
+#define SQFS_MAX_DIR_ENT 256
+
+#define SQFS_IS_BLOCK_COMPRESSED(size) (((size) & (1 << 24)) == 0)
+#define SQFS_ON_DISK_BLOCK_SIZE(size) ((size) & ((1 << 24) - 1))
+#define SQFS_IS_SPARSE_BLOCK(size) (SQFS_ON_DISK_BLOCK_SIZE(size) == 0)
+
+typedef struct {
+ uint32_t magic;
+ uint32_t inode_count;
+ uint32_t modification_time;
+ uint32_t block_size;
+ uint32_t fragment_entry_count;
+ uint16_t compression_id;
+ uint16_t block_log;
+ uint16_t flags;
+ uint16_t id_count;
+ uint16_t version_major;
+ uint16_t version_minor;
+ uint64_t root_inode_ref;
+ uint64_t bytes_used;
+ uint64_t id_table_start;
+ uint64_t xattr_id_table_start;
+ uint64_t inode_table_start;
+ uint64_t directory_table_start;
+ uint64_t fragment_table_start;
+ uint64_t export_table_start;
+} __attribute__((packed)) sqfs_super_t;
+
+typedef struct {
+ uint64_t start_offset;
+ uint32_t size;
+ uint32_t pad0;
+} sqfs_fragment_t;
+
+typedef struct {
+ uint16_t type;
+ uint16_t mode;
+ uint16_t uid_idx;
+ uint16_t gid_idx;
+ uint32_t mod_time;
+ uint32_t inode_number;
+} sqfs_inode_t;
+
+typedef struct {
+ uint32_t nlink;
+ uint32_t devno;
+} sqfs_inode_dev_t;
+
+typedef struct {
+ uint32_t nlink;
+ uint32_t devno;
+ uint32_t xattr_idx;
+} sqfs_inode_dev_ext_t;
+
+typedef struct {
+ uint32_t nlink;
+} sqfs_inode_ipc_t;
+
+typedef struct {
+ uint32_t nlink;
+ uint32_t xattr_idx;
+} sqfs_inode_ipc_ext_t;
+
+typedef struct {
+ uint32_t nlink;
+ uint32_t target_size;
+ /*uint8_t target[];*/
+} sqfs_inode_slink_t;
+
+typedef struct {
+ uint32_t nlink;
+ uint32_t target_size;
+ /*uint8_t target[];*/
+ uint32_t xattr_idx;
+} sqfs_inode_slink_ext_t;
+
+typedef struct {
+ uint32_t blocks_start;
+ uint32_t fragment_index;
+ uint32_t fragment_offset;
+ uint32_t file_size;
+ /*uint32_t block_sizes[];*/
+} sqfs_inode_file_t;
+
+typedef struct {
+ uint64_t blocks_start;
+ uint64_t file_size;
+ uint64_t sparse;
+ uint32_t nlink;
+ uint32_t fragment_idx;
+ uint32_t fragment_offset;
+ uint32_t xattr_idx;
+ /*uint32_t block_sizes[];*/
+} sqfs_inode_file_ext_t;
+
+typedef struct {
+ uint32_t start_block;
+ uint32_t nlink;
+ uint16_t size;
+ uint16_t offset;
+ uint32_t parent_inode;
+} sqfs_inode_dir_t;
+
+typedef struct {
+ uint32_t nlink;
+ uint32_t size;
+ uint32_t start_block;
+ uint32_t parent_inode;
+ uint16_t inodex_count;
+ uint16_t offset;
+ uint32_t xattr_idx;
+} sqfs_inode_dir_ext_t;
+
+typedef struct {
+ sqfs_inode_t base;
+ char *slink_target;
+ uint32_t *block_sizes;
+
+ union {
+ sqfs_inode_dev_t dev;
+ sqfs_inode_dev_ext_t dev_ext;
+ sqfs_inode_ipc_t ipc;
+ sqfs_inode_ipc_ext_t ipc_ext;
+ sqfs_inode_slink_t slink;
+ sqfs_inode_slink_ext_t slink_ext;
+ sqfs_inode_file_t file;
+ sqfs_inode_file_ext_t file_ext;
+ sqfs_inode_dir_t dir;
+ sqfs_inode_dir_ext_t dir_ext;
+ } data;
+
+ uint8_t extra[];
+} sqfs_inode_generic_t;
+
+typedef struct {
+ uint32_t count;
+ uint32_t start_block;
+ uint32_t inode_number;
+} sqfs_dir_header_t;
+
+typedef struct {
+ uint16_t offset;
+ int16_t inode_diff;
+ uint16_t type;
+ uint16_t size;
+ uint8_t name[];
+} sqfs_dir_entry_t;
+
+typedef struct {
+ uint32_t index;
+ uint32_t start_block;
+ uint32_t size;
+ uint8_t name[];
+} sqfs_dir_index_t;
+
+typedef struct {
+ uint16_t type;
+ uint16_t size;
+ uint8_t key[];
+} sqfs_xattr_entry_t;
+
+typedef struct {
+ uint32_t size;
+ uint8_t value[];
+} sqfs_xattr_value_t;
+
+typedef struct {
+ uint64_t xattr;
+ uint32_t count;
+ uint32_t size;
+} sqfs_xattr_id_t;
+
+typedef struct {
+ uint64_t xattr_table_start;
+ uint32_t xattr_ids;
+ uint32_t unused;
+} sqfs_xattr_id_table_t;
+
+
+typedef enum {
+ SQFS_COMP_GZIP = 1,
+ SQFS_COMP_LZMA = 2,
+ SQFS_COMP_LZO = 3,
+ SQFS_COMP_XZ = 4,
+ SQFS_COMP_LZ4 = 5,
+ SQFS_COMP_ZSTD = 6,
+
+ SQFS_COMP_MIN = 1,
+ SQFS_COMP_MAX = 6,
+} E_SQFS_COMPRESSOR;
+
+typedef enum {
+ SQFS_FLAG_UNCOMPRESSED_INODES = 0x0001,
+ SQFS_FLAG_UNCOMPRESSED_DATA = 0x0002,
+ SQFS_FLAG_UNCOMPRESSED_FRAGMENTS = 0x0008,
+ SQFS_FLAG_NO_FRAGMENTS = 0x0010,
+ SQFS_FLAG_ALWAYS_FRAGMENTS = 0x0020,
+ SQFS_FLAG_DUPLICATES = 0x0040,
+ SQFS_FLAG_EXPORTABLE = 0x0080,
+ SQFS_FLAG_UNCOMPRESSED_XATTRS = 0x0100,
+ SQFS_FLAG_NO_XATTRS = 0x0200,
+ SQFS_FLAG_COMPRESSOR_OPTIONS = 0x0400,
+ SQFS_FLAG_UNCOMPRESSED_IDS = 0x0800,
+} E_SQFS_SUPER_FLAGS;
+
+typedef enum {
+ SQFS_INODE_DIR = 1,
+ SQFS_INODE_FILE = 2,
+ SQFS_INODE_SLINK = 3,
+ SQFS_INODE_BDEV = 4,
+ SQFS_INODE_CDEV = 5,
+ SQFS_INODE_FIFO = 6,
+ SQFS_INODE_SOCKET = 7,
+ SQFS_INODE_EXT_DIR = 8,
+ SQFS_INODE_EXT_FILE = 9,
+ SQFS_INODE_EXT_SLINK = 10,
+ SQFS_INODE_EXT_BDEV = 11,
+ SQFS_INODE_EXT_CDEV = 12,
+ SQFS_INODE_EXT_FIFO = 13,
+ SQFS_INODE_EXT_SOCKET = 14,
+} E_SQFS_INODE_TYPE;
+
+typedef enum {
+ SQUASHFS_XATTR_USER = 0,
+ SQUASHFS_XATTR_TRUSTED = 1,
+ SQUASHFS_XATTR_SECURITY = 2,
+
+ SQUASHFS_XATTR_FLAG_OOL = 0x100,
+ SQUASHFS_XATTR_PREFIX_MASK = 0xFF,
+} E_SQFS_XATTR_TYPE;
+
+/* Returns 0 on success. Prints error messages to stderr on failure. */
+int sqfs_super_init(sqfs_super_t *super, size_t block_size, uint32_t mtime,
+ E_SQFS_COMPRESSOR compressor);
+
+/* Returns 0 on success. Prints error messages to stderr on failure. */
+int sqfs_super_write(sqfs_super_t *super, int fd);
+
+/* Returns 0 on success. Prints error messages to stderr on failure. */
+int sqfs_super_read(sqfs_super_t *super, int fd);
+
+/* Get id from xattr key prefix or -1 if not supported */
+int sqfs_get_xattr_prefix_id(const char *key);
+
+/* Get a prefix string from the ID or NULL if unknown */
+const char *sqfs_get_xattr_prefix(E_SQFS_XATTR_TYPE id);
+
+/* Check if a given xattr key can be encoded in squashfs at all. */
+bool sqfs_has_xattr(const char *key);
+
+#endif /* SQUASHFS_H */