/* _,.---._ .-._ .--.-. ,--.--------. * _,..---._ ,-.' , - `. /==/ \ .-._/==/ //==/, - , -\ * /==/, - \ /==/_, , - \|==|, \/ /, |==\ -\\==\.-. - ,-./ * |==| _ _\==| .=. |==|- \| | \==\- \`--`\==\- \ * |==| .=. |==|_ : ;=: - |==| , | -| `--`-' \==\_ \ * |==|,| | -|==| , '=' |==| - _ | |==|- | * |==| '=' /\==\ - ,_ /|==| /\ , | |==|, | * |==|-, _`/ '.='. - .' /==/, | |- | /==/ -/ * `-.`.____.' `--`--'' `--`./ `--` `--`--` * _ __ ,---. .-._ .=-.-. _,.----. * .-`.' ,`..--.' \ /==/ \ .-._ /==/_ /.' .' - \ * /==/, - \==\-/\ \ |==|, \/ /, /==|, |/==/ , ,-' * |==| _ .=. /==/-|_\ | |==|- \| ||==| ||==|- | . * |==| , '=',\==\, - \ |==| , | -||==|- ||==|_ `-' \ * |==|- '..'/==/ - ,| |==| - _ ||==| ,||==| _ , | * |==|, | /==/- /\ - \|==| /\ , ||==|- |\==\. / * /==/ - | \==\ _.\=\.-'/==/, | |- |/==/. / `-.`.___.-' * `--`---' `--` `--`./ `--``--`-` * * @(#)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. */ #if defined (__FreeBSD__) || defined (__DragonFly__) #include #include #include #elif defined (__NetBSD__) || defined (__OpenBSD__) #include #include #include #elif defined (__linux__) #include #include #endif /* if defined (__FreeBSD__) */ #include #include #include #include #include "bytes.h" #include "haggis.h" static unsigned char header[7] = {0x89, 'h', 'a', 'g', 'g', 'i', 's'}; int haggis_store_header(FILE *stream) { if (fwrite(header, 1, 7, stream) < 7) return 1; return 0; } int haggis_check_header(FILE *stream) { unsigned char *buf[7]; if (fread(buf, 1, 7, stream) < 7) return 1; if (memcmp(buf, header, 7)) return 2; return 1; } int haggis_store_device(FILE *stream, struct haggis_device *dev) { if (fwrite(dev->major.bytes, 1, 4, stream) != 4) return 1; if (fwrite(dev->minor.bytes, 1, 4, stream) != 4) return 1; return 0; } int haggis_load_device(FILE *stream, struct haggis_device *dev) { if (fread(dev->major.bytes, 1, 4, stream) != 4) return 1; if (fread(dev->minor.bytes, 1, 4, stream) != 4) return 1; return 0; } int haggis_store_cksum(FILE *stream, struct haggis_checksum *cksum) { char flag; switch (cksum->tag) { case md5: flag = 0; if (fwrite(&flag, 1, 1, stream) != 1) return 1; 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) 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) return 1; break; case skip: flag = 3; if (fwrite(&flag, 1, 1, stream) != 1) return 1; break; } return 0; } int haggis_load_cksum(FILE *stream, struct haggis_checksum *cksum) { char flag; if (fread(&flag, 1, 1, stream) != 1) return 1; switch (flag) { case md5: cksum->tag = 0; 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) return 1; break; case sha256: cksum->tag = 2; if (fread(&cksum->sum->sha256, 1, 32, stream) != 32) return 1; break; case skip: cksum->tag = 3; break; } return 0; } int validate_md5(struct haggis_file *file) { MD5_CTX ctx; u8 digest[MD5_DIGEST_LENGTH]; MD5Init(&ctx); MD5Update(&ctx, *file->data, (size_t)file->len.val); MD5Final(digest, &ctx); if (memcmp(file->cksum->sum->md5, digest, sizeof(digest))) return 2; return 0; } #if defined (__FreeBSD__) || defined (__DragonFly__) int validate_sha1(struct haggis_file *file) { SHA1_CTX ctx; u8 digest[20]; 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))) return 2; return 0; } #elif defined (__linux__) || defined (__NetBSD__) || defined (__OpenBSD__) int validate_sha1(struct haggis_file *file) { SHA1_CTX ctx; u8 digest[20]; SHA1Init(&ctx); SHA1Update(&ctx, *file->data, (size_t)file->len.val); SHA1Final(digest, &ctx); if (memcmp(file->cksum->sum->sha1, digest, sizeof(digest))) return 2; return 0; } #endif /* if defined (__FreeBSD__) */ #if defined (__FreeBSD__) || defined (__DragonFly) || defined (__NetBSD__) int validate_sha256(struct haggis_file *file) { SHA256_CTX ctx; u8 digest[SHA256_DIGEST_LENGTH]; 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))) return 2; return 0; } #elif defined (__linux__) || defined (__OpenBSD__) int validate_sha256(struct haggis_file *file) { SHA2_CTX ctx; u8 digest[SHA256_DIGEST_LENGTH]; SHA256Init(&ctx); SHA256Update(&ctx, *file->data, (size_t)file->len.val); SHA256Final(digest, &ctx); if (memcmp(file->cksum->sum->sha256, digest, sizeof(digest))) return 2; return 0; } #endif /* if defined (__FreeBSD__) */ int haggis_validate_cksum(struct haggis_file *file) { switch (file->cksum->tag) { case md5: return validate_md5(file); case sha1: return validate_sha1(file); case sha256: return validate_sha256(file); case skip: return 0; } return 0; } int haggis_store_file(FILE *stream, struct haggis_file *file) { if (store_u64(stream, file->len) != 8) return 1; 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) return 1; return 0; } int haggis_load_file(FILE *stream, struct haggis_file *file) { if (load_u64(stream, file->len) != 8) return 1; if (haggis_load_cksum(stream, file->cksum) != 0) return 1; int res = fread(file->data, 1, (size_t)file->len.val, stream); if (res != (size_t)file->len.val) return 1; return haggis_validate_cksum(file); } int haggis_store_filetype(FILE *stream, struct haggis_filetype *filetype) { size_t len; u8 flag; int res; switch (filetype->tag) { case normal: flag = 0; if (fwrite(&flag, 1, 1, stream) != 1) return 1; 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; len = (size_t)filetype->f_type->target->len.val; res = fwrite(filetype->f_type->target->name, 1, len, stream); if (res != (size_t)len) return 1; break; case softlink: flag = 2; if (fwrite(&flag, 1, 1, stream) != 1) return 1; len = (size_t)filetype->f_type->target->len.val; res = fwrite(filetype->f_type->target->name, 1, len, stream); if (res != (size_t)len) return 1; break; case directory: flag = 3; if (fwrite(&flag, 1, 1, stream) != 1) return 1; break; case character: flag = 4; if (fwrite(&flag, 1, 1, stream) != 1) return 1; 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) return 1; break; case fifo: flag = 6; if (fwrite(&flag, 1, 1, stream) != 1) return 1; break; case eof: flag = 7; if (fwrite(&flag, 1, 1, stream) != 1) return 1; break; }; return 0; } int haggis_load_filetype(FILE *stream, struct haggis_filetype *filetype) { // todo return 0; } int haggis_store_node(FILE *stream, struct haggis_node *node) { // todo return 0; } int haggis_load_node(FILE *stream, struct haggis_node *node) { // todo return 0; }