list.c (4410B)
1 #include <sys/stat.h> 2 #include <dirent.h> 3 #include <errno.h> 4 #include <limits.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <time.h> 9 #include <unistd.h> 10 11 #include "config.h" 12 #include "common.h" 13 #include "url.h" 14 #include "html.h" 15 #include "http.h" 16 17 static int list_files(const char *repository_path, struct html_row ** rows, size_t * nrows); 18 static void format_size(char *buf, size_t len, off_t size); 19 static void free_rows(struct html_row *rows, size_t nrows); 20 21 int 22 main(void) 23 { 24 char path[PATH_MAX]; 25 char template[PATH_MAX]; 26 struct html_row *rows; 27 size_t nrows; 28 struct html_block blocks[1]; 29 const char *template_name; 30 31 if (!config_access_allowed()) { 32 reply("403 Forbidden", "Forbidden"); 33 return 0; 34 } 35 36 if (build_repository_path(path, 37 sizeof(path), 38 storage_root(), 39 repository()) == -1) { 40 reply("500 Internal Server Error", 41 "Path too long"); 42 return 0; 43 } 44 if (list_files(path, &rows, &nrows) == -1) { 45 reply("500 Internal Server Error", 46 "Unable to list files"); 47 return 0; 48 } 49 50 blocks[0].name = "FILES"; 51 blocks[0].rows = rows; 52 blocks[0].nrows = nrows; 53 54 55 if (!config_write_allowed()) 56 template_name = LIST_READONLY_TEMPLATE_NAME; 57 else 58 template_name = LIST_TEMPLATE_NAME; 59 60 if (snprintf(template, sizeof(template), 61 "%s/%s", 62 simplefiles_root(), 63 template_name) >= (int) sizeof(template)) { 64 reply("500 Internal Server Error", 65 "Template path too long"); 66 free_rows(rows, nrows); 67 return 0; 68 } 69 70 if (render_template_response(template, 71 NULL, 0, 72 blocks, 1) == -1) { 73 free_rows(rows, nrows); 74 reply("500 Internal Server Error", "Unable to render template"); 75 return 0; 76 } 77 free_rows(rows, nrows); 78 return 0; 79 } 80 81 static void 82 format_size(char *buf, size_t len, off_t size) 83 { 84 if (size >= 1073741824LL) 85 snprintf(buf, len, "%.1f GB", size / 1073741824.0); 86 else if (size >= 1048576LL) 87 snprintf(buf, len, "%.1f MB", size / 1048576.0); 88 else if (size >= 1024LL) 89 snprintf(buf, len, "%.1f KB", size / 1024.0); 90 else 91 snprintf(buf, len, "%lld B", (long long) size); 92 } 93 94 static int 95 list_files(const char *repository_path, 96 struct html_row ** rows, size_t * nrows) 97 { 98 DIR *dir; 99 struct dirent *de; 100 struct stat st; 101 char path[PATH_MAX]; 102 char timebuf[32]; 103 struct tm *tm; 104 char sizebuf[32]; 105 char *encoded; 106 struct html_row *new_rows; 107 struct html_var *vars; 108 size_t count = 0; 109 110 *rows = NULL; 111 *nrows = 0; 112 113 dir = opendir(repository_path); 114 if (dir == NULL) 115 return 0; 116 117 while ((de = readdir(dir)) != NULL) { 118 if (strcmp(de->d_name, ".") == 0 || 119 strcmp(de->d_name, "..") == 0) 120 continue; 121 122 if (strcmp(de->d_name, CONFIG_FILENAME) == 0) 123 continue; 124 125 if (snprintf(path, sizeof(path), 126 "%s/%s", 127 repository_path, 128 de->d_name) >= (int) sizeof(path)) 129 continue; 130 131 if (stat(path, &st) == -1) 132 continue; 133 134 if (!S_ISREG(st.st_mode)) 135 continue; 136 137 tm = localtime(&st.st_mtime); 138 if (tm == NULL) 139 continue; 140 141 if (strftime(timebuf, sizeof(timebuf), 142 "%Y-%m-%d %H:%M", tm) == 0) 143 continue; 144 145 encoded = url_encode(de->d_name); 146 if (encoded == NULL) 147 continue; 148 149 150 new_rows = realloc(*rows, (count + 1) * sizeof(**rows)); 151 if (new_rows == NULL) { 152 free_rows(*rows, count); 153 free(encoded); 154 closedir(dir); 155 return -1; 156 } 157 *rows = new_rows; 158 159 vars = malloc(4 * sizeof(*vars)); 160 if (vars == NULL) { 161 free_rows(*rows, count); 162 free(encoded); 163 closedir(dir); 164 return -1; 165 } 166 vars[0].name = "NAME"; 167 vars[0].value = strdup(de->d_name); 168 169 vars[1].name = "URL"; 170 vars[1].value = encoded; 171 172 format_size(sizebuf, sizeof(sizebuf), st.st_size); 173 vars[2].name = "SIZE"; 174 vars[2].value = strdup(sizebuf); 175 176 vars[3].name = "MODIFIED"; 177 vars[3].value = strdup(timebuf); 178 179 if (vars[0].value == NULL || 180 vars[2].value == NULL || 181 vars[3].value == NULL) { 182 free((char *) vars[0].value); 183 free((char *) vars[1].value); 184 free((char *) vars[2].value); 185 free((char *) vars[3].value); 186 free(vars); 187 free_rows(*rows, count); 188 *rows = NULL; 189 closedir(dir); 190 return -1; 191 } 192 (*rows)[count].vars = vars; 193 (*rows)[count].nvars = 4; 194 count++; 195 } 196 197 closedir(dir); 198 199 *nrows = count; 200 return 0; 201 } 202 203 static void 204 free_rows(struct html_row *rows, size_t nrows) 205 { 206 size_t i; 207 size_t j; 208 209 for (i = 0; i < nrows; i++) { 210 for (j = 0; j < rows[i].nvars; j++) 211 free((char *) rows[i].vars[j].value); 212 213 free((struct html_var *) rows[i].vars); 214 } 215 216 free(rows); 217 }