/* * Copyright (c) 2026, Chloe M. * Provided under the BSD-3 clause */ #define _DEFAULT_SOURCE #include #include #include #include #include #include #include "blobchain/common.h" #include "blobchain/stream.h" #include "blobchain/blob.h" /* Input directory path */ static char *input_dir = NULL; static void help(void) { printf("usage: ./blobchain \n"); printf("... [-h] Display this help menu\n"); printf("... [-v] Display the version\n"); printf("... [-i] Input directory\n"); } static void version(void) { printf("Version v%s\n", BLOBCHAIN_VERSION); } static void pack_foreach(struct blob_list *blobs, const char *input_dir) { struct data_stream stream; char pathbuf[512]; struct dirent *dirent; DIR *dir; int error; if (input_dir == NULL) { return; } if ((dir = opendir(input_dir)) == NULL) { perror("opendir"); return; } while ((dirent = readdir(dir)) != NULL) { if (dirent->d_name[0] == '.') { continue; } switch (dirent->d_type) { case DT_DIR: snprintf(pathbuf, sizeof(pathbuf), "%s/%s", input_dir, dirent->d_name); pack_foreach(blobs, pathbuf); printf("[d] %s\n", pathbuf); break; case DT_REG: snprintf(pathbuf, sizeof(pathbuf), "%s/%s", input_dir, dirent->d_name); printf("[r] %s\n", pathbuf); error = stream_from_file(&stream, pathbuf); if (error < 0) { printf("fatal: could not create stream from '%s'\n", pathbuf); return; } error = blob_list_append(blobs, blob_allocate(&stream)); if (error < 0) { printf("fatal: failed to append blob '%s'\n", pathbuf); stream_destroy(&stream); continue; } stream_destroy(&stream); break; } } } static void pack_dir(void) { struct stat sb; struct blob_list blobs; if (stat(input_dir, &sb) < 0) { perror("stat"); return; } /* Must be a directory */ if (!S_ISDIR(sb.st_mode)) { printf("fatal: given path is not a directory!\n"); return; } if (blob_list_init(&blobs) < 0) { printf("fatal: failed to initialize blob list...\n"); return; } pack_foreach(&blobs, input_dir); #if BLOBCHAIN_DEBUG blob_list_dump(&blobs); #endif /* BLOBCHAIN_DEBUG */ blob_list_destroy(&blobs); } int main(int argc, char **argv) { int opt; if (argc < 2) { printf("fatal: too few arguments!\n"); help(); return -1; } while ((opt = getopt(argc, argv, "hvi:")) != -1) { switch (opt) { case 'h': help(); return -1; case 'v': version(); return -1; case 'i': input_dir = strdup(optarg); if (input_dir == NULL) { printf("fatal: out of memory\n"); return -1; } break; } } if (input_dir == NULL) { printf("fatal: expected input directory\n"); help(); return -1; } pack_dir(); free(input_dir); return 0; }