From 3e40eeff2d87d2b504c37046353c161b9aaa7318 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Sat, 19 Nov 2022 23:32:51 +0100 Subject: [PATCH] feat(package): started rewrite in C --- .editorconfig | 2 +- .gitignore | 2 +- src/package/c/dynarray.c | 43 +++++++++++++++++ src/package/c/dynarray.h | 14 ++++++ src/package/c/package.c | 94 ++++++++++++++++++++++++++++++++++++ src/package/c/package.h | 25 ++++++++++ src/package/c/package_info.c | 46 ++++++++++++++++++ src/package/c/package_info.h | 39 +++++++++++++++ 8 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 src/package/c/dynarray.c create mode 100644 src/package/c/dynarray.h create mode 100644 src/package/c/package.c create mode 100644 src/package/c/package.h create mode 100644 src/package/c/package_info.c create mode 100644 src/package/c/package_info.h diff --git a/.editorconfig b/.editorconfig index e23a3c7..e9bac80 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,6 +5,6 @@ root = true end_of_line = lf insert_final_newline = true -[*.v] +[*.{v,c,h}] # vfmt wants it :( indent_style = tab diff --git a/.gitignore b/.gitignore index aaec9ef..daeb3d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -*.c +vieter.c /data/ # Build artifacts diff --git a/src/package/c/dynarray.c b/src/package/c/dynarray.c new file mode 100644 index 0000000..a70feaf --- /dev/null +++ b/src/package/c/dynarray.c @@ -0,0 +1,43 @@ +#include "dynarray.h" + +struct dyn_array { + char **array; + size_t size; + size_t capacity; +}; + +DynArray *dynarray_init(size_t initial_capacity) { + DynArray *da = malloc(sizeof(DynArray)); + da->size = 0; + da->capacity = initial_capacity; + + return da; +} + +void dynarray_add(DynArray *da, const char *s) { + // An empty dynarray does not have an allocated internal array yet + if (da->size == 0) { + da->array = malloc(sizeof(char*) * da->capacity); + } + // Double array size if it's full + else if (da->size == da->capacity) { + da->array = realloc(da->array, da->capacity * 2); + da->capacity *= 2; + } + + da->array[da->size] = strdup(s); + da->size++; +} + +void dynarray_free(DynArray **ptp) { + DynArray *da = *ptp; + + for (size_t i = 0; i < da->size; i++) { + free(da->array[i]); + } + + free(da->array); + free(da); + + *ptp = NULL; +} diff --git a/src/package/c/dynarray.h b/src/package/c/dynarray.h new file mode 100644 index 0000000..73f5a0a --- /dev/null +++ b/src/package/c/dynarray.h @@ -0,0 +1,14 @@ +#ifndef VIETER_DYNARRAY +#define VIETER_DYNARRAY + +#include +#include + +typedef struct dyn_array DynArray; + +DynArray *dynarray_init(size_t initial_capacity); +void dynarray_add(DynArray *da, const char * s); +char ** dynarray_get_array(DynArray *da); +void dynarray_free(DynArray **ptp); + +#endif diff --git a/src/package/c/package.c b/src/package/c/package.c new file mode 100644 index 0000000..a248c92 --- /dev/null +++ b/src/package/c/package.c @@ -0,0 +1,94 @@ +#include "package.h" + +static char *ignored_names[5] = { + ".BUILDINFO", + ".INSTALL", + ".MTREE", + ".PKGINFO", + ".CHANGELOG" +}; +static int ignored_words_len = sizeof(ignored_names) / sizeof(char *); + +inline Pkg *package_init() { + return calloc(sizeof(PkgInfo), 1); +} + +Pkg *package_read_archive(const char *pkg_path) { + struct archive *a = archive_read_new(); + struct archive_entry *entry = archive_entry_new(); + + // These three are the most commonly used compression methods + archive_read_support_filter_zstd(a); + archive_read_support_filter_gzip(a); + archive_read_support_filter_xz(a); + + // Contents should always be a tarball + archive_read_support_format_tar(a); + + // TODO where does this 10240 come from? + int r = archive_read_open_filename(a, pkg_path, 10240); + + // Exit early if we weren't able to successfully open the archive for reading + if (r != ARCHIVE_OK) { + return NULL; + } + + int compression_code = archive_filter_code(a, 0); + const char *path_name; + + PkgInfo *pkg_info; + DynArray *files = dynarray_init(16); + + while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { + path_name = archive_entry_pathname(entry); + + bool ignore = false; + + for (size_t i = 0; i < ignored_words_len; i++) { + if (strcmp(path_name, ignored_names[i]) == 0) { + ignore = true; + break; + } + } + + if (!ignore) { + dynarray_add(files, path_name); + } + + if (strcmp(path_name, ".PKGINFO") == 0) { + // Read data of file into memory buffer + int size = archive_entry_size(entry); + char *buf = malloc(size); + archive_read_data(a, buf, size); + + // Parse package info string into a struct + pkg_info = package_info_init(); + package_info_parse(pkg_info, buf); + + free(buf); + } else { + archive_read_data_skip(a); + } + } + + // Get size of file + struct stat stats; + + if (stat(pkg_path, &stats) != 0) { + return NULL; + } + + pkg_info->csize = stats.st_size; + + archive_read_free(a); + archive_entry_free(entry); + + // Create final return value + Pkg *pkg = package_init(); + pkg->path = strdup(pkg_path); + pkg->info = pkg_info; + pkg->files = files; + pkg->compression = compression_code; + + return pkg; +} diff --git a/src/package/c/package.h b/src/package/c/package.h new file mode 100644 index 0000000..76ec5ac --- /dev/null +++ b/src/package/c/package.h @@ -0,0 +1,25 @@ +#ifndef VIETER_PACKAGE +#define VIETER_PACKAGE + +#include +#include +#include +#include + +#include "archive.h" +#include "archive_entry.h" + +#include "package_info.h" +#include "dynarray.h" + +typedef struct pkg { + char *path; + PkgInfo *info; + DynArray *files; + int compression; +} Pkg; + +Pkg *package_read_archive(const char *pkg_path); +void package_free(Pkg ** ptp); + +#endif diff --git a/src/package/c/package_info.c b/src/package/c/package_info.c new file mode 100644 index 0000000..a8959ff --- /dev/null +++ b/src/package/c/package_info.c @@ -0,0 +1,46 @@ +#include "package_info.h" + +PkgInfo *package_info_init() { + PkgInfo *pkg_info = calloc(1, sizeof(PkgInfo)); + + pkg_info->groups = dynarray_init(4); + pkg_info->licenses = dynarray_init(4); + pkg_info->replaces = dynarray_init(4); + pkg_info->depends = dynarray_init(4); + pkg_info->conflicts = dynarray_init(4); + pkg_info->provides = dynarray_init(4); + pkg_info->optdepends = dynarray_init(4); + pkg_info->makedepends = dynarray_init(4); + pkg_info->checkdepends = dynarray_init(4); + + return pkg_info; +} + +void package_info_free(PkgInfo **ptp) { + PkgInfo *pkg_info = *ptp; + + FREE_STRING(pkg_info->name); + FREE_STRING(pkg_info->base); + FREE_STRING(pkg_info->version); + FREE_STRING(pkg_info->description); + FREE_STRING(pkg_info->url); + FREE_STRING(pkg_info->arch); + FREE_STRING(pkg_info->packager); + FREE_STRING(pkg_info->pgpsig); + + dynarray_free(&pkg_info->groups); + dynarray_free(&pkg_info->licenses); + dynarray_free(&pkg_info->replaces); + dynarray_free(&pkg_info->depends); + dynarray_free(&pkg_info->conflicts); + dynarray_free(&pkg_info->provides); + dynarray_free(&pkg_info->optdepends); + dynarray_free(&pkg_info->makedepends); + dynarray_free(&pkg_info->checkdepends); + + *ptp = NULL; +} + +void package_info_parse(PkgInfo *pkg_info, const char *pkg_info_str) { + +} diff --git a/src/package/c/package_info.h b/src/package/c/package_info.h new file mode 100644 index 0000000..7e16f4b --- /dev/null +++ b/src/package/c/package_info.h @@ -0,0 +1,39 @@ +#ifndef VIETER_PACKAGE_INFO +#define VIETER_PACKAGE_INFO + +#define FREE_STRING(sp) if (sp != NULL) free(sp) + +#include + +#include "dynarray.h" + +typedef struct pkg_info { + char *name; + char *base; + char *version; + char *description; + int64_t size; + int64_t csize; + char *url; + char *arch; + int64_t build_date; + char *packager; + char *pgpsig; + int64_t pgpsigsize; + + DynArray *groups; + DynArray *licenses; + DynArray *replaces; + DynArray *depends; + DynArray *conflicts; + DynArray *provides; + DynArray *optdepends; + DynArray *makedepends; + DynArray *checkdepends; +} PkgInfo; + +PkgInfo *package_info_init(); +void package_info_parse(PkgInfo *pkg_info, const char *pkg_info_str); +void package_info_free(PkgInfo **ptp); + +#endif