summaryrefslogtreecommitdiff
path: root/mkfs
diff options
context:
space:
mode:
Diffstat (limited to 'mkfs')
-rw-r--r--mkfs/meta.c105
1 files changed, 99 insertions, 6 deletions
diff --git a/mkfs/meta.c b/mkfs/meta.c
index f7de5c6..4513733 100644
--- a/mkfs/meta.c
+++ b/mkfs/meta.c
@@ -6,6 +6,43 @@
#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 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;
+}
+
static size_t hard_link_count(tree_node_t *n)
{
size_t count;
@@ -22,12 +59,12 @@ static size_t hard_link_count(tree_node_t *n)
return 1;
}
-static int write_dir(meta_writer_t *dm, dir_info_t *dir)
+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;
- size_t i, count;
c = dir->children;
dir->size = 0;
@@ -37,18 +74,40 @@ static int write_dir(meta_writer_t *dm, dir_info_t *dir)
while (c != NULL) {
count = 0;
+ size = dm->offset;
for (d = c; d != NULL; d = d->next) {
if ((d->inode_ref >> 16) != (c->inode_ref >> 16))
break;
if ((d->inode_num - c->inode_num) > 0xFFFF)
break;
+
+ size += sizeof(ent) + strlen(c->name);
+
+ if (size > SQFS_META_BLOCK_SIZE) {
+ if (count > 0) {
+ break;
+ } else {
+ size %= SQFS_META_BLOCK_SIZE;
+ }
+ }
+
count += 1;
}
if (count > SQFS_MAX_DIR_ENT)
count = SQFS_MAX_DIR_ENT;
+ if (index != NULL) {
+ if (dir_index_grow(index))
+ return -1;
+
+ i = (*index)->num_nodes++;
+ (*index)->idx_nodes[i].node = c;
+ (*index)->idx_nodes[i].block = dm->block_offset;
+ (*index)->idx_nodes[i].offset = dm->offset;
+ }
+
hdr.count = htole32(count - 1);
hdr.start_block = htole32(c->inode_ref >> 16);
hdr.inode_number = htole32(c->inode_num);
@@ -80,6 +139,7 @@ static int write_dir(meta_writer_t *dm, dir_info_t *dir)
static int write_inode(sqfs_info_t *info, meta_writer_t *im, meta_writer_t *dm,
tree_node_t *node)
{
+ dir_index_t *diridx = NULL;
uint16_t uid_idx, gid_idx;
file_info_t *fi = NULL;
dir_info_t *di = NULL;
@@ -108,11 +168,14 @@ static int write_inode(sqfs_info_t *info, meta_writer_t *im, meta_writer_t *dm,
di = node->data.dir;
node->type = SQFS_INODE_DIR;
- if (write_dir(dm, di))
+ if (write_dir(dm, di, &diridx))
return -1;
if ((di->start_block) > 0xFFFFFFFFUL || di->size > 0xFFFF) {
node->type = SQFS_INODE_EXT_DIR;
+ } else {
+ free(diridx);
+ diridx = NULL;
}
break;
case S_IFREG:
@@ -135,8 +198,10 @@ static int write_inode(sqfs_info_t *info, meta_writer_t *im, meta_writer_t *dm,
base.mod_time = htole32(info->opt.def_mtime);
base.inode_number = htole32(node->inode_num);
- if (meta_writer_append(im, &base, sizeof(base)))
+ if (meta_writer_append(im, &base, sizeof(base))) {
+ free(diridx);
return -1;
+ }
switch (node->type) {
case SQFS_INODE_FIFO:
@@ -210,18 +275,46 @@ static int write_inode(sqfs_info_t *info, meta_writer_t *im, meta_writer_t *dm,
return meta_writer_append(im, &dir, sizeof(dir));
}
case SQFS_INODE_EXT_DIR: {
+ sqfs_dir_index_t idx;
+ size_t i;
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),
+ .inodex_count = htole32(diridx->num_nodes - 1),
.offset = htole16(node->data.dir->block_offset),
.xattr_idx = htole32(0xFFFFFFFF),
};
- return meta_writer_append(im, &ext, sizeof(ext));
+ if (meta_writer_append(im, &ext, sizeof(ext))) {
+ free(diridx);
+ return -1;
+ }
+
+ for (i = 0; i < diridx->num_nodes; ++i) {
+ idx.index = htole32(diridx->idx_nodes[i].offset);
+ idx.start_block = htole32(diridx->idx_nodes[i].block);
+
+ idx.size = strlen(diridx->idx_nodes[i].node->name) - 1;
+ idx.size = htole32(idx.size);
+
+ if (meta_writer_append(im, &idx, sizeof(idx))) {
+ free(diridx);
+ return -1;
+ }
+
+ if (meta_writer_append(im,
+ diridx->idx_nodes[i].node->name,
+ le32toh(idx.size) + 1)) {
+ free(diridx);
+ return -1;
+ }
+ }
+
+ free(diridx);
+ break;
}
default:
assert(0);