io: directory: implement temporary directories and delete-on-close
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
21
io/sys/darwin/misc.c
Normal 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
8
io/sys/darwin/misc.h
Normal 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
|
||||
Reference in New Issue
Block a user