diff options
Diffstat (limited to 'lib/fstree/fstree_from_dir.c')
-rw-r--r-- | lib/fstree/fstree_from_dir.c | 174 |
1 files changed, 63 insertions, 111 deletions
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; } |