rename.c (4389B)
1 #include <errno.h> 2 #include <limits.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <sys/stat.h> 7 #include <unistd.h> 8 9 #include "common.h" 10 #include "config.h" 11 #include "html.h" 12 #include "http.h" 13 #include "request.h" 14 15 static int do_get(void); 16 static int do_post(void); 17 18 19 static int 20 do_get(void) 21 { 22 char filename[NAME_MAX + 1]; 23 char path[PATH_MAX]; 24 char template[PATH_MAX]; 25 struct stat st; 26 27 if (!config_write_allowed()) { 28 reply("403 Forbidden", "Repository is read-only"); 29 return 0; 30 } 31 if (get_filename(getenv("QUERY_STRING"), 32 filename, 33 sizeof(filename)) == -1) 34 return 0; 35 36 if (build_storage_path(path, 37 sizeof(path), 38 storage_root(), 39 repository(), 40 filename) == -1) { 41 reply("500 Internal Server Error", 42 "Path too long"); 43 return 0; 44 } 45 if (stat(path, &st) == -1 || !S_ISREG(st.st_mode)) { 46 reply("404 Not Found", 47 "File not found"); 48 return 0; 49 } 50 struct html_var vars[] = { 51 {"FILENAME", filename}, 52 {"CANCEL_URI", DEFAULT_REDIRECT_URI}, 53 }; 54 55 if (snprintf(template, 56 sizeof(template), 57 "%s/%s", 58 simplefiles_root(), RENAME_TEMPLATE_NAME) >= (int) sizeof(template)) { 59 reply("500 Internal Server Error", 60 "Template path too long"); 61 return 0; 62 } 63 if (render_template_response( 64 template, 65 vars, 66 sizeof(vars) / sizeof(vars[0]), 67 NULL, 68 0) == -1) { 69 reply("500 Internal Server Error", "Template error"); 70 return 0; 71 } 72 return 0; 73 } 74 75 76 static int 77 do_post(void) 78 { 79 char *body; 80 const char *p; 81 char oldname[NAME_MAX + 1]; 82 char newname[NAME_MAX + 1]; 83 char oldpath[PATH_MAX]; 84 char newpath[PATH_MAX]; 85 long len; 86 char *end; 87 int lock_fd = -1; 88 struct stat st; 89 int rc; 90 91 if (!config_write_allowed()) { 92 reply("403 Forbidden", "Repository is read-only"); 93 return 0; 94 } 95 rc = check_csrf_origin(); 96 97 if (rc == -2) { 98 reply("500 Internal Server Error", 99 "CSRF origin is not configured"); 100 return 0; 101 } 102 if (rc == -1) { 103 reply("403 Forbidden", 104 "Forbidden"); 105 return 0; 106 } 107 p = getenv("CONTENT_LENGTH"); 108 109 if (p == NULL) { 110 reply("400 Bad Request", 111 "Missing content length"); 112 return 0; 113 } 114 errno = 0; 115 116 len = strtol(p, &end, 10); 117 118 if (errno != 0 || 119 end == p || 120 *end != '\0' || 121 len <= 0 || 122 len > 1024) { 123 reply("400 Bad Request", 124 "Invalid content length"); 125 return 0; 126 } 127 body = malloc((size_t) len + 1); 128 129 if (body == NULL) { 130 reply("500 Internal Server Error", 131 "Out of memory"); 132 return 0; 133 } 134 if (fread(body, 1, (size_t) len, stdin) 135 != (size_t) len) { 136 free(body); 137 reply("400 Bad Request", 138 "Could not read request"); 139 return 0; 140 } 141 body[len] = '\0'; 142 143 144 if (get_filename(body, 145 oldname, 146 sizeof(oldname)) == -1) { 147 free(body); 148 return 0; 149 } 150 if (get_new_filename(body, 151 newname, 152 sizeof(newname)) == -1) { 153 free(body); 154 return 0; 155 } 156 free(body); 157 158 159 if (strcmp(oldname, newname) == 0) { 160 redirect(DEFAULT_REDIRECT_URI); 161 return 0; 162 } 163 if (build_storage_path(oldpath, 164 sizeof(oldpath), 165 storage_root(), 166 repository(), 167 oldname) == -1) { 168 reply("500 Internal Server Error", 169 "Path too long"); 170 return 0; 171 } 172 if (build_storage_path(newpath, 173 sizeof(newpath), 174 storage_root(), 175 repository(), 176 newname) == -1) { 177 reply("500 Internal Server Error", 178 "Path too long"); 179 return 0; 180 } 181 lock_fd = repository_lock(repository()); 182 183 if (lock_fd == -1) { 184 reply("500 Internal Server Error", 185 "Could not lock repository"); 186 return 0; 187 } 188 if (stat(oldpath, &st) == -1 || 189 !S_ISREG(st.st_mode)) { 190 reply("404 Not Found", 191 "File not found"); 192 goto out; 193 } 194 if (stat(newpath, &st) == 0) { 195 reply("409 Conflict", 196 "Destination already exists"); 197 goto out; 198 } 199 if (errno != ENOENT) { 200 reply("500 Internal Server Error", 201 "Could not check destination"); 202 goto out; 203 } 204 if (rename(oldpath, newpath) == -1) { 205 reply("500 Internal Server Error", 206 "Could not rename file"); 207 goto out; 208 } 209 repository_unlock(lock_fd); 210 lock_fd = -1; 211 212 redirect(DEFAULT_REDIRECT_URI); 213 214 215 out: 216 if (lock_fd != -1) 217 repository_unlock(lock_fd); 218 219 return 0; 220 } 221 222 223 int 224 main(void) 225 { 226 const char *method; 227 228 method = getenv("REQUEST_METHOD"); 229 230 if (method == NULL) { 231 reply("400 Bad Request", 232 "Missing request method"); 233 return 0; 234 } 235 if (strcmp(method, "GET") == 0) 236 return do_get(); 237 238 239 if (strcmp(method, "POST") == 0) 240 return do_post(); 241 242 243 reply("405 Method Not Allowed", 244 "GET or POST required"); 245 246 return 0; 247 }