diff options
Diffstat (limited to 'lib/mirrors.c')
-rw-r--r-- | lib/mirrors.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/lib/mirrors.c b/lib/mirrors.c new file mode 100644 index 0000000..cad3f6b --- /dev/null +++ b/lib/mirrors.c @@ -0,0 +1,180 @@ +#include "spm.h" +#include "url.h" + +char **file_readlines(const char *filename, size_t start, size_t limit, ReaderFn *readerFn) { + FILE *fp = NULL; + char **result = NULL; + char *buffer = NULL; + size_t lines = 0; + + if ((fp = fopen(filename, "r")) == NULL) { + perror(filename); + fprintf(SYSERROR); + return NULL; + } + + // Allocate buffer + if ((buffer = calloc(BUFSIZ + 1, sizeof(char))) == NULL) { + perror("line buffer"); + fprintf(SYSERROR); + fclose(fp); + return NULL; + } + + // count number the of lines in the file + while ((fgets(buffer, BUFSIZ, fp)) != NULL) { + lines++; + } + + if (!lines) { + free(buffer); + fclose(fp); + return NULL; + } + + rewind(fp); + + // Handle invalid start offset + if (start > lines) { + start = 0; + } + + // Adjust line count when start offset is non-zero + if (start != 0 && start < lines) { + lines -= start; + } + + + // Handle minimum and maximum limits + if (limit == 0 || limit > lines) { + limit = lines; + } + + // Populate results array + result = calloc(lines + 1, sizeof(char *)); + for (size_t i = start; i < limit; i++) { + if (i < start) { + continue; + } + + if (fgets(buffer, BUFSIZ, fp) == NULL) { + break; + } + + if (readerFn != NULL) { + int status = readerFn(i - start, &buffer); + // A status greater than zero indicates we should ignore this line entirely and "continue" + // A status less than zero indicates we should "break" + // A zero status proceeds normally + if (status > 0) { + i--; + continue; + } else if (status < 0) { + break; + } + } + result[i - start] = strdup(buffer); + } + + free(buffer); + fclose(fp); + return result; +} + +/** + * + * @param filename + * @return + */ +char **mirror_list(const char *filename) { + char **mirrors = NULL; + char **result = NULL; + size_t count; + + // The configuration file isn't critical so if it isn't available, no big deal + if (exists(filename) != 0) { + return NULL; + } + + mirrors = file_readlines(filename, 0, 0, NULL); + if (mirrors == NULL) { + return NULL; + } + + for (count = 0; mirrors[count] != NULL; count++); + if (!count) { + return NULL; + } + + result = calloc(count + 1, sizeof(char **)); + for (size_t i = 0; mirrors[i] != NULL; i++) { + if (startswith(mirrors[i], "#") || isempty(mirrors[i])) { + continue; + } + result[i] = join((char *[]) {mirrors[i], SPM_GLOBAL.repo_target, NULL}, DIRSEPS); + free(mirrors[i]); + } + free(mirrors); + return result; +} + +void mirror_list_free(char **m) { + if (m == NULL) { + return; + } + for (size_t i = 0; m[i] != NULL; i++) { + free(m[i]); + } + free(m); +} + +void mirror_clone(Manifest *info, char *_dest) { + char *dest = NULL; + if (endswith(_dest, SPM_GLOBAL.repo_target) != 0) { + dest = strdup(_dest); + } + else { + dest = join((char *[]) {_dest, SPM_GLOBAL.repo_target, NULL}, DIRSEPS); + } + + if (exists(dest) != 0 && mkdirs(dest, 0755) != 0) { + perror("Unable to create mirror directory"); + fprintf(SYSERROR); + exit(1); + } + + printf("Remote: %s\n", info->origin); + printf("Local: %s\n", dest); + + for (size_t i = 0; i < info->records; i++) { + long response = 0; + char *archive = join((char *[]) {info->packages[i]->origin, SPM_GLOBAL.repo_target, info->packages[i]->archive, NULL}, DIRSEPS); + char *path = join((char *[]) {dest, info->packages[i]->archive, NULL}, DIRSEPS); + if (exists(path) == 0) { + char *checksum = sha256sum(path); + if (strcmp(checksum, info->packages[i]->checksum_sha256) == 0) { + printf("Skipped: %s\n", archive); + free(checksum); + free(archive); + free(path); + continue; + } + } + printf("Fetch: %s\n", archive); + if ((response = fetch(archive, path)) >= 400) { + fprintf(stderr, "WARNING: HTTP(%ld, %s): %s\n", response, http_response_str(response), archive); + } + free(archive); + free(path); + } + + // Now fetch a copy of the physical manifest + char *datafile = join((char *[]) {dest, basename(info->origin), NULL}, DIRSEPS); + long response = 0; + if ((response = fetch(info->origin, datafile) >= 400)) { + fprintf(stderr, "WARNING: HTTP(%ld, %s): %s\n", response, http_response_str(response), info->origin); + } + free(dest); + free(datafile); + printf("done!\n"); +}
\ No newline at end of file |