Progress on extracting nodes
This commit is contained in:
parent
2e8e2e9a28
commit
58ba56f852
1 changed files with 159 additions and 80 deletions
239
haggis.c
239
haggis.c
|
@ -36,6 +36,8 @@
|
|||
#include <errno.h>
|
||||
#include <limits.h> // PATH_MAX
|
||||
#include <stdint.h> // uint<x>_t
|
||||
#include <sys/syslimits.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <sha.h>
|
||||
|
@ -559,6 +561,7 @@ int haggis_init_file_node(
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
node->filetype.tag = normal;
|
||||
res = haggis_file_init(node->name.name, &node->filetype.f_type.file, a);
|
||||
if (res != 0) {
|
||||
haggis_node_deinit(node);
|
||||
|
@ -570,6 +573,30 @@ int haggis_init_file_node(
|
|||
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(
|
||||
char *file,
|
||||
haggis_algorithm a,
|
||||
|
@ -592,22 +619,6 @@ haggis_node* haggis_create_node(
|
|||
free(node);
|
||||
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;
|
||||
if (file[0] == '/') {
|
||||
namlen = strnlen(file, PATH_MAX - 1);
|
||||
|
@ -626,90 +637,157 @@ haggis_node* haggis_create_node(
|
|||
node->mtime.val = (uint64_t)st.st_mtim.tv_sec;
|
||||
mode.val = (uint16_t)(st.st_mode & 07777);
|
||||
node->mode = mode;
|
||||
switch (node->filetype.tag) {
|
||||
case normal:
|
||||
res = haggis_init_file_node(node, &st, a, map, mq);
|
||||
if (res != 0)
|
||||
return NULL;
|
||||
break;
|
||||
case block:
|
||||
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;
|
||||
}
|
||||
if (S_ISBLK(st.st_mode)) {
|
||||
node->filetype.tag = block;
|
||||
res = haggis_init_dev_node(node, &st, map, mq);
|
||||
if (res != 0)
|
||||
return NULL;
|
||||
} else if (S_ISCHR(st.st_mode)) {
|
||||
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) {
|
||||
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 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;
|
||||
ssize_t res = readlink(file, pathbuf, PATH_MAX);
|
||||
if (res == -1) {
|
||||
haggis_node_deinit(node);
|
||||
return NULL;
|
||||
}
|
||||
target = malloc(res + 1);
|
||||
memcpy(target, pathbuf, (unsigned long)res);
|
||||
haggis_filename_init(target, &node->filetype.f_type.target);
|
||||
body.f_name = file;
|
||||
msg = haggis_msg_init(NodeCreated, body);
|
||||
haggis_mq_push(mq, msg);
|
||||
return node;
|
||||
}
|
||||
} else if (S_ISLNK(st.st_mode)) {
|
||||
node->filetype.tag = softlink;
|
||||
ssize_t res = readlink(file, pathbuf, PATH_MAX);
|
||||
if (res == -1) {
|
||||
haggis_node_deinit(node);
|
||||
return NULL;
|
||||
}
|
||||
target = malloc(res + 1);
|
||||
memcpy(target, pathbuf, (unsigned long)res);
|
||||
haggis_filename_init(target, &node->filetype.f_type.target);
|
||||
body.f_name = file;
|
||||
msg = haggis_msg_init(NodeCreated, body);
|
||||
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;
|
||||
}
|
||||
body.f_name = file;
|
||||
msg = haggis_msg_init(NodeCreated, body);
|
||||
haggis_mq_push(mq, msg);
|
||||
return node;
|
||||
}
|
||||
|
||||
char* get_full_path(haggis_filename *fname, char *basedir) {
|
||||
char *path;
|
||||
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) {
|
||||
// todo
|
||||
dev_t dev;
|
||||
mode_t mode;
|
||||
char *path;
|
||||
int ret;
|
||||
|
||||
assert(geteuid() == 0);
|
||||
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) {
|
||||
// todo
|
||||
mode_t mode;
|
||||
char *path;
|
||||
int ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int haggis_extract_symlink(haggis_node *node, char *basedir) {
|
||||
// todo
|
||||
char *path;
|
||||
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);
|
||||
free(path);
|
||||
if (ret != 0)
|
||||
return errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int haggis_extract_hardlink(haggis_node *node, char *basedir) {
|
||||
// todo
|
||||
char *path, *target;
|
||||
int ret;
|
||||
FILE *fd;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -730,7 +808,8 @@ int haggis_extract_node(FILE *stream, char *basedir, haggis_node *node) {
|
|||
switch (node->filetype.tag) {
|
||||
case block:
|
||||
case character:
|
||||
return haggis_extract_dev(node, basedir);
|
||||
if (geteuid() == 0)
|
||||
return haggis_extract_dev(node, basedir);
|
||||
case fifo:
|
||||
return haggis_extract_fifo(node, basedir);
|
||||
case softlink:
|
||||
|
|
Loading…
Add table
Reference in a new issue