summaryrefslogtreecommitdiff
path: root/utils/filename.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/filename.c')
-rw-r--r--utils/filename.c175
1 files changed, 121 insertions, 54 deletions
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 <assert.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdbool.h>
@@ -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'",