diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-12-15 15:52:01 +0100 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-12-16 14:46:24 +0100 |
commit | 5e2298a3a3f00e6f55ceda2b1c35192d67c9feb4 (patch) | |
tree | af7dbe9fa5354a078b3a1dd453f15b8ef4e424ae /lib | |
parent | 9e2f960007887ea47fe273736f006569fc24df6d (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')
-rw-r--r-- | lib/common/serialize_fstree.c | 2 | ||||
-rw-r--r-- | lib/sqfs/dir_writer.c | 111 |
2 files changed, 108 insertions, 5 deletions
diff --git a/lib/common/serialize_fstree.c b/lib/common/serialize_fstree.c index 3cfcb50..457c485 100644 --- a/lib/common/serialize_fstree.c +++ b/lib/common/serialize_fstree.c @@ -168,7 +168,7 @@ int sqfs_serialize_fstree(const char *filename, sqfs_file_t *file, goto out_im; } - dirwr = sqfs_dir_writer_create(dm); + dirwr = sqfs_dir_writer_create(dm, 0); if (dirwr == NULL) { ret = SQFS_ERROR_ALLOC; goto out_dm; 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; +} |