diff --git a/io/include/blue/io/directory.h b/io/include/blue/io/directory.h index 979b232..8a6e2d1 100644 --- a/io/include/blue/io/directory.h +++ b/io/include/blue/io/directory.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #define B_DIRECTORY_ROOT ((b_directory *)NULL) @@ -19,11 +20,14 @@ typedef enum b_directory_iterator_flags { typedef struct b_directory_iterator { b_iterator _base; + struct z__b_directory_iterator *_z; + b_directory_iterator_flags flags; b_directory *root; + const b_path *filepath; char *filename; - struct z__b_directory_iterator *_z; + b_file_info info; } b_directory_iterator; #define b_directory_foreach(it, dir, flags) \ diff --git a/io/include/blue/io/file.h b/io/include/blue/io/file.h new file mode 100644 index 0000000..f7f0a3e --- /dev/null +++ b/io/include/blue/io/file.h @@ -0,0 +1,54 @@ +#ifndef BLUELIB_IO_FILE_H_ +#define BLUELIB_IO_FILE_H_ + +#include +#include +#include + +#define B_FILE(p) ((b_file *)(p)) + +struct b_directory; +struct b_path; + +typedef enum b_file_attribute { + B_FILE_ATTRIB_NORMAL = 0x01u, + B_FILE_ATTRIB_DIRECTORY = 0x02u, + B_FILE_ATTRIB_BLOCK_DEVICE = 0x04u, + B_FILE_ATTRIB_CHAR_DEVICE = 0x08u, + B_FILE_ATTRIB_SYMLINK = 0x80u, +} b_file_attribute; + +typedef enum b_file_mode { + B_FILE_READ_ONLY = 0x01u, + B_FILE_WRITE_ONLY = 0x02u, + B_FILE_READ_WRITE = 0x03u, + B_FILE_TRUNCATE = 0x04u, + B_FILE_APPEND = 0x08u, + B_FILE_BINARY = 0x10u, +} b_file_mode; + +typedef struct b_file_info { + b_file_attribute attrib; + b_file_mode mode; + + size_t length; +} b_file_info; + +typedef struct b_file b_file; + +BLUE_API enum b_status b_file_open( + struct b_directory *root, const struct b_path *path, b_file_mode mode, + b_file **out); + +BLUE_API enum b_status b_file_stat(b_file *file, b_file_info *out); + +static inline b_file *b_file_retain(b_file *file) +{ + return B_FILE(b_retain(B_OBJECT(file))); +} +static inline void b_file_release(b_file *file) +{ + b_release(B_OBJECT(file)); +} + +#endif diff --git a/io/include/blue/io/path.h b/io/include/blue/io/path.h index 7118dc8..850cca6 100644 --- a/io/include/blue/io/path.h +++ b/io/include/blue/io/path.h @@ -8,6 +8,8 @@ #define B_PATH(p) ((b_path *)p) +struct b_file_info; + typedef struct b_path b_path; BLUE_API b_path *b_path_create(); @@ -25,6 +27,7 @@ BLUE_API bool b_path_is_absolute(const b_path *path); BLUE_API bool b_path_exists(const b_path *path); BLUE_API bool b_path_is_file(const b_path *path); BLUE_API bool b_path_is_directory(const b_path *path); +BLUE_API enum b_status b_path_stat(const b_path *path, struct b_file_info *out); BLUE_API const char *b_path_ptr(const b_path *path); BLUE_API size_t b_path_length(const b_path *path); diff --git a/io/sys/darwin/directory.c b/io/sys/darwin/directory.c index f022eaf..c4dc640 100644 --- a/io/sys/darwin/directory.c +++ b/io/sys/darwin/directory.c @@ -1,9 +1,12 @@ +#include "status.h" + #include #include #include #include #include #include +#include #include struct b_directory { @@ -27,38 +30,38 @@ static struct b_object_type directory_type = { .t_release = directory_release, }; -static enum b_status status_from_errno(int error, enum b_status default_value) -{ - switch (error) { - case ENOENT: - return B_ERR_NO_ENTRY; - default: - return default_value; - } -} - enum b_status b_directory_open( struct b_directory *root, const struct b_path *path, struct b_directory **out) { enum b_status status = B_SUCCESS; + struct b_path *cwd = NULL; + + if (!root) { + cwd = b_path_create_cwd(); + } + const b_path *parts[] = { - root ? root->abs_path : NULL, + root ? root->abs_path : cwd, path, }; - b_path *new_path = b_path_join(parts, sizeof parts / sizeof *parts); + b_path *new_path = b_path_join(parts, sizeof parts / sizeof parts[0]); if (!new_path) { return B_ERR_NO_MEMORY; } + if (cwd) { + b_path_release(cwd); + } + int root_fd = root ? root->fd : AT_FDCWD; int fd = openat(root_fd, b_path_ptr(path), O_DIRECTORY); if (fd == -1) { - status = status_from_errno(errno, B_ERR_IO_FAILURE); + status = b_status_from_errno(errno, B_ERR_IO_FAILURE); b_path_release(new_path); @@ -81,6 +84,69 @@ static int ftsent_compare(const FTSENT **one, const FTSENT **two) return (strcmp((*one)->fts_name, (*two)->fts_name)); } +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); + 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); + + it->filename = ent->fts_name; + it->filepath = path; + + memset(&it->info, 0x0, sizeof it->info); + + it->info.length = ent->fts_statp->st_size; + + if (S_ISREG(ent->fts_statp->st_flags)) { + it->info.attrib |= B_FILE_ATTRIB_NORMAL; + } + + if (S_ISDIR(ent->fts_statp->st_flags)) { + it->info.attrib |= B_FILE_ATTRIB_DIRECTORY; + } + + if (S_ISBLK(ent->fts_statp->st_flags)) { + it->info.attrib |= B_FILE_ATTRIB_BLOCK_DEVICE; + } + + if (S_ISCHR(ent->fts_statp->st_flags)) { + it->info.attrib |= B_FILE_ATTRIB_CHAR_DEVICE; + } + + if (S_ISLNK(ent->fts_statp->st_flags)) { + it->info.attrib |= B_FILE_ATTRIB_SYMLINK; + } +} + +static void cleanup_iterator(struct b_directory_iterator *it) +{ + if (it->filepath) { + b_path_release((struct b_path *)it->filepath); + it->filepath = NULL; + } + + struct z__b_directory_iterator *it_data = it->_z; + memset(it, 0x0, sizeof *it); + + if (!it_data) { + return; + } + + if (it_data->fts) { + fts_close(it_data->fts); + } + + free(it_data); +} + int b_directory_iterator_begin( struct b_directory *directory, struct b_directory_iterator *it, enum b_directory_iterator_flags flags) @@ -89,6 +155,11 @@ int b_directory_iterator_begin( it->root = 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; @@ -103,16 +174,13 @@ int b_directory_iterator_begin( it_data->fts = fts_open((char *const *)path_list, fts_flags, ftsent_compare); - if (!it_data) { - return -1; - } - bool done = false; while (!done) { it_data->ent = fts_read(it_data->fts); if (!it_data->ent) { + cleanup_iterator(it); return -1; } @@ -145,9 +213,7 @@ int b_directory_iterator_begin( } } - it->filename = it_data->ent->fts_name; - it->filepath - = it_data->ent->fts_path + b_path_length(it->root->abs_path) + 1; + update_iterator_data(it); return 0; } @@ -164,6 +230,7 @@ bool b_directory_iterator_next(struct b_directory_iterator *it) it_data->ent = fts_read(it_data->fts); if (!it_data->ent) { + cleanup_iterator(it); return false; } @@ -195,9 +262,7 @@ bool b_directory_iterator_next(struct b_directory_iterator *it) } } - it->filename = it_data->ent->fts_name; - it->filepath - = it_data->ent->fts_path + b_path_length(it->root->abs_path) + 1; + update_iterator_data(it); return true; } diff --git a/io/sys/darwin/file.c b/io/sys/darwin/file.c new file mode 100644 index 0000000..e69de29 diff --git a/io/sys/darwin/path.c b/io/sys/darwin/path.c index 982b0b8..abbe0fd 100644 --- a/io/sys/darwin/path.c +++ b/io/sys/darwin/path.c @@ -1,9 +1,15 @@ +#include "status.h" + #include +#include #include #include #include +#include +#include #include #include +#include #include struct b_path { @@ -60,12 +66,13 @@ struct b_path *b_path_create_root() struct b_path *b_path_create_cwd() { - char *buf = malloc(_PC_PATH_MAX); + const long buf_len = 2048; + char *buf = malloc(buf_len); if (!buf) { return NULL; } - if (!getcwd(buf, _PC_PATH_MAX)) { + if (!getcwd(buf, buf_len)) { free(buf); return NULL; } @@ -170,17 +177,68 @@ bool b_path_is_absolute(const struct b_path *path) bool b_path_exists(const struct b_path *path) { - return false; + b_file_info info; + if (!B_OK(b_path_stat(path, &info))) { + return false; + } + + return true; } bool b_path_is_file(const struct b_path *path) { - return false; + b_file_info info; + if (!B_OK(b_path_stat(path, &info))) { + return false; + } + + return (info.attrib & B_FILE_ATTRIB_NORMAL) != 0; } bool b_path_is_directory(const struct b_path *path) { - return false; + b_file_info info; + if (!B_OK(b_path_stat(path, &info))) { + return false; + } + + return (info.attrib & B_FILE_ATTRIB_DIRECTORY) != 0; +} + +enum b_status b_path_stat(const b_path *path, struct b_file_info *out) +{ + struct stat st; + int err = stat(b_path_ptr(path), &st); + + if (err != 0) { + return b_status_from_errno(errno, B_ERR_IO_FAILURE); + } + + memset(out, 0x0, sizeof *out); + + out->length = st.st_size; + + if (S_ISREG(st.st_flags)) { + out->attrib |= B_FILE_ATTRIB_NORMAL; + } + + if (S_ISDIR(st.st_flags)) { + out->attrib |= B_FILE_ATTRIB_DIRECTORY; + } + + if (S_ISBLK(st.st_flags)) { + out->attrib |= B_FILE_ATTRIB_BLOCK_DEVICE; + } + + if (S_ISCHR(st.st_flags)) { + out->attrib |= B_FILE_ATTRIB_CHAR_DEVICE; + } + + if (S_ISLNK(st.st_flags)) { + out->attrib |= B_FILE_ATTRIB_SYMLINK; + } + + return B_SUCCESS; } const char *b_path_ptr(const struct b_path *path) @@ -195,7 +253,9 @@ size_t b_path_length(const struct b_path *path) void path_release(struct b_object *obj) { - b_path_release((struct b_path *)obj); + struct b_path *path = (struct b_path *)obj; + + b_string_release(path->pathstr); } void path_to_string(struct b_object *obj, struct b_stringstream *out) diff --git a/io/sys/darwin/status.c b/io/sys/darwin/status.c new file mode 100644 index 0000000..d446b7e --- /dev/null +++ b/io/sys/darwin/status.c @@ -0,0 +1,12 @@ +#include +#include + +enum b_status b_status_from_errno(int error, enum b_status default_value) +{ + switch (error) { + case ENOENT: + return B_ERR_NO_ENTRY; + default: + return default_value; + } +} diff --git a/io/sys/darwin/status.h b/io/sys/darwin/status.h new file mode 100644 index 0000000..801e170 --- /dev/null +++ b/io/sys/darwin/status.h @@ -0,0 +1,8 @@ +#ifndef _IO_DARWIN_STATUS_H_ +#define _IO_DARWIN_STATUS_H_ + +#include + +extern enum b_status b_status_from_errno(int error, enum b_status default_value); + +#endif diff --git a/io/sys/windows/directory.c b/io/sys/windows/directory.c index 7b2e1f8..5245a6e 100644 --- a/io/sys/windows/directory.c +++ b/io/sys/windows/directory.c @@ -44,7 +44,8 @@ static enum b_status status_from_win32_error(int error, enum b_status default_va } enum b_status b_directory_open( - struct b_directory *root, const struct b_path *path, struct b_directory **out) + struct b_directory *root, const struct b_path *path, + struct b_directory **out) { enum b_status status = B_SUCCESS; @@ -65,7 +66,7 @@ enum b_status b_directory_open( if (dir_handle == INVALID_HANDLE_VALUE) { status = status_from_win32_error(GetLastError(), B_ERR_IO_FAILURE); - + b_path_release(new_path); return status; @@ -74,14 +75,13 @@ enum b_status b_directory_open( BY_HANDLE_FILE_INFORMATION dir_info; if (!GetFileInformationByHandle(dir_handle, &dir_info)) { status = status_from_win32_error(GetLastError(), B_ERR_IO_FAILURE); - + CloseHandle(dir_handle); b_path_release(new_path); return status; } - if (!(dir_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { CloseHandle(dir_handle); b_path_release(new_path); @@ -104,7 +104,8 @@ enum b_status b_directory_open( return B_SUCCESS; } -static struct iteration_state *get_iteration_state(struct z__b_directory_iterator *it) +static struct iteration_state *get_iteration_state( + struct z__b_directory_iterator *it) { b_queue_entry *last = b_queue_last(&it->state_stack); @@ -115,7 +116,8 @@ static struct iteration_state *get_iteration_state(struct z__b_directory_iterato return b_unbox(struct iteration_state, last, entry); } -static struct iteration_state *push_iteration_state(struct z__b_directory_iterator *it) +static struct iteration_state *push_iteration_state( + struct z__b_directory_iterator *it) { struct iteration_state *state = malloc(sizeof *state); if (!state) { @@ -131,11 +133,11 @@ static struct iteration_state *push_iteration_state(struct z__b_directory_iterat static void pop_iteration_state(struct z__b_directory_iterator *it) { struct iteration_state *state = get_iteration_state(it); - + if (!state) { return; } - + b_queue_pop_back(&it->state_stack); FindClose(state->search); free(state); @@ -185,8 +187,7 @@ static bool move_into_directory(struct b_directory_iterator *it, const char *dir dir_name_p, }; - struct b_path *dir_path - = b_path_join(parts, sizeof parts / sizeof *parts); + struct b_path *dir_path = b_path_join(parts, sizeof parts / sizeof *parts); parts[0] = dir_path; parts[1] = wildcard; @@ -220,7 +221,8 @@ static bool move_into_directory(struct b_directory_iterator *it, const char *dir return true; } -static bool move_to_first_item(struct b_directory_iterator *it, const struct b_path *root_dir) +static bool move_to_first_item( + struct b_directory_iterator *it, const struct b_path *root_dir) { bool has_results = move_into_directory(it, b_path_ptr(root_dir)); @@ -255,7 +257,9 @@ static bool move_to_next_item(struct b_directory_iterator *it) while (true) { struct iteration_state *state = get_iteration_state(it->_z); - if (!state->child_search_complete && (state->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (it->flags & B_DIRECTORY_ITERATE_PARENT_FIRST)) { + if (!state->child_search_complete + && (state->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + && (it->flags & B_DIRECTORY_ITERATE_PARENT_FIRST)) { if (move_into_directory(it, state->data.cFileName)) { return true; } @@ -267,7 +271,8 @@ static bool move_to_next_item(struct b_directory_iterator *it) pop_iteration_state(it->_z); state = get_iteration_state(it->_z); - if (it->flags & B_DIRECTORY_ITERATE_PARENT_FIRST && state != NULL) { + if (it->flags & B_DIRECTORY_ITERATE_PARENT_FIRST + && state != NULL) { state->child_search_complete = true; continue; } @@ -307,7 +312,8 @@ static bool move_to_next_item(struct b_directory_iterator *it) } int b_directory_iterator_begin( - struct b_directory *directory, struct b_directory_iterator *it, enum b_directory_iterator_flags flags) + struct b_directory *directory, struct b_directory_iterator *it, + enum b_directory_iterator_flags flags) { if (b_directory_iterator_is_valid(it)) { cleanup_iterator(it); @@ -357,5 +363,4 @@ bool b_directory_iterator_is_valid(const struct b_directory_iterator *it) static void directory_release(struct b_object *obj) { - -} \ No newline at end of file +}