io: directory: implement temporary directories and delete-on-close

This commit is contained in:
2025-08-09 19:40:11 +01:00
parent 655d8b1881
commit 8bdb770ae5
5 changed files with 127 additions and 22 deletions

View File

@@ -1,5 +1,7 @@
#include "misc.h"
#include "posix.h"
#include <blue/core/error.h>
#include <blue/io/directory.h>
#include <blue/object/string.h>
#include <errno.h>
@@ -10,8 +12,13 @@
#include <sys/stat.h>
#include <unistd.h>
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);
}

View File

@@ -1,3 +1,4 @@
#include "misc.h"
#include "posix.h"
#include <blue/core/random.h>
@@ -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[] = {

21
io/sys/darwin/misc.c Normal file
View File

@@ -0,0 +1,21 @@
#include "misc.h"
#include <blue/core/random.h>
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;
}

8
io/sys/darwin/misc.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef _IO_DARWIN_MISC_H_
#define _IO_DARWIN_MISC_H_
#include <stddef.h>
extern void z__b_io_generate_tmp_filename(char *out, size_t len);
#endif