aboutsummaryrefslogtreecommitdiff
path: root/lib/sqfs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqfs')
-rw-r--r--lib/sqfs/data_reader.c314
-rw-r--r--lib/sqfs/data_writer.c528
-rw-r--r--lib/sqfs/deserialize_fstree.c304
-rw-r--r--lib/sqfs/serialize_fstree.c65
-rw-r--r--lib/sqfs/sqfs_reader.c75
-rw-r--r--lib/sqfs/statistics.c82
-rw-r--r--lib/sqfs/tree_node_from_inode.c167
-rw-r--r--lib/sqfs/write_dir.c141
-rw-r--r--lib/sqfs/write_export_table.c47
-rw-r--r--lib/sqfs/write_inode.c327
-rw-r--r--lib/sqfs/write_xattr.c279
-rw-r--r--lib/sqfs/xattr_reader.c393
12 files changed, 0 insertions, 2722 deletions
diff --git a/lib/sqfs/data_reader.c b/lib/sqfs/data_reader.c
deleted file mode 100644
index 4ad6266..0000000
--- a/lib/sqfs/data_reader.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * data_reader.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "data_reader.h"
-#include "highlevel.h"
-#include "util.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-
-struct data_reader_t {
- sqfs_fragment_t *frag;
- size_t num_fragments;
- size_t current_frag_index;
- size_t frag_used;
-
- off_t current_block;
-
- compressor_t *cmp;
- size_t block_size;
- int sqfsfd;
-
- void *block;
- void *scratch;
- void *frag_block;
-};
-
-static ssize_t read_block(data_reader_t *data, off_t offset, uint32_t size,
- void *dst)
-{
- bool compressed = SQFS_IS_BLOCK_COMPRESSED(size);
- void *ptr = compressed ? data->scratch : dst;
- ssize_t ret;
-
- size = SQFS_ON_DISK_BLOCK_SIZE(size);
-
- if (size > data->block_size)
- goto fail_bs;
-
- if (read_data_at("reading block", offset, data->sqfsfd, ptr, size))
- return -1;
-
- if (compressed) {
- ret = data->cmp->do_block(data->cmp, data->scratch, size,
- dst, data->block_size);
- if (ret <= 0) {
- fputs("extracting block failed\n", stderr);
- return -1;
- }
- size = ret;
- }
-
- return size;
-fail_bs:
- fputs("found compressed block larger than block size\n", stderr);
- return -1;
-}
-
-static int precache_data_block(data_reader_t *data, off_t location,
- uint32_t size)
-{
- ssize_t ret;
-
- if (data->current_block == location)
- return 0;
-
- ret = read_block(data, location, size, data->block);
- if (ret < 0)
- return -1;
-
- if ((size_t)ret < data->block_size)
- memset((char *)data->block + ret, 0, data->block_size - ret);
-
- data->current_block = location;
- return 0;
-}
-
-static int precache_fragment_block(data_reader_t *data, size_t idx)
-{
- ssize_t ret;
-
- if (idx == data->current_frag_index)
- return 0;
-
- if (idx >= data->num_fragments) {
- fputs("fragment index out of bounds\n", stderr);
- return -1;
- }
-
- ret = read_block(data, data->frag[idx].start_offset,
- data->frag[idx].size, data->frag_block);
- if (ret < 0)
- return -1;
-
- data->current_frag_index = idx;
- data->frag_used = ret;
- return 0;
-}
-
-data_reader_t *data_reader_create(int fd, sqfs_super_t *super,
- compressor_t *cmp)
-{
- data_reader_t *data = alloc_flex(sizeof(*data), super->block_size, 3);
- size_t i, size;
-
- if (data == NULL) {
- perror("creating data reader");
- return data;
- }
-
- data->num_fragments = super->fragment_entry_count;
- data->current_frag_index = super->fragment_entry_count;
- data->block = (char *)data + sizeof(*data);
- data->scratch = (char *)data->block + super->block_size;
- data->frag_block = (char *)data->scratch + super->block_size;
- data->current_block = -1;
- data->sqfsfd = fd;
- data->block_size = super->block_size;
- data->cmp = cmp;
-
- if (super->fragment_entry_count == 0 ||
- (super->flags & SQFS_FLAG_NO_FRAGMENTS) != 0) {
- return data;
- }
-
- if (super->fragment_table_start >= super->bytes_used) {
- fputs("Fragment table start is past end of file\n", stderr);
- free(data);
- return NULL;
- }
-
- if (SZ_MUL_OV(sizeof(data->frag[0]), data->num_fragments, &size)) {
- fputs("Too many fragments: overflow\n", stderr);
- free(data);
- return NULL;
- }
-
- data->frag = sqfs_read_table(fd, cmp, size,
- super->fragment_table_start,
- super->directory_table_start,
- super->fragment_table_start);
- if (data->frag == NULL) {
- free(data);
- return NULL;
- }
-
- for (i = 0; i < data->num_fragments; ++i) {
- data->frag[i].size = le32toh(data->frag[i].size);
- data->frag[i].start_offset =
- le64toh(data->frag[i].start_offset);
- }
-
- return data;
-}
-
-void data_reader_destroy(data_reader_t *data)
-{
- free(data->frag);
- free(data);
-}
-
-int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd,
- bool allow_sparse)
-{
- uint64_t filesz = fi->size;
- size_t fragsz = fi->size % data->block_size;
- size_t count = fi->size / data->block_size;
- off_t off = fi->startblock;
- size_t i, diff;
-
- if (fragsz != 0 && !(fi->flags & FILE_FLAG_HAS_FRAGMENT)) {
- fragsz = 0;
- ++count;
- }
-
- if (allow_sparse && ftruncate(outfd, filesz))
- goto fail_sparse;
-
- for (i = 0; i < count; ++i) {
- diff = filesz > data->block_size ? data->block_size : filesz;
- filesz -= diff;
-
- if (SQFS_IS_SPARSE_BLOCK(fi->blocks[i].size)) {
- if (allow_sparse) {
- if (lseek(outfd, diff, SEEK_CUR) == (off_t)-1)
- goto fail_sparse;
- continue;
- }
- memset(data->block, 0, diff);
- } else {
- if (precache_data_block(data, off, fi->blocks[i].size))
- return -1;
- off += SQFS_ON_DISK_BLOCK_SIZE(fi->blocks[i].size);
- }
-
- if (write_data("writing uncompressed block",
- outfd, data->block, diff)) {
- return -1;
- }
- }
-
- if (fragsz > 0) {
- if (precache_fragment_block(data, fi->fragment))
- return -1;
-
- if (fi->fragment_offset >= data->frag_used)
- goto fail_range;
-
- if ((fi->fragment_offset + fragsz - 1) >= data->frag_used)
- goto fail_range;
-
- if (write_data("writing uncompressed fragment", outfd,
- (char *)data->frag_block + fi->fragment_offset,
- fragsz)) {
- return -1;
- }
- }
-
- return 0;
-fail_range:
- fputs("attempted to read past fragment block limits\n", stderr);
- return -1;
-fail_sparse:
- perror("creating sparse output file");
- return -1;
-}
-
-ssize_t data_reader_read(data_reader_t *data, file_info_t *fi,
- uint64_t offset, void *buffer, size_t size)
-{
- size_t i, diff, fragsz, count, total = 0;
- off_t off;
- char *ptr;
-
- /* work out block count and fragment size */
- fragsz = fi->size % data->block_size;
- count = fi->size / data->block_size;
-
- if (fragsz != 0 && !(fi->flags & FILE_FLAG_HAS_FRAGMENT)) {
- fragsz = 0;
- ++count;
- }
-
- /* work out block index and on-disk location */
- off = fi->startblock;
- i = 0;
-
- while (offset > data->block_size && i < count) {
- off += SQFS_ON_DISK_BLOCK_SIZE(fi->blocks[i++].size);
- offset -= data->block_size;
- }
-
- /* copy data from blocks */
- while (i < count && size > 0) {
- diff = data->block_size - offset;
- if (size < diff)
- size = diff;
-
- if (SQFS_IS_SPARSE_BLOCK(fi->blocks[i].size)) {
- memset(buffer, 0, diff);
- } else {
- if (precache_data_block(data, off, fi->blocks[i].size))
- return -1;
-
- memcpy(buffer, (char *)data->block + offset, diff);
- off += SQFS_ON_DISK_BLOCK_SIZE(fi->blocks[i].size);
- }
-
- ++i;
- offset = 0;
- size -= diff;
- total += diff;
- buffer = (char *)buffer + diff;
- }
-
- /* copy from fragment */
- if (i == count && size > 0 && fragsz > 0) {
- if (precache_fragment_block(data, fi->fragment))
- return -1;
-
- if (fi->fragment_offset >= data->frag_used)
- goto fail_range;
-
- if ((fi->fragment_offset + fragsz - 1) >= data->frag_used)
- goto fail_range;
-
- ptr = (char *)data->frag_block + fi->fragment_offset;
- ptr += offset;
-
- if (offset >= fragsz) {
- offset = 0;
- size = 0;
- }
-
- if (offset + size > fragsz)
- size = fragsz - offset;
-
- if (size > 0) {
- memcpy(buffer, ptr + offset, size);
- total += size;
- }
- }
- return total;
-fail_range:
- fputs("attempted to read past fragment block limits\n", stderr);
- return -1;
-}
diff --git a/lib/sqfs/data_writer.c b/lib/sqfs/data_writer.c
deleted file mode 100644
index d4b402b..0000000
--- a/lib/sqfs/data_writer.c
+++ /dev/null
@@ -1,528 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * data_writer.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "block_processor.h"
-#include "data_writer.h"
-#include "highlevel.h"
-#include "util.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <zlib.h>
-
-struct data_writer_t {
- block_t *frag_block;
- sqfs_fragment_t *fragments;
- size_t num_fragments;
- size_t max_fragments;
-
- size_t devblksz;
- uint64_t bytes_written;
- off_t start;
-
- block_processor_t *proc;
- compressor_t *cmp;
- file_info_t *list;
- sqfs_super_t *super;
- int outfd;
-};
-
-enum {
- BLK_FIRST_BLOCK = BLK_USER,
- BLK_LAST_BLOCK = BLK_USER << 1,
- BLK_ALLIGN = BLK_USER << 2,
- BLK_FRAGMENT_BLOCK = BLK_USER << 3,
-};
-
-static int save_position(data_writer_t *data)
-{
- data->bytes_written = data->super->bytes_used;
- data->start = lseek(data->outfd, 0, SEEK_CUR);
-
- if (data->start == (off_t)-1) {
- perror("querying current position on squashfs image");
- return -1;
- }
-
- return 0;
-}
-
-static int restore_position(data_writer_t *data)
-{
- if (lseek(data->outfd, data->start, SEEK_SET) == (off_t)-1)
- goto fail_seek;
-
- if (ftruncate(data->outfd, data->start))
- goto fail_truncate;
-
- data->super->bytes_used = data->bytes_written;
- return 0;
-fail_seek:
- perror("seeking on squashfs image after file deduplication");
- return -1;
-fail_truncate:
- perror("truncating squashfs image after file deduplication");
- return -1;
-}
-
-static int allign_file(data_writer_t *data)
-{
- size_t diff = data->super->bytes_used % data->devblksz;
-
- if (diff == 0)
- return 0;
-
- if (padd_file(data->outfd, data->super->bytes_used, data->devblksz))
- return -1;
-
- data->super->bytes_used += data->devblksz - diff;
- return 0;
-}
-
-static int block_callback(void *user, block_t *blk)
-{
- file_info_t *fi = blk->user;
- data_writer_t *data = user;
- uint64_t ref, offset;
- uint32_t out;
-
- if (blk->flags & BLK_FIRST_BLOCK) {
- if (save_position(data))
- return -1;
-
- if ((blk->flags & BLK_ALLIGN) && allign_file(data) != 0)
- return -1;
-
- fi->startblock = data->super->bytes_used;
- }
-
- if (blk->size == 0)
- goto skip_sentinel;
-
- out = blk->size;
- if (!(blk->flags & BLK_IS_COMPRESSED))
- out |= 1 << 24;
-
- if (blk->flags & BLK_FRAGMENT_BLOCK) {
- offset = htole64(data->super->bytes_used);
- data->fragments[blk->index].start_offset = offset;
- data->fragments[blk->index].pad0 = 0;
- data->fragments[blk->index].size = htole32(out);
-
- data->super->flags &= ~SQFS_FLAG_NO_FRAGMENTS;
- data->super->flags |= SQFS_FLAG_ALWAYS_FRAGMENTS;
- } else {
- fi->blocks[blk->index].chksum = blk->checksum;
- fi->blocks[blk->index].size = htole32(out);
- }
-
- if (write_data("writing data block", data->outfd,
- blk->data, blk->size)) {
- return -1;
- }
-
- data->super->bytes_used += blk->size;
-
-skip_sentinel:
- if (blk->flags & BLK_LAST_BLOCK) {
- if ((blk->flags & BLK_ALLIGN) && allign_file(data) != 0)
- return -1;
-
- ref = find_equal_blocks(fi, data->list,
- data->super->block_size);
- if (ref > 0) {
- fi->startblock = ref;
- fi->flags |= FILE_FLAG_BLOCKS_ARE_DUPLICATE;
-
- if (restore_position(data))
- return -1;
- }
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static int flush_fragment_block(data_writer_t *data)
-{
- size_t newsz;
- void *new;
- int ret;
-
- if (data->num_fragments == data->max_fragments) {
- newsz = data->max_fragments ? data->max_fragments * 2 : 16;
- new = realloc(data->fragments,
- sizeof(data->fragments[0]) * newsz);
-
- if (new == NULL) {
- perror("appending to fragment table");
- return -1;
- }
-
- data->max_fragments = newsz;
- data->fragments = new;
- }
-
- data->frag_block->index = data->num_fragments++;
-
- ret = block_processor_enqueue(data->proc, data->frag_block);
- data->frag_block = NULL;
- return ret;
-}
-
-static int store_fragment(data_writer_t *data, block_t *frag)
-{
- file_info_t *fi = frag->user;
- size_t size;
-
- if (data->frag_block != NULL) {
- size = data->frag_block->size + frag->size;
-
- if (size > data->super->block_size) {
- if (flush_fragment_block(data))
- goto fail;
- }
- }
-
- if (data->frag_block == NULL) {
- size = sizeof(block_t) + data->super->block_size;
-
- data->frag_block = calloc(1, size);
- if (data->frag_block == NULL) {
- perror("creating fragment block");
- goto fail;
- }
-
- data->frag_block->flags = BLK_DONT_CHECKSUM;
- data->frag_block->flags |= BLK_FRAGMENT_BLOCK;
- }
-
- fi->fragment_offset = data->frag_block->size;
- fi->fragment = data->num_fragments;
-
- data->frag_block->flags |= (frag->flags & BLK_DONT_COMPRESS);
- memcpy(data->frag_block->data + data->frag_block->size,
- frag->data, frag->size);
-
- data->frag_block->size += frag->size;
- free(frag);
- return 0;
-fail:
- free(frag);
- return -1;
-}
-
-static bool is_zero_block(unsigned char *ptr, size_t size)
-{
- return ptr[0] == 0 && memcmp(ptr, ptr + 1, size - 1) == 0;
-}
-
-static int handle_fragment(data_writer_t *data, block_t *blk)
-{
- file_info_t *fi = blk->user, *ref;
-
- fi->fragment_chksum = crc32(0, blk->data, blk->size);
-
- ref = fragment_by_chksum(fi, fi->fragment_chksum, blk->size,
- data->list, data->super->block_size);
-
- if (ref != NULL) {
- fi->fragment_offset = ref->fragment_offset;
- fi->fragment = ref->fragment;
- fi->flags |= FILE_FLAG_FRAGMENT_IS_DUPLICATE;
- free(blk);
- return 0;
- }
-
- return store_fragment(data, blk);
-}
-
-static int add_sentinel_block(data_writer_t *data, file_info_t *fi,
- uint32_t flags)
-{
- block_t *blk = calloc(1, sizeof(*blk));
-
- if (blk == NULL) {
- perror("creating sentinel block");
- return -1;
- }
-
- blk->user = fi;
- blk->flags = BLK_DONT_COMPRESS | BLK_DONT_CHECKSUM | flags;
-
- return block_processor_enqueue(data->proc, blk);
-}
-
-int write_data_from_fd(data_writer_t *data, file_info_t *fi,
- int infd, int flags)
-{
- uint32_t blk_flags = BLK_FIRST_BLOCK;
- uint64_t file_size = fi->size;
- size_t diff, i = 0;
- block_t *blk;
-
- if (flags & DW_DONT_COMPRESS)
- blk_flags |= BLK_DONT_COMPRESS;
-
- if (flags & DW_ALLIGN_DEVBLK)
- blk_flags |= BLK_ALLIGN;
-
- fi->next = data->list;
- data->list = fi;
-
- for (; file_size > 0; file_size -= diff) {
- if (file_size > data->super->block_size) {
- diff = data->super->block_size;
- } else {
- diff = file_size;
- }
-
- blk = create_block(fi->input_file, infd, diff, fi, blk_flags);
- if (blk == NULL)
- return -1;
-
- blk->index = i++;
-
- if (is_zero_block(blk->data, blk->size)) {
- fi->blocks[blk->index].chksum = 0;
- fi->blocks[blk->index].size = 0;
- free(blk);
- continue;
- }
-
- if (diff < data->super->block_size &&
- !(flags & DW_DONT_FRAGMENT)) {
- fi->flags |= FILE_FLAG_HAS_FRAGMENT;
-
- if (!(blk_flags & (BLK_FIRST_BLOCK | BLK_LAST_BLOCK))) {
- blk_flags |= BLK_LAST_BLOCK;
-
- if (add_sentinel_block(data, fi, blk_flags)) {
- free(blk);
- return -1;
- }
- }
-
- if (handle_fragment(data, blk))
- return -1;
- } else {
- if (block_processor_enqueue(data->proc, blk))
- return -1;
-
- blk_flags &= ~BLK_FIRST_BLOCK;
- }
- }
-
- if (!(blk_flags & (BLK_FIRST_BLOCK | BLK_LAST_BLOCK))) {
- blk_flags |= BLK_LAST_BLOCK;
-
- if (add_sentinel_block(data, fi, blk_flags))
- return -1;
- }
-
- return 0;
-}
-
-static int check_map_valid(const sparse_map_t *map, file_info_t *fi)
-{
- const sparse_map_t *m;
- uint64_t offset;
-
- if (map != NULL) {
- offset = map->offset;
-
- for (m = map; m != NULL; m = m->next) {
- if (m->offset < offset)
- goto fail_map;
- offset = m->offset + m->count;
- }
-
- if (offset > fi->size)
- goto fail_map_size;
- }
-
- return 0;
-fail_map_size:
- fprintf(stderr, "%s: sparse file map spans beyond file size\n",
- fi->input_file);
- return -1;
-fail_map:
- fprintf(stderr,
- "%s: sparse file map is unordered or self overlapping\n",
- fi->input_file);
- return -1;
-}
-
-static int get_sparse_block(block_t *blk, file_info_t *fi, int infd,
- sparse_map_t **sparse_map, uint64_t offset,
- size_t diff)
-{
- sparse_map_t *map = *sparse_map;
- size_t start, count;
-
- while (map != NULL && map->offset < offset + diff) {
- start = 0;
- count = map->count;
-
- if (map->offset < offset)
- count -= offset - map->offset;
-
- if (map->offset > offset)
- start = map->offset - offset;
-
- if (start + count > diff)
- count = diff - start;
-
- if (read_data(fi->input_file, infd, blk->data + start, count))
- return -1;
-
- map = map->next;
- }
-
- *sparse_map = map;
- return 0;
-}
-
-int write_data_from_fd_condensed(data_writer_t *data, file_info_t *fi,
- int infd, sparse_map_t *map, int flags)
-{
- uint32_t blk_flags = BLK_FIRST_BLOCK;
- size_t diff, i = 0;
- uint64_t offset;
- block_t *blk;
-
- if (check_map_valid(map, fi))
- return -1;
-
- if (flags & DW_DONT_COMPRESS)
- blk_flags |= BLK_DONT_COMPRESS;
-
- if (flags & DW_ALLIGN_DEVBLK)
- blk_flags |= BLK_ALLIGN;
-
- for (offset = 0; offset < fi->size; offset += diff) {
- if (fi->size - offset > (uint64_t)data->super->block_size) {
- diff = data->super->block_size;
- } else {
- diff = fi->size - offset;
- }
-
- blk = alloc_flex(sizeof(*blk), 1, diff);
- blk->size = diff;
- blk->index = i++;
- blk->user = fi;
- blk->flags = blk_flags;
-
- if (get_sparse_block(blk, fi, infd, &map, offset, diff)) {
- free(blk);
- return -1;
- }
-
- if (is_zero_block(blk->data, blk->size)) {
- fi->blocks[blk->index].chksum = 0;
- fi->blocks[blk->index].size = 0;
- free(blk);
- continue;
- }
-
- if (diff < data->super->block_size &&
- !(flags & DW_DONT_FRAGMENT)) {
- fi->flags |= FILE_FLAG_HAS_FRAGMENT;
-
- if (!(blk_flags & (BLK_FIRST_BLOCK | BLK_LAST_BLOCK))) {
- blk_flags |= BLK_LAST_BLOCK;
-
- if (add_sentinel_block(data, fi, blk_flags)) {
- free(blk);
- return -1;
- }
- }
-
- if (handle_fragment(data, blk))
- return -1;
- } else {
- if (block_processor_enqueue(data->proc, blk))
- return -1;
-
- blk_flags &= ~BLK_FIRST_BLOCK;
- }
- }
-
- if (!(blk_flags & (BLK_FIRST_BLOCK | BLK_LAST_BLOCK))) {
- blk_flags |= BLK_LAST_BLOCK;
-
- if (add_sentinel_block(data, fi, blk_flags))
- return -1;
- }
-
- return 0;
-}
-
-data_writer_t *data_writer_create(sqfs_super_t *super, compressor_t *cmp,
- int outfd, size_t devblksize,
- unsigned int num_jobs)
-{
- data_writer_t *data = calloc(1, sizeof(*data));
-
- if (data == NULL) {
- perror("creating data writer");
- return NULL;
- }
-
- data->proc = block_processor_create(super->block_size, cmp, num_jobs,
- data, block_callback);
- data->cmp = cmp;
- data->super = super;
- data->outfd = outfd;
- data->devblksz = devblksize;
- return data;
-}
-
-void data_writer_destroy(data_writer_t *data)
-{
- block_processor_destroy(data->proc);
- free(data->fragments);
- free(data);
-}
-
-int data_writer_write_fragment_table(data_writer_t *data)
-{
- uint64_t start;
- size_t size;
- int ret;
-
- if (data->num_fragments == 0) {
- data->super->fragment_entry_count = 0;
- data->super->fragment_table_start = 0xFFFFFFFFFFFFFFFFUL;
- return 0;
- }
-
- size = sizeof(data->fragments[0]) * data->num_fragments;
- ret = sqfs_write_table(data->outfd, data->super, data->cmp,
- data->fragments, size, &start);
- if (ret)
- return -1;
-
- data->super->fragment_entry_count = data->num_fragments;
- data->super->fragment_table_start = start;
- return 0;
-}
-
-int data_writer_sync(data_writer_t *data)
-{
- if (data->frag_block != NULL) {
- if (flush_fragment_block(data))
- return -1;
- }
-
- return block_processor_finish(data->proc);
-}
diff --git a/lib/sqfs/deserialize_fstree.c b/lib/sqfs/deserialize_fstree.c
deleted file mode 100644
index 11670e1..0000000
--- a/lib/sqfs/deserialize_fstree.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * deserialize_fstree.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "xattr_reader.h"
-#include "meta_reader.h"
-#include "highlevel.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.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 & RDTREE_NO_DEVICES);
- case SQFS_INODE_SLINK:
- case SQFS_INODE_EXT_SLINK:
- return (flags & RDTREE_NO_SLINKS);
- case SQFS_INODE_SOCKET:
- case SQFS_INODE_EXT_SOCKET:
- return(flags & RDTREE_NO_SOCKETS);
- case SQFS_INODE_FIFO:
- case SQFS_INODE_EXT_FIFO:
- return (flags & RDTREE_NO_FIFO);
- }
- return 0;
-}
-
-static int restore_xattr(xattr_reader_t *xr, fstree_t *fs, tree_node_t *node,
- sqfs_inode_generic_t *inode)
-{
- uint32_t idx;
-
- switch (inode->base.type) {
- case SQFS_INODE_EXT_DIR:
- idx = inode->data.dir_ext.xattr_idx;
- break;
- case SQFS_INODE_EXT_FILE:
- idx = inode->data.file_ext.xattr_idx;
- break;
- case SQFS_INODE_EXT_SLINK:
- idx = inode->data.slink_ext.xattr_idx;
- break;
- case SQFS_INODE_EXT_BDEV:
- case SQFS_INODE_EXT_CDEV:
- idx = inode->data.dev_ext.xattr_idx;
- break;
- case SQFS_INODE_EXT_FIFO:
- case SQFS_INODE_EXT_SOCKET:
- idx = inode->data.ipc_ext.xattr_idx;
- break;
- default:
- return 0;
- }
-
- return xattr_reader_restore_node(xr, fs, node, idx);
-}
-
-static bool node_would_be_own_parent(tree_node_t *root, tree_node_t *n)
-{
- while (root != NULL) {
- if (root->inode_num == n->inode_num)
- return true;
-
- root = root->parent;
- }
-
- return false;
-}
-
-static int fill_dir(meta_reader_t *ir, meta_reader_t *dr, tree_node_t *root,
- sqfs_super_t *super, id_table_t *idtbl, fstree_t *fs,
- xattr_reader_t *xr, 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;
- uint32_t i;
-
- size = root->data.dir->size;
- if (size <= sizeof(hdr))
- return 0;
-
- block_start = root->data.dir->start_block;
- block_start += super->directory_table_start;
-
- if (meta_reader_seek(dr, block_start, root->data.dir->block_offset))
- return -1;
-
- while (size > sizeof(hdr)) {
- if (meta_reader_read_dir_header(dr, &hdr))
- return -1;
-
- size -= sizeof(hdr);
-
- for (i = 0; i <= hdr.count && size > sizeof(*ent); ++i) {
- ent = meta_reader_read_dir_ent(dr);
- if (ent == NULL)
- return -1;
-
- diff = sizeof(*ent) + strlen((char *)ent->name);
- if (diff > size) {
- free(ent);
- break;
- }
- size -= diff;
-
- if (should_skip(ent->type, flags)) {
- free(ent);
- continue;
- }
-
- inode = meta_reader_read_inode(ir, super,
- hdr.start_block,
- ent->offset);
- if (inode == NULL) {
- free(ent);
- return -1;
- }
-
- n = tree_node_from_inode(inode, idtbl,
- (char *)ent->name,
- super->block_size);
-
- if (n == NULL) {
- free(ent);
- free(inode);
- return -1;
- }
-
- if (node_would_be_own_parent(root, n)) {
- fputs("WARNING: Found a directory that "
- "contains itself, skipping loop back "
- "reference!\n", stderr);
- free(n);
- free(ent);
- free(inode);
- continue;
- }
-
- if (flags & RDTREE_READ_XATTR) {
- if (restore_xattr(xr, fs, n, inode)) {
- free(n);
- free(ent);
- free(inode);
- return -1;
- }
- }
-
- free(ent);
- free(inode);
-
- n->parent = root;
- n->next = root->data.dir->children;
- root->data.dir->children = n;
- }
- }
-
- n = root->data.dir->children;
- prev = NULL;
-
- while (n != NULL) {
- if (S_ISDIR(n->mode)) {
- if (fill_dir(ir, dr, n, super, idtbl, fs, xr, flags))
- return -1;
-
- if (n->data.dir->children == NULL &&
- (flags & RDTREE_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 deserialize_fstree(fstree_t *out, sqfs_super_t *super, compressor_t *cmp,
- int fd, int flags)
-{
- uint64_t block_start, limit;
- sqfs_inode_generic_t *root;
- meta_reader_t *ir, *dr;
- xattr_reader_t *xr;
- id_table_t idtbl;
- int status = -1;
- size_t offset;
-
- ir = meta_reader_create(fd, cmp, super->inode_table_start,
- super->directory_table_start);
- if (ir == NULL)
- return -1;
-
- limit = super->id_table_start;
- if (super->export_table_start < limit)
- limit = super->export_table_start;
- if (super->fragment_table_start < limit)
- limit = super->fragment_table_start;
-
- dr = meta_reader_create(fd, cmp, super->directory_table_start, limit);
- if (dr == NULL)
- goto out_ir;
-
- if (id_table_init(&idtbl))
- goto out_dr;
-
- if (id_table_read(&idtbl, fd, super, cmp))
- goto out_id;
-
- xr = xattr_reader_create(fd, super, cmp);
- if (xr == NULL)
- goto out_id;
-
- block_start = super->root_inode_ref >> 16;
- offset = super->root_inode_ref & 0xFFFF;
- root = meta_reader_read_inode(ir, super, block_start, offset);
- if (root == NULL)
- goto out_xr;
-
- if (root->base.type != SQFS_INODE_DIR &&
- root->base.type != SQFS_INODE_EXT_DIR) {
- free(root);
- fputs("File system root inode is not a directory inode!\n",
- stderr);
- goto out_xr;
- }
-
- memset(out, 0, sizeof(*out));
- out->block_size = super->block_size;
- out->defaults.st_uid = 0;
- out->defaults.st_gid = 0;
- out->defaults.st_mode = 0755;
- out->defaults.st_mtime = super->modification_time;
-
- out->root = tree_node_from_inode(root, &idtbl, "", super->block_size);
-
- if (out->root == NULL) {
- free(root);
- goto out_xr;
- }
-
- if (flags & RDTREE_READ_XATTR) {
- if (str_table_init(&out->xattr_keys,
- FSTREE_XATTR_KEY_BUCKETS)) {
- free(root);
- goto fail_fs;
- }
-
- if (str_table_init(&out->xattr_values,
- FSTREE_XATTR_VALUE_BUCKETS)) {
- free(root);
- goto fail_fs;
- }
-
- if (restore_xattr(xr, out, out->root, root)) {
- free(root);
- goto fail_fs;
- }
- }
-
- free(root);
-
- if (fill_dir(ir, dr, out->root, super, &idtbl, out, xr, flags))
- goto fail_fs;
-
- tree_node_sort_recursive(out->root);
-
- status = 0;
-out_xr:
- xattr_reader_destroy(xr);
-out_id:
- id_table_cleanup(&idtbl);
-out_dr:
- meta_reader_destroy(dr);
-out_ir:
- meta_reader_destroy(ir);
- return status;
-fail_fs:
- fstree_cleanup(out);
- goto out_xr;
-}
diff --git a/lib/sqfs/serialize_fstree.c b/lib/sqfs/serialize_fstree.c
deleted file mode 100644
index 736744b..0000000
--- a/lib/sqfs/serialize_fstree.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * serialize_fstree.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "meta_writer.h"
-#include "highlevel.h"
-#include "util.h"
-
-#include <unistd.h>
-#include <stdio.h>
-
-int sqfs_serialize_fstree(int outfd, sqfs_super_t *super, fstree_t *fs,
- compressor_t *cmp, id_table_t *idtbl)
-{
- meta_writer_t *im, *dm;
- uint32_t offset;
- uint64_t block;
- int ret = -1;
- size_t i;
-
- im = meta_writer_create(outfd, cmp, false);
- if (im == NULL)
- return -1;
-
- dm = meta_writer_create(outfd, cmp, true);
- if (dm == NULL)
- goto out_im;
-
- for (i = 2; i < fs->inode_tbl_size; ++i) {
- if (meta_writer_write_inode(fs, idtbl, im, dm,
- fs->inode_table[i])) {
- goto out;
- }
- }
-
- if (meta_writer_flush(im))
- goto out;
-
- if (meta_writer_flush(dm))
- goto out;
-
- super->root_inode_ref = fs->root->inode_ref;
-
- meta_writer_get_position(im, &block, &offset);
- super->inode_table_start = super->bytes_used;
- super->bytes_used += block;
-
- meta_writer_get_position(dm, &block, &offset);
- super->directory_table_start = super->bytes_used;
- super->bytes_used += block;
-
- if (meta_write_write_to_file(dm))
- goto out;
-
- ret = 0;
-out:
- meta_writer_destroy(dm);
-out_im:
- meta_writer_destroy(im);
- return ret;
-}
diff --git a/lib/sqfs/sqfs_reader.c b/lib/sqfs/sqfs_reader.c
deleted file mode 100644
index 197e08f..0000000
--- a/lib/sqfs/sqfs_reader.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * sqfs_reader.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "highlevel.h"
-
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-int sqfs_reader_open(sqfs_reader_t *rd, const char *filename, int rdtree_flags)
-{
- memset(rd, 0, sizeof(*rd));
-
- rd->sqfsfd = open(filename, O_RDONLY);
- if (rd->sqfsfd < 0) {
- perror(filename);
- return -1;
- }
-
- if (sqfs_super_read(&rd->super, rd->sqfsfd))
- goto fail_fd;
-
- if (!compressor_exists(rd->super.compression_id)) {
- fprintf(stderr, "%s: unknown compressor used.\n", filename);
- goto fail_fd;
- }
-
- rd->cmp = compressor_create(rd->super.compression_id, false,
- rd->super.block_size, NULL);
- if (rd->cmp == NULL)
- goto fail_fd;
-
- if (rd->super.flags & SQFS_FLAG_COMPRESSOR_OPTIONS) {
- if (rd->cmp->read_options(rd->cmp, rd->sqfsfd))
- goto fail_cmp;
- }
-
- if (rd->super.flags & SQFS_FLAG_NO_XATTRS)
- rdtree_flags &= ~RDTREE_READ_XATTR;
-
- if (deserialize_fstree(&rd->fs, &rd->super, rd->cmp, rd->sqfsfd,
- rdtree_flags)) {
- goto fail_cmp;
- }
-
- fstree_gen_file_list(&rd->fs);
-
- rd->data = data_reader_create(rd->sqfsfd, &rd->super, rd->cmp);
- if (rd->data == NULL)
- goto fail_fs;
-
- return 0;
-fail_fs:
- fstree_cleanup(&rd->fs);
-fail_cmp:
- rd->cmp->destroy(rd->cmp);
-fail_fd:
- close(rd->sqfsfd);
- memset(rd, 0, sizeof(*rd));
- return -1;
-}
-
-void sqfs_reader_close(sqfs_reader_t *rd)
-{
- data_reader_destroy(rd->data);
- fstree_cleanup(&rd->fs);
- rd->cmp->destroy(rd->cmp);
- close(rd->sqfsfd);
- memset(rd, 0, sizeof(*rd));
-}
diff --git a/lib/sqfs/statistics.c b/lib/sqfs/statistics.c
deleted file mode 100644
index 33ff7cb..0000000
--- a/lib/sqfs/statistics.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * statistics.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-#include "highlevel.h"
-
-#include <stdio.h>
-
-void sqfs_print_statistics(fstree_t *fs, sqfs_super_t *super)
-{
- size_t blocks_written = 0, duplicate_blocks = 0, sparse_blocks = 0;
- size_t ratio, file_count = 0, file_dup_count = 0;
- size_t frag_count = 0, frag_dup = 0;
- size_t i, num_blocks, sparse;
- uint64_t output_bytes = 0;
- uint64_t input_bytes = 0;
- file_info_t *fi;
- bool is_dupe;
-
- for (fi = fs->files; fi != NULL; fi = fi->next) {
- num_blocks = fi->size / fs->block_size;
- is_dupe = true;
-
- if ((fi->size % fs->block_size) &&
- !(fi->flags & FILE_FLAG_HAS_FRAGMENT)) {
- ++num_blocks;
- }
-
- for (sparse = 0, i = 0; i < num_blocks; ++i) {
- if (fi->blocks[i].size == 0)
- sparse += 1;
- }
-
- if (num_blocks > sparse) {
- if (fi->flags & FILE_FLAG_BLOCKS_ARE_DUPLICATE) {
- duplicate_blocks += num_blocks - sparse;
- } else {
- blocks_written += num_blocks - sparse;
- is_dupe = false;
- }
- }
-
- if (fi->flags & FILE_FLAG_HAS_FRAGMENT) {
- if (fi->flags & FILE_FLAG_FRAGMENT_IS_DUPLICATE) {
- frag_dup += 1;
- } else {
- frag_count += 1;
- is_dupe = false;
- }
- }
-
- if (is_dupe)
- file_dup_count += 1;
-
- sparse_blocks += sparse;
- file_count += 1;
- input_bytes += fi->size;
- }
-
- if (input_bytes > 0) {
- output_bytes = super->inode_table_start - sizeof(*super);
- ratio = (100 * output_bytes) / input_bytes;
- } else {
- ratio = 100;
- }
-
- fputs("---------------------------------------------------\n", stdout);
- printf("Input files processed: %zu\n", file_count);
- printf("Files that were complete duplicates: %zu\n", file_dup_count);
- printf("Data blocks actually written: %zu\n", blocks_written);
- printf("Fragment blocks written: %u\n", super->fragment_entry_count);
- printf("Duplicate data blocks omitted: %zu\n", duplicate_blocks);
- printf("Sparse blocks omitted: %zu\n", sparse_blocks);
- printf("Fragments actually written: %zu\n", frag_count);
- printf("Duplicated fragments omitted: %zu\n", frag_dup);
- printf("Total number of inodes: %u\n", super->inode_count);
- printf("Number of unique group/user IDs: %u\n", super->id_count);
- printf("Data compression ratio: %zu%%\n", ratio);
-}
diff --git a/lib/sqfs/tree_node_from_inode.c b/lib/sqfs/tree_node_from_inode.c
deleted file mode 100644
index 582399c..0000000
--- a/lib/sqfs/tree_node_from_inode.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * tree_node_from_inode.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "highlevel.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-static size_t compute_size(sqfs_inode_generic_t *inode, const char *name,
- size_t block_size)
-{
- size_t size = sizeof(tree_node_t) + strlen(name) + 1;
- size_t block_count = 0;
-
- switch (inode->base.type) {
- case SQFS_INODE_DIR:
- case SQFS_INODE_EXT_DIR:
- size += sizeof(dir_info_t);
- break;
- case SQFS_INODE_FILE:
- size += sizeof(file_info_t);
- block_count = inode->data.file.file_size / block_size;
- if ((inode->data.file.file_size % block_size) != 0)
- ++block_count;
- break;
- case SQFS_INODE_EXT_FILE:
- size += sizeof(file_info_t);
- block_count = inode->data.file_ext.file_size / block_size;
- if ((inode->data.file_ext.file_size % block_size) != 0)
- ++block_count;
- break;
- case SQFS_INODE_SLINK:
- case SQFS_INODE_EXT_SLINK:
- size += strlen(inode->slink_target) + 1;
- break;
- default:
- break;
- }
-
- return size + block_count * sizeof(((file_info_t *)0)->blocks[0]);
-}
-
-static void copy_block_sizes(sqfs_inode_generic_t *inode, tree_node_t *out,
- size_t block_size)
-{
- size_t i, block_count = out->data.file->size / block_size;
-
- if ((out->data.file->size % block_size) != 0) {
- if (out->data.file->fragment == 0xFFFFFFFF ||
- out->data.file->fragment_offset == 0xFFFFFFFF) {
- ++block_count;
- } else {
- out->data.file->flags |= FILE_FLAG_HAS_FRAGMENT;
- }
- }
-
- out->name += block_count * sizeof(out->data.file->blocks[0]);
-
- for (i = 0; i < block_count; ++i)
- out->data.file->blocks[i].size = inode->block_sizes[i];
-}
-
-tree_node_t *tree_node_from_inode(sqfs_inode_generic_t *inode,
- const id_table_t *idtbl,
- const char *name,
- size_t block_size)
-{
- tree_node_t *out;
-
- if (inode->base.uid_idx >= idtbl->num_ids) {
- fputs("converting inode to fs tree node: UID out of range\n",
- stderr);
- return NULL;
- }
-
- if (inode->base.gid_idx >= idtbl->num_ids) {
- fputs("converting inode to fs tree node: GID out of range\n",
- stderr);
- return NULL;
- }
-
- out = calloc(1, compute_size(inode, name, block_size));
- if (out == NULL) {
- perror("converting inode to fs tree node");
- return NULL;
- }
-
- out->uid = idtbl->ids[inode->base.uid_idx];
- out->gid = idtbl->ids[inode->base.gid_idx];
- out->mode = inode->base.mode;
- out->inode_num = inode->base.inode_number;
- out->mod_time = inode->base.mod_time;
- out->name = (char *)out->payload;
-
- switch (inode->base.type) {
- case SQFS_INODE_DIR:
- out->data.dir = (dir_info_t *)out->payload;
- out->name += sizeof(dir_info_t);
-
- out->data.dir->size = inode->data.dir.size;
- out->data.dir->start_block = inode->data.dir.start_block;
- out->data.dir->block_offset = inode->data.dir.offset;
- break;
- case SQFS_INODE_EXT_DIR:
- out->data.dir = (dir_info_t *)out->payload;
- out->name += sizeof(dir_info_t);
-
- out->data.dir->size = inode->data.dir_ext.size;
- out->data.dir->start_block = inode->data.dir_ext.start_block;
- out->data.dir->block_offset = inode->data.dir_ext.offset;
- break;
- case SQFS_INODE_FILE:
- out->data.file = (file_info_t *)out->payload;
- out->name += sizeof(file_info_t);
-
- out->data.file->size = inode->data.file.file_size;
- out->data.file->startblock = inode->data.file.blocks_start;
- out->data.file->fragment = inode->data.file.fragment_index;
- out->data.file->fragment_offset =
- inode->data.file.fragment_offset;
-
- copy_block_sizes(inode, out, block_size);
- break;
- case SQFS_INODE_EXT_FILE:
- out->data.file = (file_info_t *)out->payload;
- out->name += sizeof(file_info_t);
-
- out->data.file->size = inode->data.file_ext.file_size;
- out->data.file->sparse = inode->data.file_ext.sparse;
- out->data.file->startblock = inode->data.file_ext.blocks_start;
- out->data.file->fragment = inode->data.file_ext.fragment_idx;
- out->data.file->fragment_offset =
- inode->data.file_ext.fragment_offset;
-
- copy_block_sizes(inode, out, block_size);
- break;
- case SQFS_INODE_SLINK:
- case SQFS_INODE_EXT_SLINK:
- out->data.slink_target = (char *)out->payload;
- strcpy(out->data.slink_target, inode->slink_target);
-
- out->name = (char *)out->payload +
- strlen(inode->slink_target) + 1;
- break;
- case SQFS_INODE_BDEV:
- case SQFS_INODE_CDEV:
- out->name = (char *)out->payload;
- out->data.devno = inode->data.dev.devno;
- break;
- case SQFS_INODE_EXT_BDEV:
- case SQFS_INODE_EXT_CDEV:
- out->name = (char *)out->payload;
- out->data.devno = inode->data.dev_ext.devno;
- break;
- default:
- break;
- }
-
- strcpy(out->name, name);
- return out;
-}
diff --git a/lib/sqfs/write_dir.c b/lib/sqfs/write_dir.c
deleted file mode 100644
index 23297ad..0000000
--- a/lib/sqfs/write_dir.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * write_dir.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "meta_writer.h"
-#include "util.h"
-
-#include <assert.h>
-#include <endian.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-static int get_type(mode_t mode)
-{
- switch (mode & S_IFMT) {
- case S_IFSOCK: return SQFS_INODE_SOCKET;
- case S_IFIFO: return SQFS_INODE_FIFO;
- case S_IFLNK: return SQFS_INODE_SLINK;
- case S_IFBLK: return SQFS_INODE_BDEV;
- case S_IFCHR: return SQFS_INODE_CDEV;
- case S_IFDIR: return SQFS_INODE_DIR;
- case S_IFREG: return SQFS_INODE_FILE;
- default:
- assert(0);
- }
-}
-
-static int dir_index_grow(dir_index_t **index)
-{
- size_t size = sizeof(dir_index_t) + sizeof(idx_ref_t) * 10;
- void *new;
-
- if (*index == NULL) {
- new = calloc(1, size);
- } else {
- if ((*index)->num_nodes < (*index)->max_nodes)
- return 0;
-
- size += sizeof(idx_ref_t) * (*index)->num_nodes;
- new = realloc(*index, size);
- }
-
- if (new == NULL) {
- perror("creating directory index");
- return -1;
- }
-
- *index = new;
- (*index)->max_nodes += 10;
- return 0;
-}
-
-int meta_writer_write_dir(meta_writer_t *dm, dir_info_t *dir,
- dir_index_t **index)
-{
- size_t i, size, count;
- sqfs_dir_header_t hdr;
- sqfs_dir_entry_t ent;
- tree_node_t *c, *d;
- uint16_t *diff_u16;
- uint32_t offset;
- uint64_t block;
- int32_t diff;
-
- c = dir->children;
- dir->size = 0;
-
- meta_writer_get_position(dm, &dir->start_block, &dir->block_offset);
-
- while (c != NULL) {
- meta_writer_get_position(dm, &block, &offset);
-
- count = 0;
- size = (offset + sizeof(hdr)) % SQFS_META_BLOCK_SIZE;
-
- for (d = c; d != NULL; d = d->next) {
- if ((d->inode_ref >> 16) != (c->inode_ref >> 16))
- break;
-
- diff = d->inode_num - c->inode_num;
-
- if (diff > 32767 || diff < -32767)
- break;
-
- size += sizeof(ent) + strlen(c->name);
-
- if (count > 0 && size > SQFS_META_BLOCK_SIZE)
- break;
-
- count += 1;
- }
-
- if (count > SQFS_MAX_DIR_ENT)
- count = SQFS_MAX_DIR_ENT;
-
- if (dir_index_grow(index))
- return -1;
-
- meta_writer_get_position(dm, &block, &offset);
-
- i = (*index)->num_nodes++;
- (*index)->idx_nodes[i].node = c;
- (*index)->idx_nodes[i].block = block;
- (*index)->idx_nodes[i].index = dir->size;
-
- hdr.count = htole32(count - 1);
- hdr.start_block = htole32(c->inode_ref >> 16);
- hdr.inode_number = htole32(c->inode_num);
- dir->size += sizeof(hdr);
-
- if (meta_writer_append(dm, &hdr, sizeof(hdr)))
- return -1;
-
- d = c;
-
- for (i = 0; i < count; ++i) {
- ent.inode_diff = c->inode_num - d->inode_num;
-
- diff_u16 = (uint16_t *)&ent.inode_diff;
- *diff_u16 = htole16(*diff_u16);
-
- ent.offset = htole16(c->inode_ref & 0x0000FFFF);
- ent.type = htole16(get_type(c->mode));
- ent.size = htole16(strlen(c->name) - 1);
- dir->size += sizeof(ent) + strlen(c->name);
-
- if (meta_writer_append(dm, &ent, sizeof(ent)))
- return -1;
- if (meta_writer_append(dm, c->name, strlen(c->name)))
- return -1;
-
- c = c->next;
- }
- }
- return 0;
-}
diff --git a/lib/sqfs/write_export_table.c b/lib/sqfs/write_export_table.c
deleted file mode 100644
index e42df15..0000000
--- a/lib/sqfs/write_export_table.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * write_export_table.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "highlevel.h"
-#include "util.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-
-int write_export_table(int outfd, fstree_t *fs, sqfs_super_t *super,
- compressor_t *cmp)
-{
- uint64_t *table, start;
- size_t i, size;
- int ret;
-
- if (fs->inode_tbl_size < 1)
- return 0;
-
- table = alloc_array(sizeof(uint64_t), (fs->inode_tbl_size - 1));
-
- if (table == NULL) {
- perror("Allocating NFS export table");
- return -1;
- }
-
- for (i = 1; i < fs->inode_tbl_size; ++i) {
- if (fs->inode_table[i] == NULL) {
- table[i - 1] = htole64(0xFFFFFFFFFFFFFFFF);
- } else {
- table[i - 1] = htole64(fs->inode_table[i]->inode_ref);
- }
- }
-
- size = sizeof(uint64_t) * (fs->inode_tbl_size - 1);
- ret = sqfs_write_table(outfd, super, cmp, table, size, &start);
-
- super->export_table_start = start;
- super->flags |= SQFS_FLAG_EXPORTABLE;
- free(table);
- return ret;
-}
diff --git a/lib/sqfs/write_inode.c b/lib/sqfs/write_inode.c
deleted file mode 100644
index 1295fa9..0000000
--- a/lib/sqfs/write_inode.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * write_inode.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "meta_writer.h"
-#include "util.h"
-
-#include <assert.h>
-#include <endian.h>
-#include <stdlib.h>
-#include <string.h>
-
-static size_t hard_link_count(tree_node_t *n)
-{
- size_t count;
-
- if (S_ISDIR(n->mode)) {
- count = 2;
-
- for (n = n->data.dir->children; n != NULL; n = n->next)
- ++count;
-
- return count;
- }
-
- return 1;
-}
-
-static int get_type(tree_node_t *node)
-{
- switch (node->mode & S_IFMT) {
- case S_IFSOCK:
- if (node->xattr != NULL)
- return SQFS_INODE_EXT_SOCKET;
- return SQFS_INODE_SOCKET;
- case S_IFIFO:
- if (node->xattr != NULL)
- return SQFS_INODE_EXT_FIFO;
- return SQFS_INODE_FIFO;
- case S_IFLNK:
- if (node->xattr != NULL)
- return SQFS_INODE_EXT_SLINK;
- return SQFS_INODE_SLINK;
- case S_IFBLK:
- if (node->xattr != NULL)
- return SQFS_INODE_EXT_BDEV;
- return SQFS_INODE_BDEV;
- case S_IFCHR:
- if (node->xattr != NULL)
- return SQFS_INODE_EXT_CDEV;
- return SQFS_INODE_CDEV;
- case S_IFREG: {
- file_info_t *fi = node->data.file;
-
- if (node->xattr != NULL || fi->sparse > 0)
- return SQFS_INODE_EXT_FILE;
-
- if (fi->startblock > 0xFFFFFFFFUL || fi->size > 0xFFFFFFFFUL)
- return SQFS_INODE_EXT_FILE;
-
- if (hard_link_count(node) > 1)
- return SQFS_INODE_EXT_FILE;
-
- return SQFS_INODE_FILE;
- }
- case S_IFDIR: {
- dir_info_t *di = node->data.dir;
-
- if (node->xattr != NULL)
- return SQFS_INODE_EXT_DIR;
-
- if (di->start_block > 0xFFFFFFFFUL || di->size > 0xFFFF)
- return SQFS_INODE_EXT_DIR;
-
- return SQFS_INODE_DIR;
- }
- }
- assert(0);
-}
-
-static int write_file_blocks(fstree_t *fs, file_info_t *fi, meta_writer_t *im)
-{
- uint64_t i, count = fi->size / fs->block_size;
- uint32_t bs;
-
- if ((fi->size % fs->block_size) != 0 &&
- !(fi->flags & FILE_FLAG_HAS_FRAGMENT)) {
- ++count;
- }
-
- for (i = 0; i < count; ++i) {
- bs = htole32(fi->blocks[i].size);
-
- if (meta_writer_append(im, &bs, sizeof(bs)))
- return -1;
- }
- return 0;
-}
-
-static int write_dir_index(dir_index_t *diridx, meta_writer_t *im)
-{
- sqfs_dir_index_t idx;
- size_t i;
-
- for (i = 0; i < diridx->num_nodes; ++i) {
- idx.start_block = htole32(diridx->idx_nodes[i].block);
- idx.index = htole32(diridx->idx_nodes[i].index);
- idx.size = strlen(diridx->idx_nodes[i].node->name) - 1;
- idx.size = htole32(idx.size);
-
- if (meta_writer_append(im, &idx, sizeof(idx)))
- return -1;
-
- if (meta_writer_append(im, diridx->idx_nodes[i].node->name,
- le32toh(idx.size) + 1)) {
- return -1;
- }
- }
- return 0;
-}
-
-int meta_writer_write_inode(fstree_t *fs, id_table_t *idtbl, meta_writer_t *im,
- meta_writer_t *dm, tree_node_t *node)
-{
- dir_index_t *diridx = NULL;
- uint16_t uid_idx, gid_idx;
- sqfs_inode_t base;
- uint32_t offset;
- uint64_t block;
-
- if (id_table_id_to_index(idtbl, node->uid, &uid_idx))
- return -1;
-
- if (id_table_id_to_index(idtbl, node->gid, &gid_idx))
- return -1;
-
- meta_writer_get_position(im, &block, &offset);
- node->inode_ref = (block << 16) | offset;
-
- if (S_ISDIR(node->mode)) {
- if (meta_writer_write_dir(dm, node->data.dir, &diridx))
- return -1;
- }
-
- base.type = htole16(get_type(node));
- base.mode = htole16(node->mode);
- base.uid_idx = htole16(uid_idx);
- base.gid_idx = htole16(gid_idx);
- base.mod_time = htole32(node->mod_time);
- base.inode_number = htole32(node->inode_num);
-
- if (meta_writer_append(im, &base, sizeof(base))) {
- free(diridx);
- return -1;
- }
-
- switch (le16toh(base.type)) {
- case SQFS_INODE_FIFO:
- case SQFS_INODE_SOCKET: {
- sqfs_inode_ipc_t ipc = {
- .nlink = htole32(hard_link_count(node)),
- };
-
- return meta_writer_append(im, &ipc, sizeof(ipc));
- }
- case SQFS_INODE_EXT_FIFO:
- case SQFS_INODE_EXT_SOCKET: {
- sqfs_inode_ipc_ext_t ipc = {
- .nlink = htole32(hard_link_count(node)),
- .xattr_idx = htole32(0xFFFFFFFF),
- };
-
- if (node->xattr != NULL)
- ipc.xattr_idx = htole32(node->xattr->index);
-
- return meta_writer_append(im, &ipc, sizeof(ipc));
- }
- case SQFS_INODE_SLINK: {
- sqfs_inode_slink_t slink = {
- .nlink = htole32(hard_link_count(node)),
- .target_size = htole32(strlen(node->data.slink_target)),
- };
-
- if (meta_writer_append(im, &slink, sizeof(slink)))
- return -1;
- if (meta_writer_append(im, node->data.slink_target,
- le32toh(slink.target_size))) {
- return -1;
- }
- break;
- }
- case SQFS_INODE_EXT_SLINK: {
- sqfs_inode_slink_t slink = {
- .nlink = htole32(hard_link_count(node)),
- .target_size = htole32(strlen(node->data.slink_target)),
- };
- uint32_t xattr = htole32(0xFFFFFFFF);
-
- if (node->xattr != NULL)
- xattr = htole32(node->xattr->index);
-
- if (meta_writer_append(im, &slink, sizeof(slink)))
- return -1;
- if (meta_writer_append(im, node->data.slink_target,
- le32toh(slink.target_size))) {
- return -1;
- }
- if (meta_writer_append(im, &xattr, sizeof(xattr)))
- return -1;
- break;
- }
- case SQFS_INODE_BDEV:
- case SQFS_INODE_CDEV: {
- sqfs_inode_dev_t dev = {
- .nlink = htole32(hard_link_count(node)),
- .devno = htole32(node->data.devno),
- };
-
- return meta_writer_append(im, &dev, sizeof(dev));
- }
- case SQFS_INODE_EXT_BDEV:
- case SQFS_INODE_EXT_CDEV: {
- sqfs_inode_dev_ext_t dev = {
- .nlink = htole32(hard_link_count(node)),
- .devno = htole32(node->data.devno),
- .xattr_idx = htole32(0xFFFFFFFF),
- };
-
- if (node->xattr != NULL)
- dev.xattr_idx = htole32(node->xattr->index);
-
- return meta_writer_append(im, &dev, sizeof(dev));
- }
- case SQFS_INODE_EXT_FILE: {
- file_info_t *fi = node->data.file;
- sqfs_inode_file_ext_t ext = {
- .blocks_start = htole64(fi->startblock),
- .file_size = htole64(fi->size),
- .sparse = htole64(fi->sparse),
- .nlink = htole32(hard_link_count(node)),
- .fragment_idx = htole32(0xFFFFFFFF),
- .fragment_offset = htole32(0xFFFFFFFF),
- .xattr_idx = htole32(0xFFFFFFFF),
- };
-
- if ((fi->size % fs->block_size) != 0) {
- ext.fragment_idx = htole32(fi->fragment);
- ext.fragment_offset = htole32(fi->fragment_offset);
- }
-
- if (node->xattr != NULL)
- ext.xattr_idx = htole32(node->xattr->index);
-
- if (meta_writer_append(im, &ext, sizeof(ext)))
- return -1;
- return write_file_blocks(fs, fi, im);
- }
- case SQFS_INODE_FILE: {
- file_info_t *fi = node->data.file;
- sqfs_inode_file_t reg = {
- .blocks_start = htole32(fi->startblock),
- .fragment_index = htole32(0xFFFFFFFF),
- .fragment_offset = htole32(0xFFFFFFFF),
- .file_size = htole32(fi->size),
- };
-
- if ((fi->size % fs->block_size) != 0) {
- reg.fragment_index = htole32(fi->fragment);
- reg.fragment_offset = htole32(fi->fragment_offset);
- }
-
- if (meta_writer_append(im, &reg, sizeof(reg)))
- return -1;
- return write_file_blocks(fs, fi, im);
- }
- case SQFS_INODE_DIR: {
- sqfs_inode_dir_t dir = {
- .start_block = htole32(node->data.dir->start_block),
- .nlink = htole32(hard_link_count(node)),
- .size = htole16(node->data.dir->size),
- .offset = htole16(node->data.dir->block_offset),
- .parent_inode = node->parent ?
- htole32(node->parent->inode_num) : htole32(1),
- };
-
- return meta_writer_append(im, &dir, sizeof(dir));
- }
- case SQFS_INODE_EXT_DIR: {
- sqfs_inode_dir_ext_t ext = {
- .nlink = htole32(hard_link_count(node)),
- .size = htole32(node->data.dir->size),
- .start_block = htole32(node->data.dir->start_block),
- .parent_inode = node->parent ?
- htole32(node->parent->inode_num) : htole32(1),
- .inodex_count = htole32(0),
- .offset = htole16(node->data.dir->block_offset),
- .xattr_idx = htole32(0xFFFFFFFF),
- };
-
- if (node->xattr != NULL)
- ext.xattr_idx = htole32(node->xattr->index);
-
- if (diridx != NULL)
- ext.inodex_count = htole32(diridx->num_nodes - 1);
-
- if (meta_writer_append(im, &ext, sizeof(ext))) {
- free(diridx);
- return -1;
- }
-
- if (diridx != NULL && write_dir_index(diridx, im) != 0) {
- free(diridx);
- return -1;
- }
-
- free(diridx);
- break;
- }
- default:
- assert(0);
- }
- return 0;
-}
diff --git a/lib/sqfs/write_xattr.c b/lib/sqfs/write_xattr.c
deleted file mode 100644
index 2263fbe..0000000
--- a/lib/sqfs/write_xattr.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * write_xattr.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "meta_writer.h"
-#include "highlevel.h"
-#include "util.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-static int write_key(meta_writer_t *mw, const char *key, tree_xattr_t *xattr,
- bool value_is_ool)
-{
- sqfs_xattr_entry_t kent;
- int type;
-
- type = sqfs_get_xattr_prefix_id(key);
- if (type < 0) {
- fprintf(stderr, "unsupported xattr key '%s'\n", key);
- return -1;
- }
-
- key = strchr(key, '.');
- assert(key != NULL);
- ++key;
-
- if (value_is_ool)
- type |= SQUASHFS_XATTR_FLAG_OOL;
-
- kent.type = htole16(type);
- kent.size = htole16(strlen(key));
-
- if (meta_writer_append(mw, &kent, sizeof(kent)))
- return -1;
- if (meta_writer_append(mw, key, strlen(key)))
- return -1;
-
- xattr->size += sizeof(sqfs_xattr_entry_t) + strlen(key);
- return 0;
-}
-
-static int write_value(meta_writer_t *mw, const char *value,
- tree_xattr_t *xattr, uint64_t *value_ref_out)
-{
- sqfs_xattr_value_t vent;
- uint32_t offset;
- uint64_t block;
-
- meta_writer_get_position(mw, &block, &offset);
- *value_ref_out = (block << 16) | (offset & 0xFFFF);
-
- vent.size = htole32(strlen(value));
-
- if (meta_writer_append(mw, &vent, sizeof(vent)))
- return -1;
-
- if (meta_writer_append(mw, value, strlen(value)))
- return -1;
-
- xattr->size += sizeof(vent) + strlen(value);
- return 0;
-}
-
-static int write_value_ool(meta_writer_t *mw, uint64_t location,
- tree_xattr_t *xattr)
-{
- sqfs_xattr_value_t vent;
- uint64_t ref;
-
- vent.size = htole32(sizeof(location));
- if (meta_writer_append(mw, &vent, sizeof(vent)))
- return -1;
-
- ref = htole64(location);
- if (meta_writer_append(mw, &ref, sizeof(ref)))
- return -1;
-
- xattr->size += sizeof(vent) + sizeof(ref);
- return 0;
-}
-
-static bool should_store_ool(fstree_t *fs, const char *value, size_t index)
-{
- size_t refcount;
-
- refcount = str_table_get_ref_count(&fs->xattr_values, index);
- if (refcount < 2)
- return false;
-
- /*
- Storing in line needs this many bytes: refcount * len
-
- Storing out-of-line needs this many: len + (refcount - 1) * 8
-
- Out-of-line prefereable if:
- refcount * len > len + (refcount - 1) * 8
- => refcount * len - len > (refcount - 1) * 8
- => (refcount - 1) * len > (refcount - 1) * 8
- => len > 8
-
- Note that this only holds iff refcount - 1 != 0, i.e. refcount > 1,
- otherwise we would be dividing by 0 in the 3rd step.
- */
- return strlen(value) > sizeof(uint64_t);
-}
-
-static int write_kv_pairs(fstree_t *fs, meta_writer_t *mw, tree_xattr_t *xattr,
- uint64_t *ool_locations)
-{
- uint32_t key_idx, val_idx;
- const char *key, *value;
- uint64_t ref;
- size_t i;
-
- for (i = 0; i < xattr->num_attr; ++i) {
- key_idx = xattr->attr[i].key_index;
- val_idx = xattr->attr[i].value_index;
-
- key = str_table_get_string(&fs->xattr_keys, key_idx);
- value = str_table_get_string(&fs->xattr_values, val_idx);
-
- if (ool_locations[val_idx] == 0xFFFFFFFFFFFFFFFF) {
- if (write_key(mw, key, xattr, false))
- return -1;
-
- if (write_value(mw, value, xattr, &ref))
- return -1;
-
- if (should_store_ool(fs, value, val_idx))
- ool_locations[val_idx] = ref;
- } else {
- if (write_key(mw, key, xattr, true))
- return -1;
-
- if (write_value_ool(mw, ool_locations[val_idx], xattr))
- return -1;
- }
- }
-
- return 0;
-}
-
-static uint64_t *create_ool_locations_table(fstree_t *fs)
-{
- uint64_t *table;
- size_t i;
-
- table = alloc_array(sizeof(uint64_t), fs->xattr_values.num_strings);
-
- if (table == NULL) {
- perror("allocating Xattr OOL locations table");
- return NULL;
- }
-
- for (i = 0; i < fs->xattr_values.num_strings; ++i) {
- table[i] = 0xFFFFFFFFFFFFFFFFUL;
- }
-
- return table;
-}
-
-int write_xattr(int outfd, fstree_t *fs, sqfs_super_t *super,
- compressor_t *cmp)
-{
- uint64_t kv_start, id_start, block, *tbl, *ool_locations;
- size_t i = 0, count = 0, blocks;
- sqfs_xattr_id_table_t idtbl;
- sqfs_xattr_id_t id_ent;
- meta_writer_t *mw;
- tree_xattr_t *it;
- uint32_t offset;
-
- if (fs->xattr == NULL)
- return 0;
-
- ool_locations = create_ool_locations_table(fs);
- if (ool_locations == NULL)
- return -1;
-
- mw = meta_writer_create(outfd, cmp, false);
- if (mw == NULL)
- goto fail_ool;
-
- /* write xattr key-value pairs */
- kv_start = super->bytes_used;
-
- for (it = fs->xattr; it != NULL; it = it->next) {
- meta_writer_get_position(mw, &it->block, &it->offset);
- it->size = 0;
-
- if (write_kv_pairs(fs, mw, it, ool_locations))
- goto fail_mw;
-
- ++count;
- }
-
- if (meta_writer_flush(mw))
- goto fail_mw;
-
- meta_writer_get_position(mw, &block, &offset);
- meta_writer_reset(mw);
-
- super->bytes_used += block;
-
- /* allocate location table */
- blocks = (count * sizeof(id_ent)) / SQFS_META_BLOCK_SIZE;
-
- if ((count * sizeof(id_ent)) % SQFS_META_BLOCK_SIZE)
- ++blocks;
-
- tbl = alloc_array(sizeof(uint64_t), blocks);
-
- if (tbl == NULL) {
- perror("generating xattr ID table");
- goto fail_mw;
- }
-
- /* write ID table referring to key value pairs, record offsets */
- id_start = 0;
- tbl[i++] = htole64(super->bytes_used);
-
- for (it = fs->xattr; it != NULL; it = it->next) {
- id_ent.xattr = htole64((it->block << 16) | it->offset);
- id_ent.count = htole32(it->num_attr);
- id_ent.size = htole32(it->size);
-
- if (meta_writer_append(mw, &id_ent, sizeof(id_ent)))
- goto fail_tbl;
-
- meta_writer_get_position(mw, &block, &offset);
-
- if (block != id_start) {
- id_start = block;
- tbl[i++] = htole64(super->bytes_used + id_start);
- }
- }
-
- if (meta_writer_flush(mw))
- goto fail_tbl;
-
- meta_writer_get_position(mw, &block, &offset);
- super->bytes_used += block;
-
- /* write offset table */
- idtbl.xattr_table_start = htole64(kv_start);
- idtbl.xattr_ids = htole32(count);
- idtbl.unused = 0;
-
- if (write_data("writing xattr ID table", outfd, &idtbl, sizeof(idtbl)))
- goto fail_tbl;
-
- if (write_data("writing xattr ID table",
- outfd, tbl, sizeof(tbl[0]) * blocks)) {
- goto fail_tbl;
- }
-
- super->xattr_id_table_start = super->bytes_used;
- super->bytes_used += sizeof(idtbl) + sizeof(tbl[0]) * blocks;
- super->flags &= ~SQFS_FLAG_NO_XATTRS;
-
- free(tbl);
- meta_writer_destroy(mw);
- free(ool_locations);
- return 0;
-fail_tbl:
- free(tbl);
-fail_mw:
- meta_writer_destroy(mw);
-fail_ool:
- free(ool_locations);
- return -1;
-}
diff --git a/lib/sqfs/xattr_reader.c b/lib/sqfs/xattr_reader.c
deleted file mode 100644
index 399940f..0000000
--- a/lib/sqfs/xattr_reader.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * xattr_reader.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "xattr_reader.h"
-#include "meta_reader.h"
-#include "util.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-struct xattr_reader_t {
- uint64_t xattr_start;
-
- size_t num_id_blocks;
- size_t num_ids;
-
- uint64_t *id_block_starts;
-
- meta_reader_t *idrd;
- meta_reader_t *kvrd;
- sqfs_super_t *super;
-};
-
-static int get_id_block_locations(xattr_reader_t *xr, int sqfsfd,
- sqfs_super_t *super)
-{
- sqfs_xattr_id_table_t idtbl;
- size_t i;
-
- if (super->xattr_id_table_start >= super->bytes_used) {
- fputs("xattr ID location table is after end of filesystem\n",
- stderr);
- return -1;
- }
-
- if (read_data_at("reading xattr ID location table",
- super->xattr_id_table_start,
- sqfsfd, &idtbl, sizeof(idtbl))) {
- return -1;
- }
-
- xr->xattr_start = le64toh(idtbl.xattr_table_start);
- xr->num_ids = le32toh(idtbl.xattr_ids);
- xr->num_id_blocks =
- (xr->num_ids * sizeof(sqfs_xattr_id_t)) / SQFS_META_BLOCK_SIZE;
-
- if ((xr->num_ids * sizeof(sqfs_xattr_id_t)) % SQFS_META_BLOCK_SIZE)
- xr->num_id_blocks += 1;
-
- xr->id_block_starts = alloc_array(sizeof(uint64_t), xr->num_id_blocks);
- if (xr->id_block_starts == NULL) {
- perror("allocating xattr ID location table");
- return -1;
- }
-
- if (read_data_at("reading xattr ID block locations",
- super->xattr_id_table_start + sizeof(idtbl),
- sqfsfd, xr->id_block_starts,
- sizeof(uint64_t) * xr->num_id_blocks)) {
- goto fail;
- }
-
- for (i = 0; i < xr->num_id_blocks; ++i) {
- xr->id_block_starts[i] = le64toh(xr->id_block_starts[i]);
-
- if (xr->id_block_starts[i] > super->bytes_used) {
- fputs("found xattr ID block that is past "
- "end of filesystem\n", stderr);
- goto fail;
- }
- }
-
- return 0;
-fail:
- free(xr->id_block_starts);
- xr->id_block_starts = NULL;
- return -1;
-}
-
-static int get_xattr_desc(xattr_reader_t *xr, uint32_t idx,
- sqfs_xattr_id_t *desc)
-{
- size_t block, offset;
-
- if (idx >= xr->num_ids) {
- fprintf(stderr, "Tried to access out of bounds "
- "xattr index: 0x%08X\n", idx);
- return -1;
- }
-
- offset = (idx * sizeof(*desc)) % SQFS_META_BLOCK_SIZE;
- block = (idx * sizeof(*desc)) / SQFS_META_BLOCK_SIZE;
-
- if (meta_reader_seek(xr->idrd, xr->id_block_starts[block], offset))
- return -1;
-
- if (meta_reader_read(xr->idrd, desc, sizeof(*desc)))
- return -1;
-
- desc->xattr = le64toh(desc->xattr);
- desc->count = le32toh(desc->count);
- desc->size = le32toh(desc->size);
-
- if ((desc->xattr & 0xFFFF) >= SQFS_META_BLOCK_SIZE) {
- fputs("Found xattr ID record pointing outside "
- "metadata block\n", stderr);
- return -1;
- }
-
- if ((xr->xattr_start + (desc->xattr >> 16)) >= xr->super->bytes_used) {
- fputs("Found xattr ID record pointing past "
- "end of filesystem\n", stderr);
- return -1;
- }
-
- return 0;
-}
-
-static sqfs_xattr_entry_t *read_key(xattr_reader_t *xr)
-{
- sqfs_xattr_entry_t key, *out;
- const char *prefix;
- size_t plen, total;
-
- if (meta_reader_read(xr->kvrd, &key, sizeof(key)))
- return NULL;
-
- key.type = le16toh(key.type);
- key.size = le16toh(key.size);
-
- prefix = sqfs_get_xattr_prefix(key.type & SQUASHFS_XATTR_PREFIX_MASK);
- if (prefix == NULL) {
- fprintf(stderr, "found unknown xattr type %u\n",
- key.type & SQUASHFS_XATTR_PREFIX_MASK);
- return NULL;
- }
-
- plen = strlen(prefix);
-
- if (SZ_ADD_OV(plen, key.size, &total) || SZ_ADD_OV(total, 1, &total) ||
- SZ_ADD_OV(sizeof(*out), total, &total)) {
- errno = EOVERFLOW;
- goto fail_alloc;
- }
-
- out = calloc(1, total);
- if (out == NULL) {
- goto fail_alloc;
- }
-
- *out = key;
- memcpy(out->key, prefix, plen);
-
- if (meta_reader_read(xr->kvrd, out->key + plen, key.size)) {
- free(out);
- return NULL;
- }
-
- return out;
-fail_alloc:
- perror("allocating xattr key");
- return NULL;
-}
-
-static sqfs_xattr_value_t *read_value(xattr_reader_t *xr,
- const sqfs_xattr_entry_t *key)
-{
- size_t offset, new_offset, size;
- sqfs_xattr_value_t value, *out;
- uint64_t ref, start, new_start;
-
- if (meta_reader_read(xr->kvrd, &value, sizeof(value)))
- return NULL;
-
- if (key->type & SQUASHFS_XATTR_FLAG_OOL) {
- if (meta_reader_read(xr->kvrd, &ref, sizeof(ref)))
- return NULL;
-
- meta_reader_get_position(xr->kvrd, &start, &offset);
-
- new_start = xr->xattr_start + (ref >> 16);
- new_offset = ref & 0xFFFF;
-
- if (new_start > xr->super->bytes_used) {
- fputs("OOL xattr reference points past end of "
- "filesystem\n", stderr);
- return NULL;
- }
-
- if (new_offset >= SQFS_META_BLOCK_SIZE) {
- fputs("OOL xattr reference points outside "
- "metadata block\n", stderr);
- return NULL;
- }
-
- if (meta_reader_seek(xr->kvrd, new_start, new_offset))
- return NULL;
- }
-
- value.size = le32toh(value.size);
-
- if (SZ_ADD_OV(sizeof(*out), value.size, &size) ||
- SZ_ADD_OV(size, 1, &size)) {
- errno = EOVERFLOW;
- goto fail_alloc;
- }
-
- out = calloc(1, size);
- if (out == NULL)
- goto fail_alloc;
-
- *out = value;
-
- if (meta_reader_read(xr->kvrd, out->value, value.size))
- goto fail;
-
- if (key->type & SQUASHFS_XATTR_FLAG_OOL) {
- if (meta_reader_seek(xr->kvrd, start, offset))
- goto fail;
- }
-
- return out;
-fail_alloc:
- perror("allocating xattr value");
- return NULL;
-fail:
- free(out);
- return NULL;
-}
-
-static int restore_kv_pairs(xattr_reader_t *xr, fstree_t *fs,
- tree_node_t *node)
-{
- size_t i, key_idx, val_idx;
- sqfs_xattr_entry_t *key;
- sqfs_xattr_value_t *val;
- int ret;
-
- if (meta_reader_seek(xr->kvrd, node->xattr->block,
- node->xattr->offset)) {
- return -1;
- }
-
- for (i = 0; i < node->xattr->num_attr; ++i) {
- key = read_key(xr);
- if (key == NULL)
- return -1;
-
- val = read_value(xr, key);
- if (val == NULL)
- goto fail_key;
-
- ret = str_table_get_index(&fs->xattr_keys,
- (const char *)key->key, &key_idx);
- if (ret)
- goto fail_kv;
-
- ret = str_table_get_index(&fs->xattr_values,
- (const char *)val->value, &val_idx);
- if (ret)
- goto fail_kv;
-
- if (sizeof(size_t) > sizeof(uint32_t)) {
- if (key_idx > 0xFFFFFFFFUL) {
- fputs("too many unique xattr keys\n", stderr);
- goto fail_kv;
- }
-
- if (val_idx > 0xFFFFFFFFUL) {
- fputs("too many unique xattr values\n", stderr);
- goto fail_kv;
- }
- }
-
- node->xattr->attr[i].key_index = key_idx;
- node->xattr->attr[i].value_index = val_idx;
-
- free(key);
- free(val);
- }
-
- return 0;
-fail_kv:
- free(val);
-fail_key:
- free(key);
- return -1;
-}
-
-int xattr_reader_restore_node(xattr_reader_t *xr, fstree_t *fs,
- tree_node_t *node, uint32_t xattr)
-{
- sqfs_xattr_id_t desc;
- tree_xattr_t *it;
-
- if (xr->kvrd == NULL || xr->idrd == NULL)
- return 0;
-
- if (xattr == 0xFFFFFFFF)
- return 0;
-
- for (it = fs->xattr; it != NULL; it = it->next) {
- if (it->index == xattr) {
- node->xattr = it;
- return 0;
- }
- }
-
- if (get_xattr_desc(xr, xattr, &desc))
- return -1;
-
- node->xattr = alloc_flex(sizeof(*node->xattr),
- sizeof(node->xattr->attr[0]), desc.count);
- if (node->xattr == NULL) {
- perror("creating xattr structure");
- return -1;
- }
-
- node->xattr->num_attr = desc.count;
- node->xattr->max_attr = desc.count;
- node->xattr->block = xr->xattr_start + (desc.xattr >> 16);
- node->xattr->offset = desc.xattr & 0xFFFF;
- node->xattr->size = desc.size;
- node->xattr->index = xattr;
- node->xattr->owner = node;
-
- if (restore_kv_pairs(xr, fs, node)) {
- free(node->xattr);
- return -1;
- }
-
- node->xattr->next = fs->xattr;
- fs->xattr = node->xattr;
- return 0;
-}
-
-void xattr_reader_destroy(xattr_reader_t *xr)
-{
- if (xr->kvrd != NULL)
- meta_reader_destroy(xr->kvrd);
-
- if (xr->idrd != NULL)
- meta_reader_destroy(xr->idrd);
-
- free(xr->id_block_starts);
- free(xr);
-}
-
-xattr_reader_t *xattr_reader_create(int sqfsfd, sqfs_super_t *super,
- compressor_t *cmp)
-{
- xattr_reader_t *xr = calloc(1, sizeof(*xr));
-
- if (xr == NULL) {
- perror("creating xattr reader");
- return NULL;
- }
-
- if (super->flags & SQFS_FLAG_NO_XATTRS)
- return xr;
-
- if (super->xattr_id_table_start == 0xFFFFFFFFFFFFFFFF)
- return xr;
-
- if (get_id_block_locations(xr, sqfsfd, super))
- goto fail;
-
- xr->idrd = meta_reader_create(sqfsfd, cmp,
- super->id_table_start,
- super->bytes_used);
- if (xr->idrd == NULL)
- goto fail;
-
- xr->kvrd = meta_reader_create(sqfsfd, cmp,
- super->id_table_start,
- super->bytes_used);
- if (xr->kvrd == NULL)
- goto fail;
-
- xr->super = super;
- return xr;
-fail:
- xattr_reader_destroy(xr);
- return NULL;
-}