diff --git a/io/include/blue/io/directory.h b/io/include/blue/io/directory.h index 8a6e2d1..6dd5825 100644 --- a/io/include/blue/io/directory.h +++ b/io/include/blue/io/directory.h @@ -7,6 +7,7 @@ #include #include +#define B_DIRECTORY(p) ((b_directory *)(p)) #define B_DIRECTORY_ROOT ((b_directory *)NULL) typedef struct b_directory b_directory; @@ -36,6 +37,16 @@ typedef struct b_directory_iterator { BLUE_API b_status b_directory_open( b_directory *root, const b_path *path, b_directory **out); +BLUE_API const b_path *b_directory_get_path(const b_directory *dir); + +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_directory( + const b_directory *root, const b_path *path); +BLUE_API b_status b_directory_path_stat( + const b_directory *root, const b_path *path, struct b_file_info *out); +BLUE_API b_status b_directory_path_unlink( + const b_directory *root, const b_path *path); BLUE_API int b_directory_iterator_begin( b_directory *directory, b_directory_iterator *it, @@ -44,4 +55,14 @@ 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_OBJECT(dir))); +} + +static inline void b_directory_release(b_directory *dir) +{ + b_release(B_OBJECT(dir)); +} + #endif diff --git a/io/include/blue/io/file.h b/io/include/blue/io/file.h index f7f0a3e..70fc4d9 100644 --- a/io/include/blue/io/file.h +++ b/io/include/blue/io/file.h @@ -5,11 +5,19 @@ #include #include -#define B_FILE(p) ((b_file *)(p)) +#define B_FILE(p) ((b_file *)(p)) + +#define B_OFFSET_CURRENT ((size_t) - 1) struct b_directory; struct b_path; +typedef enum b_seek_basis { + B_SEEK_BEGINNING, + B_SEEK_CURRENT, + B_SEEK_END +} b_seek_basis; + typedef enum b_file_attribute { B_FILE_ATTRIB_NORMAL = 0x01u, B_FILE_ATTRIB_DIRECTORY = 0x02u, @@ -21,10 +29,14 @@ typedef enum 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_READ_WRITE = B_FILE_READ_ONLY | B_FILE_WRITE_ONLY, B_FILE_TRUNCATE = 0x04u, - B_FILE_APPEND = 0x08u, - B_FILE_BINARY = 0x10u, + B_FILE_CREATE = 0x08u, + B_FILE_CREATE_ONLY = 0x10u | B_FILE_CREATE, + B_FILE_APPEND = 0x20u, + B_FILE_BINARY = 0x40u, + B_FILE_DELETE_ON_CLOSE = 0x80u, + B_FILE_SHADOW = 0x100u, } b_file_mode; typedef struct b_file_info { @@ -36,11 +48,26 @@ typedef struct b_file_info { typedef struct b_file b_file; -BLUE_API enum b_status b_file_open( +BLUE_API b_status b_file_open( struct b_directory *root, const struct b_path *path, b_file_mode mode, b_file **out); +BLUE_API b_status b_file_open_temp(b_file_mode mode, b_file **out); +BLUE_API b_status b_file_open_shadow( + b_file *original, b_file_mode mode, b_file **out); -BLUE_API enum b_status b_file_stat(b_file *file, b_file_info *out); +BLUE_API b_status b_file_stat(b_file *file, b_file_info *out); +BLUE_API b_status b_file_size(b_file *file, size_t *out_len); +BLUE_API b_status b_file_cursor(b_file *file, size_t *out_pos); +BLUE_API b_status b_file_resize(b_file *file, size_t len); +BLUE_API b_status b_file_seek(b_file *file, long long offset, b_seek_basis basis); + +BLUE_API b_status b_file_swap_shadow(b_file *main_file, b_file *shadow_file); + +BLUE_API b_status b_file_read( + b_file *file, size_t offset, size_t len, void *buf, size_t *nr_read); +BLUE_API b_status b_file_write( + b_file *file, size_t offset, size_t len, const void *buf, + size_t *nr_written); static inline b_file *b_file_retain(b_file *file) { diff --git a/io/include/blue/io/path.h b/io/include/blue/io/path.h index 850cca6..2cae7d3 100644 --- a/io/include/blue/io/path.h +++ b/io/include/blue/io/path.h @@ -6,7 +6,9 @@ #include #include -#define B_PATH(p) ((b_path *)p) +#define B_PATH(p) ((b_path *)p) + +#define B_RV_PATH(cstr) B_RV(b_path_create_from_str(cstr)) struct b_file_info; @@ -27,7 +29,13 @@ 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 b_status b_path_stat(const b_path *path, struct b_file_info *out); +BLUE_API b_status b_path_unlink(const b_path *path); + +BLUE_API enum b_status b_path_get_directory( + const b_path *path, b_path **out_dir_path); +BLUE_API enum b_status b_path_get_filename( + const b_path *path, struct b_string *out_name); 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 c4dc640..5c893a3 100644 --- a/io/sys/darwin/directory.c +++ b/io/sys/darwin/directory.c @@ -1,4 +1,4 @@ -#include "status.h" +#include "posix.h" #include #include @@ -79,6 +79,112 @@ enum b_status b_directory_open( return B_SUCCESS; } +const struct b_path *b_directory_get_path(const struct b_directory *dir) +{ + return dir->abs_path; +} + +bool b_directory_path_exists( + const struct b_directory *root, const struct 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; +} + +bool b_directory_path_is_file( + const struct b_directory *root, const struct 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; +} + +bool b_directory_path_is_directory( + const struct b_directory *root, const struct 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; +} + +enum b_status b_directory_path_stat( + const struct b_directory *root, const struct 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_ERR_NO_MEMORY; + } + + enum b_status status = b_path_stat(abs_path, out); + b_path_release(abs_path); + + return status; +} + +enum b_status b_directory_path_unlink( + const struct b_directory *root, const struct 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 B_ERR_NO_MEMORY; + } + + enum b_status status = b_path_unlink(abs_path); + b_path_release(abs_path); + + return status; +} + static int ftsent_compare(const FTSENT **one, const FTSENT **two) { return (strcmp((*one)->fts_name, (*two)->fts_name)); @@ -151,6 +257,8 @@ int b_directory_iterator_begin( struct 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; @@ -286,4 +394,8 @@ bool b_directory_iterator_is_valid(const struct b_directory_iterator *it) static void directory_release(struct b_object *obj) { + struct b_directory *dir = B_DIRECTORY(obj); + + close(dir->fd); + b_path_release(dir->abs_path); } diff --git a/io/sys/darwin/file.c b/io/sys/darwin/file.c index e69de29..6073b05 100644 --- a/io/sys/darwin/file.c +++ b/io/sys/darwin/file.c @@ -0,0 +1,390 @@ +#include "posix.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct b_file { + struct b_object base; + enum b_file_mode mode; + int fd; + struct b_path *path; +}; + +static void file_release(struct b_object *obj); + +static struct b_object_type file_type = { + .t_name = "corelib::file", + .t_flags = B_OBJECT_FUNDAMENTAL, + .t_id = B_OBJECT_TYPE_FILE, + .t_instance_size = sizeof(struct b_file), + .t_release = file_release, +}; + +static unsigned int b_mode_to_unix_mode(enum b_file_mode mode) +{ + unsigned int result = 0; + + if (mode & B_FILE_READ_WRITE) { + result |= O_RDWR; + } else if (mode & B_FILE_READ_ONLY) { + result |= O_RDONLY; + } else if (mode & B_FILE_WRITE_ONLY) { + result |= O_WRONLY; + } else { + return 0; + } + + if (mode & B_FILE_TRUNCATE) { + result |= O_TRUNC; + } + + if (mode & B_FILE_CREATE) { + result |= O_CREAT; + } + + if ((mode & B_FILE_CREATE_ONLY) == B_FILE_CREATE_ONLY) { + result |= O_EXCL; + } + + return result; +} + +enum b_status b_file_open( + struct b_directory *root, const struct b_path *path, + enum b_file_mode mode, struct b_file **out) +{ + struct b_path *file_path = b_path_retain((struct b_path *)path); + unsigned int flags = b_mode_to_unix_mode(mode); + + if (flags == 0) { + b_path_release(file_path); + return B_ERR_INVALID_ARGUMENT; + } + + struct b_path *root_path = NULL; + if (root) { + root_path = b_path_retain( + (struct b_path *)b_directory_get_path(root)); + } else { + root_path = b_path_create_cwd(); + } + + const struct b_path *parts[] = { + root_path, + file_path, + }; + + struct b_path *abs_path + = b_path_join(parts, sizeof parts / sizeof parts[0]); + b_path_release(root_path); + b_path_release(file_path); + + if (!abs_path) { + return B_ERR_NO_MEMORY; + } + + int fd = open(b_path_ptr(abs_path), flags, 0644); + if (fd == -1) { + b_path_release(abs_path); + return b_status_from_errno(errno, B_ERR_IO_FAILURE); + } + + struct b_file *file + = (struct b_file *)b_object_type_instantiate(&file_type); + if (!file) { + close(fd); + b_path_release(abs_path); + return B_ERR_NO_MEMORY; + } + + file->fd = fd; + file->path = abs_path; + file->mode = mode; + + *out = file; + return B_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; +} + +enum b_status b_file_open_temp(enum b_file_mode mode, struct b_file **out) +{ + mode |= B_FILE_DELETE_ON_CLOSE; + + char name[16]; + char path[128]; + + while (1) { + generate_tmp_filename(name, sizeof name); + snprintf(path, sizeof path, "/tmp/%s", name); + struct b_path *rpath = b_path_create_from_cstr(path); + + enum b_status status = b_file_open( + B_DIRECTORY_ROOT, rpath, mode | B_FILE_CREATE_ONLY, out); + + if (status == B_ERR_NAME_EXISTS) { + b_path_release(rpath); + continue; + } + + b_path_unlink(rpath); + b_path_release(rpath); + + return status; + } +} + +enum b_status b_file_open_shadow( + struct b_file *original, enum b_file_mode mode, struct b_file **out) +{ + mode |= B_FILE_SHADOW | B_FILE_DELETE_ON_CLOSE | B_FILE_CREATE; + + struct b_path *dir; + b_path_get_directory(original->path, &dir); + + struct b_string *filename = b_string_create(); + b_path_get_filename(original->path, filename); + + b_string_prepend_cstr(filename, ".~"); + + struct b_path *shadow_filename + = b_path_create_from_cstr(b_string_ptr(filename)); + b_string_release(filename); + + const struct b_path *parts[] = { + dir, + shadow_filename, + }; + + struct b_path *shadow_filepath + = b_path_join(parts, sizeof parts / sizeof parts[0]); + b_path_release(dir); + b_path_release(shadow_filename); + + if (b_path_exists(shadow_filepath)) { + b_path_unlink(shadow_filepath); + } + + struct b_file *shadow_file; + enum b_status status = b_file_open( + B_DIRECTORY_ROOT, shadow_filepath, mode, &shadow_file); + b_path_release(shadow_filepath); + + if (!B_OK(status)) { + return status; + } + + *out = shadow_file; + return B_SUCCESS; +} + +enum b_status b_file_stat(struct b_file *file, struct b_file_info *out) +{ + struct stat st; + int err = fstat(file->fd, &st); + + if (err != 0) { + return b_status_from_errno(errno, B_ERR_IO_FAILURE); + } + + memset(out, 0x0, sizeof *out); + + return b_file_info_from_stat(&st, out); +} + +enum b_status b_file_size(struct b_file *file, size_t *out_len) +{ + off_t cur = lseek(file->fd, 0, SEEK_CUR); + if (cur == (off_t)-1) { + return b_status_from_errno(errno, B_ERR_IO_FAILURE); + } + + off_t len = lseek(file->fd, 0, SEEK_END); + if (len == (off_t)-1) { + return b_status_from_errno(errno, B_ERR_IO_FAILURE); + } + + cur = lseek(file->fd, cur, SEEK_SET); + if (cur == (off_t)-1) { + return b_status_from_errno(errno, B_ERR_IO_FAILURE); + } + + *out_len = (size_t)len; + return B_SUCCESS; +} + +enum b_status b_file_cursor(struct b_file *file, size_t *out_pos) +{ + off_t cur = lseek(file->fd, 0, SEEK_CUR); + if (cur == (off_t)-1) { + return b_status_from_errno(errno, B_ERR_IO_FAILURE); + } + + *out_pos = (size_t)cur; + return B_SUCCESS; +} + +enum b_status b_file_resize(struct b_file *file, size_t len) +{ + int err = ftruncate(file->fd, len); + if (err == 0) { + return B_SUCCESS; + } + + return b_status_from_errno(errno, B_ERR_IO_FAILURE); +} + +enum b_status b_file_seek( + struct b_file *file, long long offset, enum b_seek_basis basis) +{ + int whence; + switch (basis) { + case B_SEEK_BEGINNING: + whence = SEEK_SET; + break; + case B_SEEK_CURRENT: + whence = SEEK_CUR; + break; + case B_SEEK_END: + whence = SEEK_END; + break; + default: + return B_ERR_INVALID_ARGUMENT; + } + + int err = lseek(file->fd, offset, whence); + if (err == 0) { + return B_SUCCESS; + } + + return b_status_from_errno(errno, B_ERR_IO_FAILURE); +} + +enum b_status b_file_swap_shadow(struct b_file *main_file, struct b_file *shadow_file) +{ + if (main_file->mode & B_FILE_SHADOW) { + return B_ERR_NOT_SUPPORTED; + } + + if (!(shadow_file->mode & B_FILE_SHADOW)) { + return B_ERR_NOT_SUPPORTED; + } + + struct b_path *dir_path; + b_path_get_directory(main_file->path, &dir_path); + + struct b_path *tmp_path = NULL; + + while (1) { + char tmp_name[16]; + generate_tmp_filename(tmp_name, sizeof tmp_name); + struct b_path *tmp_name_p = b_path_create_from_cstr(tmp_name); + + const struct b_path *parts[] = { + dir_path, + tmp_name_p, + }; + + tmp_path = b_path_join(parts, sizeof parts / sizeof parts[0]); + + b_path_release(tmp_name_p); + + if (!b_path_exists(tmp_path)) { + break; + } + + b_path_release(tmp_path); + tmp_path = NULL; + } + + b_path_release(dir_path); + + int err; + + err = rename(b_path_ptr(main_file->path), b_path_ptr(tmp_path)); + err = rename(b_path_ptr(shadow_file->path), b_path_ptr(main_file->path)); + err = rename(b_path_ptr(tmp_path), b_path_ptr(shadow_file->path)); + + b_path_release(tmp_path); + + int fd = main_file->fd; + main_file->fd = shadow_file->fd; + shadow_file->fd = fd; + + return B_SUCCESS; +} + +enum b_status b_file_read( + struct b_file *file, size_t offset, size_t len, void *buf, size_t *nr_read) +{ + if (offset != B_OFFSET_CURRENT) { + lseek(file->fd, offset, SEEK_SET); + } + + long r = read(file->fd, buf, len); + + enum b_status status = B_SUCCESS; + + if (r < 0) { + status = b_status_from_errno(errno, B_ERR_IO_FAILURE); + } + + *nr_read = r; + return status; +} + +enum b_status b_file_write( + struct b_file *file, size_t offset, size_t len, const void *buf, + size_t *nr_written) +{ + if (offset != B_OFFSET_CURRENT) { + lseek(file->fd, offset, SEEK_SET); + } + + long w = write(file->fd, buf, len); + + enum b_status status = B_SUCCESS; + + if (w < 0) { + status = b_status_from_errno(errno, B_ERR_IO_FAILURE); + } + + *nr_written = w; + return status; +} + +static void file_release(struct b_object *obj) +{ + struct b_file *file = (struct b_file *)obj; + close(file->fd); + + if (file->mode & B_FILE_DELETE_ON_CLOSE) { + b_path_unlink(file->path); + } + + b_path_release(file->path); +} diff --git a/io/sys/darwin/path.c b/io/sys/darwin/path.c index abbe0fd..55007e7 100644 --- a/io/sys/darwin/path.c +++ b/io/sys/darwin/path.c @@ -1,4 +1,4 @@ -#include "status.h" +#include "posix.h" #include #include @@ -216,27 +216,65 @@ enum b_status b_path_stat(const b_path *path, struct b_file_info *out) memset(out, 0x0, sizeof *out); - out->length = st.st_size; + return b_file_info_from_stat(&st, out); +} - if (S_ISREG(st.st_flags)) { - out->attrib |= B_FILE_ATTRIB_NORMAL; +enum b_status b_path_unlink(const b_path *path) +{ + int err = unlink(b_string_ptr(path->pathstr)); + return err == 0 ? B_SUCCESS : b_status_from_errno(errno, B_ERR_IO_FAILURE); +} + +enum b_status b_path_get_directory( + const struct b_path *path, struct b_path **out_dir_path) +{ + struct b_string *path_str = path->pathstr; + long len = b_string_get_size(path_str, B_STRLEN_NORMAL); + + const char *path_cstr = b_string_ptr(path_str); + char *sep = strrchr(path_cstr, '/'); + + if (!sep) { + *out_dir_path = b_path_create(); + return B_SUCCESS; } - if (S_ISDIR(st.st_flags)) { - out->attrib |= B_FILE_ATTRIB_DIRECTORY; + size_t dir_path_len = (size_t)(sep - path_cstr); + struct b_string *dir_path_s = b_string_substr(path_str, 0, dir_path_len); + + struct b_path *dir_path + = b_path_create_from_cstr(b_string_ptr(dir_path_s)); + b_string_release(dir_path_s); + + *out_dir_path = dir_path; + + return B_SUCCESS; +} + +enum b_status b_path_get_filename( + const struct b_path *path, struct b_string *out_name) +{ + struct b_string *path_str = path->pathstr; + long len = b_string_get_size(path_str, B_STRLEN_NORMAL); + + char *sep = strrchr(b_string_ptr(path_str), '/'); + + if (!sep) { + b_string_append_s(out_name, path_str); + return B_SUCCESS; } - if (S_ISBLK(st.st_flags)) { - out->attrib |= B_FILE_ATTRIB_BLOCK_DEVICE; + const char *filename = sep; + while (*filename == '/' && *filename != '\0') { + filename++; } - if (S_ISCHR(st.st_flags)) { - out->attrib |= B_FILE_ATTRIB_CHAR_DEVICE; + if (*filename == '\0') { + b_string_clear(out_name); + return B_SUCCESS; } - if (S_ISLNK(st.st_flags)) { - out->attrib |= B_FILE_ATTRIB_SYMLINK; - } + b_string_append_cstr(out_name, filename); return B_SUCCESS; } diff --git a/io/sys/darwin/posix.c b/io/sys/darwin/posix.c new file mode 100644 index 0000000..77ae01c --- /dev/null +++ b/io/sys/darwin/posix.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include + +enum b_status b_status_from_errno(int error, enum b_status default_value) +{ + switch (error) { + case 0: + return B_SUCCESS; + case ENOENT: + return B_ERR_NO_ENTRY; + case EEXIST: + return B_ERR_NAME_EXISTS; + case ENOMEM: + return B_ERR_NO_MEMORY; + case EINVAL: + return B_ERR_INVALID_ARGUMENT; + case EIO: + return B_ERR_IO_FAILURE; + case EISDIR: + return B_ERR_IS_DIRECTORY; + case ENOTDIR: + return B_ERR_NOT_DIRECTORY; + case ENOTSUP: + case ENOSYS: + return B_ERR_NOT_SUPPORTED; + default: + return default_value; + } +} + +enum b_status b_file_info_from_stat(const struct stat *st, struct b_file_info *out) +{ + out->length = st->st_size; + + if (S_ISREG(st->st_mode)) { + out->attrib |= B_FILE_ATTRIB_NORMAL; + } + + if (S_ISDIR(st->st_mode)) { + out->attrib |= B_FILE_ATTRIB_DIRECTORY; + } + + if (S_ISBLK(st->st_mode)) { + out->attrib |= B_FILE_ATTRIB_BLOCK_DEVICE; + } + + if (S_ISCHR(st->st_mode)) { + out->attrib |= B_FILE_ATTRIB_CHAR_DEVICE; + } + + if (S_ISLNK(st->st_mode)) { + out->attrib |= B_FILE_ATTRIB_SYMLINK; + } + + return B_SUCCESS; +} diff --git a/io/sys/darwin/posix.h b/io/sys/darwin/posix.h new file mode 100644 index 0000000..7efffe9 --- /dev/null +++ b/io/sys/darwin/posix.h @@ -0,0 +1,13 @@ +#ifndef _IO_DARWIN_POSIX_H_ +#define _IO_DARWIN_POSIX_H_ + +#include + +struct stat; +struct b_file_info; + +extern enum b_status b_status_from_errno(int error, enum b_status default_value); +extern enum b_status b_file_info_from_stat( + const struct stat *in, struct b_file_info *out); + +#endif diff --git a/io/sys/darwin/status.c b/io/sys/darwin/status.c deleted file mode 100644 index d446b7e..0000000 --- a/io/sys/darwin/status.c +++ /dev/null @@ -1,12 +0,0 @@ -#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 deleted file mode 100644 index 801e170..0000000 --- a/io/sys/darwin/status.h +++ /dev/null @@ -1,8 +0,0 @@ -#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