summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/highlevel.h18
-rw-r--r--include/sqfs/inode.h4
-rw-r--r--lib/Makemodule.am4
-rw-r--r--lib/sqfs/write_inode.c149
-rw-r--r--lib/sqfshelper/serialize_fstree.c62
-rw-r--r--lib/sqfshelper/tree_node_to_inode.c228
-rw-r--r--lib/sqfshelper/write_inode.c328
7 files changed, 446 insertions, 347 deletions
diff --git a/include/highlevel.h b/include/highlevel.h
index 576f686..379430d 100644
--- a/include/highlevel.h
+++ b/include/highlevel.h
@@ -103,20 +103,6 @@ int sqfs_reader_open(sqfs_reader_t *rd, const char *filename,
/* Cleanup after a successfull sqfs_reader_open */
void sqfs_reader_close(sqfs_reader_t *rd);
-/*
- High level helper function to serialize a tree_node_t to a squashfs inode
- and write it to a meta data writer.
-
- The inode is written to `im`. If it is a directory node, the directory
- contents are written to `dm` using meta_writer_write_dir. The given
- id_table_t is used to store the uid and gid on the fly and write the
- coresponding indices to the inode structure.
-
- Returns 0 on success. Prints error messages to stderr on failure.
- */
-int meta_writer_write_inode(fstree_t *fs, id_table_t *idtbl, meta_writer_t *im,
- sqfs_dir_writer_t *dirw, tree_node_t *node);
-
void compressor_print_available(void);
E_SQFS_COMPRESSOR compressor_get_default(void);
@@ -129,4 +115,8 @@ void compressor_print_help(E_SQFS_COMPRESSOR id);
int xattr_reader_restore_node(xattr_reader_t *xr, fstree_t *fs,
tree_node_t *node, uint32_t xattr);
+sqfs_inode_generic_t *tree_node_to_inode(fstree_t *fs, id_table_t *idtbl,
+ tree_node_t *node,
+ size_t *file_num_blocks);
+
#endif /* HIGHLEVEL_H */
diff --git a/include/sqfs/inode.h b/include/sqfs/inode.h
index 6fb56b6..1f50b2a 100644
--- a/include/sqfs/inode.h
+++ b/include/sqfs/inode.h
@@ -10,6 +10,7 @@
#include "config.h"
#include "sqfs/meta_reader.h"
+#include "sqfs/meta_writer.h"
#include <stdint.h>
@@ -141,6 +142,9 @@ sqfs_inode_generic_t *meta_reader_read_inode(meta_reader_t *ir,
uint64_t block_start,
size_t offset);
+int meta_writer_write_inode(meta_writer_t *ir, sqfs_inode_generic_t *n,
+ size_t file_num_blocks);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/Makemodule.am b/lib/Makemodule.am
index 1f709c1..186719e 100644
--- a/lib/Makemodule.am
+++ b/lib/Makemodule.am
@@ -24,7 +24,7 @@ libsqfshelper_a_SOURCES += lib/sqfshelper/serialize_fstree.c
libsqfshelper_a_SOURCES += lib/sqfshelper/statistics.c
libsqfshelper_a_SOURCES += lib/sqfshelper/tree_node_from_inode.c
libsqfshelper_a_SOURCES += lib/sqfshelper/sqfs_reader.c
-libsqfshelper_a_SOURCES += lib/sqfshelper/write_inode.c
+libsqfshelper_a_SOURCES += lib/sqfshelper/tree_node_to_inode.c
libsqfshelper_a_SOURCES += lib/sqfshelper/write_export_table.c
libsqfshelper_a_SOURCES += lib/sqfshelper/print_version.c
libsqfshelper_a_SOURCES += lib/sqfshelper/xattr_reader.c
@@ -52,7 +52,7 @@ libsquashfs_la_SOURCES += lib/sqfs/meta_writer.c lib/sqfs/super.c
libsquashfs_la_SOURCES += lib/sqfs/id_table.c lib/sqfs/dir_writer.c
libsquashfs_la_SOURCES += lib/sqfs/write_table.c include/highlevel.h
libsquashfs_la_SOURCES += lib/sqfs/read_super.c lib/sqfs/meta_reader.c
-libsquashfs_la_SOURCES += lib/sqfs/read_inode.c
+libsquashfs_la_SOURCES += lib/sqfs/read_inode.c lib/sqfs/write_inode.c
libsquashfs_la_SOURCES += lib/sqfs/readdir.c
libsquashfs_la_SOURCES += lib/sqfs/xattr.c lib/sqfs/xattr_reader.c
libsquashfs_la_SOURCES += lib/sqfs/read_table.c
diff --git a/lib/sqfs/write_inode.c b/lib/sqfs/write_inode.c
new file mode 100644
index 0000000..a2d87f9
--- /dev/null
+++ b/lib/sqfs/write_inode.c
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * write_inode.c
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#include "config.h"
+
+#include "sqfs/inode.h"
+
+static int write_block_sizes(meta_writer_t *ir, sqfs_inode_generic_t *n,
+ size_t file_num_blocks)
+{
+ uint32_t sizes[file_num_blocks];
+ size_t i;
+
+ for (i = 0; i < file_num_blocks; ++i)
+ sizes[i] = htole32(n->block_sizes[i]);
+
+ return meta_writer_append(ir, sizes,
+ sizeof(uint32_t) * file_num_blocks);
+}
+
+int meta_writer_write_inode(meta_writer_t *ir, sqfs_inode_generic_t *n,
+ size_t file_num_blocks)
+{
+ sqfs_inode_t base;
+
+ base.type = htole16(n->base.type);
+ base.mode = htole16(n->base.mode);
+ base.uid_idx = htole16(n->base.uid_idx);
+ base.gid_idx = htole16(n->base.gid_idx);
+ base.mod_time = htole32(n->base.mod_time);
+ base.inode_number = htole32(n->base.inode_number);
+
+ if (meta_writer_append(ir, &base, sizeof(base)))
+ return -1;
+
+ switch (n->base.type) {
+ case SQFS_INODE_DIR: {
+ sqfs_inode_dir_t dir = {
+ .start_block = htole32(n->data.dir.start_block),
+ .nlink = htole32(n->data.dir.nlink),
+ .size = htole16(n->data.dir.size),
+ .offset = htole16(n->data.dir.offset),
+ .parent_inode = htole32(n->data.dir.parent_inode),
+ };
+ return meta_writer_append(ir, &dir, sizeof(dir));
+ }
+ case SQFS_INODE_FILE: {
+ sqfs_inode_file_t file = {
+ .blocks_start = htole32(n->data.file.blocks_start),
+ .fragment_index = htole32(n->data.file.fragment_index),
+ .fragment_offset =
+ htole32(n->data.file.fragment_offset),
+ .file_size = htole32(n->data.file.file_size),
+ };
+ if (meta_writer_append(ir, &file, sizeof(file)))
+ return -1;
+ return write_block_sizes(ir, n, file_num_blocks);
+ }
+ case SQFS_INODE_SLINK: {
+ sqfs_inode_slink_t slink = {
+ .nlink = htole32(n->data.slink.nlink),
+ .target_size = htole32(n->data.slink.target_size),
+ };
+ if (meta_writer_append(ir, &slink, sizeof(slink)))
+ return -1;
+ return meta_writer_append(ir, n->slink_target,
+ n->data.slink.target_size);
+ }
+ case SQFS_INODE_BDEV:
+ case SQFS_INODE_CDEV: {
+ sqfs_inode_dev_t dev = {
+ .nlink = htole32(n->data.dev.nlink),
+ .devno = htole32(n->data.dev.devno),
+ };
+ return meta_writer_append(ir, &dev, sizeof(dev));
+ }
+ case SQFS_INODE_FIFO:
+ case SQFS_INODE_SOCKET: {
+ sqfs_inode_ipc_t ipc = {
+ .nlink = htole32(n->data.ipc.nlink),
+ };
+ return meta_writer_append(ir, &ipc, sizeof(ipc));
+ }
+ case SQFS_INODE_EXT_DIR: {
+ sqfs_inode_dir_ext_t dir = {
+ .nlink = htole32(n->data.dir_ext.nlink),
+ .size = htole32(n->data.dir_ext.size),
+ .start_block = htole32(n->data.dir_ext.start_block),
+ .parent_inode = htole32(n->data.dir_ext.parent_inode),
+ .inodex_count = htole16(n->data.dir_ext.inodex_count),
+ .offset = htole16(n->data.dir_ext.offset),
+ .xattr_idx = htole32(n->data.dir_ext.xattr_idx),
+ };
+ return meta_writer_append(ir, &dir, sizeof(dir));
+ }
+ case SQFS_INODE_EXT_FILE: {
+ sqfs_inode_file_ext_t file = {
+ .blocks_start = htole64(n->data.file_ext.blocks_start),
+ .file_size = htole64(n->data.file_ext.file_size),
+ .sparse = htole64(n->data.file_ext.sparse),
+ .nlink = htole32(n->data.file_ext.nlink),
+ .fragment_idx = htole32(n->data.file_ext.fragment_idx),
+ .fragment_offset =
+ htole32(n->data.file_ext.fragment_offset),
+ .xattr_idx = htole32(n->data.file_ext.xattr_idx),
+ };
+ if (meta_writer_append(ir, &file, sizeof(file)))
+ return -1;
+ return write_block_sizes(ir, n, file_num_blocks);
+ }
+ case SQFS_INODE_EXT_SLINK: {
+ sqfs_inode_slink_t slink = {
+ .nlink = htole32(n->data.slink_ext.nlink),
+ .target_size = htole32(n->data.slink_ext.target_size),
+ };
+ uint32_t xattr = htole32(n->data.slink_ext.xattr_idx);
+
+ if (meta_writer_append(ir, &slink, sizeof(slink)))
+ return -1;
+ if (meta_writer_append(ir, n->slink_target,
+ n->data.slink_ext.target_size)) {
+ return -1;
+ }
+ return meta_writer_append(ir, &xattr, sizeof(xattr));
+ }
+ case SQFS_INODE_EXT_BDEV:
+ case SQFS_INODE_EXT_CDEV: {
+ sqfs_inode_dev_ext_t dev = {
+ .nlink = htole32(n->data.dev_ext.nlink),
+ .devno = htole32(n->data.dev_ext.devno),
+ .xattr_idx = htole32(n->data.dev_ext.xattr_idx),
+ };
+ return meta_writer_append(ir, &dev, sizeof(dev));
+ }
+ case SQFS_INODE_EXT_FIFO:
+ case SQFS_INODE_EXT_SOCKET: {
+ sqfs_inode_ipc_ext_t ipc = {
+ .nlink = htole32(n->data.ipc_ext.nlink),
+ .xattr_idx = htole32(n->data.ipc_ext.xattr_idx),
+ };
+ return meta_writer_append(ir, &ipc, sizeof(ipc));
+ }
+ }
+
+ return -1;
+}
diff --git a/lib/sqfshelper/serialize_fstree.c b/lib/sqfshelper/serialize_fstree.c
index 53e2236..f8f3913 100644
--- a/lib/sqfshelper/serialize_fstree.c
+++ b/lib/sqfshelper/serialize_fstree.c
@@ -11,17 +11,46 @@
#include "util.h"
#include <unistd.h>
+#include <stdlib.h>
#include <stdio.h>
+static int write_dir_entries(sqfs_dir_writer_t *dirw, tree_node_t *node)
+{
+ tree_node_t *it;
+ uint64_t ref;
+ int ret;
+
+ if (sqfs_dir_writer_begin(dirw))
+ return -1;
+
+ for (it = node->data.dir->children; it != NULL; it = it->next) {
+ ret = sqfs_dir_writer_add_entry(dirw, it->name, it->inode_num,
+ it->inode_ref, it->mode);
+ if (ret)
+ return -1;
+ }
+
+ if (sqfs_dir_writer_end(dirw))
+ return -1;
+
+ ref = sqfs_dir_writer_get_dir_reference(dirw);
+
+ node->data.dir->size = sqfs_dir_writer_get_size(dirw);
+ node->data.dir->start_block = ref >> 16;
+ node->data.dir->block_offset = ref & 0xFFFF;
+ return 0;
+}
+
int sqfs_serialize_fstree(int outfd, sqfs_super_t *super, fstree_t *fs,
compressor_t *cmp, id_table_t *idtbl)
{
+ sqfs_inode_generic_t *inode;
sqfs_dir_writer_t *dirwr;
meta_writer_t *im, *dm;
+ size_t i, count;
uint32_t offset;
uint64_t block;
int ret = -1;
- size_t i;
im = meta_writer_create(outfd, cmp, false);
if (im == NULL)
@@ -36,10 +65,37 @@ int sqfs_serialize_fstree(int outfd, sqfs_super_t *super, fstree_t *fs,
goto out_dm;
for (i = 2; i < fs->inode_tbl_size; ++i) {
- if (meta_writer_write_inode(fs, idtbl, im, dirwr,
- fs->inode_table[i])) {
+ if (S_ISDIR(fs->inode_table[i]->mode)) {
+ if (write_dir_entries(dirwr, fs->inode_table[i]))
+ goto out;
+ }
+
+ inode = tree_node_to_inode(fs, idtbl, fs->inode_table[i],
+ &count);
+ if (inode == NULL)
+ goto out;
+
+ if (inode->base.type == SQFS_INODE_EXT_DIR) {
+ inode->data.dir_ext.inodex_count =
+ sqfs_dir_writer_get_index_size(dirwr);
+ }
+
+ meta_writer_get_position(im, &block, &offset);
+ fs->inode_table[i]->inode_ref = (block << 16) | offset;
+
+ if (meta_writer_write_inode(im, inode, count)) {
+ free(inode);
goto out;
}
+
+ if (inode->base.type == SQFS_INODE_EXT_DIR) {
+ if (sqfs_dir_writer_write_index(dirwr, im)) {
+ free(inode);
+ goto out;
+ }
+ }
+
+ free(inode);
}
if (meta_writer_flush(im))
diff --git a/lib/sqfshelper/tree_node_to_inode.c b/lib/sqfshelper/tree_node_to_inode.c
new file mode 100644
index 0000000..21e30dd
--- /dev/null
+++ b/lib/sqfshelper/tree_node_to_inode.c
@@ -0,0 +1,228 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * write_inode.c
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#include "config.h"
+
+#include "highlevel.h"
+#include "sqfs/inode.h"
+#include "sqfs/dir.h"
+#include "util.h"
+
+#include <assert.h>
+#include <endian.h>
+#include <stdlib.h>
+#include <string.h>
+
+static size_t hard_link_count(tree_node_t *n)
+{
+ size_t count;
+
+ if (S_ISDIR(n->mode)) {
+ count = 2;
+
+ for (n = n->data.dir->children; n != NULL; n = n->next)
+ ++count;
+
+ return count;
+ }
+
+ return 1;
+}
+
+static int get_type(tree_node_t *node)
+{
+ switch (node->mode & S_IFMT) {
+ case S_IFSOCK:
+ if (node->xattr != NULL)
+ return SQFS_INODE_EXT_SOCKET;
+ return SQFS_INODE_SOCKET;
+ case S_IFIFO:
+ if (node->xattr != NULL)
+ return SQFS_INODE_EXT_FIFO;
+ return SQFS_INODE_FIFO;
+ case S_IFLNK:
+ if (node->xattr != NULL)
+ return SQFS_INODE_EXT_SLINK;
+ return SQFS_INODE_SLINK;
+ case S_IFBLK:
+ if (node->xattr != NULL)
+ return SQFS_INODE_EXT_BDEV;
+ return SQFS_INODE_BDEV;
+ case S_IFCHR:
+ if (node->xattr != NULL)
+ return SQFS_INODE_EXT_CDEV;
+ return SQFS_INODE_CDEV;
+ case S_IFREG: {
+ file_info_t *fi = node->data.file;
+
+ if (node->xattr != NULL || fi->sparse > 0)
+ return SQFS_INODE_EXT_FILE;
+
+ if (fi->startblock > 0xFFFFFFFFUL || fi->size > 0xFFFFFFFFUL)
+ return SQFS_INODE_EXT_FILE;
+
+ return SQFS_INODE_FILE;
+ }
+ case S_IFDIR: {
+ dir_info_t *di = node->data.dir;
+
+ if (node->xattr != NULL)
+ return SQFS_INODE_EXT_DIR;
+
+ if (di->start_block > 0xFFFFFFFFUL || di->size > 0xFFFF)
+ return SQFS_INODE_EXT_DIR;
+
+ return SQFS_INODE_DIR;
+ }
+ }
+ assert(0);
+}
+
+sqfs_inode_generic_t *tree_node_to_inode(fstree_t *fs, id_table_t *idtbl,
+ tree_node_t *node,
+ size_t *file_num_blocks)
+{
+ size_t i, extra = 0, block_count = 0;
+ sqfs_inode_generic_t *inode;
+ uint16_t uid_idx, gid_idx;
+ uint32_t xattr = 0xFFFFFFFF;
+ file_info_t *fi = NULL;
+
+ if (S_ISLNK(node->mode)) {
+ extra = strlen(node->data.slink_target);
+ } else if (S_ISREG(node->mode)) {
+ fi = node->data.file;
+
+ block_count = fi->size / fs->block_size;
+
+ if ((fi->size % fs->block_size) != 0 &&
+ !(fi->flags & FILE_FLAG_HAS_FRAGMENT)) {
+ ++block_count;
+ }
+
+ extra = block_count * sizeof(uint32_t);
+ }
+
+ inode = alloc_flex(sizeof(*inode), 1, extra);
+ if (inode == NULL) {
+ perror("creating inode from file system tree node");
+ return NULL;
+ }
+
+ if (S_ISLNK(node->mode)) {
+ inode->slink_target = (char *)inode->extra;
+
+ memcpy(inode->extra, node->data.slink_target, extra);
+ } else if (S_ISREG(node->mode)) {
+ inode->block_sizes = (uint32_t *)inode->extra;
+
+ for (i = 0; i < block_count; ++i) {
+ inode->block_sizes[i] =
+ node->data.file->blocks[i].size;
+ }
+ }
+
+ if (id_table_id_to_index(idtbl, node->uid, &uid_idx))
+ goto fail;
+
+ if (id_table_id_to_index(idtbl, node->gid, &gid_idx))
+ goto fail;
+
+ if (node->xattr != NULL)
+ xattr = node->xattr->index;
+
+ inode->base.type = get_type(node);
+ inode->base.mode = node->mode;
+ inode->base.uid_idx = uid_idx;
+ inode->base.gid_idx = gid_idx;
+ inode->base.mod_time = node->mod_time;
+ inode->base.inode_number = node->inode_num;
+
+ switch (inode->base.type) {
+ case SQFS_INODE_FIFO:
+ case SQFS_INODE_SOCKET:
+ inode->data.ipc.nlink = hard_link_count(node);
+ break;
+ case SQFS_INODE_EXT_FIFO:
+ case SQFS_INODE_EXT_SOCKET:
+ inode->data.ipc_ext.nlink = hard_link_count(node);
+ inode->data.ipc_ext.xattr_idx = xattr;
+ break;
+ case SQFS_INODE_SLINK:
+ inode->data.slink.nlink = hard_link_count(node);
+ inode->data.slink.target_size = extra;
+ break;
+ case SQFS_INODE_EXT_SLINK:
+ inode->data.slink_ext.nlink = hard_link_count(node);
+ inode->data.slink_ext.target_size = extra;
+ inode->data.slink_ext.xattr_idx = xattr;
+ break;
+ case SQFS_INODE_BDEV:
+ case SQFS_INODE_CDEV:
+ inode->data.dev.nlink = hard_link_count(node);
+ inode->data.dev.devno = node->data.devno;
+ break;
+ case SQFS_INODE_EXT_BDEV:
+ case SQFS_INODE_EXT_CDEV:
+ inode->data.dev_ext.nlink = hard_link_count(node);
+ inode->data.dev_ext.devno = node->data.devno;
+ inode->data.dev_ext.xattr_idx = xattr;
+ break;
+ case SQFS_INODE_FILE:
+ inode->data.file.blocks_start = fi->startblock;
+ inode->data.file.fragment_index = 0xFFFFFFFF;
+ inode->data.file.fragment_offset = 0xFFFFFFFF;
+ inode->data.file.file_size = fi->size;
+
+ if ((fi->size % fs->block_size) != 0 &&
+ (fi->flags & FILE_FLAG_HAS_FRAGMENT)) {
+ inode->data.file.fragment_index = fi->fragment;
+ inode->data.file.fragment_offset = fi->fragment_offset;
+ }
+ break;
+ case SQFS_INODE_EXT_FILE:
+ inode->data.file_ext.blocks_start = fi->startblock;
+ inode->data.file_ext.file_size = fi->size;
+ inode->data.file_ext.sparse = fi->sparse;
+ inode->data.file_ext.nlink = hard_link_count(node);
+ inode->data.file_ext.fragment_idx = 0xFFFFFFFF;
+ inode->data.file_ext.fragment_offset = 0xFFFFFFFF;
+ inode->data.file_ext.xattr_idx = xattr;
+
+ if ((fi->size % fs->block_size) != 0 &&
+ (fi->flags & FILE_FLAG_HAS_FRAGMENT)) {
+ inode->data.file_ext.fragment_idx = fi->fragment;
+ inode->data.file_ext.fragment_offset =
+ fi->fragment_offset;
+ }
+ break;
+ case SQFS_INODE_DIR:
+ inode->data.dir.start_block = node->data.dir->start_block;
+ inode->data.dir.nlink = hard_link_count(node);
+ inode->data.dir.size = node->data.dir->size;
+ inode->data.dir.offset = node->data.dir->block_offset;
+ inode->data.dir.parent_inode = node->parent ?
+ node->parent->inode_num : 1;
+ break;
+ case SQFS_INODE_EXT_DIR:
+ inode->data.dir_ext.nlink = hard_link_count(node);
+ inode->data.dir_ext.size = node->data.dir->size;
+ inode->data.dir_ext.start_block = node->data.dir->start_block;
+ inode->data.dir_ext.parent_inode = node->parent ?
+ node->parent->inode_num : 1;
+ inode->data.dir_ext.offset = node->data.dir->block_offset;
+ inode->data.dir_ext.xattr_idx = xattr;
+ break;
+ default:
+ goto fail;
+ }
+
+ *file_num_blocks = block_count;
+ return inode;
+fail:
+ free(inode);
+ return NULL;
+}
diff --git a/lib/sqfshelper/write_inode.c b/lib/sqfshelper/write_inode.c
deleted file mode 100644
index d9dfe53..0000000
--- a/lib/sqfshelper/write_inode.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * write_inode.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "highlevel.h"
-#include "sqfs/inode.h"
-#include "sqfs/dir.h"
-#include "util.h"
-
-#include <assert.h>
-#include <endian.h>
-#include <stdlib.h>
-#include <string.h>
-
-static size_t hard_link_count(tree_node_t *n)
-{
- size_t count;
-
- if (S_ISDIR(n->mode)) {
- count = 2;
-
- for (n = n->data.dir->children; n != NULL; n = n->next)
- ++count;
-
- return count;
- }
-
- return 1;
-}
-
-static int get_type(tree_node_t *node)
-{
- switch (node->mode & S_IFMT) {
- case S_IFSOCK:
- if (node->xattr != NULL)
- return SQFS_INODE_EXT_SOCKET;
- return SQFS_INODE_SOCKET;
- case S_IFIFO:
- if (node->xattr != NULL)
- return SQFS_INODE_EXT_FIFO;
- return SQFS_INODE_FIFO;
- case S_IFLNK:
- if (node->xattr != NULL)
- return SQFS_INODE_EXT_SLINK;
- return SQFS_INODE_SLINK;
- case S_IFBLK:
- if (node->xattr != NULL)
- return SQFS_INODE_EXT_BDEV;
- return SQFS_INODE_BDEV;
- case S_IFCHR:
- if (node->xattr != NULL)
- return SQFS_INODE_EXT_CDEV;
- return SQFS_INODE_CDEV;
- case S_IFREG: {
- file_info_t *fi = node->data.file;
-
- if (node->xattr != NULL || fi->sparse > 0)
- return SQFS_INODE_EXT_FILE;
-
- if (fi->startblock > 0xFFFFFFFFUL || fi->size > 0xFFFFFFFFUL)
- return SQFS_INODE_EXT_FILE;
-
- if (hard_link_count(node) > 1)
- return SQFS_INODE_EXT_FILE;
-
- return SQFS_INODE_FILE;
- }
- case S_IFDIR: {
- dir_info_t *di = node->data.dir;
-
- if (node->xattr != NULL)
- return SQFS_INODE_EXT_DIR;
-
- if (di->start_block > 0xFFFFFFFFUL || di->size > 0xFFFF)
- return SQFS_INODE_EXT_DIR;
-
- return SQFS_INODE_DIR;
- }
- }
- assert(0);
-}
-
-static int write_file_blocks(fstree_t *fs, file_info_t *fi, meta_writer_t *im)
-{
- uint64_t i, count = fi->size / fs->block_size;
- uint32_t bs;
-
- if ((fi->size % fs->block_size) != 0 &&
- !(fi->flags & FILE_FLAG_HAS_FRAGMENT)) {
- ++count;
- }
-
- for (i = 0; i < count; ++i) {
- bs = htole32(fi->blocks[i].size);
-
- if (meta_writer_append(im, &bs, sizeof(bs)))
- return -1;
- }
- return 0;
-}
-
-static int write_dir_entries(sqfs_dir_writer_t *dirw, tree_node_t *node)
-{
- tree_node_t *it;
- uint64_t ref;
- int ret;
-
- if (sqfs_dir_writer_begin(dirw))
- return -1;
-
- for (it = node->data.dir->children; it != NULL; it = it->next) {
- ret = sqfs_dir_writer_add_entry(dirw, it->name, it->inode_num,
- it->inode_ref, it->mode);
- if (ret)
- return -1;
- }
-
- if (sqfs_dir_writer_end(dirw))
- return -1;
-
- ref = sqfs_dir_writer_get_dir_reference(dirw);
-
- node->data.dir->size = sqfs_dir_writer_get_size(dirw);
- node->data.dir->start_block = ref >> 16;
- node->data.dir->block_offset = ref & 0xFFFF;
- return 0;
-}
-
-int meta_writer_write_inode(fstree_t *fs, id_table_t *idtbl, meta_writer_t *im,
- sqfs_dir_writer_t *dirw, tree_node_t *node)
-{
- uint16_t uid_idx, gid_idx;
- sqfs_inode_t base;
- uint32_t offset;
- uint64_t block;
-
- if (id_table_id_to_index(idtbl, node->uid, &uid_idx))
- return -1;
-
- if (id_table_id_to_index(idtbl, node->gid, &gid_idx))
- return -1;
-
- meta_writer_get_position(im, &block, &offset);
- node->inode_ref = (block << 16) | offset;
-
- if (S_ISDIR(node->mode)) {
- if (write_dir_entries(dirw, node))
- return -1;
- }
-
- base.type = htole16(get_type(node));
- base.mode = htole16(node->mode);
- base.uid_idx = htole16(uid_idx);
- base.gid_idx = htole16(gid_idx);
- base.mod_time = htole32(node->mod_time);
- base.inode_number = htole32(node->inode_num);
-
- if (meta_writer_append(im, &base, sizeof(base)))
- return -1;
-
- switch (le16toh(base.type)) {
- case SQFS_INODE_FIFO:
- case SQFS_INODE_SOCKET: {
- sqfs_inode_ipc_t ipc = {
- .nlink = htole32(hard_link_count(node)),
- };
-
- return meta_writer_append(im, &ipc, sizeof(ipc));
- }
- case SQFS_INODE_EXT_FIFO:
- case SQFS_INODE_EXT_SOCKET: {
- sqfs_inode_ipc_ext_t ipc = {
- .nlink = htole32(hard_link_count(node)),
- .xattr_idx = htole32(0xFFFFFFFF),
- };
-
- if (node->xattr != NULL)
- ipc.xattr_idx = htole32(node->xattr->index);
-
- return meta_writer_append(im, &ipc, sizeof(ipc));
- }
- case SQFS_INODE_SLINK: {
- sqfs_inode_slink_t slink = {
- .nlink = htole32(hard_link_count(node)),
- .target_size = htole32(strlen(node->data.slink_target)),
- };
-
- if (meta_writer_append(im, &slink, sizeof(slink)))
- return -1;
- if (meta_writer_append(im, node->data.slink_target,
- le32toh(slink.target_size))) {
- return -1;
- }
- break;
- }
- case SQFS_INODE_EXT_SLINK: {
- sqfs_inode_slink_t slink = {
- .nlink = htole32(hard_link_count(node)),
- .target_size = htole32(strlen(node->data.slink_target)),
- };
- uint32_t xattr = htole32(0xFFFFFFFF);
-
- if (node->xattr != NULL)
- xattr = htole32(node->xattr->index);
-
- if (meta_writer_append(im, &slink, sizeof(slink)))
- return -1;
- if (meta_writer_append(im, node->data.slink_target,
- le32toh(slink.target_size))) {
- return -1;
- }
- if (meta_writer_append(im, &xattr, sizeof(xattr)))
- return -1;
- break;
- }
- case SQFS_INODE_BDEV:
- case SQFS_INODE_CDEV: {
- sqfs_inode_dev_t dev = {
- .nlink = htole32(hard_link_count(node)),
- .devno = htole32(node->data.devno),
- };
-
- return meta_writer_append(im, &dev, sizeof(dev));
- }
- case SQFS_INODE_EXT_BDEV:
- case SQFS_INODE_EXT_CDEV: {
- sqfs_inode_dev_ext_t dev = {
- .nlink = htole32(hard_link_count(node)),
- .devno = htole32(node->data.devno),
- .xattr_idx = htole32(0xFFFFFFFF),
- };
-
- if (node->xattr != NULL)
- dev.xattr_idx = htole32(node->xattr->index);
-
- return meta_writer_append(im, &dev, sizeof(dev));
- }
- case SQFS_INODE_EXT_FILE: {
- file_info_t *fi = node->data.file;
- sqfs_inode_file_ext_t ext = {
- .blocks_start = htole64(fi->startblock),
- .file_size = htole64(fi->size),
- .sparse = htole64(fi->sparse),
- .nlink = htole32(hard_link_count(node)),
- .fragment_idx = htole32(0xFFFFFFFF),
- .fragment_offset = htole32(0xFFFFFFFF),
- .xattr_idx = htole32(0xFFFFFFFF),
- };
-
- if ((fi->size % fs->block_size) != 0) {
- ext.fragment_idx = htole32(fi->fragment);
- ext.fragment_offset = htole32(fi->fragment_offset);
- }
-
- if (node->xattr != NULL)
- ext.xattr_idx = htole32(node->xattr->index);
-
- if (meta_writer_append(im, &ext, sizeof(ext)))
- return -1;
- return write_file_blocks(fs, fi, im);
- }
- case SQFS_INODE_FILE: {
- file_info_t *fi = node->data.file;
- sqfs_inode_file_t reg = {
- .blocks_start = htole32(fi->startblock),
- .fragment_index = htole32(0xFFFFFFFF),
- .fragment_offset = htole32(0xFFFFFFFF),
- .file_size = htole32(fi->size),
- };
-
- if ((fi->size % fs->block_size) != 0) {
- reg.fragment_index = htole32(fi->fragment);
- reg.fragment_offset = htole32(fi->fragment_offset);
- }
-
- if (meta_writer_append(im, &reg, sizeof(reg)))
- return -1;
- return write_file_blocks(fs, fi, im);
- }
- case SQFS_INODE_DIR: {
- sqfs_inode_dir_t dir = {
- .start_block = htole32(node->data.dir->start_block),
- .nlink = htole32(hard_link_count(node)),
- .size = htole16(node->data.dir->size),
- .offset = htole16(node->data.dir->block_offset),
- .parent_inode = node->parent ?
- htole32(node->parent->inode_num) : htole32(1),
- };
-
- return meta_writer_append(im, &dir, sizeof(dir));
- }
- case SQFS_INODE_EXT_DIR: {
- size_t idx_size;
- 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),
- .offset = htole16(node->data.dir->block_offset),
- .xattr_idx = htole32(0xFFFFFFFF),
- };
-
- if (node->xattr != NULL)
- ext.xattr_idx = htole32(node->xattr->index);
-
- idx_size = sqfs_dir_writer_get_index_size(dirw);
-
- if (idx_size > 0)
- ext.inodex_count = htole32(idx_size - 1);
-
- if (meta_writer_append(im, &ext, sizeof(ext)))
- return -1;
-
- if (sqfs_dir_writer_write_index(dirw, im))
- return -1;
- break;
- }
- default:
- assert(0);
- }
- return 0;
-}