io: directory: implement temporary directories and delete-on-close
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user