aboutsummaryrefslogtreecommitdiff
path: root/lib/fstree
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fstree')
-rw-r--r--lib/fstree/fstree.c140
-rw-r--r--lib/fstree/fstree_from_dir.c174
-rw-r--r--lib/fstree/node_stat.c7
3 files changed, 115 insertions, 206 deletions
diff --git a/lib/fstree/fstree.c b/lib/fstree/fstree.c
index 3f6387a..12b32fb 100644
--- a/lib/fstree/fstree.c
+++ b/lib/fstree/fstree.c
@@ -6,19 +6,26 @@
#include <stdio.h>
#include <errno.h>
-static tree_node_t *mknode(tree_node_t *parent, const char *name,
- size_t name_len, size_t extra_len,
- uint16_t mode, uint32_t uid, uint32_t gid)
+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) + extra_len;
+ size_t size = sizeof(tree_node_t);
tree_node_t *n;
+ char *ptr;
- switch (mode & S_IFMT) {
+ 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;
}
@@ -32,19 +39,32 @@ static tree_node_t *mknode(tree_node_t *parent, const char *name,
n->parent = parent;
}
- n->uid = uid;
- n->gid = gid;
- n->mode = mode;
+ n->uid = sb->st_uid;
+ n->gid = sb->st_gid;
+ n->mode = sb->st_mode;
- switch (mode & S_IFMT) {
+ 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;
}
@@ -103,9 +123,8 @@ static tree_node_t *get_parent_node(fstree_t *fs, tree_node_t *root,
n = child_by_name(root, path, end - path);
if (n == NULL) {
- n = mknode(root, path, end - path, 0,
- S_IFDIR | fs->default_mode,
- fs->default_uid, fs->default_gid);
+ n = fstree_mknode(fs, root, path, end - path, NULL,
+ &fs->defaults);
if (n == NULL)
return NULL;
@@ -119,91 +138,32 @@ static tree_node_t *get_parent_node(fstree_t *fs, tree_node_t *root,
return root;
}
-tree_node_t *fstree_add(fstree_t *fs, const char *path, uint16_t mode,
- uint32_t uid, uint32_t gid, size_t extra_len)
+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;
- name = strrchr(path, '/');
- name = (name == NULL ? path : (name + 1));
-
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(mode) &&
- child->data.dir->created_implicitly) {
- child->data.dir->created_implicitly = false;
- return child;
- }
-
- errno = EEXIST;
- return NULL;
- }
-
- return mknode(parent, name, strlen(name), extra_len, mode, uid, gid);
-}
-
-tree_node_t *fstree_add_file(fstree_t *fs, const char *path, uint16_t mode,
- uint32_t uid, uint32_t gid, uint64_t filesz,
- const char *input)
-{
- tree_node_t *node;
- size_t count, extra;
- char *ptr;
-
- count = filesz / fs->block_size;
- extra = sizeof(uint32_t) * count;
-
- if (input != NULL)
- extra += strlen(input) + 1;
-
- mode &= 07777;
- node = fstree_add(fs, path, S_IFREG | mode, uid, gid, extra);
-
- if (node != NULL) {
- if (input != NULL) {
- ptr = (char *)(node->data.file->blocksizes + count);
- strcpy(ptr, input);
- node->data.file->input_file = ptr;
- } else {
- node->data.file->input_file = NULL;
+ if (!S_ISDIR(child->mode) || !S_ISDIR(sb->st_mode) ||
+ !child->data.dir->created_implicitly) {
+ errno = EEXIST;
+ return NULL;
}
- node->data.file->size = filesz;
- }
- return node;
-}
-
-tree_node_t *fstree_add_generic(fstree_t *fs, const char *path,
- const struct stat *sb, const char *extra)
-{
- size_t payload = 0;
- tree_node_t *node;
-
- if (S_ISREG(sb->st_mode)) {
- return fstree_add_file(fs, path, sb->st_mode, sb->st_uid,
- sb->st_gid, sb->st_size, extra);
- }
-
- if (S_ISLNK(sb->st_mode))
- payload = strlen(extra) + 1;
-
- node = fstree_add(fs, path, sb->st_mode, sb->st_uid,
- sb->st_gid, payload);
- if (node == NULL)
- return NULL;
-
- if (S_ISLNK(sb->st_mode)) {
- strcpy(node->data.slink_target, extra);
- } else if (S_ISBLK(sb->st_mode) || S_ISCHR(sb->st_mode)) {
- node->data.devno = sb->st_rdev;
+ child->data.dir->created_implicitly = false;
+ return child;
}
- return node;
+ return fstree_mknode(fs, parent, name, strlen(name), extra, sb);
}
int fstree_add_xattr(fstree_t *fs, tree_node_t *node,
@@ -347,10 +307,13 @@ int fstree_init(fstree_t *fs, size_t block_size, uint32_t mtime,
{
memset(fs, 0, sizeof(*fs));
- fs->default_uid = default_uid;
- fs->default_gid = default_gid;
- fs->default_mode = default_mode & 07777;
- fs->default_mtime = mtime;
+ fs->defaults.st_uid = default_uid;
+ fs->defaults.st_gid = default_gid;
+ fs->defaults.st_mode = S_IFDIR | (default_mode & 07777);
+ fs->defaults.st_mtime = mtime;
+ fs->defaults.st_ctime = mtime;
+ fs->defaults.st_atime = mtime;
+ fs->defaults.st_blksize = block_size;
fs->block_size = block_size;
if (str_table_init(&fs->xattr_keys, FSTREE_XATTR_KEY_BUCKETS))
@@ -361,8 +324,7 @@ int fstree_init(fstree_t *fs, size_t block_size, uint32_t mtime,
return -1;
}
- fs->root = mknode(NULL, "", 0, 0, S_IFDIR | fs->default_mode,
- default_uid, default_gid);
+ fs->root = fstree_mknode(fs, NULL, "", 0, NULL, &fs->defaults);
if (fs->root == NULL) {
perror("initializing file system tree");
diff --git a/lib/fstree/fstree_from_dir.c b/lib/fstree/fstree_from_dir.c
index fb906f1..ea1ebe9 100644
--- a/lib/fstree/fstree_from_dir.c
+++ b/lib/fstree/fstree_from_dir.c
@@ -7,55 +7,57 @@
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
+#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
-static size_t path_size(tree_node_t *n)
+static char *get_file_path(tree_node_t *n, const char *name)
{
- size_t size = 0;
+ char *ptr, *new;
- while (n != NULL) {
- size += strlen(n->name) + 1;
- n = n->parent;
+ if (n->parent == NULL) {
+ ptr = strdup(name);
+ if (ptr == NULL)
+ goto fail;
+ return ptr;
}
- return size;
-}
+ ptr = fstree_get_path(n);
+ if (ptr == NULL)
+ goto fail;
-static char *print_path(char *ptr, tree_node_t *n)
-{
- if (n->parent != NULL) {
- ptr = print_path(ptr, n->parent);
- *(ptr++) = '/';
- strcpy(ptr, n->name);
- return ptr + strlen(ptr);
- }
+ assert(canonicalize_name(ptr) == 0);
+
+ new = realloc(ptr, strlen(ptr) + strlen(name) + 2);
+ if (new == NULL)
+ goto fail;
+ ptr = new;
+ strcat(ptr, "/");
+ strcat(ptr, name);
return ptr;
+fail:
+ perror("getting absolute file path");
+ free(ptr);
+ return NULL;
}
-static int populate_dir(tree_node_t *root, int fd, size_t blocksize,
- const char *rootdir)
+static int populate_dir(fstree_t *fs, tree_node_t *root)
{
- size_t size, blockcount;
+ char *extra = NULL;
struct dirent *ent;
struct stat sb;
tree_node_t *n;
- ssize_t ret;
- void *ptr;
DIR *dir;
- int cfd;
- dir = fdopendir(fd);
+ dir = opendir(".");
if (dir == NULL) {
- perror("fdopendir");
- close(fd);
+ perror("opendir");
return -1;
}
for (;;) {
- n = NULL;
errno = 0;
ent = readdir(dir);
@@ -70,120 +72,70 @@ static int populate_dir(tree_node_t *root, int fd, size_t blocksize,
if (!strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "."))
continue;
- if (fstatat(fd, ent->d_name, &sb, AT_SYMLINK_NOFOLLOW)) {
+ if (fstatat(AT_FDCWD, ent->d_name, &sb, AT_SYMLINK_NOFOLLOW)) {
perror(ent->d_name);
goto fail;
}
- size = sizeof(tree_node_t) + strlen(ent->d_name) + 1;
-
- switch (sb.st_mode & S_IFMT) {
- case S_IFLNK:
- size += sb.st_size + 1;
- break;
- case S_IFREG:
- blockcount = sb.st_size / blocksize + 1;
-
- size += sizeof(file_info_t);
- size += sizeof(uint32_t) * blockcount;
+ if (S_ISLNK(sb.st_mode)) {
+ extra = alloca(sb.st_size + 1);
+ if (extra == NULL)
+ goto fail_rdlink;
- size += path_size(root) + strlen(ent->d_name) + 1;
- size += strlen(rootdir) + 2;
- break;
- case S_IFDIR:
- size += sizeof(dir_info_t);
- break;
+ if (readlink(ent->d_name, extra, sb.st_size) < 0)
+ goto fail_rdlink;
+ } else if (S_ISREG(sb.st_mode)) {
+ extra = get_file_path(root, ent->d_name);
+ if (extra == NULL)
+ goto fail;
}
- n = calloc(1, size);
+ n = fstree_mknode(fs, root, ent->d_name, strlen(ent->d_name),
+ extra, &sb);
if (n == NULL) {
- perror("allocating tree node");
+ perror("creating tree node");
goto fail;
}
- n->uid = sb.st_uid;
- n->gid = sb.st_gid;
- n->mode = sb.st_mode;
- n->parent = root;
-
- ptr = n->payload;
-
- switch (sb.st_mode & S_IFMT) {
- case S_IFLNK:
- ret = readlinkat(fd, ent->d_name, ptr, sb.st_size);
- if (ret < 0) {
- perror("readlink");
- goto fail;
- }
-
- n->data.slink_target = ptr;
- ptr = (char *)ptr + strlen(ptr) + 1;
- break;
- case S_IFBLK:
- case S_IFCHR:
- n->data.devno = sb.st_rdev;
- break;
- case S_IFDIR:
- n->data.dir = ptr;
- ptr = (char *)ptr + sizeof(dir_info_t);
- break;
- case S_IFREG:
- n->data.file = ptr;
- ptr = (char *)ptr + sizeof(file_info_t);
- ptr = (char *)ptr + sizeof(uint32_t) * blockcount;
-
- n->data.file->input_file = ptr;
- n->data.file->size = sb.st_size;
-
- strcpy(ptr, rootdir);
- ptr = (char *)ptr + strlen(ptr);
- ptr = print_path(ptr, root);
-
- *((char*)ptr) = '/';
- strcpy((char *)ptr + 1, ent->d_name);
- ptr = (char *)ptr + strlen(ptr) + 1;
- break;
- }
-
- n->name = ptr;
- strcpy(ptr, ent->d_name);
-
- n->next = root->data.dir->children;
- root->data.dir->children = n;
+ free(extra);
+ extra = NULL;
}
+ closedir(dir);
+
for (n = root->data.dir->children; n != NULL; n = n->next) {
if (S_ISDIR(n->mode)) {
- cfd = openat(fd, n->name, O_RDONLY | O_DIRECTORY);
- if (cfd < 0) {
- perror(n->name);
- goto fail_dir;
- }
+ if (pushd(n->name))
+ return -1;
- if (populate_dir(n, cfd, blocksize, rootdir)) {
- close(cfd);
- goto fail_dir;
- }
+ if (populate_dir(fs, n))
+ return -1;
+
+ if (popd())
+ return -1;
}
}
- closedir(dir);
return 0;
+fail_rdlink:
+ perror("readlink");
fail:
- free(n);
-fail_dir:
closedir(dir);
+ free(extra);
return -1;
}
int fstree_from_dir(fstree_t *fs, const char *path)
{
- int fd = open(path, O_RDONLY | O_DIRECTORY);
+ int ret;
- if (fd < 0) {
- perror(path);
+ if (pushd(path))
return -1;
- }
- return populate_dir(fs->root, fd, fs->block_size, path);
+ ret = populate_dir(fs, fs->root);
+
+ if (popd())
+ ret = -1;
+
+ return ret;
}
diff --git a/lib/fstree/node_stat.c b/lib/fstree/node_stat.c
index a6ec097..8f62a0f 100644
--- a/lib/fstree/node_stat.c
+++ b/lib/fstree/node_stat.c
@@ -7,17 +7,12 @@ void fstree_node_stat(fstree_t *fs, tree_node_t *node, struct stat *sb)
{
tree_node_t *n;
- memset(sb, 0, sizeof(*sb));
-
+ *sb = fs->defaults;
sb->st_ino = node->inode_num;
sb->st_mode = node->mode;
sb->st_nlink = 1;
sb->st_uid = node->uid;
sb->st_gid = node->gid;
- sb->st_blksize = fs->block_size;
- sb->st_mtime = fs->default_mtime;
- sb->st_atime = sb->st_mtime;
- sb->st_ctime = sb->st_mtime;
switch (node->mode & S_IFMT) {
case S_IFDIR: