summaryrefslogtreecommitdiff
path: root/lib/sqfs/dir_writer.c
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-12-15 15:52:01 +0100
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-12-16 14:46:24 +0100
commit5e2298a3a3f00e6f55ceda2b1c35192d67c9feb4 (patch)
treeaf7dbe9fa5354a078b3a1dd453f15b8ef4e424ae /lib/sqfs/dir_writer.c
parent9e2f960007887ea47fe273736f006569fc24df6d (diff)
Add ability to sqfs_dir_writer to create an export table
If the dir writer is used to create the directory table, it neccessarily sees every single inode number and coresponding location for all inodes that are referenced by the filesystem tree. This means it can easily collect that information internally to create an export table later on. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs/dir_writer.c')
-rw-r--r--lib/sqfs/dir_writer.c111
1 files changed, 107 insertions, 4 deletions
diff --git a/lib/sqfs/dir_writer.c b/lib/sqfs/dir_writer.c
index bdd5dd1..78256a1 100644
--- a/lib/sqfs/dir_writer.c
+++ b/lib/sqfs/dir_writer.c
@@ -9,6 +9,8 @@
#include "sqfs/meta_writer.h"
#include "sqfs/dir_writer.h"
+#include "sqfs/super.h"
+#include "sqfs/table.h"
#include "sqfs/inode.h"
#include "sqfs/error.h"
#include "sqfs/block.h"
@@ -45,6 +47,10 @@ struct sqfs_dir_writer_t {
size_t dir_size;
size_t ent_count;
sqfs_meta_writer_t *dm;
+
+ sqfs_u64 *export_tbl;
+ size_t export_tbl_max;
+ size_t export_tbl_count;
};
static int get_type(sqfs_u16 mode)
@@ -86,13 +92,76 @@ static void writer_reset(sqfs_dir_writer_t *writer)
writer->ent_count = 0;
}
-sqfs_dir_writer_t *sqfs_dir_writer_create(sqfs_meta_writer_t *dm)
+static int add_export_table_entry(sqfs_dir_writer_t *writer,
+ sqfs_u32 inum, sqfs_u64 iref)
+{
+ size_t i, new_max;
+ sqfs_u64 *new;
+
+ if (writer->export_tbl == NULL)
+ return 0;
+
+ if (inum < 1)
+ return SQFS_ERROR_ARG_INVALID;
+
+ new_max = writer->export_tbl_max;
+
+ while ((inum - 1) >= new_max) {
+ if (SZ_MUL_OV(new_max, 2, &new_max))
+ return SQFS_ERROR_ALLOC;
+ }
+
+ if (new_max > writer->export_tbl_max) {
+ if (SZ_MUL_OV(new_max, sizeof(writer->export_tbl[0]), &new_max))
+ return SQFS_ERROR_ALLOC;
+
+ new = realloc(writer->export_tbl, new_max);
+ if (new == NULL)
+ return SQFS_ERROR_ALLOC;
+
+ new_max /= sizeof(writer->export_tbl[0]);
+
+ for (i = writer->export_tbl_max; i < new_max; ++i)
+ new[i] = 0xFFFFFFFFFFFFFFFFUL;
+
+ writer->export_tbl = new;
+ writer->export_tbl_max = new_max;
+ }
+
+ writer->export_tbl[inum - 1] = iref;
+
+ if ((inum - 1) >= writer->export_tbl_count)
+ writer->export_tbl_count = inum;
+
+ return 0;
+}
+
+sqfs_dir_writer_t *sqfs_dir_writer_create(sqfs_meta_writer_t *dm,
+ sqfs_u32 flags)
{
- sqfs_dir_writer_t *writer = calloc(1, sizeof(*writer));
+ sqfs_dir_writer_t *writer;
+ if (flags & ~SQFS_DIR_WRITER_CREATE_ALL_FLAGS)
+ return NULL;
+
+ writer = calloc(1, sizeof(*writer));
if (writer == NULL)
return NULL;
+ if (flags & SQFS_DIR_WRITER_CREATE_EXPORT_TABLE) {
+ writer->export_tbl_max = 512;
+
+ writer->export_tbl = calloc(sizeof(writer->export_tbl[0]),
+ writer->export_tbl_max);
+ if (writer->export_tbl == NULL) {
+ free(writer);
+ return NULL;
+ }
+
+ memset(writer->export_tbl, 0xFF,
+ sizeof(writer->export_tbl[0]) * writer->export_tbl_max);
+ }
+
writer->dm = dm;
return writer;
}
@@ -100,6 +169,7 @@ sqfs_dir_writer_t *sqfs_dir_writer_create(sqfs_meta_writer_t *dm)
void sqfs_dir_writer_destroy(sqfs_dir_writer_t *writer)
{
writer_reset(writer);
+ free(writer->export_tbl);
free(writer);
}
@@ -123,15 +193,19 @@ int sqfs_dir_writer_add_entry(sqfs_dir_writer_t *writer, const char *name,
sqfs_u16 mode)
{
dir_entry_t *ent;
- int type;
+ int type, err;
type = get_type(mode);
if (type < 0)
return type;
- if (name[0] == '\0')
+ if (name[0] == '\0' || inode_num < 1)
return SQFS_ERROR_ARG_INVALID;
+ err = add_export_table_entry(writer, inode_num, inode_ref);
+ if (err)
+ return err;
+
ent = alloc_flex(sizeof(*ent), 1, strlen(name));
if (ent == NULL)
return SQFS_ERROR_ALLOC;
@@ -358,3 +432,32 @@ sqfs_inode_generic_t
return inode;
}
+
+int sqfs_dir_writer_write_export_table(sqfs_dir_writer_t *writer,
+ sqfs_file_t *file,
+ sqfs_compressor_t *cmp,
+ sqfs_u32 root_inode_num,
+ sqfs_u64 root_inode_ref,
+ sqfs_super_t *super)
+{
+ sqfs_u64 start;
+ size_t size;
+ int ret;
+
+ ret = add_export_table_entry(writer, root_inode_num, root_inode_ref);
+ if (ret)
+ return 0;
+
+ if (writer->export_tbl_count == 0)
+ return 0;
+
+ size = sizeof(writer->export_tbl[0]) * writer->export_tbl_count;
+
+ ret = sqfs_write_table(file, cmp, writer->export_tbl, size, &start);
+ if (ret)
+ return ret;
+
+ super->export_table_start = start;
+ super->flags |= SQFS_FLAG_EXPORTABLE;
+ return 0;
+}