io: directory: implement new b_iterator interface

This commit is contained in:
2025-11-01 10:03:59 +00:00
parent ec500c04ad
commit 5d3a987b0e
2 changed files with 145 additions and 123 deletions

View File

@@ -15,12 +15,17 @@ B_DECLS_BEGIN;
struct b_directory_p; struct b_directory_p;
#define B_TYPE_DIRECTORY (b_directory_get_type()) #define B_TYPE_DIRECTORY (b_directory_get_type())
#define B_TYPE_DIRECTORY_ITERATOR (b_directory_iterator_get_type())
B_DECLARE_TYPE(b_directory); B_DECLARE_TYPE(b_directory);
B_DECLARE_TYPE(b_directory_iterator);
B_TYPE_CLASS_DECLARATION_BEGIN(b_directory) B_TYPE_CLASS_DECLARATION_BEGIN(b_directory)
B_TYPE_CLASS_DECLARATION_END(b_directory) B_TYPE_CLASS_DECLARATION_END(b_directory)
B_TYPE_CLASS_DECLARATION_BEGIN(b_directory_iterator)
B_TYPE_CLASS_DECLARATION_END(b_directory_iterator)
struct z__b_directory_iterator; struct z__b_directory_iterator;
typedef enum b_directory_iterator_flags { typedef enum b_directory_iterator_flags {
@@ -34,24 +39,14 @@ typedef enum b_directory_open_flags {
B_DIRECTORY_OPEN_DELETE_ON_CLOSE = 0x04u, B_DIRECTORY_OPEN_DELETE_ON_CLOSE = 0x04u,
} b_directory_open_flags; } b_directory_open_flags;
typedef struct b_directory_iterator { typedef struct b_directory_entry {
b_iterator _base;
struct z__b_directory_iterator *_z;
struct b_directory_p *_p;
b_directory_iterator_flags flags;
b_directory *root;
const b_path *filepath; const b_path *filepath;
char *filename; char *filename;
b_file_info info; b_file_info info;
} b_directory_iterator; } b_directory_entry;
#define b_directory_foreach(it, dir, flags) \
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_type b_directory_get_type(void);
BLUE_API b_type b_directory_iterator_get_type(void);
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,
@@ -72,12 +67,8 @@ BLUE_API b_result b_directory_path_stat(
BLUE_API b_result b_directory_path_unlink( BLUE_API b_result b_directory_path_unlink(
const b_directory *root, const b_path *path); const b_directory *root, const b_path *path);
BLUE_API int b_directory_iterator_begin( BLUE_API b_iterator *b_directory_begin(
b_directory *directory, b_directory_iterator *it, b_directory *dir, b_directory_iterator_flags flags);
b_directory_iterator_flags flags);
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);
B_DECLS_END; B_DECLS_END;

View File

@@ -25,9 +25,16 @@ struct b_directory_p {
b_path *d_path_abs; b_path *d_path_abs;
}; };
struct z__b_directory_iterator { struct b_directory_iterator_p {
struct b_directory_p *_p;
FTS *fts; FTS *fts;
FTSENT *ent; FTSENT *ent;
b_directory_iterator_flags flags;
b_directory *root;
b_directory_entry entry;
}; };
/*** PRIVATE FUNCTIONS ********************************************************/ /*** PRIVATE FUNCTIONS ********************************************************/
@@ -55,13 +62,14 @@ static b_result directory_delete(b_directory *dir, struct b_directory_p *dir_p)
{ {
enum b_status status = B_SUCCESS; enum b_status status = B_SUCCESS;
struct b_directory_iterator it; b_iterator *it = b_directory_begin(dir, B_DIRECTORY_ITERATE_PARENT_LAST);
b_directory_iterator_begin(dir, &it, B_DIRECTORY_ITERATE_PARENT_LAST); while (B_OK(b_iterator_get_status(it))) {
while (b_directory_iterator_is_valid(&it)) { b_iterator_erase(it);
status = b_directory_iterator_erase(&it);
if (!B_OK(status)) {
return B_RESULT_STATUS(status);
} }
status = b_iterator_get_status(it);
if (!B_OK(status) && status != B_ERR_NO_DATA) {
return B_RESULT_STATUS(status);
} }
status = b_path_unlink(dir_p->d_path_abs); status = b_path_unlink(dir_p->d_path_abs);
@@ -190,7 +198,7 @@ static b_result create_directory(struct b_directory_p *root, const char *path)
static b_result create_directory_hierarchy( static b_result create_directory_hierarchy(
struct b_directory_p *root, const char *path) struct b_directory_p *root, const char *path)
{ {
int root_fd = root->d_fd; int root_fd = root ? root->d_fd : AT_FDCWD;
char *path_buf = b_strdup(path); char *path_buf = b_strdup(path);
if (!path_buf) { if (!path_buf) {
@@ -417,22 +425,6 @@ static void directory_fini(b_object *obj, void *priv)
b_path_unref(dir->d_path_abs); 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 *******************************************************/ /*** ITERATOR FUNCTIONS *******************************************************/
static int ftsent_compare(const FTSENT **one, const FTSENT **two) static int ftsent_compare(const FTSENT **one, const FTSENT **two)
@@ -440,89 +432,71 @@ static int ftsent_compare(const FTSENT **one, const FTSENT **two)
return (strcmp((*one)->fts_name, (*two)->fts_name)); return (strcmp((*one)->fts_name, (*two)->fts_name));
} }
static void update_iterator_data(struct b_directory_iterator *it) static void update_iterator_data(struct b_directory_iterator_p *it)
{ {
struct z__b_directory_iterator *it_data = it->_z; if (it->entry.filepath) {
b_path_unref((b_path *)it->entry.filepath);
if (it->filepath) { it->entry.filepath = NULL;
b_path_unref((b_path *)it->filepath);
it->filepath = NULL;
} }
FTSENT *ent = it_data->ent; FTSENT *ent = it->ent;
b_path *path = b_path_create_from_cstr( b_path *path = b_path_create_from_cstr(
ent->fts_path + b_path_length(it->_p->d_path_abs) + 1); ent->fts_path + b_path_length(it->_p->d_path_abs) + 1);
it->filename = ent->fts_name; it->entry.filename = ent->fts_name;
it->filepath = path; it->entry.filepath = path;
memset(&it->info, 0x0, sizeof it->info); memset(&it->entry.info, 0x0, sizeof it->entry.info);
it->info.length = ent->fts_statp->st_size; it->entry.info.length = ent->fts_statp->st_size;
if (S_ISREG(ent->fts_statp->st_mode)) { if (S_ISREG(ent->fts_statp->st_mode)) {
it->info.attrib |= B_FILE_ATTRIB_NORMAL; it->entry.info.attrib |= B_FILE_ATTRIB_NORMAL;
} }
if (S_ISDIR(ent->fts_statp->st_mode)) { if (S_ISDIR(ent->fts_statp->st_mode)) {
it->info.attrib |= B_FILE_ATTRIB_DIRECTORY; it->entry.info.attrib |= B_FILE_ATTRIB_DIRECTORY;
} }
if (S_ISBLK(ent->fts_statp->st_mode)) { if (S_ISBLK(ent->fts_statp->st_mode)) {
it->info.attrib |= B_FILE_ATTRIB_BLOCK_DEVICE; it->entry.info.attrib |= B_FILE_ATTRIB_BLOCK_DEVICE;
} }
if (S_ISCHR(ent->fts_statp->st_mode)) { if (S_ISCHR(ent->fts_statp->st_mode)) {
it->info.attrib |= B_FILE_ATTRIB_CHAR_DEVICE; it->entry.info.attrib |= B_FILE_ATTRIB_CHAR_DEVICE;
} }
if (S_ISLNK(ent->fts_statp->st_mode)) { if (S_ISLNK(ent->fts_statp->st_mode)) {
it->info.attrib |= B_FILE_ATTRIB_SYMLINK; it->entry.info.attrib |= B_FILE_ATTRIB_SYMLINK;
} }
} }
static void cleanup_iterator(struct b_directory_iterator *it) static void iterator_fini(b_object *obj, void *priv)
{ {
if (it->filepath) { struct b_directory_iterator_p *it = priv;
b_path_unref((b_path *)it->filepath);
it->filepath = NULL; if (it->entry.filepath) {
b_path_unref((b_path *)it->entry.filepath);
it->entry.filepath = NULL;
} }
struct z__b_directory_iterator *it_data = it->_z; if (it->fts) {
memset(it, 0x0, sizeof *it); fts_close(it->fts);
if (!it_data) {
return;
} }
if (it_data->fts) {
fts_close(it_data->fts);
}
free(it_data);
} }
int b_directory_iterator_begin( b_iterator *b_directory_begin(
b_directory *directory, struct b_directory_iterator *it, b_directory *directory, enum b_directory_iterator_flags flags)
enum b_directory_iterator_flags flags)
{ {
memset(it, 0x0, sizeof *it); b_iterator *it_obj = b_object_create(B_TYPE_DIRECTORY_ITERATOR);
struct b_directory_iterator_p *it
= b_object_get_private(it_obj, B_TYPE_DIRECTORY_ITERATOR);
it->flags = flags; it->flags = flags;
it->root = directory; it->root = directory;
it->_p = b_object_get_private(directory, B_TYPE_DIRECTORY); it->_p = b_object_get_private(directory, B_TYPE_DIRECTORY);
struct z__b_directory_iterator *it_data = malloc(sizeof *it_data);
if (!it_data) {
return -1;
}
memset(it_data, 0x0, sizeof *it_data);
it->_z = it_data;
int fts_flags = FTS_COMFOLLOW | FTS_NOCHDIR; int fts_flags = FTS_COMFOLLOW | FTS_NOCHDIR;
const char *path_list[] = { const char *path_list[] = {
@@ -530,24 +504,23 @@ int b_directory_iterator_begin(
NULL, NULL,
}; };
it_data->fts it->fts = fts_open((char *const *)path_list, fts_flags, ftsent_compare);
= fts_open((char *const *)path_list, fts_flags, ftsent_compare);
bool done = false; bool done = false;
while (!done) { while (!done) {
it_data->ent = fts_read(it_data->fts); it->ent = fts_read(it->fts);
if (!it_data->ent) { if (!it->ent) {
cleanup_iterator(it); b_iterator_set_status(it_obj, B_ERR_NO_DATA);
return -1; return it_obj;
} }
if (it_data->ent->fts_level == 0) { if (it->ent->fts_level == 0) {
continue; continue;
} }
switch (it_data->ent->fts_info) { switch (it->ent->fts_info) {
case FTS_DOT: case FTS_DOT:
continue; continue;
case FTS_F: case FTS_F:
@@ -573,31 +546,41 @@ int b_directory_iterator_begin(
} }
update_iterator_data(it); update_iterator_data(it);
return 0; return it_obj;
} }
bool b_directory_iterator_next(struct b_directory_iterator *it) static b_iterator *iterator_begin(b_object *obj)
{ {
struct z__b_directory_iterator *it_data = it->_z; return b_directory_begin(obj, B_DIRECTORY_ITERATE_PARENT_FIRST);
if (!it_data || !it_data->fts) { }
return false;
static const b_iterator *iterator_cbegin(const b_object *obj)
{
return b_directory_begin((b_object *)obj, B_DIRECTORY_ITERATE_PARENT_FIRST);
}
static enum b_status iterator_move_next(const b_iterator *obj)
{
struct b_directory_iterator_p *it
= b_object_get_private(obj, B_TYPE_DIRECTORY_ITERATOR);
if (!it || !it->fts) {
return B_ERR_NO_DATA;
} }
bool done = false; bool done = false;
while (!done) { while (!done) {
it_data->ent = fts_read(it_data->fts); it->ent = fts_read(it->fts);
if (!it_data->ent) { if (!it->ent) {
cleanup_iterator(it); return B_ERR_NO_DATA;
return false;
} }
if (it_data->ent->fts_level == 0) { if (it->ent->fts_level == 0) {
continue; continue;
} }
switch (it_data->ent->fts_info) { switch (it->ent->fts_info) {
case FTS_DOT: case FTS_DOT:
continue; continue;
case FTS_F: case FTS_F:
@@ -622,31 +605,79 @@ bool b_directory_iterator_next(struct b_directory_iterator *it)
} }
update_iterator_data(it); update_iterator_data(it);
return true; return B_SUCCESS;
} }
enum b_status b_directory_iterator_erase(struct b_directory_iterator *it) static enum b_status iterator_erase(b_iterator *obj)
{ {
b_result result = b_directory_path_unlink(it->root, it->filepath); struct b_directory_iterator_p *it
= b_object_get_private(obj, B_TYPE_DIRECTORY_ITERATOR);
b_result result = b_directory_path_unlink(it->root, it->entry.filepath);
if (b_result_is_error(result)) { if (b_result_is_error(result)) {
enum b_status status = b_error_get_status_code(result); enum b_status status = b_error_get_status_code(result);
b_error_release(result); b_error_release(result);
return status; return status;
} }
b_directory_iterator_next(it); return iterator_move_next(obj);
return B_SUCCESS;
} }
bool b_directory_iterator_is_valid(const struct b_directory_iterator *it) static b_iterator_value iterator_get_value(b_iterator *obj)
{ {
if (!it->_z) { struct b_directory_iterator_p *it
return false; = b_object_get_private(obj, B_TYPE_DIRECTORY_ITERATOR);
}
if (!it->_z->ent) { return B_ITERATOR_VALUE_PTR(&it->entry);
return false;
}
return true;
} }
static const b_iterator_value iterator_get_cvalue(const b_iterator *obj)
{
struct b_directory_iterator_p *it
= b_object_get_private(obj, B_TYPE_DIRECTORY_ITERATOR);
return B_ITERATOR_VALUE_CPTR(&it->entry);
}
/*** CLASS DEFINITION *********************************************************/
// ---- b_directory 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_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
B_INTERFACE_ENTRY(it_begin) = iterator_begin;
B_INTERFACE_ENTRY(it_cbegin) = iterator_cbegin;
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
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_IMPLEMENTS(B_TYPE_ITERABLE);
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)
// ---- b_directory_iterator DEFINITION
B_TYPE_CLASS_DEFINITION_BEGIN(b_directory_iterator)
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_INTERFACE_BEGIN(b_iterator, B_TYPE_ITERATOR)
B_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
B_INTERFACE_ENTRY(it_erase) = iterator_erase;
B_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
B_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
B_TYPE_CLASS_INTERFACE_END(b_iterator, B_TYPE_ITERATOR)
B_TYPE_CLASS_DEFINITION_END(b_directory_iterator)
B_TYPE_DEFINITION_BEGIN(b_directory_iterator)
B_TYPE_ID(0xc707fce6, 0xc895, 0x4925, 0x8700, 0xa60641dee0cc);
B_TYPE_EXTENDS(B_TYPE_ITERATOR);
B_TYPE_CLASS(b_directory_iterator_class);
B_TYPE_INSTANCE_PRIVATE(struct b_directory_iterator_p);
B_TYPE_DEFINITION_END(b_directory_iterator)