diff --git a/include/vieter_package.h b/include/vieter_package.h index 179ff57..c9a941e 100644 --- a/include/vieter_package.h +++ b/include/vieter_package.h @@ -1,21 +1,23 @@ #ifndef VIETER_PACKAGE #define VIETER_PACKAGE -#include -#include -#include -#include - -#include -#include - typedef struct vieter_package vieter_package; +typedef enum vieter_package_error { + vieter_package_ok = 0, + vieter_package_unarchive_error = 1, + vieter_package_stat_error = 2 +} vieter_package_error; + +/* + * Allocate an empty package + */ +vieter_package *vieter_package_init(); + /* * Parse package file into something usable by libvieter. - * The pointer returned by this function will need to freed at a later point. */ -vieter_package *vieter_package_read_archive(const char *pkg_path); +vieter_package_error vieter_package_read_archive(vieter_package *pkg, const char *pkg_path); /* * Deallocate a package. diff --git a/src/package/vieter_package.c b/src/package/vieter_package.c index 3bb19ba..d1ef6c4 100644 --- a/src/package/vieter_package.c +++ b/src/package/vieter_package.c @@ -1,30 +1,29 @@ +#include +#include +#include +#include + #include "vieter_package_internal.h" #include "sha256.h" -#define SMALL_BUFF_SIZE 128 - #define ADD_STRING(section, field) if (pkg_info->field != 0) { \ - snprintf(aux, SMALL_BUFF_SIZE, section, pkg_info->field); \ - if (buff_size < strlen(description) + SMALL_BUFF_SIZE + 1) { \ + size_to_be_written = snprintf(aux, small_buff_size, section, pkg_info->field); \ + if (size_to_be_written > small_buff_size) { \ + aux = realloc(aux, size_to_be_written + 1); \ + small_buff_size = size_to_be_written + 1; \ + snprintf(aux, small_buff_size, section, pkg_info->field); \ + } \ + if (buff_size < strlen(description) + small_buff_size + 1) { \ description = realloc(description, buff_size * 2); \ buff_size *= 2; \ } \ strcat(description, aux); \ } + #define ADD_ARRAY(section, field) i = 0; if (pkg_info->field != NULL) { \ - snprintf(aux, SMALL_BUFF_SIZE, section, pkg_info->field->array[i]); i++; \ - if (buff_size < strlen(description) + SMALL_BUFF_SIZE + 1) { \ - description = realloc(description, buff_size * 2); \ - buff_size *= 2; \ - } \ - strcat(description, aux); \ + ADD_STRING(section, field->array[i]); i++; \ while (pkg_info->field->array[i] != NULL) { \ - snprintf(aux, SMALL_BUFF_SIZE, "\n%s", pkg_info->field->array[i]); i++; \ - if (buff_size < strlen(description) + SMALL_BUFF_SIZE + 1) { \ - description = realloc(description, buff_size * 2); \ - buff_size *= 2; \ - } \ - strcat(description, aux); \ + ADD_STRING("\n%s", field->array[i]); i++; \ } \ } @@ -41,7 +40,7 @@ vieter_package *vieter_package_init() { return calloc(sizeof(vieter_package_info), 1); } -vieter_package *vieter_package_read_archive(const char *pkg_path) { +vieter_package_error vieter_package_read_archive(vieter_package *pkg, const char *pkg_path) { struct archive *a = archive_read_new(); struct archive_entry *entry = archive_entry_new(); @@ -58,7 +57,7 @@ vieter_package *vieter_package_read_archive(const char *pkg_path) { // Exit early if we weren't able to successfully open the archive for reading if (r != ARCHIVE_OK) { - return NULL; + return vieter_package_unarchive_error; } int compression_code = archive_filter_code(a, 0); @@ -104,7 +103,9 @@ vieter_package *vieter_package_read_archive(const char *pkg_path) { struct stat stats; if (stat(pkg_path, &stats) != 0) { - return NULL; + // errno is set if stat() fails; the calling function should check + // the value of errno in case vieter_package_stat_error is returned + return vieter_package_stat_error; } pkg_info->csize = stats.st_size; @@ -112,31 +113,31 @@ vieter_package *vieter_package_read_archive(const char *pkg_path) { archive_read_free(a); // Create final return value - vieter_package *pkg = vieter_package_init(); pkg->path = strdup(pkg_path); pkg->info = pkg_info; pkg->files = files; pkg->compression = compression_code; - return pkg; + return vieter_package_ok; } void vieter_package_sha256sum(vieter_package *pkg, char *res) { FILE *f = fopen(pkg->path, "r"); - fseek(f, 0, SEEK_END); - size_t size = ftell(f); - rewind(f); - unsigned char *in = malloc(size); - fread(in, 1, size, f); - fclose(f); + // Try to read 100KiB at a time + unsigned char *in = malloc(102400); + // Actual number of bytes read + size_t read_size; - unsigned char hash[32]; SHA256_CTX *ctx = malloc(sizeof(SHA256_CTX)); - sha256_init(ctx); - sha256_update(ctx, in, size); + while ((read_size = fread(in, 1, 102400, f)) != 0) { + sha256_update(ctx, in, read_size); + } + unsigned char hash[SHA256_BLOCK_SIZE]; + sha256_final(ctx, hash); + fclose(f); free(in); free(ctx); @@ -147,8 +148,8 @@ void vieter_package_sha256sum(vieter_package *pkg, char *res) { unsigned int half_byte = 0; int j = 0; - // We advance in the string 2 bytes for every one byte of the hash - for (int i = 0; i < 32; i++) { + // We advance 2 bytes in the string for every one byte of the hash + for (int i = 0; i < SHA256_BLOCK_SIZE; i++) { // We transform the first half byte into the second character to keep // each byte from becoming reversed in the final string half_byte = hash[i] & 0b1111; @@ -170,19 +171,32 @@ void vieter_package_sha256sum(vieter_package *pkg, char *res) { res[j] = '\0'; } + + char *vieter_package_to_description(vieter_package *pkg) { vieter_package_info *pkg_info = pkg->info; size_t buff_size = 1024; - char aux[SMALL_BUFF_SIZE]; + int small_buff_size = 128; + int size_to_be_written; + char *aux = malloc(sizeof(char) * small_buff_size); char *description = malloc(sizeof(char) * buff_size); // Helper variable for ADD_ARRAY macro int i; // special case for FILENAME // assuming .pkg.tar.zst; other formats are valid, this should account for that - snprintf(aux, SMALL_BUFF_SIZE, "%%FILENAME%%\n%s-%s-%s.pkg.tar.zst", pkg_info->name, + size_to_be_written = snprintf(aux, small_buff_size, "%%FILENAME%%\n%s-%s-%s.pkg.tar.zst", pkg_info->name, pkg_info->version, pkg_info->arch); + + // We neither want to let an arbritrarily long input to overflow the buffer + // nor to truncate perfectly valid inputs + if (size_to_be_written > small_buff_size) { + aux = realloc(aux, size_to_be_written + 1); + small_buff_size = size_to_be_written + 1; + snprintf(aux, small_buff_size, "%%FILENAME%%\n%s-%s-%s.pkg.tar.zst", pkg_info->name, + pkg_info->version, pkg_info->arch); + } strcpy(description, aux); ADD_STRING("\n\n%%NAME%%\n%s", name); @@ -193,11 +207,11 @@ char *vieter_package_to_description(vieter_package *pkg) { ADD_STRING("\n\n%%CSIZE%%\n%ld", csize); ADD_STRING("\n\n%%ISIZE%%\n%ld", size); - char checksum[65]; + char checksum[SHA256_BLOCK_SIZE * 2 + 1]; vieter_package_sha256sum(pkg, checksum); - snprintf(aux, SMALL_BUFF_SIZE, "\n\n%%SHA256SUM%%\n%s", checksum); - if (buff_size < strlen(description) + SMALL_BUFF_SIZE + 1) { + snprintf(aux, small_buff_size, "\n\n%%SHA256SUM%%\n%s", checksum); + if (buff_size < strlen(description) + small_buff_size + 1) { description = realloc(description, buff_size * 2); buff_size *= 2; } @@ -216,8 +230,7 @@ char *vieter_package_to_description(vieter_package *pkg) { ADD_ARRAY("\n\n%%MAKEDEPENDS%%\n%s", makedepends); ADD_ARRAY("\n\n%%CHECKDEPENDS%%\n%s", checkdepends); - snprintf(aux, SMALL_BUFF_SIZE, "\n\n"); - strcat(description, aux); + strcat(description, "\n\n"); return description; } diff --git a/src/package/vieter_package_dynarray.c b/src/package/vieter_package_dynarray.c index 2cc20b6..6da07ee 100644 --- a/src/package/vieter_package_dynarray.c +++ b/src/package/vieter_package_dynarray.c @@ -12,12 +12,18 @@ void vieter_package_dynarray_add(vieter_package_dynarray *da, const char *s) { // An empty vieter_package_dynarray does not have an allocated internal array yet if (da->size == 0) { da->array = malloc(sizeof(char*) * da->capacity); + + // Initialise all char*'s to 0 so array[i] == NULL can be used to see if field is empty + memset(da->array, 0, sizeof(char*) * da->capacity); } // Double array size if it's full else if (da->size == da->capacity) { // if the realloc fails, access to memory in da->array is lost da->array = realloc(da->array, sizeof(char*) * da->capacity * 2); da->capacity *= 2; + + // Same as the previous memset, but only for newly allocated pointers + memset(da->array + da->size, 0, sizeof(char*) * da->capacity / 2); } da->array[da->size] = strdup(s); diff --git a/test/package/test_package.c b/test/package/test_package.c index 5bbda26..3c8b249 100644 --- a/test/package/test_package.c +++ b/test/package/test_package.c @@ -39,8 +39,9 @@ void test_info_parse() { } void test_pkg_read_archive_files() { - vieter_package *pkg = vieter_package_read_archive("./test/package/xcursor-dmz-0.4.5-2-any.pkg.tar.zst"); - TEST_ASSERT_(pkg != NULL, "failure parsing pkg archive"); + vieter_package *pkg = vieter_package_init(); + vieter_package_error e = vieter_package_read_archive(pkg, "./test/package/xcursor-dmz-0.4.5-2-any.pkg.tar.zst"); + TEST_ASSERT_(e == vieter_package_ok, "failure parsing pkg archive"); FILE *f = fopen("./test/package/files", "r"); TEST_ASSERT_(f != NULL, "could not find test files file in ./test/package"); @@ -58,12 +59,12 @@ void test_pkg_read_archive_files() { TEST_CHECK(pkg->compression = 14); vieter_package_free(&pkg); - } void test_pkg_read_archive_desc() { - vieter_package *pkg = vieter_package_read_archive("./test/package/xcursor-dmz-0.4.5-2-any.pkg.tar.zst"); - TEST_ASSERT_(pkg != NULL, "failure parsing pkg archive"); + vieter_package *pkg = vieter_package_init(); + vieter_package_error e = vieter_package_read_archive(pkg, "./test/package/xcursor-dmz-0.4.5-2-any.pkg.tar.zst"); + TEST_ASSERT_(e == vieter_package_ok, "failure parsing pkg archive"); char *description = vieter_package_to_description(pkg);