util.c (2750B)
1 #include <assert.h> 2 #include <bearssl.h> 3 #include <errno.h> 4 #include <gmni/gmni.h> 5 #include <libgen.h> 6 #include <limits.h> 7 #include <stdint.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <sys/stat.h> 12 #include <unistd.h> 13 #include "util.h" 14 15 void 16 posix_dirname(char *path, char *dname) 17 { 18 char p[PATH_MAX+1]; 19 char *t; 20 21 assert(strlen(path) <= PATH_MAX); 22 23 strcpy(p, path); 24 t = dirname(p); 25 memmove(dname, t, strlen(t) + 1); 26 } 27 28 /** Make directory and all of its parents */ 29 int 30 mkdirs(char *path, mode_t mode) 31 { 32 char dname[PATH_MAX + 1]; 33 posix_dirname(path, dname); 34 if (strcmp(dname, "/") == 0) { 35 return 0; 36 } 37 if (mkdirs(dname, mode) != 0) { 38 return -1; 39 } 40 if (mkdir(path, mode) != 0 && errno != EEXIST) { 41 return -1; 42 } 43 errno = 0; 44 return 0; 45 } 46 47 char * 48 getpath(const struct pathspec *paths, size_t npaths) { 49 for (size_t i = 0; i < npaths; i++) { 50 const char *var = ""; 51 if (paths[i].var) { 52 var = getenv(paths[i].var); 53 } 54 if (var) { 55 char *out = calloc(1, 56 strlen(var) + strlen(paths[i].path) + 1); 57 strcat(strcat(out, var), paths[i].path); 58 return out; 59 } 60 } 61 return NULL; 62 } 63 64 int 65 download_resp(FILE *out, struct gemini_response resp, const char *path, 66 char *url) 67 { 68 char path_buf[PATH_MAX]; 69 int n = 0; 70 assert(path); 71 switch (path[0]) { 72 case '\0': 73 strcpy(path_buf, "./"); 74 break; 75 case '~': 76 n = snprintf(path_buf, PATH_MAX, "%s/%s", getenv("HOME"), &path[1]); 77 if (n > PATH_MAX) { 78 fprintf(stderr, 79 "Path %s exceeds limit of %d bytes and has been truncated\n", 80 path_buf, PATH_MAX); 81 return 1; 82 } 83 break; 84 default: 85 if (strlen(path) > PATH_MAX) { 86 fprintf(stderr, "Path %s exceeds limit of %d bytes\n", 87 path, PATH_MAX); 88 return 1; 89 } 90 strcpy(path_buf, path); 91 } 92 char path_res[PATH_MAX]; 93 if (path_buf[strlen(path_buf)-1] == '/') { 94 n = snprintf(path_res, PATH_MAX, "%s%s", path_buf, basename(url)); 95 if (n > PATH_MAX) { 96 fprintf(stderr, 97 "Path %s exceeds limit of %d bytes and has been truncated\n", 98 path_res, PATH_MAX); 99 return 1; 100 } 101 } else { 102 strcpy(path_res, path_buf); 103 } 104 FILE *f = fopen(path_res, "w"); 105 if (f == NULL) { 106 fprintf(stderr, "Could not open %s for writing: %s\n", 107 path_res, strerror(errno)); 108 return 1; 109 } 110 fprintf(out, "Downloading %s to %s\n", url, path_res); 111 char buf[BUFSIZ]; 112 for (int n = 1; n > 0;) { 113 if (resp.sc) { 114 n = br_sslio_read(&resp.body, buf, BUFSIZ); 115 } else { 116 n = read(resp.fd, buf, BUFSIZ); 117 } 118 if (n < 0) { 119 break; 120 } 121 ssize_t w = 0; 122 while (w < (ssize_t)n) { 123 ssize_t x = fwrite(&buf[w], 1, n - w, f); 124 if (ferror(f)) { 125 fprintf(stderr, "Error: write: %s\n", 126 strerror(errno)); 127 return 1; 128 } 129 w += x; 130 } 131 } 132 fprintf(out, "Finished download\n"); 133 fclose(f); 134 return 0; 135 }