diff --git a/io/include/blue/io/directory.h b/io/include/blue/io/directory.h index db7a081..1ffda09 100644 --- a/io/include/blue/io/directory.h +++ b/io/include/blue/io/directory.h @@ -1,16 +1,25 @@ -#ifndef BLUELIB_IO_DIRECTORY_H_ -#define BLUELIB_IO_DIRECTORY_H_ +#ifndef BLUE_IO_DIRECTORY_H_ +#define BLUE_IO_DIRECTORY_H_ #include #include +#include #include #include #include -#define B_DIRECTORY(p) ((b_directory *)(p)) #define B_DIRECTORY_ROOT ((b_directory *)NULL) -typedef struct b_directory b_directory; +B_DECLS_BEGIN; + +struct b_directory_p; + +#define B_TYPE_DIRECTORY (b_directory_get_type()) + +B_DECLARE_TYPE(b_directory); + +B_TYPE_CLASS_DECLARATION_BEGIN(b_directory) +B_TYPE_CLASS_DECLARATION_END(b_directory) struct z__b_directory_iterator; @@ -28,6 +37,7 @@ typedef enum b_directory_open_flags { typedef struct b_directory_iterator { b_iterator _base; struct z__b_directory_iterator *_z; + struct b_directory_p *_p; b_directory_iterator_flags flags; b_directory *root; @@ -41,6 +51,8 @@ typedef struct b_directory_iterator { for (int z__b_unique_name() = b_directory_iterator_begin(dir, it, flags); \ b_directory_iterator_is_valid(it); b_directory_iterator_next(it)) +BLUE_API b_type b_directory_get_type(void); + BLUE_API b_result b_directory_open( b_directory *root, const b_path *path, b_directory_open_flags flags, b_directory **out); @@ -67,14 +79,6 @@ BLUE_API bool b_directory_iterator_next(b_directory_iterator *it); BLUE_API b_status b_directory_iterator_erase(b_directory_iterator *it); BLUE_API bool b_directory_iterator_is_valid(const b_directory_iterator *it); -static inline b_directory *b_directory_retain(b_directory *dir) -{ - return B_DIRECTORY(b_retain(B_DSREF(dir))); -} - -static inline void b_directory_release(b_directory *dir) -{ - b_release(B_DSREF(dir)); -} +B_DECLS_END; #endif diff --git a/io/sys/darwin/directory.c b/io/sys/darwin/directory.c index 1928060..1b40412 100644 --- a/io/sys/darwin/directory.c +++ b/io/sys/darwin/directory.c @@ -2,8 +2,8 @@ #include "posix.h" #include -#include #include +#include #include #include #include @@ -12,16 +12,17 @@ #include #include +/*** PRIVATE DATA *************************************************************/ + enum directory_flags { DIRECTORY_DELETE_ON_CLOSE = 0x01u, }; -struct b_directory { - struct b_dsref base; - enum directory_flags flags; - int fd; - struct b_path *rel_path; - struct b_path *abs_path; +struct b_directory_p { + enum directory_flags d_flags; + int d_fd; + b_path *d_path_rel; + b_path *d_path_abs; }; struct z__b_directory_iterator { @@ -29,19 +30,147 @@ struct z__b_directory_iterator { FTSENT *ent; }; -static void directory_release(struct b_dsref *obj); - -static struct b_dsref_type directory_type = { - .t_name = "corelib::directory", - .t_flags = B_DSREF_FUNDAMENTAL, - .t_id = B_DSREF_TYPE_PATH, - .t_instance_size = sizeof(struct b_directory), - .t_release = directory_release, -}; - -static b_result create_directory(struct b_directory *root, const char *path) +/*** PRIVATE FUNCTIONS ********************************************************/ +static const b_path *directory_get_path(const struct b_directory_p *dir) { - int root_fd = root ? root->fd : -1; + return dir->d_path_abs; +} + +static const b_path *directory_get_rel_path(const struct b_directory_p *dir) +{ + return dir->d_path_rel; +} + +static const char *directory_get_path_cstr(const struct b_directory_p *dir) +{ + return b_path_ptr(dir->d_path_abs); +} + +static const char *directory_get_rel_path_cstr(const struct b_directory_p *dir) +{ + return b_path_ptr(dir->d_path_rel); +} + +static b_result directory_delete(b_directory *dir, struct b_directory_p *dir_p) +{ + 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_p->d_path_abs); + if (!B_OK(status)) { + return B_RESULT_STATUS(status); + } + + return B_RESULT_SUCCESS; +} + +static bool directory_path_exists( + const struct b_directory_p *root, const b_path *path) +{ + const b_path *parts[] = { + root ? root->d_path_abs : NULL, + path, + }; + + b_path *abs_path = b_path_join(parts, sizeof parts / sizeof parts[0]); + if (!abs_path) { + return false; + } + + bool result = b_path_exists(abs_path); + b_path_unref(abs_path); + + return result; +} + +static bool directory_path_is_file( + const struct b_directory_p *root, const b_path *path) +{ + const b_path *parts[] = { + root ? root->d_path_abs : NULL, + path, + }; + + b_path *abs_path = b_path_join(parts, sizeof parts / sizeof parts[0]); + if (!abs_path) { + return false; + } + + bool result = b_path_is_file(abs_path); + b_path_unref(abs_path); + + return result; +} + +static bool directory_path_is_directory( + const struct b_directory_p *root, const b_path *path) +{ + const b_path *parts[] = { + root ? root->d_path_abs : NULL, + path, + }; + + b_path *abs_path = b_path_join(parts, sizeof parts / sizeof parts[0]); + if (!abs_path) { + return false; + } + + bool result = b_path_is_directory(abs_path); + b_path_unref(abs_path); + + return result; +} + +static b_result directory_path_stat( + const struct b_directory_p *root, const b_path *path, + struct b_file_info *out) +{ + const b_path *parts[] = { + root ? root->d_path_abs : NULL, + path, + }; + + b_path *abs_path = b_path_join(parts, sizeof parts / sizeof parts[0]); + if (!abs_path) { + return B_RESULT_ERR(NO_MEMORY); + } + + enum b_status status = b_path_stat(abs_path, out); + b_path_unref(abs_path); + + return B_RESULT_STATUS(status); +} + +static b_result directory_path_unlink( + const struct b_directory_p *root, const b_path *path) +{ + const b_path *parts[] = { + root ? root->d_path_abs : NULL, + path, + }; + + b_path *abs_path = b_path_join(parts, sizeof parts / sizeof parts[0]); + if (!abs_path) { + return B_RESULT_ERR(NO_MEMORY); + } + + enum b_status status = b_path_unlink(abs_path); + b_path_unref(abs_path); + + return B_RESULT_STATUS(status); +} + +static b_result create_directory(struct b_directory_p *root, const char *path) +{ + int root_fd = root ? root->d_fd : -1; int err; if (root_fd == -1) { @@ -55,12 +184,13 @@ static b_result create_directory(struct b_directory *root, const char *path) } return b_result_from_errno_with_subfilepath( - errno, path, b_directory_get_rel_path_cstr(root), B_ERR_IO_FAILURE); + errno, path, directory_get_rel_path_cstr(root), B_ERR_IO_FAILURE); } -static b_result create_directory_hierarchy(struct b_directory *root, const char *path) +static b_result create_directory_hierarchy( + struct b_directory_p *root, const char *path) { - int root_fd = root->fd; + int root_fd = root->d_fd; char *path_buf = b_strdup(path); if (!path_buf) { @@ -78,8 +208,7 @@ static b_result create_directory_hierarchy(struct b_directory *root, const char int err = mkdirat(root_fd, path_buf, 0755); if (err != 0 && errno != EEXIST) { result = b_result_from_errno_with_subfilepath( - errno, path_buf, - b_directory_get_rel_path_cstr(root), + errno, path_buf, directory_get_rel_path_cstr(root), B_ERR_IO_FAILURE); break; } @@ -90,7 +219,7 @@ static b_result create_directory_hierarchy(struct b_directory *root, const char int err = mkdirat(root_fd, path_buf, 0755); if (err != 0 && errno != EEXIST) { result = b_result_from_errno_with_subfilepath( - errno, path_buf, b_directory_get_rel_path_cstr(root), + errno, path_buf, directory_get_rel_path_cstr(root), B_ERR_IO_FAILURE); } @@ -98,13 +227,13 @@ static b_result create_directory_hierarchy(struct b_directory *root, const char return result; } -b_result b_directory_open( - struct b_directory *root, const struct b_path *path, - b_directory_open_flags flags, struct b_directory **out) +static b_result directory_open( + struct b_directory_p *root, const b_path *path, + b_directory_open_flags flags, b_directory **out) { enum b_status status = B_SUCCESS; - int root_fd = root ? root->fd : AT_FDCWD; + int root_fd = root ? root->d_fd : AT_FDCWD; const char *path_cstr = b_path_ptr(path); if (root) { @@ -132,17 +261,16 @@ b_result b_directory_open( return B_RESULT_STATUS(status); } - struct b_directory *dir - = (struct b_directory *)b_dsref_type_instantiate(&directory_type); - - struct b_path *cwd = NULL; + b_directory *dir = b_object_create(B_TYPE_DIRECTORY); + b_path *cwd = NULL; + struct b_directory_p *p = b_object_get_private(dir, B_TYPE_DIRECTORY); if (!root) { cwd = b_path_create_cwd(); } const b_path *parts[] = { - root ? root->abs_path : cwd, + root ? root->d_path_abs : cwd, path, }; @@ -152,15 +280,15 @@ b_result b_directory_open( } if (cwd) { - b_path_release(cwd); + b_path_unref(cwd); } - dir->abs_path = new_path; - dir->rel_path = b_path_duplicate(path); - dir->fd = fd; + p->d_path_abs = new_path; + p->d_path_rel = b_path_duplicate(path); + p->d_fd = fd; if (flags & B_DIRECTORY_OPEN_DELETE_ON_CLOSE) { - dir->flags = DIRECTORY_DELETE_ON_CLOSE; + p->d_flags = DIRECTORY_DELETE_ON_CLOSE; } *out = dir; @@ -168,7 +296,17 @@ b_result b_directory_open( return B_RESULT_SUCCESS; } -b_result b_directory_open_temp(struct b_directory **out) +/*** PUBLIC FUNCTIONS *********************************************************/ + +b_result b_directory_open( + b_directory *root, const b_path *path, b_directory_open_flags flags, + b_directory **out) +{ + B_CLASS_DISPATCH_STATIC( + B_TYPE_DIRECTORY, directory_open, root, path, flags, out); +} + +b_result b_directory_open_temp(b_directory **out) { char name[16]; char path[128]; @@ -176,194 +314,127 @@ b_result b_directory_open_temp(struct b_directory **out) 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); + b_path *rpath = b_path_create_from_cstr(path); - struct b_directory *dir = NULL; + b_directory *dir = NULL; b_result status = b_directory_open( B_DIRECTORY_ROOT, rpath, B_DIRECTORY_OPEN_CREATE, &dir); + struct b_directory_p *p + = b_object_get_private(dir, B_TYPE_DIRECTORY); if (b_error_get_status_code(status) == B_ERR_NAME_EXISTS) { - b_path_release(rpath); + b_path_unref(rpath); continue; } if (dir) { - dir->flags |= DIRECTORY_DELETE_ON_CLOSE; + p->d_flags |= DIRECTORY_DELETE_ON_CLOSE; } b_path_unlink(rpath); - b_path_release(rpath); + b_path_unref(rpath); return status; } } -const struct b_path *b_directory_get_path(const struct b_directory *dir) +const b_path *b_directory_get_path(const b_directory *dir) { - if (!dir) { - return NULL; - } - - return dir->abs_path; + B_CLASS_DISPATCH_STATIC_0(B_TYPE_DIRECTORY, directory_get_path, dir); } -const struct b_path *b_directory_get_rel_path(const struct b_directory *dir) +const b_path *b_directory_get_rel_path(const b_directory *dir) { - if (!dir) { - return NULL; - } - - return dir->rel_path; + B_CLASS_DISPATCH_STATIC_0(B_TYPE_DIRECTORY, directory_get_rel_path, dir); } -const char *b_directory_get_path_cstr(const struct b_directory *dir) +const char *b_directory_get_path_cstr(const b_directory *dir) { - if (!dir) { - return NULL; - } - - return b_path_ptr(dir->abs_path); + B_CLASS_DISPATCH_STATIC_0(B_TYPE_DIRECTORY, directory_get_path_cstr, dir); } -const char *b_directory_get_rel_path_cstr(const struct b_directory *dir) +const char *b_directory_get_rel_path_cstr(const b_directory *dir) { - if (!dir) { - return NULL; - } - - return b_path_ptr(dir->rel_path); + B_CLASS_DISPATCH_STATIC_0( + B_TYPE_DIRECTORY, directory_get_rel_path_cstr, dir); } -static b_result directory_delete(struct b_directory *dir) +b_result b_directory_delete(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; + struct b_directory_p *p = b_object_get_private(dir, B_TYPE_DIRECTORY); + p->d_flags |= DIRECTORY_DELETE_ON_CLOSE; /* TODO allow object release functions to return a b_result value */ - b_directory_release(dir); + b_directory_unref(dir); return B_RESULT_SUCCESS; } -bool b_directory_path_exists( - const struct b_directory *root, const struct b_path *path) +bool b_directory_path_exists(const b_directory *root, const b_path *path) { - const struct b_path *parts[] = { - root ? root->abs_path : NULL, - path, - }; - - struct b_path *abs_path - = b_path_join(parts, sizeof parts / sizeof parts[0]); - if (!abs_path) { - return false; - } - - bool result = b_path_exists(abs_path); - b_path_release(abs_path); - - return result; + B_CLASS_DISPATCH_STATIC(B_TYPE_DIRECTORY, directory_path_exists, root, path); } -bool b_directory_path_is_file( - const struct b_directory *root, const struct b_path *path) +bool b_directory_path_is_file(const b_directory *root, const b_path *path) { - const struct b_path *parts[] = { - root ? root->abs_path : NULL, - path, - }; - - struct b_path *abs_path - = b_path_join(parts, sizeof parts / sizeof parts[0]); - if (!abs_path) { - return false; - } - - bool result = b_path_is_file(abs_path); - b_path_release(abs_path); - - return result; + B_CLASS_DISPATCH_STATIC( + B_TYPE_DIRECTORY, directory_path_is_file, root, path); } -bool b_directory_path_is_directory( - const struct b_directory *root, const struct b_path *path) +bool b_directory_path_is_directory(const b_directory *root, const b_path *path) { - const struct b_path *parts[] = { - root ? root->abs_path : NULL, - path, - }; - - struct b_path *abs_path - = b_path_join(parts, sizeof parts / sizeof parts[0]); - if (!abs_path) { - return false; - } - - bool result = b_path_is_directory(abs_path); - b_path_release(abs_path); - - return result; + B_CLASS_DISPATCH_STATIC( + B_TYPE_DIRECTORY, directory_path_is_directory, root, path); } b_result b_directory_path_stat( - const struct b_directory *root, const struct b_path *path, - struct b_file_info *out) + const b_directory *root, const b_path *path, struct b_file_info *out) { - const struct b_path *parts[] = { - root ? root->abs_path : NULL, - path, - }; - - struct b_path *abs_path - = b_path_join(parts, sizeof parts / sizeof parts[0]); - if (!abs_path) { - return B_RESULT_ERR(NO_MEMORY); - } - - enum b_status status = b_path_stat(abs_path, out); - b_path_release(abs_path); - - return B_RESULT_STATUS(status); + B_CLASS_DISPATCH_STATIC( + B_TYPE_DIRECTORY, directory_path_stat, root, path, out); } -b_result b_directory_path_unlink( - const struct b_directory *root, const struct b_path *path) +b_result b_directory_path_unlink(const b_directory *root, const b_path *path) { - const struct b_path *parts[] = { - root ? root->abs_path : NULL, - path, - }; + B_CLASS_DISPATCH_STATIC(B_TYPE_DIRECTORY, directory_path_unlink, root, path); +} - struct b_path *abs_path - = b_path_join(parts, sizeof parts / sizeof parts[0]); - if (!abs_path) { - return B_RESULT_ERR(NO_MEMORY); +/*** VIRTUAL FUNCTIONS ********************************************************/ + +static void directory_init(b_object *obj, void *priv) +{ + struct b_directory_p *dir = priv; +} + +static void directory_fini(b_object *obj, void *priv) +{ + struct b_directory_p *dir = priv; + + close(dir->d_fd); + + if (dir->d_flags & DIRECTORY_DELETE_ON_CLOSE) { + directory_delete(obj, dir); } - enum b_status status = b_path_unlink(abs_path); - b_path_release(abs_path); - - return B_RESULT_STATUS(status); + b_path_unref(dir->d_path_abs); } +/*** CLASS DEFINITION *********************************************************/ + +B_TYPE_CLASS_DEFINITION_BEGIN(b_directory) + B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT) + B_INTERFACE_ENTRY(to_string) = NULL; + B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) +B_TYPE_CLASS_DEFINITION_END(b_directory) + +B_TYPE_DEFINITION_BEGIN(b_directory) + B_TYPE_ID(0x10d36546, 0x7f96, 0x464b, 0xbc4d, 0xe504b283fa45); + B_TYPE_CLASS(b_directory_class); + B_TYPE_INSTANCE_PRIVATE(struct b_directory_p); + B_TYPE_INSTANCE_INIT(directory_init); + B_TYPE_INSTANCE_FINI(directory_fini); +B_TYPE_DEFINITION_END(b_directory) + +/*** ITERATOR FUNCTIONS *******************************************************/ + static int ftsent_compare(const FTSENT **one, const FTSENT **two) { return (strcmp((*one)->fts_name, (*two)->fts_name)); @@ -374,14 +445,14 @@ static void update_iterator_data(struct b_directory_iterator *it) struct z__b_directory_iterator *it_data = it->_z; if (it->filepath) { - b_path_release((struct b_path *)it->filepath); + b_path_unref((b_path *)it->filepath); it->filepath = NULL; } FTSENT *ent = it_data->ent; - struct b_path *path = b_path_create_from_cstr( - ent->fts_path + b_path_length(it->root->abs_path) + 1); + b_path *path = b_path_create_from_cstr( + ent->fts_path + b_path_length(it->_p->d_path_abs) + 1); it->filename = ent->fts_name; it->filepath = path; @@ -414,7 +485,7 @@ static void update_iterator_data(struct b_directory_iterator *it) static void cleanup_iterator(struct b_directory_iterator *it) { if (it->filepath) { - b_path_release((struct b_path *)it->filepath); + b_path_unref((b_path *)it->filepath); it->filepath = NULL; } @@ -433,13 +504,14 @@ static void cleanup_iterator(struct b_directory_iterator *it) } int b_directory_iterator_begin( - struct b_directory *directory, struct b_directory_iterator *it, + b_directory *directory, struct b_directory_iterator *it, enum b_directory_iterator_flags flags) { memset(it, 0x0, sizeof *it); it->flags = flags; it->root = directory; + it->_p = b_object_get_private(directory, B_TYPE_DIRECTORY); struct z__b_directory_iterator *it_data = malloc(sizeof *it_data); @@ -454,7 +526,7 @@ int b_directory_iterator_begin( int fts_flags = FTS_COMFOLLOW | FTS_NOCHDIR; const char *path_list[] = { - b_path_ptr(directory->abs_path), + b_path_ptr(it->_p->d_path_abs), NULL, }; @@ -578,16 +650,3 @@ bool b_directory_iterator_is_valid(const struct b_directory_iterator *it) return true; } - -static void directory_release(struct b_dsref *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); -}