| File: | utils/filename.c |
| Warning: | line 296, column 7 The 1st argument to 'fstatat' is between -99 and -1 but should be a valid file descriptor or AT_FDCWD |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright 2006 Richard Wilson <info@tinct.net> | |||
| 3 | * | |||
| 4 | * This file is part of NetSurf, http://www.netsurf-browser.org/ | |||
| 5 | * | |||
| 6 | * NetSurf is free software; you can redistribute it and/or modify | |||
| 7 | * it under the terms of the GNU General Public License as published by | |||
| 8 | * the Free Software Foundation; version 2 of the License. | |||
| 9 | * | |||
| 10 | * NetSurf is distributed in the hope that it will be useful, | |||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 13 | * GNU General Public License for more details. | |||
| 14 | * | |||
| 15 | * You should have received a copy of the GNU General Public License | |||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 17 | */ | |||
| 18 | ||||
| 19 | /** \file | |||
| 20 | * Provides a central method of obtaining unique filenames. | |||
| 21 | * | |||
| 22 | * A maximum of 2^24 files can be allocated at any point in time. | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #include <assert.h> | |||
| 26 | #include <sys/types.h> | |||
| 27 | #include <stdbool.h> | |||
| 28 | #include <string.h> | |||
| 29 | #include <stdio.h> | |||
| 30 | #include <stdlib.h> | |||
| 31 | #include <errno(*__errno_location ()).h> | |||
| 32 | #include <fcntl.h> | |||
| 33 | #include <sys/stat.h> | |||
| 34 | #include <unistd.h> | |||
| 35 | ||||
| 36 | #include "utils/dirent.h" | |||
| 37 | #include "utils/errors.h" | |||
| 38 | #include "utils/file.h" | |||
| 39 | #include "utils/filename.h" | |||
| 40 | #include "utils/log.h" | |||
| 41 | #include "utils/utils.h" | |||
| 42 | ||||
| 43 | #define FULL_WORD(unsigned int)0xffffffffu (unsigned int)0xffffffffu | |||
| 44 | #define START_PREFIX('0' + '0' * 10) ('0' + '0' * 10) | |||
| 45 | ||||
| 46 | struct directory { | |||
| 47 | int numeric_prefix; /** numeric representation of prefix */ | |||
| 48 | char prefix[10]; /** directory prefix, eg '00/11/52/' */ | |||
| 49 | unsigned int low_used; /** first 32 files, 1 bit per file */ | |||
| 50 | unsigned int high_used; /** last 32 files, 1 bit per file */ | |||
| 51 | struct directory *next; /** next directory (sorted by prefix) */ | |||
| 52 | }; | |||
| 53 | ||||
| 54 | ||||
| 55 | static struct directory *root = NULL((void*)0); | |||
| 56 | static char filename_buffer[12]; | |||
| 57 | static char filename_directory[256]; | |||
| 58 | ||||
| 59 | static struct directory *filename_create_directory(const char *prefix); | |||
| 60 | static bool_Bool filename_flush_directory(const char *folder, int depth); | |||
| 61 | ||||
| 62 | /** | |||
| 63 | * Request a new, unique, filename. | |||
| 64 | * | |||
| 65 | * \return a pointer to a shared buffer containing the new filename, | |||
| 66 | * NULL on failure | |||
| 67 | */ | |||
| 68 | const char *filename_request(void) | |||
| 69 | { | |||
| 70 | struct directory *dir; | |||
| 71 | int i = -1; | |||
| 72 | ||||
| 73 | for (dir = root; dir; dir = dir->next) { | |||
| 74 | if ((dir->low_used & dir->high_used) != FULL_WORD(unsigned int)0xffffffffu) { | |||
| 75 | if (dir->low_used != FULL_WORD(unsigned int)0xffffffffu) { | |||
| 76 | for (i = 0; (dir->low_used & (1 << i)); i++); | |||
| 77 | } else { | |||
| 78 | for (i = 0; (dir->high_used & (1 << i)); i++); | |||
| 79 | i += 32; | |||
| 80 | } | |||
| 81 | break; | |||
| 82 | } | |||
| 83 | } | |||
| 84 | ||||
| 85 | if (i == -1) { | |||
| 86 | /* no available slots - create a new directory */ | |||
| 87 | dir = filename_create_directory(NULL((void*)0)); | |||
| 88 | if (dir == NULL((void*)0)) { | |||
| 89 | NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 90 , }; nslog__log(&_nslog_ctx, "Failed to create a new directory." ); } } while(0) | |||
| 90 | "Failed to create a new directory.")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 90 , }; nslog__log(&_nslog_ctx, "Failed to create a new directory." ); } } while(0); | |||
| 91 | return NULL((void*)0); | |||
| 92 | } | |||
| 93 | i = 63; | |||
| 94 | } | |||
| 95 | ||||
| 96 | if (i < 32) | |||
| 97 | dir->low_used |= (1 << i); | |||
| 98 | else | |||
| 99 | dir->high_used |= (1 << (i - 32)); | |||
| 100 | ||||
| 101 | i = i % 99; | |||
| 102 | ||||
| 103 | snprintf(filename_buffer, sizeof(filename_buffer), "%s%.2u", dir->prefix, (unsigned int)i); | |||
| 104 | ||||
| 105 | return filename_buffer; | |||
| 106 | } | |||
| 107 | ||||
| 108 | ||||
| 109 | /** | |||
| 110 | * Claim a specific filename. | |||
| 111 | * | |||
| 112 | * \param filename the filename to claim | |||
| 113 | * \return whether the claim was successful | |||
| 114 | */ | |||
| 115 | bool_Bool filename_claim(const char *filename) | |||
| 116 | { | |||
| 117 | char dir_prefix[9]; | |||
| 118 | int file; | |||
| 119 | struct directory *dir; | |||
| 120 | ||||
| 121 | /* filename format is always '01/23/45/XX' */ | |||
| 122 | strncpy(dir_prefix, filename, 9); | |||
| 123 | dir_prefix[8] = '\0'; | |||
| 124 | file = (filename[10] + filename[9] * 10 - START_PREFIX('0' + '0' * 10)); | |||
| 125 | ||||
| 126 | /* create the directory */ | |||
| 127 | dir = filename_create_directory(dir_prefix); | |||
| 128 | if (dir == NULL((void*)0)) | |||
| 129 | return false0; | |||
| 130 | ||||
| 131 | /* update the entry */ | |||
| 132 | if (file < 32) { | |||
| 133 | if (dir->low_used & (1 << file)) | |||
| 134 | return false0; | |||
| 135 | dir->low_used |= (1 << file); | |||
| 136 | } else { | |||
| 137 | if (dir->high_used & (1 << (file - 32))) | |||
| 138 | return false0; | |||
| 139 | dir->high_used |= (1 << (file - 32)); | |||
| 140 | } | |||
| 141 | ||||
| 142 | return true1; | |||
| 143 | } | |||
| 144 | ||||
| 145 | ||||
| 146 | /** | |||
| 147 | * Releases a filename for future use. | |||
| 148 | * | |||
| 149 | * \param filename the filename to release | |||
| 150 | */ | |||
| 151 | void filename_release(const char *filename) | |||
| 152 | { | |||
| 153 | struct directory *dir; | |||
| 154 | int index, file; | |||
| 155 | ||||
| 156 | /* filename format is always '01/23/45/XX' */ | |||
| 157 | index = ((filename[7] + filename[6] * 10 - START_PREFIX('0' + '0' * 10)) | | |||
| 158 | ((filename[4] + filename[3] * 10 - START_PREFIX('0' + '0' * 10)) << 6) | | |||
| 159 | ((filename[1] + filename[0] * 10 - START_PREFIX('0' + '0' * 10)) << 12)); | |||
| 160 | file = (filename[10] + filename[9] * 10 - START_PREFIX('0' + '0' * 10)); | |||
| 161 | ||||
| 162 | /* modify the correct directory entry */ | |||
| 163 | for (dir = root; dir; dir = dir->next) { | |||
| 164 | if (dir->numeric_prefix == index) { | |||
| 165 | if (file < 32) | |||
| 166 | dir->low_used &= ~(1 << file); | |||
| 167 | else | |||
| 168 | dir->high_used &= ~(1 << (file - 32)); | |||
| 169 | return; | |||
| 170 | } | |||
| 171 | } | |||
| 172 | } | |||
| 173 | ||||
| 174 | ||||
| 175 | /** | |||
| 176 | * Initialise the filename provider. | |||
| 177 | */ | |||
| 178 | bool_Bool filename_initialise(void) | |||
| 179 | { | |||
| 180 | char *directory, *start; | |||
| 181 | int ret; | |||
| 182 | ||||
| 183 | directory = strdup(TEMP_FILENAME_PREFIX"/tmp/WWW/NetSurf/Misc"); | |||
| 184 | if (directory == NULL((void*)0)) | |||
| 185 | return false0; | |||
| 186 | ||||
| 187 | for (start = directory; *start != '\0'; start++) { | |||
| 188 | if (*start == '/') { | |||
| 189 | *start = '\0'; | |||
| 190 | NSLOG(netsurf, INFO, "Creating \"%s\"", directory)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 190 , }; nslog__log(&_nslog_ctx, "Creating \"%s\"", directory ); } } while(0); | |||
| 191 | ret = nsmkdir(directory, S_IRWXU)mkdir((directory), ((0400|0200|0100))); | |||
| 192 | if (ret != 0 && errno(*__errno_location ()) != EEXIST17) { | |||
| 193 | NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 195 , }; nslog__log(&_nslog_ctx, "Failed to create directory \"%s\"" , directory); } } while(0) | |||
| 194 | "Failed to create directory \"%s\"",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 195 , }; nslog__log(&_nslog_ctx, "Failed to create directory \"%s\"" , directory); } } while(0) | |||
| 195 | directory)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 195 , }; nslog__log(&_nslog_ctx, "Failed to create directory \"%s\"" , directory); } } while(0); | |||
| 196 | free(directory); | |||
| 197 | return false0; | |||
| 198 | } | |||
| 199 | ||||
| 200 | *start = '/'; | |||
| 201 | } | |||
| 202 | } | |||
| 203 | ||||
| 204 | NSLOG(netsurf, INFO, "Temporary directory location: %s", directory)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 204 , }; nslog__log(&_nslog_ctx, "Temporary directory location: %s" , directory); } } while(0); | |||
| 205 | ret = nsmkdir(directory, S_IRWXU)mkdir((directory), ((0400|0200|0100))); | |||
| 206 | ||||
| 207 | free(directory); | |||
| 208 | ||||
| 209 | if (ret != 0) { | |||
| 210 | return false0; | |||
| 211 | } | |||
| 212 | return true1; | |||
| 213 | } | |||
| 214 | ||||
| 215 | ||||
| 216 | /** | |||
| 217 | * Deletes all files in the cache directory that are not accounted for. | |||
| 218 | */ | |||
| 219 | void filename_flush(void) | |||
| ||||
| 220 | { | |||
| 221 | while (filename_flush_directory(TEMP_FILENAME_PREFIX"/tmp/WWW/NetSurf/Misc", 0)); | |||
| 222 | } | |||
| 223 | ||||
| 224 | ||||
| 225 | /** | |||
| 226 | * Deletes some files in a directory that are not accounted for. | |||
| 227 | * | |||
| 228 | * A single call to this function may not delete all the files in | |||
| 229 | * a directory. It should be called until it returns false. | |||
| 230 | * | |||
| 231 | * \param folder the folder to search | |||
| 232 | * \param depth the folder depth | |||
| 233 | * \returns whether further calls may be needed | |||
| 234 | */ | |||
| 235 | bool_Bool filename_flush_directory(const char *folder, int depth) | |||
| 236 | { | |||
| 237 | DIR *parent; | |||
| 238 | struct dirent *entry; | |||
| 239 | bool_Bool changed = false0; | |||
| 240 | bool_Bool del; | |||
| 241 | int number, i; | |||
| 242 | int prefix = 0; | |||
| 243 | unsigned int prefix_mask = (0x3f << 12); | |||
| 244 | char child[256]; | |||
| 245 | const char *prefix_start = NULL((void*)0); | |||
| 246 | struct directory *dir = NULL((void*)0); | |||
| 247 | ||||
| 248 | /* Maximum permissible depth is 3 */ | |||
| 249 | assert(depth <= 3)((depth <= 3) ? (void) (0) : __assert_fail ("depth <= 3" , "utils/filename.c", 249, __extension__ __PRETTY_FUNCTION__) ); | |||
| 250 | ||||
| 251 | if (depth
| |||
| 252 | /* Not a top-level directory, so determine the prefix | |||
| 253 | * by removing the last /XX component */ | |||
| 254 | prefix_start = folder + strlen(folder) - depth * 3 + 1; | |||
| 255 | } | |||
| 256 | ||||
| 257 | /* Calculate the numeric prefix */ | |||
| 258 | for (i = 0; i < depth; i++) { | |||
| 259 | number = prefix_start[1] + prefix_start[0] * 10 - START_PREFIX('0' + '0' * 10); | |||
| 260 | prefix |= (number << (12 - i * 6)); | |||
| 261 | prefix_mask |= (0x3f << (12 - i * 6)); | |||
| 262 | prefix_start += 3; | |||
| 263 | } | |||
| 264 | ||||
| 265 | /* If we're flushing a leaf directory, find it in the list */ | |||
| 266 | if (depth
| |||
| 267 | for (dir = root; dir; dir = dir->next) { | |||
| 268 | if (dir->numeric_prefix == prefix) | |||
| 269 | break; | |||
| 270 | } | |||
| 271 | ||||
| 272 | if (dir == NULL((void*)0)) | |||
| 273 | return false0; | |||
| 274 | } | |||
| 275 | ||||
| 276 | parent = opendir(folder); | |||
| 277 | if (parent
| |||
| 278 | return false0; | |||
| 279 | ||||
| 280 | while ((entry = readdir(parent))) { | |||
| 281 | int written; | |||
| 282 | struct stat statbuf; | |||
| 283 | ||||
| 284 | /* Ignore '.' and '..' */ | |||
| 285 | if (strcmp(entry->d_name, ".") == 0 || | |||
| 286 | strcmp(entry->d_name, "..") == 0) | |||
| 287 | continue; | |||
| 288 | ||||
| 289 | written = snprintf(child, sizeof(child), "%s/%s", | |||
| 290 | folder, entry->d_name); | |||
| 291 | if (written == sizeof(child)) { | |||
| 292 | child[sizeof(child) - 1] = '\0'; | |||
| 293 | } | |||
| 294 | ||||
| 295 | #if (defined(HAVE_DIRFD) && defined(HAVE_FSTATAT)) | |||
| 296 | if (fstatat(dirfd(parent), entry->d_name, &statbuf, | |||
| ||||
| 297 | AT_SYMLINK_NOFOLLOW0x100) == -1) { | |||
| 298 | #else | |||
| 299 | if (stat(child, &statbuf) == -1) { | |||
| 300 | #endif | |||
| 301 | NSLOG(netsurf, INFO, "Unable to stat %s: %s", child,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 302 , }; nslog__log(&_nslog_ctx, "Unable to stat %s: %s", child , strerror((*__errno_location ()))); } } while(0) | |||
| 302 | strerror(errno))do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 302 , }; nslog__log(&_nslog_ctx, "Unable to stat %s: %s", child , strerror((*__errno_location ()))); } } while(0); | |||
| 303 | continue; | |||
| 304 | } | |||
| 305 | ||||
| 306 | /* first 3 depths are directories only, then files only */ | |||
| 307 | if (depth < 3) { | |||
| 308 | /* Delete any unexpected files */ | |||
| 309 | del = !S_ISDIR(statbuf.st_mode)((((statbuf.st_mode)) & 0170000) == (0040000)); | |||
| 310 | } else { | |||
| 311 | /* Delete any unexpected directories */ | |||
| 312 | del = S_ISDIR(statbuf.st_mode)((((statbuf.st_mode)) & 0170000) == (0040000)); | |||
| 313 | } | |||
| 314 | ||||
| 315 | /* check we are a file numbered '00' -> '63' */ | |||
| 316 | if (del == false0 && (entry->d_name[0] >= '0') && | |||
| 317 | (entry->d_name[0] <= '6') && | |||
| 318 | (entry->d_name[1] >= '0') && | |||
| 319 | (entry->d_name[1] <= '9') && | |||
| 320 | (entry->d_name[2] == '\0')) { | |||
| 321 | number = atoi(entry->d_name); | |||
| 322 | ||||
| 323 | if (number >= 0 && number <= 63) { | |||
| 324 | if (depth == 3) { | |||
| 325 | /* File: delete if not in bitfield */ | |||
| 326 | if (number < 32) | |||
| 327 | del = !(dir->low_used & | |||
| 328 | (1 << number)); | |||
| 329 | else | |||
| 330 | del = !(dir->high_used & | |||
| 331 | (1 << (number - 32))); | |||
| 332 | } else { | |||
| 333 | /* Directory: delete unless in list */ | |||
| 334 | del = true1; | |||
| 335 | ||||
| 336 | /* Insert into numeric prefix */ | |||
| 337 | prefix &= ~(0x3f << (12 - depth * 6)); | |||
| 338 | prefix |= (number << (12 - depth * 6)); | |||
| 339 | ||||
| 340 | /* Find in dir list */ | |||
| 341 | for (dir = root; dir; dir = dir->next) { | |||
| 342 | number = dir->numeric_prefix & | |||
| 343 | prefix_mask; | |||
| 344 | if (number == prefix) { | |||
| 345 | /* In list: retain */ | |||
| 346 | del = false0; | |||
| 347 | break; | |||
| 348 | } | |||
| 349 | } | |||
| 350 | } | |||
| 351 | } else { | |||
| 352 | /* Unexpected name: delete */ | |||
| 353 | del = true1; | |||
| 354 | } | |||
| 355 | } else { | |||
| 356 | /* Unexpected name: delete */ | |||
| 357 | del = true1; | |||
| 358 | } | |||
| 359 | ||||
| 360 | /* continue if this is a file we want to retain */ | |||
| 361 | if (del == false0 && (!S_ISDIR(statbuf.st_mode)((((statbuf.st_mode)) & 0170000) == (0040000)))) | |||
| 362 | continue; | |||
| 363 | ||||
| 364 | /* delete or recurse */ | |||
| 365 | if (del) { | |||
| 366 | if (S_ISDIR(statbuf.st_mode)((((statbuf.st_mode)) & 0170000) == (0040000))) { | |||
| 367 | changed = (netsurf_recursive_rm(child) == | |||
| 368 | NSERROR_OK); | |||
| 369 | } else { | |||
| 370 | #if (defined(HAVE_DIRFD) && defined(HAVE_UNLINKAT)) | |||
| 371 | if (unlinkat(dirfd(parent), entry->d_name, 0)) { | |||
| 372 | #else | |||
| 373 | if (unlink(child)) { | |||
| 374 | #endif | |||
| 375 | NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 376 , }; nslog__log(&_nslog_ctx, "Failed to remove '%s'", child ); } } while(0) | |||
| 376 | "Failed to remove '%s'", child)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 376 , }; nslog__log(&_nslog_ctx, "Failed to remove '%s'", child ); } } while(0); | |||
| 377 | } else | |||
| 378 | changed = true1; | |||
| 379 | } | |||
| 380 | } else { | |||
| 381 | while (filename_flush_directory(child, depth + 1)); | |||
| 382 | } | |||
| 383 | } | |||
| 384 | ||||
| 385 | closedir(parent); | |||
| 386 | ||||
| 387 | return changed; | |||
| 388 | } | |||
| 389 | ||||
| 390 | ||||
| 391 | /** | |||
| 392 | * Creates a new directory. | |||
| 393 | * | |||
| 394 | * \param prefix the prefix to use, or NULL to allocate a new one | |||
| 395 | * \return a new directory structure, or NULL on memory exhaustion or | |||
| 396 | * creation failure | |||
| 397 | * | |||
| 398 | * Empty directories are never deleted, except by an explicit call to | |||
| 399 | * filename_flush(). | |||
| 400 | */ | |||
| 401 | static struct directory *filename_create_directory(const char *prefix) | |||
| 402 | { | |||
| 403 | char *last_1, *last_2; | |||
| 404 | int index; | |||
| 405 | struct directory *old_dir, *new_dir, *prev_dir = NULL((void*)0); | |||
| 406 | char dir_prefix[16]; | |||
| 407 | int i; | |||
| 408 | ||||
| 409 | /* get the lowest unique prefix, or use the provided one */ | |||
| 410 | if (prefix == NULL((void*)0)) { | |||
| 411 | for (index = 0, old_dir = root; old_dir; | |||
| 412 | index++, old_dir = old_dir->next) { | |||
| 413 | if (old_dir->numeric_prefix != index) | |||
| 414 | break; | |||
| 415 | ||||
| 416 | prev_dir = old_dir; | |||
| 417 | } | |||
| 418 | ||||
| 419 | sprintf(dir_prefix, "%.2i/%.2i/%.2i/", | |||
| 420 | ((index >> 12) & 63), | |||
| 421 | ((index >> 6) & 63), | |||
| 422 | ((index >> 0) & 63)); | |||
| 423 | ||||
| 424 | prefix = dir_prefix; | |||
| 425 | } else { | |||
| 426 | /* prefix format is always '01/23/45/' */ | |||
| 427 | index = ((prefix[7] + prefix[6] * 10 - START_PREFIX('0' + '0' * 10)) | | |||
| 428 | ((prefix[4] + prefix[3] * 10 - START_PREFIX('0' + '0' * 10)) << 6) | | |||
| 429 | ((prefix[1] + prefix[0] * 10 - START_PREFIX('0' + '0' * 10)) << 12)); | |||
| 430 | ||||
| 431 | for (old_dir = root; old_dir; old_dir = old_dir->next) { | |||
| 432 | if (old_dir->numeric_prefix == index) | |||
| 433 | return old_dir; | |||
| 434 | ||||
| 435 | else if (old_dir->numeric_prefix > index) | |||
| 436 | break; | |||
| 437 | ||||
| 438 | prev_dir = old_dir; | |||
| 439 | } | |||
| 440 | } | |||
| 441 | ||||
| 442 | /* allocate a new directory */ | |||
| 443 | new_dir = malloc(sizeof(struct directory)); | |||
| 444 | if (new_dir == NULL((void*)0)) { | |||
| 445 | NSLOG(netsurf, INFO, "No memory for malloc()")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 445 , }; nslog__log(&_nslog_ctx, "No memory for malloc()"); } } while(0); | |||
| 446 | return NULL((void*)0); | |||
| 447 | } | |||
| 448 | ||||
| 449 | strncpy(new_dir->prefix, prefix, 9); | |||
| 450 | new_dir->prefix[9] = '\0'; | |||
| 451 | new_dir->low_used = new_dir->high_used = 0; | |||
| 452 | new_dir->numeric_prefix = index; | |||
| 453 | ||||
| 454 | if (prev_dir == NULL((void*)0)) { | |||
| 455 | new_dir->next = root; | |||
| 456 | root = new_dir; | |||
| 457 | } else { | |||
| 458 | new_dir->next = prev_dir->next; | |||
| 459 | prev_dir->next = new_dir; | |||
| 460 | } | |||
| 461 | ||||
| 462 | /* if the previous directory has the same parent then we can simply | |||
| 463 | * create the child. */ | |||
| 464 | if (prev_dir && strncmp(prev_dir->prefix, new_dir->prefix, 6) == 0) { | |||
| 465 | new_dir->prefix[8] = '\0'; | |||
| 466 | sprintf(filename_directory, "%s/%s", | |||
| 467 | TEMP_FILENAME_PREFIX"/tmp/WWW/NetSurf/Misc", | |||
| 468 | new_dir->prefix); | |||
| 469 | new_dir->prefix[8] = '/'; | |||
| 470 | ||||
| 471 | if (!is_dir(filename_directory)) { | |||
| 472 | if (!nsmkdir(filename_directory, S_IRWXU)mkdir((filename_directory), ((0400|0200|0100)))) | |||
| 473 | return new_dir; | |||
| 474 | ||||
| 475 | /* the user has probably deleted the parent directory | |||
| 476 | * whilst we are running if there is an error, so we | |||
| 477 | * don't report this yet and try to create the | |||
| 478 | * structure normally. */ | |||
| 479 | NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 481 , }; nslog__log(&_nslog_ctx, "Failed to create optimised structure '%s'" , filename_directory); } } while(0) | |||
| 480 | "Failed to create optimised structure '%s'",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 481 , }; nslog__log(&_nslog_ctx, "Failed to create optimised structure '%s'" , filename_directory); } } while(0) | |||
| 481 | filename_directory)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 481 , }; nslog__log(&_nslog_ctx, "Failed to create optimised structure '%s'" , filename_directory); } } while(0); | |||
| 482 | } | |||
| 483 | } | |||
| 484 | ||||
| 485 | /* create the directory structure */ | |||
| 486 | sprintf(filename_directory, "%s/", TEMP_FILENAME_PREFIX"/tmp/WWW/NetSurf/Misc"); | |||
| 487 | last_1 = filename_directory + SLEN(TEMP_FILENAME_PREFIX)(sizeof(("/tmp/WWW/NetSurf/Misc")) - 1) + 1; | |||
| 488 | last_2 = new_dir->prefix; | |||
| 489 | ||||
| 490 | /* create each subdirectory, up to the maximum depth of 3 */ | |||
| 491 | for (i = 0; i < 3 && *last_2; i++) { | |||
| 492 | *last_1++ = *last_2++; | |||
| 493 | while (*last_2 && *last_2 != '/') | |||
| 494 | *last_1++ = *last_2++; | |||
| 495 | ||||
| 496 | if (*last_2) { | |||
| 497 | last_1[0] = '\0'; | |||
| 498 | ||||
| 499 | if (!is_dir(filename_directory)) { | |||
| 500 | if (nsmkdir(filename_directory, S_IRWXU)mkdir((filename_directory), ((0400|0200|0100)))) { | |||
| 501 | NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 503 , }; nslog__log(&_nslog_ctx, "Failed to create directory '%s'" , filename_directory); } } while(0) | |||
| 502 | "Failed to create directory '%s'",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 503 , }; nslog__log(&_nslog_ctx, "Failed to create directory '%s'" , filename_directory); } } while(0) | |||
| 503 | filename_directory)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "utils/filename.c", sizeof("utils/filename.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 503 , }; nslog__log(&_nslog_ctx, "Failed to create directory '%s'" , filename_directory); } } while(0); | |||
| 504 | return NULL((void*)0); | |||
| 505 | } | |||
| 506 | } | |||
| 507 | } | |||
| 508 | } | |||
| 509 | ||||
| 510 | return new_dir; | |||
| 511 | } |