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 {
|
typedef enum b_directory_open_flags {
|
||||||
B_DIRECTORY_OPEN_CREATE = 0x01u,
|
B_DIRECTORY_OPEN_CREATE = 0x01u,
|
||||||
B_DIRECTORY_OPEN_CREATE_INTERMEDIATE = 0x03u,
|
B_DIRECTORY_OPEN_CREATE_INTERMEDIATE = 0x03u,
|
||||||
|
B_DIRECTORY_OPEN_DELETE_ON_CLOSE = 0x04u,
|
||||||
} b_directory_open_flags;
|
} b_directory_open_flags;
|
||||||
|
|
||||||
typedef struct b_directory_iterator {
|
typedef struct b_directory_iterator {
|
||||||
@@ -43,10 +44,12 @@ typedef struct b_directory_iterator {
|
|||||||
BLUE_API b_result b_directory_open(
|
BLUE_API b_result b_directory_open(
|
||||||
b_directory *root, const b_path *path, b_directory_open_flags flags,
|
b_directory *root, const b_path *path, b_directory_open_flags flags,
|
||||||
b_directory **out);
|
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_path(const b_directory *dir);
|
||||||
BLUE_API const b_path *b_directory_get_rel_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_path_cstr(const b_directory *dir);
|
||||||
BLUE_API const char *b_directory_get_rel_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_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);
|
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 "posix.h"
|
||||||
|
|
||||||
|
#include <blue/core/error.h>
|
||||||
#include <blue/io/directory.h>
|
#include <blue/io/directory.h>
|
||||||
#include <blue/object/string.h>
|
#include <blue/object/string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -10,8 +12,13 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
enum directory_flags {
|
||||||
|
DIRECTORY_DELETE_ON_CLOSE = 0x01u,
|
||||||
|
};
|
||||||
|
|
||||||
struct b_directory {
|
struct b_directory {
|
||||||
struct b_object base;
|
struct b_object base;
|
||||||
|
enum directory_flags flags;
|
||||||
int fd;
|
int fd;
|
||||||
struct b_path *rel_path;
|
struct b_path *rel_path;
|
||||||
struct b_path *abs_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)
|
static b_result create_directory(struct b_directory *root, const char *path)
|
||||||
{
|
{
|
||||||
int root_fd = root->fd;
|
int root_fd = root ? root->fd : -1;
|
||||||
int err = mkdirat(root_fd, path, 0755);
|
int err;
|
||||||
|
|
||||||
|
if (root_fd == -1) {
|
||||||
|
err = mkdir(path, 0755);
|
||||||
|
} else {
|
||||||
|
err = mkdirat(root_fd, path, 0755);
|
||||||
|
}
|
||||||
|
|
||||||
if (err == 0 || errno == EEXIST) {
|
if (err == 0 || errno == EEXIST) {
|
||||||
return B_RESULT_SUCCESS;
|
return B_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -145,11 +159,45 @@ b_result b_directory_open(
|
|||||||
dir->rel_path = b_path_duplicate(path);
|
dir->rel_path = b_path_duplicate(path);
|
||||||
dir->fd = fd;
|
dir->fd = fd;
|
||||||
|
|
||||||
|
if (flags & B_DIRECTORY_OPEN_DELETE_ON_CLOSE) {
|
||||||
|
dir->flags = DIRECTORY_DELETE_ON_CLOSE;
|
||||||
|
}
|
||||||
|
|
||||||
*out = dir;
|
*out = dir;
|
||||||
|
|
||||||
return B_RESULT_SUCCESS;
|
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)
|
const struct b_path *b_directory_get_path(const struct b_directory *dir)
|
||||||
{
|
{
|
||||||
if (!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);
|
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(
|
bool b_directory_path_exists(
|
||||||
const struct b_directory *root, const struct b_path *path)
|
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)
|
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;
|
return B_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,5 +584,10 @@ static void directory_release(struct b_object *obj)
|
|||||||
struct b_directory *dir = B_DIRECTORY(obj);
|
struct b_directory *dir = B_DIRECTORY(obj);
|
||||||
|
|
||||||
close(dir->fd);
|
close(dir->fd);
|
||||||
|
|
||||||
|
if (dir->flags & DIRECTORY_DELETE_ON_CLOSE) {
|
||||||
|
directory_delete(dir);
|
||||||
|
}
|
||||||
|
|
||||||
b_path_release(dir->abs_path);
|
b_path_release(dir->abs_path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "misc.h"
|
||||||
#include "posix.h"
|
#include "posix.h"
|
||||||
|
|
||||||
#include <blue/core/random.h>
|
#include <blue/core/random.h>
|
||||||
@@ -118,24 +119,6 @@ b_result b_file_open(
|
|||||||
return B_RESULT_SUCCESS;
|
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)
|
b_result b_file_open_temp(enum b_file_mode mode, struct b_file **out)
|
||||||
{
|
{
|
||||||
mode |= B_FILE_DELETE_ON_CLOSE;
|
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];
|
char path[128];
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
generate_tmp_filename(name, sizeof name);
|
z__b_io_generate_tmp_filename(name, sizeof name);
|
||||||
snprintf(path, sizeof path, "/tmp/%s", name);
|
snprintf(path, sizeof path, "/tmp/%s", name);
|
||||||
struct b_path *rpath = b_path_create_from_cstr(path);
|
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) {
|
while (1) {
|
||||||
char tmp_name[16];
|
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);
|
struct b_path *tmp_name_p = b_path_create_from_cstr(tmp_name);
|
||||||
|
|
||||||
const struct b_path *parts[] = {
|
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