diff options
-rw-r--r-- | mkfs/Makemodule.am | 1 | ||||
-rw-r--r-- | mkfs/meta.c | 140 | ||||
-rw-r--r-- | mkfs/mkfs.h | 15 | ||||
-rw-r--r-- | mkfs/write_dir.c | 123 |
4 files changed, 154 insertions, 125 deletions
diff --git a/mkfs/Makemodule.am b/mkfs/Makemodule.am index 31340d1..8691fd7 100644 --- a/mkfs/Makemodule.am +++ b/mkfs/Makemodule.am @@ -1,5 +1,6 @@ gensquashfs_SOURCES = mkfs/mkfs.c mkfs/mkfs.h mkfs/block.c gensquashfs_SOURCES += mkfs/options.c mkfs/meta.c mkfs/xattr.c +gensquashfs_SOURCES += mkfs/write_dir.c gensquashfs_LDADD = libsquashfs.a libfstree.a libcompress.a libutil.a gensquashfs_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/mkfs/meta.c b/mkfs/meta.c index 8f344ef..1510524 100644 --- a/mkfs/meta.c +++ b/mkfs/meta.c @@ -6,56 +6,26 @@ #include <assert.h> #include <endian.h> -typedef struct { - tree_node_t *node; - uint32_t block; - uint32_t offset; -} idx_ref_t; - -typedef struct { - size_t num_nodes; - size_t max_nodes; - idx_ref_t idx_nodes[]; -} dir_index_t; - -static int get_type(mode_t mode) +static int get_type(tree_node_t *node) { - 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; + int type; + + switch (node->mode & S_IFMT) { + case S_IFSOCK: type = SQFS_INODE_SOCKET; break; + case S_IFIFO: type = SQFS_INODE_FIFO; break; + case S_IFLNK: type = SQFS_INODE_SLINK; break; + case S_IFBLK: type = SQFS_INODE_BDEV; break; + case S_IFCHR: type = SQFS_INODE_CDEV; break; + case S_IFDIR: type = SQFS_INODE_DIR; break; + case S_IFREG: type = SQFS_INODE_FILE; break; 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; - } + if (node->xattr != NULL) + type = SQFS_INODE_EXT_TYPE(type); - *index = new; - (*index)->max_nodes += 10; - return 0; + return type; } static size_t hard_link_count(tree_node_t *n) @@ -74,83 +44,6 @@ static size_t hard_link_count(tree_node_t *n) return 1; } -static int 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; - uint32_t offset; - uint64_t block; - - 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; - - /* XXX: difference is actually signed */ - if ((d->inode_num - c->inode_num) > 0x7FFF) - 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].offset = offset; - - 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.offset = htole16(c->inode_ref & 0x0000FFFF); - ent.inode_number = htole16(c->inode_num - d->inode_num); - 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; -} - static int write_inode(sqfs_info_t *info, meta_writer_t *im, meta_writer_t *dm, tree_node_t *node) { @@ -175,10 +68,7 @@ static int write_inode(sqfs_info_t *info, meta_writer_t *im, meta_writer_t *dm, info->super.inode_count += 1; - type = get_type(node->mode); - - if (node->xattr != NULL) - type = SQFS_INODE_EXT_TYPE(type); + type = get_type(node); if (S_ISDIR(node->mode)) { di = node->data.dir; diff --git a/mkfs/mkfs.h b/mkfs/mkfs.h index c73b74e..15d349e 100644 --- a/mkfs/mkfs.h +++ b/mkfs/mkfs.h @@ -2,6 +2,7 @@ #ifndef MKFS_H #define MKFS_H +#include "meta_writer.h" #include "squashfs.h" #include "compress.h" #include "id_table.h" @@ -18,6 +19,18 @@ #include <errno.h> typedef struct { + tree_node_t *node; + uint32_t block; + uint32_t offset; +} idx_ref_t; + +typedef struct { + size_t num_nodes; + size_t max_nodes; + idx_ref_t idx_nodes[]; +} dir_index_t; + +typedef struct { unsigned int def_uid; unsigned int def_gid; unsigned int def_mode; @@ -65,4 +78,6 @@ int sqfs_write_inodes(sqfs_info_t *info); int write_xattr(sqfs_info_t *info); +int write_dir(meta_writer_t *dm, dir_info_t *dir, dir_index_t **index); + #endif /* MKFS_H */ diff --git a/mkfs/write_dir.c b/mkfs/write_dir.c new file mode 100644 index 0000000..c8afb9b --- /dev/null +++ b/mkfs/write_dir.c @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +#include "mkfs.h" +#include "util.h" + +#include <assert.h> +#include <endian.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 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; + uint32_t offset; + uint64_t block; + + 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; + + /* XXX: difference is actually signed */ + if ((d->inode_num - c->inode_num) > 0x7FFF) + 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].offset = offset; + + 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.offset = htole16(c->inode_ref & 0x0000FFFF); + ent.inode_number = htole16(c->inode_num - d->inode_num); + 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; +} |