From 2bc5861dc035a1f753e8f017d005319a0f6fc193 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Thu, 21 Sep 2023 22:58:32 -0400 Subject: [PATCH] Wrote the `extract_node` functionality; TODO: test it; --- haggis.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 84 insertions(+), 14 deletions(-) diff --git a/haggis.c b/haggis.c index d6d893c..fee190a 100644 --- a/haggis.c +++ b/haggis.c @@ -32,11 +32,14 @@ #include "haggis.h" #include "mq.h" +#include #include #include +#include #include // PATH_MAX +#include +#include #include // uint_t -#include #include #if defined(__FreeBSD__) || defined(__DragonFly__) @@ -714,14 +717,16 @@ int haggis_extract_dev(haggis_node *node, char *basedir) { dev_t dev; mode_t mode; char *path; - int ret; + int ret, major, minor; assert(geteuid() == 0); assert(node->filetype.tag == block || node->filetype.tag == character); path = get_full_path(&node->name, basedir); if (path == NULL) return errno; - dev = makedev((int)node->filetype.f_type.dev.major.val, (int)node->filetype.f_type.dev.minor.val); + major = (int)node->filetype.f_type.dev.major.val; + minor = (int)node->filetype.f_type.dev.minor.val; + dev = makedev(major, minor); mode = (mode_t)node->mode.val; ret = mknod(path, mode, dev); free(path); @@ -746,14 +751,15 @@ int haggis_extract_fifo(haggis_node *node, char *basedir) { } int haggis_extract_symlink(haggis_node *node, char *basedir) { - char *path; + char *path, *target; int ret; assert(node->filetype.tag == softlink); path = get_full_path(&node->name, basedir); if (path == NULL) return 1; - ret = symlink(node->filetype.f_type.target.name, path); + target = node->filetype.f_type.target.name; + ret = symlink(target, path); free(path); if (ret != 0) return errno; @@ -791,39 +797,103 @@ int haggis_extract_hardlink(haggis_node *node, char *basedir) { return 0; } +int mkdir_p(char *dir) { + struct stat st; + + if (!stat(dir, &st)) + return 0; + + if (mkdir_p(dirname(strndup(dir, PATH_MAX)))) + return 1; + return mkdir(dir, 0755); +} + int haggis_extract_dir(haggis_node *node, char *basedir) { - // todo + char *path; + assert(node->filetype.tag == directory); + path = get_full_path(&node->name, basedir); + if (mkdir_p(path)) { + free(path); + return errno; + } + free(path); return 0; } int haggis_extract_file(haggis_node *node, char *basedir) { - // todo + char *path; + FILE *fd; + size_t len; + int ret; + assert(node->filetype.tag == normal); + path = get_full_path(&node->name, basedir); + if (path == NULL) { + return 1; + } + if (mkdir_p(dirname(strndup(path, PATH_MAX)))) { + free(path); + return errno; + } + fd = fopen(path, "w"); + if (fd == NULL) { + free(path); + return 1; + } + len = (size_t)node->filetype.f_type.file.len.val; + ret = fwrite(node->filetype.f_type.file.data, len, 1, fd); + if (ret != len) { + return 2; + } + free(path); return 0; } int haggis_extract_node(FILE *stream, char *basedir, haggis_node *node) { - // todo + // todo: take a `haggis_mq` pointer as a parameter + char *path, *dir; + int ret; + + path = get_full_path(&node->name, basedir); + dir = dirname(strndup(path, PATH_MAX)); + mkdir_p(dir); switch (node->filetype.tag) { case block: case character: if (geteuid() == 0) - return haggis_extract_dev(node, basedir); + ret = haggis_extract_dev(node, basedir); + // todo: Add message type for skipped file and add it to queue if we're + // not root when calling this. We want this to be a warning, but not a + // fatal error. + break; case fifo: - return haggis_extract_fifo(node, basedir); + ret = haggis_extract_fifo(node, basedir); + break; case softlink: return haggis_extract_symlink(node, basedir); case hardlink: - return haggis_extract_hardlink(node, basedir); + ret = haggis_extract_hardlink(node, basedir); + break; case directory: - return haggis_extract_dir(node, basedir); + ret = haggis_extract_dir(node, basedir); + break; case normal: - return haggis_extract_file(node, basedir); + ret = haggis_extract_file(node, basedir); + break; case eof: return 0; } - return 0; + if (geteuid() == 0) { + ret = chown(path, (uid_t)node->uid.val, (gid_t)node->gid.val); + if (ret != 0) { + free(path); + return errno; + } + } + ret = chmod(path, (mode_t)node->mode.val); + // todo: make a 'NodeCreated' message and add it to the message queue + return ret; } int haggis_load_node(FILE *stream, haggis_node *node) {