diff options
-rw-r--r-- | lib/Makemodule.am | 4 | ||||
-rw-r--r-- | lib/fstree/add_by_path.c | 82 | ||||
-rw-r--r-- | lib/fstree/fstree.c | 280 | ||||
-rw-r--r-- | lib/fstree/mknode.c | 72 | ||||
-rw-r--r-- | lib/fstree/xattr.c | 141 |
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); +} |