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 "haggis.h"
#include "mq.h" #include "mq.h"
#include <asm-generic/errno-base.h>
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <libgen.h>
#include <limits.h> // PATH_MAX #include <limits.h> // PATH_MAX
#include <linux/limits.h>
#include <stddef.h>
#include <stdint.h> // uint<x>_t #include <stdint.h> // uint<x>_t
#include <sys/syslimits.h>
#include <sys/unistd.h> #include <sys/unistd.h>
#if defined(__FreeBSD__) || defined(__DragonFly__) #if defined(__FreeBSD__) || defined(__DragonFly__)
@ -714,14 +717,16 @@ int haggis_extract_dev(haggis_node *node, char *basedir) {
dev_t dev; dev_t dev;
mode_t mode; mode_t mode;
char *path; char *path;
int ret; int ret, major, minor;
assert(geteuid() == 0); assert(geteuid() == 0);
assert(node->filetype.tag == block || node->filetype.tag == character); assert(node->filetype.tag == block || node->filetype.tag == character);
path = get_full_path(&node->name, basedir); path = get_full_path(&node->name, basedir);
if (path == NULL) if (path == NULL)
return errno; 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; mode = (mode_t)node->mode.val;
ret = mknod(path, mode, dev); ret = mknod(path, mode, dev);
free(path); free(path);
@ -746,14 +751,15 @@ int haggis_extract_fifo(haggis_node *node, char *basedir) {
} }
int haggis_extract_symlink(haggis_node *node, char *basedir) { int haggis_extract_symlink(haggis_node *node, char *basedir) {
char *path; char *path, *target;
int ret; int ret;
assert(node->filetype.tag == softlink); assert(node->filetype.tag == softlink);
path = get_full_path(&node->name, basedir); path = get_full_path(&node->name, basedir);
if (path == NULL) if (path == NULL)
return 1; return 1;
ret = symlink(node->filetype.f_type.target.name, path); target = node->filetype.f_type.target.name;
ret = symlink(target, path);
free(path); free(path);
if (ret != 0) if (ret != 0)
return errno; return errno;
@ -791,39 +797,103 @@ int haggis_extract_hardlink(haggis_node *node, char *basedir) {
return 0; 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) { int haggis_extract_dir(haggis_node *node, char *basedir) {
// todo char *path;
assert(node->filetype.tag == directory); assert(node->filetype.tag == directory);
path = get_full_path(&node->name, basedir);
if (mkdir_p(path)) {
free(path);
return errno;
}
free(path);
return 0; return 0;
} }
int haggis_extract_file(haggis_node *node, char *basedir) { int haggis_extract_file(haggis_node *node, char *basedir) {
// todo char *path;
FILE *fd;
size_t len;
int ret;
assert(node->filetype.tag == normal); 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; return 0;
} }
int haggis_extract_node(FILE *stream, char *basedir, haggis_node *node) { 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) { switch (node->filetype.tag) {
case block: case block:
case character: case character:
if (geteuid() == 0) 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: case fifo:
return haggis_extract_fifo(node, basedir); ret = haggis_extract_fifo(node, basedir);
break;
case softlink: case softlink:
return haggis_extract_symlink(node, basedir); return haggis_extract_symlink(node, basedir);
case hardlink: case hardlink:
return haggis_extract_hardlink(node, basedir); ret = haggis_extract_hardlink(node, basedir);
break;
case directory: case directory:
return haggis_extract_dir(node, basedir); ret = haggis_extract_dir(node, basedir);
break;
case normal: case normal:
return haggis_extract_file(node, basedir); ret = haggis_extract_file(node, basedir);
break;
case eof: case eof:
return 0; 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) { int haggis_load_node(FILE *stream, haggis_node *node) {