summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sqfs/dir_writer.h66
-rw-r--r--lib/common/serialize_fstree.c2
-rw-r--r--lib/sqfs/dir_writer.c111
3 files changed, 172 insertions, 7 deletions
diff --git a/include/sqfs/dir_writer.h b/include/sqfs/dir_writer.h
index 81a651c..c390050 100644
--- a/include/sqfs/dir_writer.h
+++ b/include/sqfs/dir_writer.h
@@ -58,6 +58,30 @@
* writer used for inodes.
*/
+/**
+ * @enum SQFS_DIR_WRITER_CREATE_FLAGS
+ *
+ * @brief Flags that can be set for @ref sqfs_dir_writer_create
+ */
+typedef enum {
+ /**
+ * @brief Record all inode locations to create an export table.
+ *
+ * For NFS export support, SquashFS needs an extra table that maps
+ * inode numbers directly to on-disk locations.
+ *
+ * Since the @ref sqfs_dir_writer_t "sees" all inode numbers and
+ * coresponding locations and easily create such a table.
+ *
+ * If this flag is set for @ref sqfs_dir_writer_create, the result
+ * directory wrter collects such a table which it can then write to
+ * disk using @ref sqfs_dir_writer_write_export_table.
+ */
+ SQFS_DIR_WRITER_CREATE_EXPORT_TABLE = 0x01,
+
+ SQFS_DIR_WRITER_CREATE_ALL_FLAGS = 0x01
+} SQFS_DIR_WRITER_CREATE_FLAGS;
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -69,11 +93,13 @@ extern "C" {
*
* @param dm A pointer to a meta data writer that the generated directory
* entries should be written to.
+ * @param flags A combination of @ref SQFS_DIR_WRITER_CREATE_FLAGS.
*
* @return A pointer to a directory writer on success, NULL on
- * allocation failure.
+ * allocation failure or if flags has unknown flags set.
*/
-SQFS_API sqfs_dir_writer_t *sqfs_dir_writer_create(sqfs_meta_writer_t *dm);
+SQFS_API sqfs_dir_writer_t *sqfs_dir_writer_create(sqfs_meta_writer_t *dm,
+ sqfs_u32 flags);
/**
* @brief Destroy a directory writer and free all its memory.
@@ -217,6 +243,42 @@ SQFS_API sqfs_inode_generic_t
*sqfs_dir_writer_create_inode(const sqfs_dir_writer_t *writer, size_t hlinks,
sqfs_u32 xattr, sqfs_u32 parent_ino);
+/**
+ * @brief Write an export table to a SquashFS image.
+ *
+ * @memberof sqfs_dir_writer_t
+ *
+ * If the @ref sqfs_dir_writer_t was created with the
+ * @ref SQFS_DIR_WRITER_CREATE_EXPORT_TABLE flag set, it has an internal table
+ * that maps all inode numbers to inode references. After writing the fragment
+ * table, this function can be used to write this inode mapping table for NFS
+ * export support.
+ *
+ * It is safe to call this function if the writer has been created without the
+ * flag. In this case, it is simply a noop.
+ *
+ * In theory, the writer "sees" the entire directory tree and for each entry,
+ * the inode number and on-disk location, so it can build this table. The only
+ * inode it never sees is the root inode, so that information has to be passed
+ * to this function to add it to the table just before writing it to disk.
+ *
+ * @param writer A pointer to a directory writer object.
+ * @param file The ouput file to write the table to.
+ * @param cmp The compressor to use to compress the table.
+ * @param root_inode_num The inode number of the root inode.
+ * @param root_inode_ref An inode reference for the root inode.
+ * @param super A pointer to the super block. Location of the export table and
+ * the exportable flag are set.
+ *
+ * @return Zero on success, a @ref E_SQFS_ERROR value on failure.
+ */
+SQFS_API 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);
+
#ifdef __cplusplus
}
#endif
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;
+}