From 7b94a728aec2e7ab40cc02fe6c22ef9ab0bf6fcf Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Tue, 3 Oct 2023 01:53:59 -0400 Subject: [PATCH] Get device file ezxtraction working and tested --- Makefile | 2 +- haggis.c | 86 ++++++++++++++++++++++++++++------------- include/haggis.h | 2 +- mq.c | 14 +++++++ test/Makefile | 13 +++++-- test/extract_dev_node.c | 42 ++++++++++++++++++++ 6 files changed, 127 insertions(+), 32 deletions(-) create mode 100644 test/extract_dev_node.c diff --git a/Makefile b/Makefile index 4b45bfb..0649feb 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ srcs += linkmap.c objs = $(srcs:.c=.o) -all: libhaggis.a libhaggis.so +all: shared static shared: libhaggis.so diff --git a/haggis.c b/haggis.c index e10c5f7..b5895d5 100644 --- a/haggis.c +++ b/haggis.c @@ -36,6 +36,7 @@ #include #include #include // PATH_MAX +#include #include #include // uint_t #include @@ -592,7 +593,7 @@ int haggis_init_dev_node( } } haggis_device_init(st->st_rdev, &node->filetype.f_type.dev); - body.f_name = node->name.name; + body.f_name = strndup(node->name.name, PATH_MAX); msg = haggis_msg_init(NodeCreated, body); haggis_mq_push(mq, msg); return 0; @@ -711,6 +712,17 @@ char* get_full_path(haggis_filename *fname, char *basedir) { return path; } +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_dev(haggis_node *node, char *basedir) { dev_t dev; mode_t mode; @@ -722,10 +734,18 @@ int haggis_extract_dev(haggis_node *node, char *basedir) { path = get_full_path(&node->name, basedir); if (path == NULL) return errno; + if (mkdir_p(dirname(strndup(path, PATH_MAX)))) { + free(path); + return 2; + } 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; + if (node->filetype.tag == block) { + mode = (mode_t)node->mode.val | S_IFBLK; + } else if (node->filetype.tag == character) { + mode = (mode_t)node->mode.val | S_IFCHR; + } ret = mknod(path, mode, dev); free(path); return ret; @@ -740,6 +760,10 @@ int haggis_extract_fifo(haggis_node *node, char *basedir) { path = get_full_path(&node->name, basedir); if (path == NULL) return 1; + if (mkdir_p(dirname(strndup(path, PATH_MAX)))) { + free(path); + return 2; + } mode = (mode_t)node->mode.val; ret = mkfifo(path, mode); free(path); @@ -756,6 +780,10 @@ int haggis_extract_symlink(haggis_node *node, char *basedir) { path = get_full_path(&node->name, basedir); if (path == NULL) return 1; + if (mkdir_p(dirname(strndup(path, PATH_MAX)))) { + free(path); + return 2; + } target = node->filetype.f_type.target.name; ret = symlink(target, path); free(path); @@ -773,6 +801,10 @@ int haggis_extract_hardlink(haggis_node *node, char *basedir) { path = get_full_path(&node->name, basedir); if (path == NULL) return 1; + if (mkdir_p(dirname(strndup(path, PATH_MAX)))) { + free(path); + return 2; + } target = get_full_path(&node->filetype.f_type.target, basedir); if (target == NULL) { free(path); @@ -780,6 +812,10 @@ int haggis_extract_hardlink(haggis_node *node, char *basedir) { } if (access(target, F_OK) == -1) { fd = fopen(target, "w"); + if (mkdir_p(dirname(strndup(target, PATH_MAX)))) { + free(path); + return 2; + } if (fd == NULL) { free(path); free(target); @@ -795,17 +831,6 @@ 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) { char *path; @@ -819,7 +844,7 @@ int haggis_extract_dir(haggis_node *node, char *basedir) { return 0; } -int haggis_extract_file(haggis_node *node, char *basedir) { +char* haggis_extract_file(haggis_node *node, char *basedir) { char *path; FILE *fd; size_t len; @@ -828,32 +853,33 @@ int haggis_extract_file(haggis_node *node, char *basedir) { assert(node->filetype.tag == normal); path = get_full_path(&node->name, basedir); if (path == NULL) { - return 1; + return NULL; } if (mkdir_p(dirname(strndup(path, PATH_MAX)))) { free(path); - return errno; + return NULL; } fd = fopen(path, "w"); if (fd == NULL) { free(path); - return 1; + return NULL; } 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); + fclose(fd); + return NULL; } fflush(fd); fclose(fd); - free(path); - return 0; + return path; } -int haggis_extract_node(FILE *stream, char *basedir, haggis_node *node) { - // todo: take a `haggis_mq` pointer as a parameter - char *path, *dir; - int ret; +int haggis_extract_node(char *basedir, haggis_node *node, haggis_mq *mq) { + haggis_msg *msg; + char *path, *dir, *fullpath; + int ret; path = get_full_path(&node->name, basedir); dir = dirname(strndup(path, PATH_MAX)); @@ -879,7 +905,10 @@ int haggis_extract_node(FILE *stream, char *basedir, haggis_node *node) { ret = haggis_extract_dir(node, basedir); break; case normal: - ret = haggis_extract_file(node, basedir); + fullpath = haggis_extract_file(node, basedir); + if (fullpath == NULL) { + ret = errno; + } break; case eof: return 0; @@ -892,7 +921,12 @@ int haggis_extract_node(FILE *stream, char *basedir, haggis_node *node) { } } ret = chmod(path, (mode_t)node->mode.val); - // todo: make a 'NodeCreated' message and add it to the message queue + msg = calloc(1, sizeof(haggis_msg)); + if (msg == NULL) + return 2; + msg->tag = NodeExtracted; + msg->body.f_name = strndup(node->name.name, PATH_MAX); + haggis_mq_push(mq, msg); return ret; } diff --git a/include/haggis.h b/include/haggis.h index 4f4d2b2..b089e56 100644 --- a/include/haggis.h +++ b/include/haggis.h @@ -168,7 +168,7 @@ void haggis_linkmap_deinit(haggis_linkmap *map); char* haggis_linkmap_get_or_add(haggis_linkmap *map, ino_t inode, char *path); void haggis_node_deinit(haggis_node *node); haggis_node* haggis_create_node(char *file, haggis_algorithm a, haggis_linkmap *map, haggis_mq *mq); -int haggis_extract_node(FILE *stream, char *basedir, haggis_node *node); +int haggis_extract_node(char *basedir, haggis_node *node, haggis_mq *mq); int haggis_load_node(FILE *stream, haggis_node *node); int haggis_store_node(FILE *stream, haggis_node *node); diff --git a/mq.c b/mq.c index 58519aa..b3d25e5 100644 --- a/mq.c +++ b/mq.c @@ -33,6 +33,7 @@ #include #include // free, malloc +#include "haggis.h" #include "mq.h" haggis_msg* haggis_msg_init(haggis_message_type tag, haggis_message_body body) { @@ -45,6 +46,19 @@ haggis_msg* haggis_msg_init(haggis_message_type tag, haggis_message_body body) { return msg; } +void haggis_msg_deinit(haggis_msg *msg) { + switch (msg->tag) { + case NodeCreated: + case NodeExtracted: + free(msg->body.f_name); + break; + case EndOfArchive: + case ArchiveError: + break; + } + free(msg); +} + int haggis_mq_init(haggis_mq *mq) { int ret; diff --git a/test/Makefile b/test/Makefile index 6ec1663..8c94194 100644 --- a/test/Makefile +++ b/test/Makefile @@ -71,25 +71,30 @@ tests += create_fifo_node tests += create_dev_node tests += create_file_node tests += mq_push_pop +tests += extract_dev_node total != echo $(tests) | wc -w | awk '{ print $$1 }' .PHONY: test test: $(tests) output @echo -e "\n\t=== \e[0;33mRunning $(total) tests\e[0m ===\n" - @idx=1 ; success=0 ; fail=0; for t in $(tests) ; \ + @idx=1 ; success=0 ; fail=0; skip=0; for t in $(tests) ; \ do printf "[%02i/$(total)] %-25s" $${idx} $${t} ; \ idx=$$(expr $${idx} + 1) ; \ ./$${t} ; \ - if [ $$? -eq 0 ] ; \ + retval=$$? ; \ + if [ $${retval} -eq 0 ] ; \ then echo -e '\e[0;32mSuccess\e[0m' ; \ success=$$(expr $${success} + 1) ; \ + elif [ $${retval} -eq 255 ] ; \ + then echo Skipped ; \ + skip=$$(expr $${skip} + 1) ; \ else echo -e '\e[0;31mFailure\e[0m' ; \ fail=$$(expr $${fail} + 1) ; \ fi ; done || true ; \ if [ $${fail} == 0 ] ; \ - then echo -e '\nResults: \e[0;32mOk\e[0m.' "$${success} succeeded; $${fail} failed" ; \ - else echo -e '\nResults: \e[0;31mFAILED\e[0m.' "$${success} succeeded; $${fail} failed\n" ; \ + then echo -e '\nResults: \e[0;32mOk\e[0m.' "$${success} succeeded; $${fail} failed; $${skip} skipped" ; \ + else echo -e '\nResults: \e[0;31mFAILED\e[0m.' "$${success} succeeded; $${fail} failed; $${skip} skipped" ; \ fi output: diff --git a/test/extract_dev_node.c b/test/extract_dev_node.c new file mode 100644 index 0000000..87bc0dd --- /dev/null +++ b/test/extract_dev_node.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "haggis.h" +#include "mq.h" + +int main() { + haggis_node *node = NULL; + haggis_linkmap *map = NULL; + haggis_mq mq; + haggis_msg *msg; + char *path = "/dev/null", *msg_text; + int ret = 0; + + if (geteuid() != 0) + return -1; + map = haggis_linkmap_init(); + assert(map != NULL); + if (haggis_mq_init(&mq)) + return errno; + node = haggis_create_node(path, sha256, map, &mq); + assert(node != NULL); + assert(node->filetype.tag == block || node->filetype.tag == character); + assert(memcmp(node->name.name, "dev/null", 8) == 0); + msg = haggis_mq_pop(&mq); + assert(msg->tag == NodeCreated); + assert(memcmp(msg->body.f_name, "dev/null", 8) == 0); + haggis_msg_deinit(msg); + ret = haggis_extract_node("output/extracted", node, &mq); + msg = haggis_mq_pop(&mq); + assert(msg->tag == NodeExtracted); + assert(memcmp(msg->body.f_name, "dev/null", 8) == 0); + haggis_msg_deinit(msg); + haggis_node_deinit(node); + haggis_linkmap_deinit(map); + return 0; +} \ No newline at end of file