aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Makemodule.am4
-rw-r--r--lib/fstree/add_by_path.c82
-rw-r--r--lib/fstree/fstree.c280
-rw-r--r--lib/fstree/mknode.c72
-rw-r--r--lib/fstree/xattr.c141
5 files changed, 298 insertions, 281 deletions
diff --git a/lib/Makemodule.am b/lib/Makemodule.am
index 3d0cf41..b2e39b1 100644
--- a/lib/Makemodule.am
+++ b/lib/Makemodule.am
@@ -1,7 +1,9 @@
libfstree_a_SOURCES = lib/fstree/fstree.c lib/fstree/fstree_from_file.c
libfstree_a_SOURCES += lib/fstree/fstree_sort.c lib/fstree/fstree_from_dir.c
libfstree_a_SOURCES += lib/fstree/gen_inode_table.c lib/fstree/get_path.c
-libfstree_a_SOURCES += lib/fstree/node_stat.c include/fstree.h
+libfstree_a_SOURCES += lib/fstree/node_stat.c lib/fstree/mknode.c
+libfstree_a_SOURCES += lib/fstree/add_by_path.c lib/fstree/xattr.c
+libfstree_a_SOURCES += include/fstree.h
libfstree_a_CFLAGS = $(AM_CFLAGS)
libfstree_a_CPPFLAGS = $(AM_CPPFLAGS)
diff --git a/lib/fstree/add_by_path.c b/lib/fstree/add_by_path.c
new file mode 100644
index 0000000..2cd3b4a
--- /dev/null
+++ b/lib/fstree/add_by_path.c
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include "fstree.h"
+
+#include <string.h>
+#include <errno.h>
+
+static tree_node_t *child_by_name(tree_node_t *root, const char *name,
+ size_t len)
+{
+ tree_node_t *n = root->data.dir->children;
+
+ while (n != NULL) {
+ if (strncmp(n->name, name, len) == 0 && n->name[len] == '\0')
+ break;
+
+ n = n->next;
+ }
+
+ return n;
+}
+
+static tree_node_t *get_parent_node(fstree_t *fs, tree_node_t *root,
+ const char *path)
+{
+ const char *end;
+ tree_node_t *n;
+
+ for (;;) {
+ if (!S_ISDIR(root->mode)) {
+ errno = ENOTDIR;
+ return NULL;
+ }
+
+ end = strchr(path, '/');
+ if (end == NULL)
+ break;
+
+ n = child_by_name(root, path, end - path);
+
+ if (n == NULL) {
+ n = fstree_mknode(fs, root, path, end - path, NULL,
+ &fs->defaults);
+ if (n == NULL)
+ return NULL;
+
+ n->data.dir->created_implicitly = true;
+ }
+
+ root = n;
+ path = end + 1;
+ }
+
+ return root;
+}
+
+tree_node_t *fstree_add_generic(fstree_t *fs, const char *path,
+ const struct stat *sb, const char *extra)
+{
+ tree_node_t *child, *parent;
+ const char *name;
+
+ parent = get_parent_node(fs, fs->root, path);
+ if (parent == NULL)
+ return NULL;
+
+ name = strrchr(path, '/');
+ name = (name == NULL ? path : (name + 1));
+
+ child = child_by_name(parent, name, strlen(name));
+ if (child != NULL) {
+ if (!S_ISDIR(child->mode) || !S_ISDIR(sb->st_mode) ||
+ !child->data.dir->created_implicitly) {
+ errno = EEXIST;
+ return NULL;
+ }
+
+ child->data.dir->created_implicitly = false;
+ return child;
+ }
+
+ return fstree_mknode(fs, parent, name, strlen(name), extra, sb);
+}
diff --git a/lib/fstree/fstree.c b/lib/fstree/fstree.c
index 12b32fb..a976dda 100644
--- a/lib/fstree/fstree.c
+++ b/lib/fstree/fstree.c
@@ -4,74 +4,6 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
-#include <errno.h>
-
-tree_node_t *fstree_mknode(fstree_t *fs, tree_node_t *parent, const char *name,
- size_t name_len, const char *extra,
- const struct stat *sb)
-{
- size_t size = sizeof(tree_node_t);
- tree_node_t *n;
- char *ptr;
-
- switch (sb->st_mode & S_IFMT) {
- case S_IFLNK:
- size += strlen(extra) + 1;
- break;
- case S_IFDIR:
- size += sizeof(*n->data.dir);
- break;
- case S_IFREG:
- size += sizeof(*n->data.file);
- size += (sb->st_size / fs->block_size) * sizeof(uint32_t);
- if (extra != NULL)
- size += strlen(extra) + 1;
- break;
- }
-
- n = calloc(1, size + name_len + 1);
- if (n == NULL)
- return NULL;
-
- if (parent != NULL) {
- n->next = parent->data.dir->children;
- parent->data.dir->children = n;
- n->parent = parent;
- }
-
- n->uid = sb->st_uid;
- n->gid = sb->st_gid;
- n->mode = sb->st_mode;
-
- switch (sb->st_mode & S_IFMT) {
- case S_IFDIR:
- n->data.dir = (dir_info_t *)n->payload;
- break;
- case S_IFREG:
- n->data.file = (file_info_t *)n->payload;
- n->data.file->size = sb->st_size;
- if (extra == NULL)
- break;
-
- ptr = (char *)n->data.file->blocksizes;
- ptr += (sb->st_size / fs->block_size) * sizeof(uint32_t);
- n->data.file->input_file = ptr;
- strcpy(n->data.file->input_file, extra);
- break;
- case S_IFLNK:
- n->data.slink_target = (char *)n->payload;
- strcpy(n->data.slink_target, extra);
- break;
- case S_IFBLK:
- case S_IFCHR:
- n->data.devno = sb->st_rdev;
- break;
- }
-
- n->name = (char *)n + size;
- memcpy(n->name, name, name_len);
- return n;
-}
static void free_recursive(tree_node_t *n)
{
@@ -89,218 +21,6 @@ static void free_recursive(tree_node_t *n)
free(n);
}
-static tree_node_t *child_by_name(tree_node_t *root, const char *name,
- size_t len)
-{
- tree_node_t *n = root->data.dir->children;
-
- while (n != NULL) {
- if (strncmp(n->name, name, len) == 0 && n->name[len] == '\0')
- break;
-
- n = n->next;
- }
-
- return n;
-}
-
-static tree_node_t *get_parent_node(fstree_t *fs, tree_node_t *root,
- const char *path)
-{
- const char *end;
- tree_node_t *n;
-
- for (;;) {
- if (!S_ISDIR(root->mode)) {
- errno = ENOTDIR;
- return NULL;
- }
-
- end = strchr(path, '/');
- if (end == NULL)
- break;
-
- n = child_by_name(root, path, end - path);
-
- if (n == NULL) {
- n = fstree_mknode(fs, root, path, end - path, NULL,
- &fs->defaults);
- if (n == NULL)
- return NULL;
-
- n->data.dir->created_implicitly = true;
- }
-
- root = n;
- path = end + 1;
- }
-
- return root;
-}
-
-tree_node_t *fstree_add_generic(fstree_t *fs, const char *path,
- const struct stat *sb, const char *extra)
-{
- tree_node_t *child, *parent;
- const char *name;
-
- parent = get_parent_node(fs, fs->root, path);
- if (parent == NULL)
- return NULL;
-
- name = strrchr(path, '/');
- name = (name == NULL ? path : (name + 1));
-
- child = child_by_name(parent, name, strlen(name));
- if (child != NULL) {
- if (!S_ISDIR(child->mode) || !S_ISDIR(sb->st_mode) ||
- !child->data.dir->created_implicitly) {
- errno = EEXIST;
- return NULL;
- }
-
- child->data.dir->created_implicitly = false;
- return child;
- }
-
- return fstree_mknode(fs, parent, name, strlen(name), extra, sb);
-}
-
-int fstree_add_xattr(fstree_t *fs, tree_node_t *node,
- const char *key, const char *value)
-{
- tree_xattr_t *xattr, *prev, *it;
- size_t key_idx, value_idx;
-
- if (str_table_get_index(&fs->xattr_keys, key, &key_idx))
- return -1;
-
- if (str_table_get_index(&fs->xattr_values, value, &value_idx))
- return -1;
-
- if (sizeof(size_t) > sizeof(uint32_t)) {
- if (key_idx > 0xFFFFFFFFUL) {
- fputs("Too many unique xattr keys\n", stderr);
- return -1;
- }
-
- if (value_idx > 0xFFFFFFFFUL) {
- fputs("Too many unique xattr values\n", stderr);
- return -1;
- }
- }
-
- if (node->xattr == NULL) {
- xattr = calloc(1, sizeof(*xattr) + sizeof(uint64_t) * 4);
- if (xattr == NULL) {
- perror("adding extended attributes");
- return -1;
- }
-
- xattr->max_attr = 4;
- xattr->owner = node;
-
- xattr->next = fs->xattr;
- fs->xattr = xattr;
-
- node->xattr = xattr;
- } else {
- xattr = node->xattr;
-
- if (xattr->max_attr == xattr->num_attr) {
- prev = NULL;
- it = fs->xattr;
-
- while (it != xattr) {
- prev = it;
- it = it->next;
- }
-
- if (prev == NULL) {
- fs->xattr = xattr->next;
- } else {
- prev->next = xattr->next;
- }
-
- node->xattr = NULL;
-
- it = realloc(xattr, sizeof(*xattr) +
- sizeof(uint64_t) * xattr->max_attr * 2);
-
- if (it == NULL) {
- perror("adding extended attributes");
- free(xattr);
- return -1;
- }
-
- xattr = it;
- xattr->max_attr *= 2;
-
- node->xattr = xattr;
- xattr->next = fs->xattr;
- fs->xattr = xattr;
- }
- }
-
- xattr->ref[xattr->num_attr] = (uint64_t)key_idx << 32;
- xattr->ref[xattr->num_attr] |= (uint64_t)value_idx;
- xattr->num_attr += 1;
- return 0;
-}
-
-static int cmp_u64(const void *lhs, const void *rhs)
-{
- uint64_t l = *((uint64_t *)lhs), r = *((uint64_t *)rhs);
-
- return l < r ? -1 : (l > r ? 1 : 0);
-}
-
-void fstree_xattr_reindex(fstree_t *fs)
-{
- tree_xattr_t *it;
- size_t index = 0;
-
- for (it = fs->xattr; it != NULL; it = it->next)
- it->index = index++;
-}
-
-void fstree_xattr_deduplicate(fstree_t *fs)
-{
- tree_xattr_t *it, *it1, *prev;
- int diff;
-
- for (it = fs->xattr; it != NULL; it = it->next)
- qsort(it->ref, it->num_attr, sizeof(it->ref[0]), cmp_u64);
-
- prev = NULL;
- it = fs->xattr;
-
- while (it != NULL) {
- for (it1 = fs->xattr; it1 != it; it1 = it1->next) {
- if (it1->num_attr != it->num_attr)
- continue;
-
- diff = memcmp(it1->ref, it->ref,
- it->num_attr * sizeof(it->ref[0]));
- if (diff == 0)
- break;
- }
-
- if (it1 != it) {
- prev->next = it->next;
- it->owner->xattr = it1;
-
- free(it);
- it = prev->next;
- } else {
- prev = it;
- it = it->next;
- }
- }
-
- fstree_xattr_reindex(fs);
-}
-
int fstree_init(fstree_t *fs, size_t block_size, uint32_t mtime,
uint16_t default_mode, uint32_t default_uid,
uint32_t default_gid)
diff --git a/lib/fstree/mknode.c b/lib/fstree/mknode.c
new file mode 100644
index 0000000..247e2b5
--- /dev/null
+++ b/lib/fstree/mknode.c
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include "fstree.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+tree_node_t *fstree_mknode(fstree_t *fs, tree_node_t *parent, const char *name,
+ size_t name_len, const char *extra,
+ const struct stat *sb)
+{
+ size_t size = sizeof(tree_node_t);
+ tree_node_t *n;
+ char *ptr;
+
+ switch (sb->st_mode & S_IFMT) {
+ case S_IFLNK:
+ size += strlen(extra) + 1;
+ break;
+ case S_IFDIR:
+ size += sizeof(*n->data.dir);
+ break;
+ case S_IFREG:
+ size += sizeof(*n->data.file);
+ size += (sb->st_size / fs->block_size) * sizeof(uint32_t);
+ if (extra != NULL)
+ size += strlen(extra) + 1;
+ break;
+ }
+
+ n = calloc(1, size + name_len + 1);
+ if (n == NULL)
+ return NULL;
+
+ if (parent != NULL) {
+ n->next = parent->data.dir->children;
+ parent->data.dir->children = n;
+ n->parent = parent;
+ }
+
+ n->uid = sb->st_uid;
+ n->gid = sb->st_gid;
+ n->mode = sb->st_mode;
+
+ switch (sb->st_mode & S_IFMT) {
+ case S_IFDIR:
+ n->data.dir = (dir_info_t *)n->payload;
+ break;
+ case S_IFREG:
+ n->data.file = (file_info_t *)n->payload;
+ n->data.file->size = sb->st_size;
+ if (extra == NULL)
+ break;
+
+ ptr = (char *)n->data.file->blocksizes;
+ ptr += (sb->st_size / fs->block_size) * sizeof(uint32_t);
+ n->data.file->input_file = ptr;
+ strcpy(n->data.file->input_file, extra);
+ break;
+ case S_IFLNK:
+ n->data.slink_target = (char *)n->payload;
+ strcpy(n->data.slink_target, extra);
+ break;
+ case S_IFBLK:
+ case S_IFCHR:
+ n->data.devno = sb->st_rdev;
+ break;
+ }
+
+ n->name = (char *)n + size;
+ memcpy(n->name, name, name_len);
+ return n;
+}
diff --git a/lib/fstree/xattr.c b/lib/fstree/xattr.c
new file mode 100644
index 0000000..916ab6e
--- /dev/null
+++ b/lib/fstree/xattr.c
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include "fstree.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+int fstree_add_xattr(fstree_t *fs, tree_node_t *node,
+ const char *key, const char *value)
+{
+ tree_xattr_t *xattr, *prev, *it;
+ size_t key_idx, value_idx;
+
+ if (str_table_get_index(&fs->xattr_keys, key, &key_idx))
+ return -1;
+
+ if (str_table_get_index(&fs->xattr_values, value, &value_idx))
+ return -1;
+
+ if (sizeof(size_t) > sizeof(uint32_t)) {
+ if (key_idx > 0xFFFFFFFFUL) {
+ fputs("Too many unique xattr keys\n", stderr);
+ return -1;
+ }
+
+ if (value_idx > 0xFFFFFFFFUL) {
+ fputs("Too many unique xattr values\n", stderr);
+ return -1;
+ }
+ }
+
+ if (node->xattr == NULL) {
+ xattr = calloc(1, sizeof(*xattr) + sizeof(uint64_t) * 4);
+ if (xattr == NULL) {
+ perror("adding extended attributes");
+ return -1;
+ }
+
+ xattr->max_attr = 4;
+ xattr->owner = node;
+
+ xattr->next = fs->xattr;
+ fs->xattr = xattr;
+
+ node->xattr = xattr;
+ } else {
+ xattr = node->xattr;
+
+ if (xattr->max_attr == xattr->num_attr) {
+ prev = NULL;
+ it = fs->xattr;
+
+ while (it != xattr) {
+ prev = it;
+ it = it->next;
+ }
+
+ if (prev == NULL) {
+ fs->xattr = xattr->next;
+ } else {
+ prev->next = xattr->next;
+ }
+
+ node->xattr = NULL;
+
+ it = realloc(xattr, sizeof(*xattr) +
+ sizeof(uint64_t) * xattr->max_attr * 2);
+
+ if (it == NULL) {
+ perror("adding extended attributes");
+ free(xattr);
+ return -1;
+ }
+
+ xattr = it;
+ xattr->max_attr *= 2;
+
+ node->xattr = xattr;
+ xattr->next = fs->xattr;
+ fs->xattr = xattr;
+ }
+ }
+
+ xattr->ref[xattr->num_attr] = (uint64_t)key_idx << 32;
+ xattr->ref[xattr->num_attr] |= (uint64_t)value_idx;
+ xattr->num_attr += 1;
+ return 0;
+}
+
+static int cmp_u64(const void *lhs, const void *rhs)
+{
+ uint64_t l = *((uint64_t *)lhs), r = *((uint64_t *)rhs);
+
+ return l < r ? -1 : (l > r ? 1 : 0);
+}
+
+void fstree_xattr_reindex(fstree_t *fs)
+{
+ tree_xattr_t *it;
+ size_t index = 0;
+
+ for (it = fs->xattr; it != NULL; it = it->next)
+ it->index = index++;
+}
+
+void fstree_xattr_deduplicate(fstree_t *fs)
+{
+ tree_xattr_t *it, *it1, *prev;
+ int diff;
+
+ for (it = fs->xattr; it != NULL; it = it->next)
+ qsort(it->ref, it->num_attr, sizeof(it->ref[0]), cmp_u64);
+
+ prev = NULL;
+ it = fs->xattr;
+
+ while (it != NULL) {
+ for (it1 = fs->xattr; it1 != it; it1 = it1->next) {
+ if (it1->num_attr != it->num_attr)
+ continue;
+
+ diff = memcmp(it1->ref, it->ref,
+ it->num_attr * sizeof(it->ref[0]));
+ if (diff == 0)
+ break;
+ }
+
+ if (it1 != it) {
+ prev->next = it->next;
+ it->owner->xattr = it1;
+
+ free(it);
+ it = prev->next;
+ } else {
+ prev = it;
+ it = it->next;
+ }
+ }
+
+ fstree_xattr_reindex(fs);
+}