Get device file ezxtraction working and tested

This commit is contained in:
Nathan Fisher 2023-10-03 01:53:59 -04:00
parent 349c9389dd
commit 7b94a728ae
6 changed files with 127 additions and 32 deletions

View file

@ -54,7 +54,7 @@ srcs += linkmap.c
objs = $(srcs:.c=.o)
all: libhaggis.a libhaggis.so
all: shared static
shared: libhaggis.so

View file

@ -36,6 +36,7 @@
#include <errno.h>
#include <libgen.h>
#include <limits.h> // PATH_MAX
#include <linux/limits.h>
#include <stddef.h>
#include <stdint.h> // uint<x>_t
#include <sys/unistd.h>
@ -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;
}

View file

@ -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);

14
mq.c
View file

@ -33,6 +33,7 @@
#include <stdio.h>
#include <stdlib.h> // 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;

View file

@ -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:

42
test/extract_dev_node.c Normal file
View file

@ -0,0 +1,42 @@
#include <errno.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#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;
}