Progress on extracting nodes

This commit is contained in:
Nathan Fisher 2023-09-19 20:46:48 -04:00
parent 2e8e2e9a28
commit 58ba56f852

197
haggis.c
View file

@ -36,6 +36,8 @@
#include <errno.h> #include <errno.h>
#include <limits.h> // PATH_MAX #include <limits.h> // PATH_MAX
#include <stdint.h> // uint<x>_t #include <stdint.h> // uint<x>_t
#include <sys/syslimits.h>
#include <sys/unistd.h>
#if defined(__FreeBSD__) || defined(__DragonFly__) #if defined(__FreeBSD__) || defined(__DragonFly__)
#include <sha.h> #include <sha.h>
@ -559,6 +561,7 @@ int haggis_init_file_node(
return 0; return 0;
} }
} }
node->filetype.tag = normal;
res = haggis_file_init(node->name.name, &node->filetype.f_type.file, a); res = haggis_file_init(node->name.name, &node->filetype.f_type.file, a);
if (res != 0) { if (res != 0) {
haggis_node_deinit(node); haggis_node_deinit(node);
@ -570,6 +573,30 @@ int haggis_init_file_node(
return 0; return 0;
} }
int haggis_init_dev_node(
haggis_node *node,
struct stat *st,
haggis_linkmap *map,
haggis_mq *mq
) {
haggis_message_body body;
haggis_msg *msg;
char *target;
if (st->st_nlink > 1) {
target = haggis_linkmap_get_or_add(map, st->st_ino, node->name.name);
if (target != NULL) {
haggis_init_hardlink_node(node, target, map, mq);
return 0;
}
}
haggis_device_init(st->st_rdev, &node->filetype.f_type.dev);
body.f_name = node->name.name;
msg = haggis_msg_init(NodeCreated, body);
haggis_mq_push(mq, msg);
return 0;
}
haggis_node* haggis_create_node( haggis_node* haggis_create_node(
char *file, char *file,
haggis_algorithm a, haggis_algorithm a,
@ -592,22 +619,6 @@ haggis_node* haggis_create_node(
free(node); free(node);
return NULL; return NULL;
} }
if (S_ISBLK(st.st_mode)) {
node->filetype.tag = block;
} else if (S_ISCHR(st.st_mode)) {
node->filetype.tag = character;
} else if (S_ISDIR(st.st_mode)) {
node->filetype.tag = directory;
} else if (S_ISFIFO(st.st_mode)) {
node->filetype.tag = fifo;
} else if (S_ISLNK(st.st_mode)) {
node->filetype.tag = softlink;
} else if (S_ISREG(st.st_mode)) {
node->filetype.tag = normal;
} else {
free(node);
return NULL;
}
errno = 0; errno = 0;
if (file[0] == '/') { if (file[0] == '/') {
namlen = strnlen(file, PATH_MAX - 1); namlen = strnlen(file, PATH_MAX - 1);
@ -626,13 +637,20 @@ haggis_node* haggis_create_node(
node->mtime.val = (uint64_t)st.st_mtim.tv_sec; node->mtime.val = (uint64_t)st.st_mtim.tv_sec;
mode.val = (uint16_t)(st.st_mode & 07777); mode.val = (uint16_t)(st.st_mode & 07777);
node->mode = mode; node->mode = mode;
switch (node->filetype.tag) { if (S_ISBLK(st.st_mode)) {
case normal: node->filetype.tag = block;
res = haggis_init_file_node(node, &st, a, map, mq); res = haggis_init_dev_node(node, &st, map, mq);
if (res != 0) if (res != 0)
return NULL; return NULL;
break; } else if (S_ISCHR(st.st_mode)) {
case block: node->filetype.tag = character;
res = haggis_init_dev_node(node, &st, map, mq);
if (res != 0)
return NULL;
} else if (S_ISDIR(st.st_mode)) {
node->filetype.tag = directory;
} else if (S_ISFIFO(st.st_mode)) {
node->filetype.tag = fifo;
if (st.st_nlink > 1) { if (st.st_nlink > 1) {
target = haggis_linkmap_get_or_add(map, st.st_ino, file); target = haggis_linkmap_get_or_add(map, st.st_ino, file);
if (target != NULL) { if (target != NULL) {
@ -640,35 +658,7 @@ haggis_node* haggis_create_node(
return node; return node;
} }
} }
haggis_device_init(st.st_rdev, &node->filetype.f_type.dev); } else if (S_ISLNK(st.st_mode)) {
break;
case character:
if (st.st_nlink > 1) {
target = haggis_linkmap_get_or_add(map, st.st_ino, file);
if (target != NULL) {
haggis_init_hardlink_node(node, target, map, mq);
return node;
}
}
haggis_device_init(st.st_rdev, &node->filetype.f_type.dev);
break;
case fifo:
if (st.st_nlink > 1) {
target = haggis_linkmap_get_or_add(map, st.st_ino, file);
if (target != NULL) {
haggis_init_hardlink_node(node, target, map, mq);
return node;
}
}
return node;
case directory:
case hardlink:
case eof:
body.f_name = NULL;
msg = haggis_msg_init(EndOfArchive, body);
haggis_mq_push(mq, msg);
return node;
case softlink:
node->filetype.tag = softlink; node->filetype.tag = softlink;
ssize_t res = readlink(file, pathbuf, PATH_MAX); ssize_t res = readlink(file, pathbuf, PATH_MAX);
if (res == -1) { if (res == -1) {
@ -681,35 +671,123 @@ haggis_node* haggis_create_node(
body.f_name = file; body.f_name = file;
msg = haggis_msg_init(NodeCreated, body); msg = haggis_msg_init(NodeCreated, body);
haggis_mq_push(mq, msg); haggis_mq_push(mq, msg);
} else if (S_ISREG(st.st_mode)) {
node->filetype.tag = normal;
res = haggis_init_file_node(node, &st, a, map, mq);
if (res != 0)
return NULL;
} else {
free(node);
return NULL;
}
return node; return node;
} }
body.f_name = file;
msg = haggis_msg_init(NodeCreated, body); char* get_full_path(haggis_filename *fname, char *basedir) {
haggis_mq_push(mq, msg); char *path;
return node; int pathlen;
if (basedir == NULL) {
path = calloc(1, (int)fname->len.val + 1);
if (path == NULL)
return NULL;
memcpy(path, fname->name, fname->len.val);
} else {
if (fname->name[0] == '/') {
pathlen = strnlen(basedir, PATH_MAX) + (int)fname->len.val + 1;
path = calloc(1, pathlen);
if (path == NULL)
return NULL;
snprintf(path, pathlen, "%s%s", basedir, fname->name);
} else {
pathlen = strnlen(basedir, PATH_MAX) + (int)fname->len.val + 2;
path = calloc(1, pathlen);
if (path == NULL)
return NULL;
snprintf(path, pathlen, "%s/%s", basedir, fname->name);
}
}
return path;
} }
int haggis_extract_dev(haggis_node *node, char *basedir) { int haggis_extract_dev(haggis_node *node, char *basedir) {
// todo dev_t dev;
mode_t mode;
char *path;
int ret;
assert(geteuid() == 0);
assert(node->filetype.tag == block || node->filetype.tag == character); assert(node->filetype.tag == block || node->filetype.tag == character);
return 0; 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);
mode = (mode_t)node->mode.val;
ret = mknod(path, mode, dev);
free(path);
return ret;
} }
int haggis_extract_fifo(haggis_node *node, char *basedir) { int haggis_extract_fifo(haggis_node *node, char *basedir) {
// todo mode_t mode;
char *path;
int ret;
assert(node->filetype.tag == fifo); assert(node->filetype.tag == fifo);
path = get_full_path(&node->name, basedir);
if (path == NULL)
return 1;
mode = (mode_t)node->mode.val;
ret = mkfifo(path, mode);
free(path);
if (ret !=0)
return errno;
return 0; return 0;
} }
int haggis_extract_symlink(haggis_node *node, char *basedir) { int haggis_extract_symlink(haggis_node *node, char *basedir) {
// todo char *path;
int ret;
assert(node->filetype.tag == softlink); 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);
free(path);
if (ret != 0)
return errno;
return 0; return 0;
} }
int haggis_extract_hardlink(haggis_node *node, char *basedir) { int haggis_extract_hardlink(haggis_node *node, char *basedir) {
// todo char *path, *target;
int ret;
FILE *fd;
assert(node->filetype.tag == hardlink); assert(node->filetype.tag == hardlink);
path = get_full_path(&node->name, basedir);
if (path == NULL)
return 1;
target = get_full_path(&node->filetype.f_type.target, basedir);
if (target == NULL) {
free(path);
return 1;
}
if (access(target, F_OK) == -1) {
fd = fopen(target, "w");
if (fd == NULL) {
free(path);
free(target);
return errno;
}
fclose(fd);
}
ret = link(target, path);
free(path);
free(target);
if (ret != 0)
return errno;
return 0; return 0;
} }
@ -730,6 +808,7 @@ int haggis_extract_node(FILE *stream, char *basedir, haggis_node *node) {
switch (node->filetype.tag) { switch (node->filetype.tag) {
case block: case block:
case character: case character:
if (geteuid() == 0)
return haggis_extract_dev(node, basedir); return haggis_extract_dev(node, basedir);
case fifo: case fifo:
return haggis_extract_fifo(node, basedir); return haggis_extract_fifo(node, basedir);