diff --git a/include/bytes.h b/include/bytes.h index 70d1d51..31911e8 100644 --- a/include/bytes.h +++ b/include/bytes.h @@ -31,10 +31,9 @@ */ #ifndef BYTES_H -#define BYTES_H +#define BYTES_H 1 -#include -#include +#include // FILE #include "haggis.h" diff --git a/include/haggis.h b/include/haggis.h index 9a49de0..87722e8 100644 --- a/include/haggis.h +++ b/include/haggis.h @@ -31,10 +31,11 @@ */ #ifndef HAGGIS_H -#define HAGGIS_H +#define HAGGIS_H 1 -#include -#include +#include "linklist.h" +#include // uint_t +#include // FILE typedef uint8_t u8; @@ -73,12 +74,12 @@ typedef union { typedef struct { haggis_algorithm tag; - haggis_sum *sum; + haggis_sum sum; } haggis_checksum; typedef struct { u64 len; - haggis_checksum *cksum; + haggis_checksum cksum; u8 *data; } haggis_file; @@ -99,9 +100,9 @@ typedef enum { } haggis_typeflag; typedef union { - haggis_file *file; - haggis_filename *target; - haggis_device *dev; + haggis_file file; + haggis_filename target; + haggis_device dev; } haggis_ft; typedef struct { @@ -118,7 +119,9 @@ typedef struct { haggis_filetype *filetype; } haggis_node; -haggis_node* haggis_create_node(char *file); +haggis_node* haggis_node_init(); +void haggis_node_deinit(haggis_node *node); +haggis_node* haggis_create_node(char *file, haggis_hardlink_list *list); int haggis_extract_node(FILE *stram, haggis_node *node); int haggis_load_node(FILE *stream, haggis_node *node); int haggis_store_node(FILE *stream, haggis_node *node); diff --git a/include/jobq.h b/include/jobq.h index df9a0c2..a70980d 100644 --- a/include/jobq.h +++ b/include/jobq.h @@ -31,12 +31,9 @@ */ #ifndef JOBQ_H -#define JOBQ_H +#define JOBQ_H 1 #include -#include -#include -#include #include "haggis.h" diff --git a/src/haggis.c b/src/haggis.c index 2c43fbd..035fc3d 100644 --- a/src/haggis.c +++ b/src/haggis.c @@ -30,8 +30,9 @@ * other than his own. */ -#include -#include +#include // PATH_MAX +#include // uint_t + #if defined(__FreeBSD__) || defined(__DragonFly__) #include #include @@ -43,16 +44,19 @@ #elif defined(__linux__) #include #include +#include // major, minor, dev_t #endif /* if defined (__FreeBSD__) */ - #include -#include -#include -#include -#include + +#include // fopen, fread, fwrite, FILE +#include // free, malloc +#include // memcpy, strlen +#include // readlink +#include // stat #include "bytes.h" #include "haggis.h" +#include "linklist.h" static unsigned char header[7] = {0x89, 'h', 'a', 'g', 'g', 'i', 's'}; @@ -71,6 +75,15 @@ int haggis_check_header(FILE *stream) { return 1; } +void haggis_device_init(dev_t rdev, haggis_device *dev) { + dev->major.val = (uint32_t)major(rdev); + dev->minor.val = (uint32_t)minor(rdev); +} + +void haggis_device_deinit(haggis_device *dev) { + free(dev); +} + int haggis_store_device(FILE *stream, haggis_device *dev) { if (fwrite(dev->major.bytes, 1, 4, stream) != 4) return 1; @@ -80,9 +93,9 @@ int haggis_store_device(FILE *stream, haggis_device *dev) { } int haggis_load_device(FILE *stream, haggis_ft *ft) { - if (fread(ft->dev->major.bytes, 1, 4, stream) != 4) + if (fread(ft->dev.major.bytes, 1, 4, stream) != 4) return 1; - if (fread(ft->dev->minor.bytes, 1, 4, stream) != 4) + if (fread(ft->dev.minor.bytes, 1, 4, stream) != 4) return 1; return 0; } @@ -95,21 +108,21 @@ int haggis_store_cksum(FILE *stream, haggis_checksum *cksum) { flag = 0; if (fwrite(&flag, 1, 1, stream) != 1) return 1; - if (fwrite(cksum->sum->md5, 1, 16, stream) != 16) + if (fwrite(cksum->sum.md5, 1, 16, stream) != 16) return 1; break; case sha1: flag = 1; if (fwrite(&flag, 1, 1, stream) != 1) return 1; - if (fwrite(cksum->sum->sha1, 1, 20, stream) != 20) + if (fwrite(cksum->sum.sha1, 1, 20, stream) != 20) return 1; break; case sha256: flag = 2; if (fwrite(&flag, 1, 1, stream) != 1) return 1; - if (fwrite(cksum->sum->sha256, 1, 32, stream) != 32) + if (fwrite(cksum->sum.sha256, 1, 32, stream) != 32) return 1; break; case skip: @@ -129,17 +142,17 @@ int haggis_load_cksum(FILE *stream, haggis_checksum *cksum) { switch (flag) { case md5: cksum->tag = 0; - if (fread(&cksum->sum->md5, 1, 16, stream) != 16) + if (fread(&cksum->sum.md5, 1, 16, stream) != 16) return 1; break; case sha1: cksum->tag = 1; - if (fread(&cksum->sum->sha1, 1, 20, stream) != 20) + if (fread(&cksum->sum.sha1, 1, 20, stream) != 20) return 1; break; case sha256: cksum->tag = 2; - if (fread(&cksum->sum->sha256, 1, 32, stream) != 32) + if (fread(&cksum->sum.sha256, 1, 32, stream) != 32) return 1; break; case skip: @@ -156,7 +169,7 @@ int validate_md5(haggis_file *file) { MD5Init(&ctx); MD5Update(&ctx, file->data, (size_t)file->len.val); MD5Final(digest, &ctx); - if (memcmp(file->cksum->sum->md5, digest, sizeof(digest))) + if (memcmp(file->cksum.sum.md5, digest, sizeof(digest))) return 2; return 0; } @@ -169,7 +182,7 @@ int validate_sha1(haggis_file *file) { SHA1_Init(&ctx); SHA1_Update(&ctx, file->data, (size_t)file->len.val); SHA1_Final(digest, &ctx); - if (memcmp(file->cksum->sum->sha1, digest, sizeof(digest))) + if (memcmp(file->cksum.sum.sha1, digest, sizeof(digest))) return 2; return 0; } @@ -181,7 +194,7 @@ int validate_sha1(haggis_file *file) { SHA1Init(&ctx); SHA1Update(&ctx, file->data, (size_t)file->len.val); SHA1Final(digest, &ctx); - if (memcmp(file->cksum->sum->sha1, digest, sizeof(digest))) + if (memcmp(file->cksum.sum.sha1, digest, sizeof(digest))) return 2; return 0; } @@ -195,7 +208,7 @@ int validate_sha256(haggis_file *file) { SHA256_Init(&ctx); SHA256_Update(&ctx, file->data, (size_t)file->len.val); SHA256_Final(digest, &ctx); - if (memcmp(file->cksum->sum->sha256, digest, sizeof(digest))) + if (memcmp(file->cksum.sum.sha256, digest, sizeof(digest))) return 2; return 0; } @@ -207,14 +220,14 @@ int validate_sha256(haggis_file *file) { SHA256Init(&ctx); SHA256Update(&ctx, file->data, (size_t)file->len.val); SHA256Final(digest, &ctx); - if (memcmp(file->cksum->sum->sha256, digest, sizeof(digest))) + if (memcmp(file->cksum.sum.sha256, digest, sizeof(digest))) return 2; return 0; } #endif /* if defined (__FreeBSD__) */ int haggis_validate_cksum(haggis_file *file) { - switch (file->cksum->tag) { + switch (file->cksum.tag) { case md5: return validate_md5(file); case sha1: @@ -227,10 +240,45 @@ int haggis_validate_cksum(haggis_file *file) { return 0; } +haggis_file* haggis_file_init(char *path) { + FILE *f; + long len; + haggis_file *hf; + + f = fopen(path, "r"); + if (f == NULL) return NULL; + if (fseek(f, 0, SEEK_END) == -1) { + fclose(f); + return NULL; + } + len = ftell(f); + if (len == -1) { + fclose(f); + return NULL; + } + hf = malloc(sizeof(haggis_file)); + if (hf == NULL) return NULL; + hf->len.val = (uint64_t)len; + rewind(f); + hf->data = malloc((size_t)len); + if (fread(hf->data, 1, (size_t)len, f) != (size_t)len) { + free(hf->data); + free(hf); + fclose(f); + return NULL; + } + fclose(f); + return hf; +} + +void haggis_file_deinit(haggis_file *f) { + if (f->data != NULL) free(f->data); +} + int haggis_store_file(FILE *stream, haggis_file *file) { if (store_u64(stream, file->len) != 8) return 1; - if (haggis_store_cksum(stream, file->cksum) != 0) + if (haggis_store_cksum(stream, &file->cksum) != 0) return 1; int res = fwrite(file->data, 1, (size_t)file->len.val, stream); if (res != (size_t)file->len.val) @@ -239,30 +287,38 @@ int haggis_store_file(FILE *stream, haggis_file *file) { } int haggis_load_file(FILE *stream, haggis_ft *ft) { - u64 len; - len.val = 0; - - if (load_u64(stream, len) != 8) + if (load_u64(stream, ft->file.len) != 8) return 1; - ft->file->len = len; - if (haggis_load_cksum(stream, ft->file->cksum) != 0) + if (haggis_load_cksum(stream, &ft->file.cksum) != 0) return 1; - u8 *data = malloc((size_t)len.val); - if (data == NULL) + ft->file.data = malloc((size_t)ft->file.len.val); + if (ft->file.data == NULL) return -1; - int res = fread(data, 1, (size_t)ft->file->len.val, stream); - if (res != (size_t)ft->file->len.val) { + int res = fread(ft->file.data, 1, (size_t)ft->file.len.val, stream); + if (res != (size_t)ft->file.len.val) { free(ft); return 1; } - ft->file->data = data; - if (haggis_validate_cksum(ft->file)) { + if (haggis_validate_cksum(&ft->file)) { free(ft); return 1; } return 0; } +haggis_filename* haggis_filename_init(char *target, haggis_filename *fname) { + size_t len; + + len = strlen(target) - 1; + fname->len.val = (uint16_t)len; + fname->name = target; + return fname; +} + +void haggis_filename_deinit(haggis_filename *fname) { + if (fname->name != NULL) free(fname->name); +} + int haggis_load_filename(FILE *stream, haggis_filename *n) { u16 len; char *name; @@ -293,10 +349,10 @@ int haggis_load_filetype(FILE *stream, haggis_typeflag tag, haggis_filetype *fil file->tag = 0; return haggis_load_file(stream, file->f_type); case hardlink: - return haggis_load_filename(stream, file->f_type->target); + return haggis_load_filename(stream, &file->f_type->target); file->tag = 1; case softlink: - return haggis_load_filename(stream, file->f_type->target); + return haggis_load_filename(stream, &file->f_type->target); file->tag = 2; case directory: file->tag = 3; @@ -325,19 +381,19 @@ int haggis_store_filetype(FILE *stream, haggis_filetype *filetype) { flag = 0; if (fwrite(&flag, 1, 1, stream) != 1) return 1; - if (haggis_store_file(stream, filetype->f_type->file) != 0) + if (haggis_store_file(stream, &filetype->f_type->file) != 0) return 1; break; case hardlink: flag = 1; if (fwrite(&flag, 1, 1, stream) != 1) return 1; - return haggis_store_filename(stream, filetype->f_type->target); + return haggis_store_filename(stream, &filetype->f_type->target); case softlink: flag = 2; if (fwrite(&flag, 1, 1, stream) != 1) return 1; - return haggis_store_filename(stream, filetype->f_type->target); + return haggis_store_filename(stream, &filetype->f_type->target); case directory: flag = 3; if (fwrite(&flag, 1, 1, stream) != 1) @@ -347,14 +403,14 @@ int haggis_store_filetype(FILE *stream, haggis_filetype *filetype) { flag = 4; if (fwrite(&flag, 1, 1, stream) != 1) return 1; - if (haggis_store_device(stream, filetype->f_type->dev) != 0) + if (haggis_store_device(stream, &filetype->f_type->dev) != 0) return 1; break; case block: flag = 5; if (fwrite(&flag, 1, 1, stream) != 1) return 1; - if (haggis_store_device(stream, filetype->f_type->dev) != 0) + if (haggis_store_device(stream, &filetype->f_type->dev) != 0) return 1; break; case fifo: @@ -383,17 +439,50 @@ u16 haggis_derive_mode(u16 raw, haggis_filetype *ft) { return mode; } -haggis_node* haggis_create_node(char *file) { +void haggis_node_deinit(haggis_node *node) { + if (node == NULL) return; + if (node->name != NULL) haggis_filename_deinit(node->name); + switch (node->filetype->tag) { + case normal: + if (node->filetype->f_type->file.data != NULL) { + free(node->filetype->f_type->file.data); + } + break; + case hardlink: + case softlink: + if (node->filetype->f_type->target.name != NULL) { + haggis_filename_deinit(&node->filetype->f_type->target); + } + break; + case character: + case block: + case directory: + case fifo: + case eof: + break; + }; + free(node); +} + +haggis_node* haggis_create_node(char *file, haggis_hardlink_list *list) { struct stat *st = NULL; haggis_typeflag tf; u16 mode; u32 uid; u32 gid; u64 mtime; - haggis_node *node = malloc(sizeof(haggis_node)); + char *target; + char pathbuf[PATH_MAX]; + haggis_filename *fname; + haggis_file *f; + haggis_node *node; + node = malloc(sizeof(haggis_node)); if (node == NULL) return NULL; + node->filetype = malloc(sizeof(haggis_filetype)); + if (node->filetype == NULL) + return NULL; if (stat(file, st) != 0) { free(node); return NULL; @@ -419,21 +508,93 @@ haggis_node* haggis_create_node(char *file) { gid.val = (uint32_t)st->st_gid; node->gid = gid; mtime.val = (uint64_t)st->st_mtim.tv_sec; + node->mtime = mtime; mode.val = (uint16_t)(st->st_mode & 07777); node->mode = mode; switch (tf) { case normal: + target = haggis_linklist_get_or_put(list, st->st_ino, file); + if (target == NULL) { + node->filetype->tag = normal; + f = haggis_file_init(file); + if (f == NULL) { + haggis_node_deinit(node); + return NULL; + } + } else { + node->filetype->tag = hardlink; + fname = haggis_filename_init(target, &node->filetype->f_type->target); + if (fname == NULL) { + haggis_node_deinit(node); + return NULL; + } + } + break; case block: + target = haggis_linklist_get_or_put(list, st->st_ino, file); + if (target == NULL) { + node->filetype->tag = block; + haggis_device_init(st->st_rdev, &node->filetype->f_type->dev); + } else { + node->filetype->tag = hardlink; + fname = haggis_filename_init(target, &node->filetype->f_type->target); + if (fname == NULL) { + haggis_node_deinit(node); + return NULL; + } + } + break; case character: + target = haggis_linklist_get_or_put(list, st->st_ino, file); + if (target == NULL) { + node->filetype->tag = character; + haggis_device_init(st->st_rdev, &node->filetype->f_type->dev); + } else { + node->filetype->tag = hardlink; + fname = haggis_filename_init(target, &node->filetype->f_type->target); + if (fname == NULL) { + haggis_node_deinit(node); + return NULL; + } + } + break; case fifo: + target = haggis_linklist_get_or_put(list, st->st_ino, file); + if (target == NULL) { + node->filetype->tag = fifo; + } else { + node->filetype->tag = hardlink; + fname = haggis_filename_init(target, &node->filetype->f_type->target); + if (fname == NULL) { + haggis_node_deinit(node); + return NULL; + } + fname->name = target; + } break; case directory: + node->filetype->tag = directory; break; case hardlink: + node->filetype->tag = hardlink; break; 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); + fname = haggis_filename_init(target, &node->filetype->f_type->target); + if (fname == NULL) { + haggis_node_deinit(node); + return NULL; + } break; case eof: + node->filetype->tag = eof; break; } // todo diff --git a/src/jobq.c b/src/jobq.c index e402dce..85367e3 100644 --- a/src/jobq.c +++ b/src/jobq.c @@ -29,6 +29,7 @@ * as such so that the author does not get blamed for bugs * other than his own. */ +#include // free, malloc #include "jobq.h" diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..e69de29 diff --git a/test/checksum.c b/test/checksum.c new file mode 100644 index 0000000..e69de29 diff --git a/test/device.c b/test/device.c new file mode 100644 index 0000000..e69de29 diff --git a/test/filename.c b/test/filename.c new file mode 100644 index 0000000..e69de29 diff --git a/test/haggis_private.h b/test/haggis_private.h new file mode 100644 index 0000000..872d65c --- /dev/null +++ b/test/haggis_private.h @@ -0,0 +1,64 @@ +/* _,.---._ .-._ .--.-. ,--.--------. + * _,..---._ ,-.' , - `. /==/ \ .-._/==/ //==/, - , -\ + * /==/, - \ /==/_, , - \|==|, \/ /, |==\ -\\==\.-. - ,-./ + * |==| _ _\==| .=. |==|- \| | \==\- \`--`\==\- \ + * |==| .=. |==|_ : ;=: - |==| , | -| `--`-' \==\_ \ + * |==|,| | -|==| , '=' |==| - _ | |==|- | + * |==| '=' /\==\ - ,_ /|==| /\ , | |==|, | + * |==|-, _`/ '.='. - .' /==/, | |- | /==/ -/ + * `-.`.____.' `--`--'' `--`./ `--` `--`--` + * _ __ ,---. .-._ .=-.-. _,.----. + * .-`.' ,`..--.' \ /==/ \ .-._ /==/_ /.' .' - \ + * /==/, - \==\-/\ \ |==|, \/ /, /==|, |/==/ , ,-' + * |==| _ .=. /==/-|_\ | |==|- \| ||==| ||==|- | . + * |==| , '=',\==\, - \ |==| , | -||==|- ||==|_ `-' \ + * |==|- '..'/==/ - ,| |==| - _ ||==| ,||==| _ , | + * |==|, | /==/- /\ - \|==| /\ , ||==|- |\==\. / + * /==/ - | \==\ _.\=\.-'/==/, | |- |/==/. / `-.`.___.-' + * `--`---' `--` `--`./ `--``--`-` + * + * @(#)Copyright (c) 2023, Nathan D. Fisher. + * + * This is free software. It comes with NO WARRANTY. + * Permission to use, modify and distribute this source code + * is granted subject to the following conditions. + * 1/ that the above copyright notice and this notice + * are preserved in all copies and that due credit be given + * to the author. + * 2/ that any changes to this code are clearly commented + * as such so that the author does not get blamed for bugs + * other than his own. +*/ + +#ifndef HAGGIS_PRIVATE_H +#define HAGGIS_PRIVATE_H 1 + +#include + +#include + +#include "haggis.h" + +int haggis_store_header(FILE *stream); +int haggis_check_header(FILE *stream); +haggis_device* haggis_device_init(dev_t rdev); +void haggis_device_deinit(haggis_device *dev); +int haggis_store_device(FILE *stream, haggis_device *dev); +int haggis_load_device(FILE *stream, haggis_ft *ft); +int haggis_store_cksum(FILE *stream, haggis_checksum *cksum); +int haggis_load_cksum(FILE *stream, haggis_checksum *cksum); +int validate_md5(haggis_file *file); +int validate_sha1(haggis_file *file); +int validate_sha256(haggis_file *file); +int haggis_validate_cksum(haggis_file *file); +haggis_file* haggis_file_init(char *path); +int haggis_store_file(FILE *stream, haggis_file *file); +int haggis_load_file(FILE *stream, haggis_ft *ft); +haggis_filename* haggis_filename_init(char *target); +void haggis_filename_deinit(haggis_filename *fname); +int haggis_load_filename(FILE *stream, haggis_filename *n); +int haggis_store_filename(FILE *stream, haggis_filename *n); +int haggis_load_filetype(FILE *stream, haggis_typeflag tag, haggis_filetype *file); +int haggis_store_filetype(FILE *stream, haggis_filetype *filetype); + +#endif // !HAGGIS_PRIVATE_H