aboutsummaryrefslogtreecommitdiff
path: root/src/manifest.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/manifest.c')
-rw-r--r--src/manifest.c668
1 files changed, 0 insertions, 668 deletions
diff --git a/src/manifest.c b/src/manifest.c
deleted file mode 100644
index 1b2b600..0000000
--- a/src/manifest.c
+++ /dev/null
@@ -1,668 +0,0 @@
-/**
- * @file manifest.c
- */
-#include "spm.h"
-#include <fnmatch.h>
-#include "url.h"
-
-/**
- * Compare `ManifestPackage` packages (lazily)
- * @param a
- * @param b
- * @return 0 = same, !0 = different
- */
-int manifest_package_cmp(ManifestPackage *a, ManifestPackage *b) {
- int result = 0;
- if (a == NULL || b == NULL) {
- return -1;
- }
- result += strcmp(a->origin, b->origin);
- result += strcmp(a->archive, b->archive);
- result += strcmp(a->checksum_sha256, b->checksum_sha256);
- return result;
-}
-
-void manifest_package_separator_swap(char **name) {
- // Replace unwanted separators in the package name with placeholder to prevent splitting on the wrong one
- int delim_count = num_chars((*name), SPM_PACKAGE_MEMBER_SEPARATOR) - SPM_PACKAGE_MIN_DELIM;
-
- if (delim_count < 0) {
- return;
- }
-
- for (size_t t = 0; t < strlen((*name)); t++) {
- if (delim_count == 0) break;
- if ((*name)[t] == SPM_PACKAGE_MEMBER_SEPARATOR) {
- (*name)[t] = SPM_PACKAGE_MEMBER_SEPARATOR_PLACEHOLD;
- delim_count--;
- }
- }
-}
-
-void manifest_package_separator_restore(char **name) {
- char separator[2];
- char placeholder[2];
- snprintf(separator, sizeof(separator), "%c", SPM_PACKAGE_MEMBER_SEPARATOR);
- snprintf(placeholder, sizeof(placeholder), "%c", SPM_PACKAGE_MEMBER_SEPARATOR_PLACEHOLD);
-
- replace_text((*name), placeholder, separator);
-}
-
-/**
- * Generate a `Manifest` of package data
- * @param package_dir a directory containing SPM packages
- * @return `Manifest`
- */
-Manifest *manifest_from(const char *package_dir) {
- char *package_filter[] = {SPM_PACKAGE_EXTENSION, NULL}; // We only want packages
- FSTree *fsdata = NULL;
- fsdata = fstree(package_dir, package_filter, SPM_FSTREE_FLT_ENDSWITH);
-
- Manifest *info = (Manifest *)calloc(1, sizeof(Manifest));
- info->records = fsdata->files_length;
- info->packages = (ManifestPackage **) calloc(info->records + 1, sizeof(ManifestPackage *));
- if (info->packages == NULL) {
- perror("Failed to allocate package array");
- fprintf(SYSERROR);
- free(info);
- fstree_free(fsdata);
- return NULL;
- }
-
- if (SPM_GLOBAL.verbose) {
- printf("Initializing package manifest:\n");
- }
- strncpy(info->origin, package_dir, SPM_PACKAGE_MEMBER_ORIGIN_SIZE);
-
-
- char *tmpdir = spm_mkdtemp("spm_manifest_from", NULL);
- if (!tmpdir) {
- perror("failed to create temporary directory");
- fprintf(SYSERROR);
- free(info);
- fstree_free(fsdata);
- return NULL;
- }
-
- for (size_t i = 0; i < fsdata->files_length; i++) {
- float percent = (((float)i + 1) / fsdata->files_length) * 100;
-
- if (SPM_GLOBAL.verbose) {
- printf("[%3.0f%%] %s\n", percent, basename(fsdata->files[i]));
- }
-
- // Initialize package record
- info->packages[i] = (ManifestPackage *) calloc(1, sizeof(ManifestPackage));
- if (info->packages[i] == NULL) {
- perror("Failed to allocate package record");
- fprintf(SYSERROR);
- fstree_free(fsdata);
- free(info);
- rmdirs(tmpdir);
- return NULL;
- }
-
- // Swap extra package separators with a bogus character
- manifest_package_separator_swap(&fsdata->files[i]);
-
- // Split the package name into parts
- char psep[2];
- snprintf(psep, sizeof(psep), "%c", SPM_PACKAGE_MEMBER_SEPARATOR);
- char **parts = split(fsdata->files[i], psep);
-
- // Restore package separator
- manifest_package_separator_restore(&parts[0]);
- manifest_package_separator_restore(&fsdata->files[i]);
-
- // Populate `ManifestPackage` record
- info->packages[i]->size = (size_t) get_file_size(fsdata->files[i]);
- strncpy(info->packages[i]->origin, info->origin, SPM_PACKAGE_MEMBER_ORIGIN_SIZE);
- strncpy(info->packages[i]->archive, basename(fsdata->files[i]), SPM_PACKAGE_MEMBER_SIZE);
- strncpy(info->packages[i]->name, basename(parts[0]), SPM_PACKAGE_MEMBER_SIZE);
- strncpy(info->packages[i]->version, parts[1], SPM_PACKAGE_MEMBER_SIZE);
- strncpy(info->packages[i]->revision, parts[2], SPM_PACKAGE_MEMBER_SIZE);
- strdelsuffix(info->packages[i]->revision, SPM_PACKAGE_EXTENSION);
-
- // Read package requirement specs
- char *archive = join((char *[]) {info->origin, info->packages[i]->archive, NULL}, DIRSEPS);
- if (tar_extract_file(archive, SPM_META_DEPENDS, tmpdir) != 0) {
- // TODO: at this point is the package is invalid? .SPM_DEPENDS should be there...
- fprintf(stderr, "extraction failure: %s\n", archive);
- rmdirs(tmpdir);
- exit(1);
- }
- char *depfile = join((char *[]) {tmpdir, SPM_META_DEPENDS, NULL}, DIRSEPS);
- info->packages[i]->requirements = file_readlines(depfile, 0, 0, NULL);
-
- // Record count of requirement specs
- if (info->packages[i]->requirements != NULL) {
- for (size_t rec = 0; info->packages[i]->requirements[rec] != NULL; rec++) {
- strip(info->packages[i]->requirements[rec]);
- info->packages[i]->requirements_records++;
- }
- }
-
- unlink(depfile);
- free(depfile);
- free(archive);
- split_free(parts);
- }
-
- fstree_free(fsdata);
- rmdirs(tmpdir);
- return info;
-}
-
-/**
- * Free a `Manifest` structure
- * @param info `Manifest`
- */
-void manifest_free(Manifest *info) {
- for (size_t i = 0; i < info->records; i++) {
- manifest_package_free(info->packages[i]);
- }
- free(info);
-}
-
-/**
- * Free a `ManifestPackage` structure
- * @param info `ManifestPackage`
- */
-void manifest_package_free(ManifestPackage *info) {
- for (size_t i = 0; i < info->requirements_records; i++) {
- free(info->requirements[i]);
- }
- free(info->requirements);
- free(info);
-}
-
-/**
- * Write a `Manifest` to the configuration directory
- * @param info
- * @param pkgdir
- * @return
- */
-int manifest_write(Manifest *info, const char *pkgdir) {
- char *reqs = NULL;
- char path[PATH_MAX];
- char path_manifest[PATH_MAX];
-
- memset(path, '\0', sizeof(path));
- memset(path_manifest, '\0', sizeof(path));
-
- strcpy(path, pkgdir);
-
- // Append the repo target if its missing
- if (strstr(path, SPM_GLOBAL.repo_target) == NULL) {
- strcat(path, DIRSEPS);
- strcat(path, SPM_GLOBAL.repo_target);
- }
- strcpy(path_manifest, path);
-
- // Append the manifest filename if its missing
- if (!endswith(path_manifest, SPM_MANIFEST_FILENAME)) {
- strcat(path_manifest, DIRSEPS);
- strcat(path_manifest, SPM_MANIFEST_FILENAME);
- }
-
- FILE *fp = fopen(path_manifest, "w+");
- if (fp == NULL) {
- perror(path_manifest);
- fprintf(SYSERROR);
- return -1;
- }
-#ifdef _DEBUG
- if (SPM_GLOBAL.verbose) {
- for (size_t i = 0; i < info->records; i++) {
- printf("%-20s: %s\n"
- "%-20s: %zu\n"
- "%-20s: %s\n"
- "%-20s: %s\n"
- "%-20s: %s\n"
- "%-20s: %zu\n",
- "archive", info->packages[i]->archive,
- "size", info->packages[i]->size,
- "name", info->packages[i]->name,
- "version", info->packages[i]->version,
- "revision", info->packages[i]->revision,
- "requirements_records", info->packages[i]->requirements_records
- );
- reqs = join(info->packages[i]->requirements, ", ");
- printf("%-20s: %s\n", "requirements", reqs ? reqs : "NONE");
- free(reqs);
- printf("\n");
- }
- }
-#endif
-
- if (SPM_GLOBAL.verbose) {
- printf("Generating manifest file: %s\n", path_manifest);
- }
- fprintf(fp, "%s\n", SPM_MANIFEST_HEADER);
- char data[BUFSIZ];
- for (size_t i = 0; i < info->records; i++) {
- // write CSV-like manifest
- memset(data, '\0', BUFSIZ);
- char *dptr = data;
- float percent = (((float)i + 1) / info->records) * 100;
- if (SPM_GLOBAL.verbose) {
- printf("[%3.0f%%] %s\n", percent, info->packages[i]->archive);
- }
- reqs = join(info->packages[i]->requirements, ",");
- char *archive = join((char *[]) {path, info->packages[i]->archive, NULL}, DIRSEPS);
- char *checksum_sha256 = sha256sum(archive);
-
- sprintf(dptr, "%s|" // archive
- "%zu|" // size
- "%s|" // name
- "%s|" // version
- "%s|" // revision
- "%zu|" // requirements_records
- "%s|" // requirements
- "%s" // checksum_md5
- , info->packages[i]->archive,
- info->packages[i]->size,
- info->packages[i]->name,
- info->packages[i]->version,
- info->packages[i]->revision,
- info->packages[i]->requirements_records,
- reqs ? reqs : SPM_MANIFEST_NODATA,
- checksum_sha256 ? checksum_sha256 : SPM_MANIFEST_NODATA);
- fprintf(fp, "%s\n", dptr);
- free(reqs);
- free(archive);
- if (checksum_sha256 != NULL)
- free(checksum_sha256);
- }
- fclose(fp);
- return 0;
-}
-
-/**
- *
- * @param url
- * @param dest
- * @return
- */
-int fetch(const char *url, const char *dest) {
- URL_FILE *handle = NULL;
- FILE *outf = NULL;
- size_t chunk_size = 0xffff;
- size_t nread = 0;
- char *buffer = calloc(chunk_size + 1, sizeof(char));
- if (!buffer) {
- perror("fetch buffer too big");
- return -1;
- }
-
- handle = url_fopen(url, "r");
- if(!handle) {
- fprintf(stderr, "couldn't url_fopen() %s\n", url);
- return 2;
- }
-
- outf = fopen(dest, "wb+");
- if(!outf) {
- perror("couldn't open fread output file\n");
- return 1;
- }
-
- do {
- nread = url_fread(buffer, 1, chunk_size, handle);
- if (handle->http_status >= 400) {
- free(buffer);
- fclose(outf);
- if (exists(dest) == 0) {
- unlink(dest);
- }
-
- long http_status = handle->http_status;
- url_fclose(handle);
- return http_status;
- }
- fwrite(buffer, 1, nread, outf);
- } while (nread);
-
- free(buffer);
- fclose(outf);
- url_fclose(handle);
- return 0;
-}
-
-int manifest_validate(void) {
- size_t line_count;
- int problems;
- char data[BUFSIZ];
- FILE *fp;
-
- if (exists(SPM_GLOBAL.package_manifest) != 0) {
- return -1;
- }
-
- if ((fp = fopen(SPM_GLOBAL.package_manifest, "r")) == NULL) {
- perror(SPM_GLOBAL.package_manifest);
- return -2;
- }
-
- line_count = 0;
- problems = 0;
- while (fgets(data, BUFSIZ, fp) != NULL) {
- int separators;
- if (line_count == 0) {
- if (strncmp(data, SPM_MANIFEST_HEADER, strlen(SPM_MANIFEST_HEADER)) != 0) {
- fprintf(stderr, "Invalid manifest header: %s (expecting '%s')\n", strip(data), SPM_MANIFEST_HEADER);
- problems++;
- line_count++;
- }
- }
- else if ((separators = num_chars(data, SPM_MANIFEST_SEPARATOR)) != SPM_MANIFEST_SEPARATOR_MAX) {
- fprintf(stderr, "Invalid manifest record on line %zu: %s (expecting %d separators, found %d)\n", line_count, strip(data), SPM_MANIFEST_SEPARATOR_MAX, separators);
- problems++;
- }
- line_count++;
- }
- return problems;
-}
-
-/**
- * Read the package manifest stored in the configuration directory
- * @return `Manifest` structure
- */
-Manifest *manifest_read(char *file_or_url) {
- FILE *fp = NULL;
- char *filename = SPM_MANIFEST_FILENAME;
- char *tmpdir = NULL;
- char path[PATH_MAX];
- char *pathptr = path;
- memset(path, '\0', PATH_MAX);
-
- // When file_or_url is NULL we want to use the global manifest
- if (file_or_url == NULL) {
- // TODO: move this out
- strcpy(path, SPM_GLOBAL.package_dir);
- }
- else {
- tmpdir = spm_mkdtemp("spm_manifest_read_XXXXXX", SPM_GLOBAL.repo_target);
- if (exists(tmpdir) != 0) {
- fprintf(stderr, "Failed to create temporary storage directory\n");
- fprintf(SYSERROR);
- return NULL;
- }
-
- snprintf(pathptr, PATH_MAX - 1, "%s%s%s%s%s", tmpdir, DIRSEPS, SPM_GLOBAL.repo_target, DIRSEPS, filename);
- }
-
- const char *target_is;
- if (strstr(file_or_url, SPM_GLOBAL.repo_target) != NULL) {
- target_is = "";
- }
- else {
- target_is = SPM_GLOBAL.repo_target;
- }
-
- char *remote_manifest = join_ex(DIRSEPS, file_or_url, target_is, filename, NULL);
-
- if (exists(pathptr) != 0) {
- // TODO: Move this out
- int fetch_status = fetch(remote_manifest, pathptr);
- if (fetch_status >= 400) {
- fprintf(stderr, "HTTP %d: %s: %s\n", fetch_status, http_response_str(fetch_status), remote_manifest);
- free(remote_manifest);
- return NULL;
- }
- else if (fetch_status == 1 || fetch_status < 0) {
- free(remote_manifest);
- return NULL;
- }
- }
-
- int valid = 0;
- size_t total_records = 0;
- char data[BUFSIZ];
- char *dptr = data;
- memset(dptr, '\0', BUFSIZ);
-
- fp = fopen(pathptr, "r+");
- if (!fp) {
- perror(filename);
- fprintf(SYSERROR);
- return NULL;
- }
-
- while (fgets(dptr, BUFSIZ, fp) != NULL) {
- total_records++;
- }
- total_records--; // header does not count
- rewind(fp);
-
- Manifest *info = (Manifest *)calloc(1, sizeof(Manifest));
- info->packages = (ManifestPackage **)calloc(total_records + 1, sizeof(ManifestPackage *));
-
- // Record manifest's origin
- memset(info->origin, '\0', SPM_PACKAGE_MEMBER_ORIGIN_SIZE);
- if (remote_manifest != NULL) {
- strcpy(info->origin, remote_manifest);
- }
- else {
- strcpy(info->origin, path);
- }
- free(remote_manifest);
-
- // Check validity of the manifest's formatting and field length
- if ((valid = manifest_validate()) != 0) {
- return NULL;
- }
-
- // Begin parsing the manifest
- char separator = SPM_MANIFEST_SEPARATOR;
- size_t i = 0;
-
- // Consume header
- if (fgets(dptr, BUFSIZ, fp) == NULL) {
- // file is probably empty
- return NULL;
- }
-
- info->records = total_records;
- while (fgets(dptr, BUFSIZ, fp) != NULL) {
- dptr = strip(dptr);
- char *garbage;
- char **parts = split(dptr, &separator);
- char *_origin = NULL;
- if (file_or_url != NULL) {
- _origin = strdup(file_or_url);
- }
- else {
- _origin = dirname(path);
- }
-
- info->packages[i] = (ManifestPackage *)calloc(1, sizeof(ManifestPackage));
-
- strncpy(info->packages[i]->origin, _origin, SPM_PACKAGE_MEMBER_ORIGIN_SIZE);
- free(_origin);
-
- strncpy(info->packages[i]->archive, parts[0], SPM_PACKAGE_MEMBER_SIZE);
- info->packages[i]->size = strtoul(parts[1], &garbage, 10);
- strncpy(info->packages[i]->name, parts[2], SPM_PACKAGE_MEMBER_SIZE);
- strncpy(info->packages[i]->version, parts[3], SPM_PACKAGE_MEMBER_SIZE);
- strncpy(info->packages[i]->revision, parts[4], SPM_PACKAGE_MEMBER_SIZE);
- info->packages[i]->requirements_records = (size_t) atoi(parts[5]);
-
- info->packages[i]->requirements = NULL;
- if (strncmp(parts[6], SPM_MANIFEST_NODATA, strlen(SPM_MANIFEST_NODATA)) != 0) {
- info->packages[i]->requirements = split(parts[6], ",");
-
- }
- if (strncmp(parts[7], SPM_MANIFEST_NODATA, strlen(SPM_MANIFEST_NODATA)) != 0) {
- memset(info->packages[i]->checksum_sha256, '\0', SHA256_DIGEST_STRING_LENGTH);
- strcpy(info->packages[i]->checksum_sha256, parts[7]);
-
- }
-
- split_free(parts);
- i++;
- }
-
- if (tmpdir != NULL) {
- rmdirs(tmpdir);
- free(tmpdir);
- }
- fclose(fp);
- return info;
-}
-
-/**
- * Find a package in a `Manifest`
- * @param info `Manifest`
- * @param _package package name
- * @return found=`ManifestPackage`, not found=NULL
- */
-ManifestPackage *manifest_search(Manifest *info, const char *_package) {
- ManifestPackage *match = NULL;
- char package[PATH_MAX];
-
- memset(package, '\0', PATH_MAX);
- strncpy(package, _package, PATH_MAX);
-
- if ((match = find_by_strspec(info, package)) != NULL) {
- return match;
- }
- return NULL;
-}
-
-/**
- * Duplicate a `ManifestPackage`
- * @param manifest
- * @return `ManifestPackage`
- */
-ManifestPackage *manifest_package_copy(ManifestPackage *manifest) {
- if (manifest == NULL) {
- return NULL;
- }
-
- ManifestPackage *result = calloc(1, sizeof(ManifestPackage));
- memcpy(result, manifest, sizeof(ManifestPackage));
-
- if (manifest->requirements_records > 0) {
- result->requirements = (char **)calloc(manifest->requirements_records, sizeof(char *));
- for (size_t i = 0; i < manifest->requirements_records; i++) {
- result->requirements[i] = strdup(manifest->requirements[i]);
- }
- }
-
- return result;
-}
-
-/**
- *
- * @param ManifestList `pManifestList`
- */
-void manifestlist_free(ManifestList *pManifestList) {
- for (size_t i = 0; i < pManifestList->num_inuse; i++) {
- manifest_free(pManifestList->data[i]);
- }
- free(pManifestList->data);
- free(pManifestList);
-}
-
-/**
- * Append a value to the list
- * @param ManifestList `pManifestList`
- * @param str
- */
-void manifestlist_append(ManifestList *pManifestList, char *path) {
- Manifest *manifest = manifest_read(path);
- if (manifest == NULL) {
- fprintf(stderr, "Failed to create manifest in memory\n");
- fprintf(SYSERROR);
- exit(1);
- }
-
- Manifest **tmp = realloc(pManifestList->data, (pManifestList->num_alloc + 1) * sizeof(Manifest *));
- if (tmp == NULL) {
- manifestlist_free(pManifestList);
- perror("failed to append to array");
- exit(1);
- }
- pManifestList->data = tmp;
- pManifestList->data[pManifestList->num_inuse] = manifest;
- pManifestList->num_inuse++;
- pManifestList->num_alloc++;
-}
-
-ManifestPackage *manifestlist_search(ManifestList *pManifestList, const char *_package) {
- ManifestPackage *found[255] = {0,};
- ManifestPackage *result = NULL;
- ssize_t offset = -1;
-
- for (size_t i = 0; i < manifestlist_count(pManifestList); i++) {
- Manifest *item = manifestlist_item(pManifestList, i);
- result = manifest_search(item, _package);
- if (result != NULL) {
- offset++;
- found[offset] = result;
- }
- }
-
- if (offset < 0) {
- return NULL;
- }
- return found[offset];
-}
-
-/**
- * Get the count of values stored in a `pManifestList`
- * @param ManifestList
- * @return
- */
-size_t manifestlist_count(ManifestList *pManifestList) {
- return pManifestList->num_inuse;
-}
-
-/**
- * Set value at index
- * @param ManifestList
- * @param value string
- * @return
- */
-void manifestlist_set(ManifestList *pManifestList, size_t index, Manifest *value) {
- Manifest *item = NULL;
- if (index > manifestlist_count(pManifestList)) {
- return;
- }
- if ((item = manifestlist_item(pManifestList, index)) == NULL) {
- return;
- }
- memcpy(pManifestList->data[index], value, sizeof(Manifest));
-}
-
-/**
- * Retrieve data from a `pManifestList`
- * @param ManifestList
- * @param index
- * @return string
- */
-Manifest *manifestlist_item(ManifestList *pManifestList, size_t index) {
- if (index > manifestlist_count(pManifestList)) {
- return NULL;
- }
- return pManifestList->data[index];
-}
-
-/**
- * Initialize an empty `pManifestList`
- * @return `pManifestList`
- */
-ManifestList *manifestlist_init() {
- ManifestList *pManifestList = calloc(1, sizeof(ManifestList));
- if (pManifestList == NULL) {
- perror("failed to allocate array");
- exit(errno);
- }
- pManifestList->num_inuse = 0;
- pManifestList->num_alloc = 1;
- pManifestList->data = calloc(pManifestList->num_alloc, sizeof(char *));
- return pManifestList;
-}
-
-