From b0962da79ab6505ff177266b03724cc292efc714 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Fri, 29 May 2009 13:26:58 +0000 Subject: Much tidying, additional commentary, and fix for insane bit mask calculation. svn path=/trunk/netsurf/; revision=7623 --- utils/filename.c | 175 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 121 insertions(+), 54 deletions(-) (limited to 'utils') diff --git a/utils/filename.c b/utils/filename.c index 77ec7d6b2..5ec84b9c3 100644 --- a/utils/filename.c +++ b/utils/filename.c @@ -22,6 +22,7 @@ * A maximum of 2^24 files can be allocated at any point in time. */ +#include #include #include #include @@ -36,9 +37,8 @@ #include "utils/url.h" #include "utils/utils.h" -#define FULL_WORD (unsigned int)4294967295U -/* '0' + '0' * 10 */ -#define START_PREFIX 528 +#define FULL_WORD (unsigned int)0xffffffffu +#define START_PREFIX ('0' + '0' * 10) struct directory { int numeric_prefix; /** numeric representation of prefix */ @@ -60,13 +60,15 @@ static bool filename_delete_recursive(char *folder); /** * Request a new, unique, filename. * - * \return a pointer to a shared buffer containing the new filename or NULL on failure + * \return a pointer to a shared buffer containing the new filename, + * NULL on failure */ -const char *filename_request(void) { +const char *filename_request(void) +{ struct directory *dir; int i = -1; - for (dir = root; dir; dir = dir->next) + for (dir = root; dir; dir = dir->next) { if ((dir->low_used & dir->high_used) != FULL_WORD) { if (dir->low_used != FULL_WORD) { for (i = 0; (dir->low_used & (1 << i)); i++); @@ -76,20 +78,25 @@ const char *filename_request(void) { } break; } + } + if (i == -1) { /* no available slots - create a new directory */ dir = filename_create_directory(NULL); - if (!dir) { + if (dir == NULL) { LOG(("Failed to create a new directory.")); return NULL; } i = 63; } + if (i < 32) dir->low_used |= (1 << i); else dir->high_used |= (1 << (i - 32)); + sprintf(filename_buffer, "%s%.2i", dir->prefix, i); + return filename_buffer; } @@ -100,7 +107,8 @@ const char *filename_request(void) { * \param filename the filename to claim * \return whether the claim was successful */ -bool filename_claim(const char *filename) { +bool filename_claim(const char *filename) +{ char dir_prefix[9]; int file; struct directory *dir; @@ -112,7 +120,7 @@ bool filename_claim(const char *filename) { /* create the directory */ dir = filename_create_directory(dir_prefix); - if (!dir) + if (dir == NULL) return false; /* update the entry */ @@ -125,6 +133,7 @@ bool filename_claim(const char *filename) { return false; dir->high_used |= (1 << (file - 32)); } + return true; } @@ -134,7 +143,8 @@ bool filename_claim(const char *filename) { * * \param filename the filename to release */ -void filename_release(const char *filename) { +void filename_release(const char *filename) +{ struct directory *dir; int index, file; @@ -145,7 +155,7 @@ void filename_release(const char *filename) { file = (filename[10] + filename[9] * 10 - START_PREFIX); /* modify the correct directory entry */ - for (dir = root; dir; dir = dir->next) + for (dir = root; dir; dir = dir->next) { if (dir->numeric_prefix == index) { if (file < 32) dir->low_used &= ~(1 << file); @@ -153,17 +163,19 @@ void filename_release(const char *filename) { dir->high_used &= ~(1 << (file - 32)); return; } + } } /** * Initialise the filename provider. */ -bool filename_initialise(void) { +bool filename_initialise(void) +{ char *directory, *start; directory = strdup(TEMP_FILENAME_PREFIX); - if (!directory) + if (directory == NULL) return false; for (start = directory; *start != '\0'; start++) { @@ -173,9 +185,12 @@ bool filename_initialise(void) { *start = '/'; } } + LOG(("Temporary directory location: %s", directory)); mkdir(directory, S_IRWXU); + free(directory); + return true; } @@ -183,7 +198,8 @@ bool filename_initialise(void) { /** * Deletes all files in the cache directory that are not accounted for. */ -void filename_flush(void) { +void filename_flush(void) +{ while (filename_flush_directory(TEMP_FILENAME_PREFIX, 0)); } @@ -198,32 +214,44 @@ void filename_flush(void) { * \param depth the folder depth * \returns whether further calls may be needed */ -bool filename_flush_directory(const char *folder, int depth) { +bool filename_flush_directory(const char *folder, int depth) +{ DIR *parent; struct dirent *entry; bool changed = false; bool del; int number, i; int prefix = 0; - unsigned int prefix_mask = (63 << 12); + unsigned int prefix_mask = (0x3f << 12); char child[256]; const char *prefix_start = NULL; struct directory *dir = NULL; - /* find out directory details */ - if (depth > 0) + /* Maximum permissible depth is 3 */ + assert(depth <= 3); + + if (depth > 0) { + /* Not a top-level directory, so determine the prefix + * by removing the last /XX component */ prefix_start = folder + strlen(folder) - depth * 3 + 1; - for (i = 0; ((i < depth) && (i < 3)); i++) { + } + + /* Calculate the numeric prefix */ + for (i = 0; i < depth; i++) { number = prefix_start[1] + prefix_start[0] * 10 - START_PREFIX; prefix |= (number << (12 - i * 6)); - prefix_mask |= (63 << (6 - i * 6)); + prefix_mask |= (0x3f << (12 - i * 6)); prefix_start += 3; } + + /* If we're flushing a leaf directory, find it in the list */ if (depth == 3) { - for (dir = root; dir; dir = dir->next) + for (dir = root; dir; dir = dir->next) { if (dir->numeric_prefix == prefix) break; - if ((!dir) || (dir->numeric_prefix != prefix)) + } + + if (dir == NULL) return false; } @@ -232,31 +260,39 @@ bool filename_flush_directory(const char *folder, int depth) { while ((entry = readdir(parent))) { struct stat statbuf; - if (!strcmp(entry->d_name, ".") || - !strcmp(entry->d_name, "..")) + /* Ignore '.' and '..' */ + if (strcmp(entry->d_name, ".") == 0 || + strcmp(entry->d_name, "..") == 0) continue; - snprintf(child, 256, "%s/%s", folder, entry->d_name); + snprintf(child, sizeof(child), "%s/%s", folder, entry->d_name); + child[sizeof(child) - 1] = '\0'; + if (stat(child, &statbuf) == -1) { - LOG(("Unable to stat %s, even though it just got returned from readdir(): %s", child, strerror(errno))); + LOG(("Unable to stat %s: %s", child, strerror(errno))); continue; } /* first 3 depths are directories only, then files only */ - if (depth < 3) + if (depth < 3) { + /* Delete any unexpected files */ del = !S_ISDIR(statbuf.st_mode); - else + } else { + /* Delete any unexpected directories */ del = S_ISDIR(statbuf.st_mode); + } /* check we are a file numbered '00' -> '63' */ - if ((!del) && (entry->d_name[0] >= '0') && + if (del == false && (entry->d_name[0] >= '0') && (entry->d_name[0] <= '6') && (entry->d_name[1] >= '0') && (entry->d_name[1] <= '9') && (entry->d_name[2] == '\0')) { number = atoi(entry->d_name); - if ((number >= 0) && (number <= 63)) { + + if (number >= 0 && number <= 63) { if (depth == 3) { + /* File: delete if not in bitfield */ if (number < 32) del = !(dir->low_used & (1 << number)); @@ -264,33 +300,42 @@ bool filename_flush_directory(const char *folder, int depth) { del = !(dir->high_used & (1 << (number - 32))); } else { + /* Directory: delete unless in list */ del = true; - prefix &= ~(63 << (12 - depth * 6)); + + /* Insert into numeric prefix */ + prefix &= ~(0x3f << (12 - depth * 6)); prefix |= (number << (12 - depth * 6)); + + /* Find in dir list */ for (dir = root; dir; dir = dir->next) { number = dir->numeric_prefix & prefix_mask; if (number == prefix) { + /* In list: retain */ del = false; break; } } } } else { + /* Unexpected name: delete */ del = true; } } else { + /* Unexpected name: delete */ del = true; } - /* continue if we are a valid reference so far */ - if ((!del) && (!S_ISDIR(statbuf.st_mode))) + + /* continue if this is a file we want to retain */ + if (del == false && (!S_ISDIR(statbuf.st_mode))) continue; + /* delete or recurse */ - snprintf(child, 256, "%s/%s", folder, entry->d_name); - child[255] = '\0'; if (del) { if (S_ISDIR(statbuf.st_mode)) filename_delete_recursive(child); + if (remove(child)) LOG(("Failed to remove '%s'", child)); else @@ -301,6 +346,7 @@ bool filename_flush_directory(const char *folder, int depth) { } closedir(parent); + return changed; } @@ -311,7 +357,8 @@ bool filename_flush_directory(const char *folder, int depth) { * \param directory the directory to delete * \return true on success, false otherwise */ -bool filename_delete_recursive(char *folder) { +bool filename_delete_recursive(char *folder) +{ DIR *parent; struct dirent *entry; char child[256]; @@ -320,21 +367,26 @@ bool filename_delete_recursive(char *folder) { parent = opendir(folder); while ((entry = readdir(parent))) { - if ((!strcmp(entry->d_name, ".")) || - (!strcmp(entry->d_name, ".."))) + /* Ignore '.' and '..' */ + if (strcmp(entry->d_name, ".") == 0 || + strcmp(entry->d_name, "..") == 0) continue; - snprintf(child, 256, "%s/%s", folder, entry->d_name); + + snprintf(child, sizeof(child), "%s/%s", folder, entry->d_name); + child[sizeof(child) - 1] = '\0'; + if (stat(child, &statbuf) == -1) { - LOG(("Unable to stat %s, even though it just got returned from readdir(): %s", child, strerror(errno))); + LOG(("Unable to stat %s: %s", child, strerror(errno))); continue; - } + if (S_ISDIR(statbuf.st_mode)) { if (!filename_delete_recursive(child)) { closedir(parent); return false; } } + if (remove(child)) { LOG(("Failed to remove '%s'", child)); closedir(parent); @@ -343,6 +395,7 @@ bool filename_delete_recursive(char *folder) { } closedir(parent); + return true; } @@ -357,7 +410,8 @@ bool filename_delete_recursive(char *folder) { * Empty directories are never deleted, except by an explicit call to * filename_flush(). */ -static struct directory *filename_create_directory(const char *prefix) { +static struct directory *filename_create_directory(const char *prefix) +{ char *last_1, *last_2; int index; struct directory *old_dir, *new_dir, *prev_dir = NULL; @@ -365,42 +419,51 @@ static struct directory *filename_create_directory(const char *prefix) { int i; /* get the lowest unique prefix, or use the provided one */ - if (!prefix) { - for (index = 0, old_dir = root; old_dir; index++, - prev_dir = old_dir, old_dir = old_dir->next) + if (prefix == NULL) { + for (index = 0, old_dir = root; old_dir; + index++, old_dir = old_dir->next) { if (old_dir->numeric_prefix != index) break; + + prev_dir = old_dir; + } + sprintf(dir_prefix, "%.2i/%.2i/%.2i/", ((index >> 12) & 63), ((index >> 6) & 63), ((index >> 0) & 63)); + prefix = dir_prefix; } else { /* prefix format is always '01/23/45/' */ index = ((prefix[7] + prefix[6] * 10 - START_PREFIX) | ((prefix[4] + prefix[3] * 10 - START_PREFIX) << 6) | ((prefix[1] + prefix[0] * 10 - START_PREFIX) << 12)); - for (old_dir = root; old_dir; prev_dir = old_dir, - old_dir = old_dir->next) { + + for (old_dir = root; old_dir; old_dir = old_dir->next) { if (old_dir->numeric_prefix == index) return old_dir; + else if (old_dir->numeric_prefix > index) break; + + prev_dir = old_dir; } } /* allocate a new directory */ - new_dir = (struct directory *)malloc(sizeof(struct directory)); - if (!new_dir) { + new_dir = malloc(sizeof(struct directory)); + if (new_dir == NULL) { LOG(("No memory for malloc()")); return NULL; } + strncpy(new_dir->prefix, prefix, 9); new_dir->prefix[9] = '\0'; new_dir->low_used = new_dir->high_used = 0; new_dir->numeric_prefix = index; - if (!prev_dir) { + if (prev_dir == NULL) { new_dir->next = root; root = new_dir; } else { @@ -410,12 +473,13 @@ static struct directory *filename_create_directory(const char *prefix) { /* if the previous directory has the same parent then we can simply * create the child. */ - if ((prev_dir) && (!strncmp(prev_dir->prefix, new_dir->prefix, 6))) { + if (prev_dir && strncmp(prev_dir->prefix, new_dir->prefix, 6) == 0) { new_dir->prefix[8] = '\0'; sprintf(filename_directory, "%s/%s", TEMP_FILENAME_PREFIX, new_dir->prefix); new_dir->prefix[8] = '/'; + if (!is_dir(filename_directory)) { if (!mkdir(filename_directory, S_IRWXU)) return new_dir; @@ -430,16 +494,19 @@ static struct directory *filename_create_directory(const char *prefix) { } /* create the directory structure */ - sprintf(filename_directory, "%s/", - TEMP_FILENAME_PREFIX); - last_1 = filename_directory + strlen(TEMP_FILENAME_PREFIX) + 1; + sprintf(filename_directory, "%s/", TEMP_FILENAME_PREFIX); + last_1 = filename_directory + SLEN(TEMP_FILENAME_PREFIX) + 1; last_2 = new_dir->prefix; + + /* create each subdirectory, up to the maximum depth of 3 */ for (i = 0; i < 3 && *last_2; i++) { *last_1++ = *last_2++; while (*last_2 && *last_2 != '/') *last_1++ = *last_2++; + if (*last_2) { last_1[0] = '\0'; + if (!is_dir(filename_directory)) { if (mkdir(filename_directory, S_IRWXU)) { LOG(("Failed to create directory '%s'", -- cgit v1.2.3