summaryrefslogtreecommitdiff
path: root/lib/sqfs/dir_writer.c
diff options
context:
space:
mode:
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;
+}