From 8bdb770ae529d1bad675301ef446f891e1c97d71 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sat, 9 Aug 2025 19:40:11 +0100 Subject: [PATCH] io: directory: implement temporary directories and delete-on-close --- io/include/blue/io/directory.h | 3 ++ io/sys/darwin/directory.c | 94 +++++++++++++++++++++++++++++++++- io/sys/darwin/file.c | 23 ++------- io/sys/darwin/misc.c | 21 ++++++++ io/sys/darwin/misc.h | 8 +++ 5 files changed, 127 insertions(+), 22 deletions(-) create mode 100644 io/sys/darwin/misc.c create mode 100644 io/sys/darwin/misc.h diff --git a/io/include/blue/io/directory.h b/io/include/blue/io/directory.h index 244511a..cd5c508 100644 --- a/io/include/blue/io/directory.h +++ b/io/include/blue/io/directory.h @@ -22,6 +22,7 @@ typedef enum b_directory_iterator_flags { typedef enum b_directory_open_flags { B_DIRECTORY_OPEN_CREATE = 0x01u, B_DIRECTORY_OPEN_CREATE_INTERMEDIATE = 0x03u, + B_DIRECTORY_OPEN_DELETE_ON_CLOSE = 0x04u, } b_directory_open_flags; typedef struct b_directory_iterator { @@ -43,10 +44,12 @@ typedef struct b_directory_iterator { BLUE_API b_result b_directory_open( b_directory *root, const b_path *path, b_directory_open_flags flags, b_directory **out); +BLUE_API b_result b_directory_open_temp(b_directory **out); BLUE_API const b_path *b_directory_get_path(const b_directory *dir); BLUE_API const b_path *b_directory_get_rel_path(const b_directory *dir); BLUE_API const char *b_directory_get_path_cstr(const b_directory *dir); BLUE_API const char *b_directory_get_rel_path_cstr(const b_directory *dir); +BLUE_API b_result b_directory_delete(b_directory *dir); BLUE_API bool b_directory_path_exists(const b_directory *root, const b_path *path); BLUE_API bool b_directory_path_is_file(const b_directory *root, const b_path *path); diff --git a/io/sys/darwin/directory.c b/io/sys/darwin/directory.c index d213f75..b8d4b08 100644 --- a/io/sys/darwin/directory.c +++ b/io/sys/darwin/directory.c @@ -1,5 +1,7 @@ +#include "misc.h" #include "posix.h" +#include #include #include #include @@ -10,8 +12,13 @@ #include #include +enum directory_flags { + DIRECTORY_DELETE_ON_CLOSE = 0x01u, +}; + struct b_directory { struct b_object base; + enum directory_flags flags; int fd; struct b_path *rel_path; struct b_path *abs_path; @@ -34,8 +41,15 @@ static struct b_object_type directory_type = { static b_result create_directory(struct b_directory *root, const char *path) { - int root_fd = root->fd; - int err = mkdirat(root_fd, path, 0755); + int root_fd = root ? root->fd : -1; + int err; + + if (root_fd == -1) { + err = mkdir(path, 0755); + } else { + err = mkdirat(root_fd, path, 0755); + } + if (err == 0 || errno == EEXIST) { return B_RESULT_SUCCESS; } @@ -145,11 +159,45 @@ b_result b_directory_open( dir->rel_path = b_path_duplicate(path); dir->fd = fd; + if (flags & B_DIRECTORY_OPEN_DELETE_ON_CLOSE) { + dir->flags = DIRECTORY_DELETE_ON_CLOSE; + } + *out = dir; return B_RESULT_SUCCESS; } +b_result b_directory_open_temp(struct b_directory **out) +{ + char name[16]; + char path[128]; + + while (1) { + z__b_io_generate_tmp_filename(name, sizeof name); + snprintf(path, sizeof path, "/tmp/%s", name); + struct b_path *rpath = b_path_create_from_cstr(path); + + struct b_directory *dir = NULL; + b_result status = b_directory_open( + B_DIRECTORY_ROOT, rpath, B_DIRECTORY_OPEN_CREATE, &dir); + + if (b_error_get_status_code(status) == B_ERR_NAME_EXISTS) { + b_path_release(rpath); + continue; + } + + if (dir) { + dir->flags |= DIRECTORY_DELETE_ON_CLOSE; + } + + b_path_unlink(rpath); + b_path_release(rpath); + + return status; + } +} + const struct b_path *b_directory_get_path(const struct b_directory *dir) { if (!dir) { @@ -186,6 +234,35 @@ const char *b_directory_get_rel_path_cstr(const struct b_directory *dir) return b_path_ptr(dir->rel_path); } +static b_result directory_delete(struct b_directory *dir) +{ + enum b_status status = B_SUCCESS; + + struct b_directory_iterator it; + b_directory_iterator_begin(dir, &it, B_DIRECTORY_ITERATE_PARENT_LAST); + while (b_directory_iterator_is_valid(&it)) { + status = b_directory_iterator_erase(&it); + if (!B_OK(status)) { + return B_RESULT_STATUS(status); + } + } + + status = b_path_unlink(dir->abs_path); + if (!B_OK(status)) { + return B_RESULT_STATUS(status); + } + + return B_RESULT_SUCCESS; +} + +b_result b_directory_delete(struct b_directory *dir) +{ + dir->flags |= DIRECTORY_DELETE_ON_CLOSE; + /* TODO allow object release functions to return a b_result value */ + b_directory_release(dir); + return B_RESULT_SUCCESS; +} + bool b_directory_path_exists( const struct b_directory *root, const struct b_path *path) { @@ -478,6 +555,14 @@ bool b_directory_iterator_next(struct b_directory_iterator *it) enum b_status b_directory_iterator_erase(struct b_directory_iterator *it) { + b_result result = b_directory_path_unlink(it->root, it->filepath); + if (b_result_is_error(result)) { + enum b_status status = b_error_get_status_code(result); + b_error_release(result); + return status; + } + + b_directory_iterator_next(it); return B_SUCCESS; } @@ -499,5 +584,10 @@ static void directory_release(struct b_object *obj) struct b_directory *dir = B_DIRECTORY(obj); close(dir->fd); + + if (dir->flags & DIRECTORY_DELETE_ON_CLOSE) { + directory_delete(dir); + } + b_path_release(dir->abs_path); } diff --git a/io/sys/darwin/file.c b/io/sys/darwin/file.c index 0249004..7d8a7d8 100644 --- a/io/sys/darwin/file.c +++ b/io/sys/darwin/file.c @@ -1,3 +1,4 @@ +#include "misc.h" #include "posix.h" #include @@ -118,24 +119,6 @@ b_result b_file_open( return B_RESULT_SUCCESS; } -static void generate_tmp_filename(char *out, size_t len) -{ - static const char *alphabet - = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "01234567" - "89+=-_."; - static const size_t alphabet_len = 67; - - b_random_ctx *ctx = b_random_global_ctx(); - - for (size_t i = 0; i < len; i++) { - int v = b_random_next_int64(ctx) % alphabet_len; - out[i] = alphabet[v]; - } - - out[len - 1] = 0; -} - b_result b_file_open_temp(enum b_file_mode mode, struct b_file **out) { mode |= B_FILE_DELETE_ON_CLOSE; @@ -144,7 +127,7 @@ b_result b_file_open_temp(enum b_file_mode mode, struct b_file **out) char path[128]; while (1) { - generate_tmp_filename(name, sizeof name); + z__b_io_generate_tmp_filename(name, sizeof name); snprintf(path, sizeof path, "/tmp/%s", name); struct b_path *rpath = b_path_create_from_cstr(path); @@ -423,7 +406,7 @@ enum b_status b_file_swap_shadow(struct b_file *main_file, struct b_file *shadow while (1) { char tmp_name[16]; - generate_tmp_filename(tmp_name, sizeof tmp_name); + z__b_io_generate_tmp_filename(tmp_name, sizeof tmp_name); struct b_path *tmp_name_p = b_path_create_from_cstr(tmp_name); const struct b_path *parts[] = { diff --git a/io/sys/darwin/misc.c b/io/sys/darwin/misc.c new file mode 100644 index 0000000..005aa8d --- /dev/null +++ b/io/sys/darwin/misc.c @@ -0,0 +1,21 @@ +#include "misc.h" + +#include + +void z__b_io_generate_tmp_filename(char *out, size_t len) +{ + static const char *alphabet + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "01234567" + "89+=-_."; + static const size_t alphabet_len = 67; + + b_random_ctx *ctx = b_random_global_ctx(); + + for (size_t i = 0; i < len; i++) { + int v = b_random_next_int64(ctx) % alphabet_len; + out[i] = alphabet[v]; + } + + out[len - 1] = 0; +} diff --git a/io/sys/darwin/misc.h b/io/sys/darwin/misc.h new file mode 100644 index 0000000..82106f5 --- /dev/null +++ b/io/sys/darwin/misc.h @@ -0,0 +1,8 @@ +#ifndef _IO_DARWIN_MISC_H_ +#define _IO_DARWIN_MISC_H_ + +#include + +extern void z__b_io_generate_tmp_filename(char *out, size_t len); + +#endif