Wrote the extract_node functionality; TODO: test it;

This commit is contained in:
Nathan Fisher 2023-09-21 22:58:32 -04:00
parent 58ba56f852
commit 2bc5861dc0

View file

@ -32,11 +32,14 @@
#include "haggis.h"
#include "mq.h"
#include <asm-generic/errno-base.h>
#include <assert.h>
#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/syslimits.h>
#include <sys/unistd.h>
#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) {