From a723efcc67b6c14ff0dd1efd1ba88596e959daaa Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Tue, 10 Oct 2023 20:59:07 -0400 Subject: Add libakiyo Signed-off-by: Andrew Opalach --- src/util/file/file.c | 0 src/util/file/file.h | 82 ++++++++++++++++++ src/util/file/file_linux.c | 203 +++++++++++++++++++++++++++++++++++++++++++++ src/util/file/file_stdio.c | 100 ++++++++++++++++++++++ src/util/file/util.c | 25 ++++++ 5 files changed, 410 insertions(+) create mode 100644 src/util/file/file.c create mode 100644 src/util/file/file.h create mode 100644 src/util/file/file_linux.c create mode 100644 src/util/file/file_stdio.c create mode 100644 src/util/file/util.c (limited to 'src/util/file') diff --git a/src/util/file/file.c b/src/util/file/file.c new file mode 100644 index 0000000..e69de29 diff --git a/src/util/file/file.h b/src/util/file/file.h new file mode 100644 index 0000000..465d76a --- /dev/null +++ b/src/util/file/file.h @@ -0,0 +1,82 @@ +#pragma once + +#ifdef AKIYO_FILE_STDIO_COMPAT +#include +#else +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#endif +#endif + +#include + +enum { + AKI_ENTRY_FILE = 0, + AKI_ENTRY_DIR, + AKI_ENTRY_OTHER +}; + +struct aki_file { +#ifdef AKIYO_FILE_STDIO_COMPAT + FILE *file; +#else +#ifndef _WIN32 + s32 fd; +#else + // WINDOWS +#endif +#endif + size_t filesize; +}; + +struct aki_dir { +#ifdef AKIYO_FILE_STDIO_COMPAT +#else +#ifndef _WIN32 + DIR *dir; +#else + // WINDOWS +#endif +#endif + str path; +}; + +struct aki_dir_entry { + u8 type; +#ifdef AKIYO_FILE_STDIO_COMPAT +#else +#ifndef _WIN32 + struct dirent *entry; +#else + // WINDOWS +#endif +#endif + str name; + str path; +}; + +bool aki_file_open(struct aki_file *file, str *path, bool create); +bool aki_file_exists(str *path); +bool aki_file_truncate(struct aki_file *file, off_t size); +off_t aki_file_seek(struct aki_file *file, off_t offset, s32 whence); +size_t aki_file_get_filesize(struct aki_file *file); +bool aki_file_write(struct aki_file *file, void *buf, size_t size); +bool aki_file_read(struct aki_file *file, void *buf, size_t size); +s32 aki_file_read_as_str(struct aki_file *file, str *out); +s32 aki_file_read_as_c_str(struct aki_file *file, char **out); +void *aki_file_mmap(struct aki_file *file); +void *aki_file_mremap(struct aki_file *file, size_t size, void *old_map); +void aki_file_munmap(struct aki_file *file, void *map); +void aki_file_close(struct aki_file *file); + +bool aki_dir_open(struct aki_dir *dir, str *path); +void aki_dir_close(struct aki_dir *dir); +bool aki_dir_exists(str *path); +bool aki_dir_create(str *path); +bool aki_dir_read(struct aki_dir *dir, struct aki_dir_entry *entry); +void aki_dir_entry_free(struct aki_dir_entry *entry); diff --git a/src/util/file/file_linux.c b/src/util/file/file_linux.c new file mode 100644 index 0000000..97e9688 --- /dev/null +++ b/src/util/file/file_linux.c @@ -0,0 +1,203 @@ +#include +#include + +#include "../error.h" + +#include "file.h" + +bool aki_file_open(struct aki_file *file, str *path, bool create) +{ + char *c_str = al_str_to_c_str(path); + s32 flags = O_RDWR; + if (create) flags |= O_CREAT; + file->fd = open(c_str, flags, 0666); + al_free(c_str); + if (file->fd == -1) { + al_log_error("file", "open(%.*s) failed (%s).", AL_STR_PRINTF(path), aki_strerror(errno)); + return false; + } + struct stat sb; + s32 res = fstat(file->fd, &sb); + if (res == -1) { + al_log_error("file", "fstat() failed (%s).", aki_strerror(errno)); + close(file->fd); + return false; + } + file->filesize = sb.st_size; + return true; +} + +bool aki_file_exists(str *path) +{ + char *c_str = al_str_to_c_str(path); + s32 ret = access(c_str, F_OK); + al_free(c_str); + if (ret != 0) { + al_log_error("file", "access(%.*s, F_OK) failed (%s).", AL_STR_PRINTF(path), aki_strerror(errno)); + } + return ret == 0; +} + +off_t aki_file_seek(struct aki_file *file, off_t offset, s32 whence) +{ + off_t res = lseek(file->fd, offset, whence); + if (res == (off_t)-1) { + al_log_error("file", "lseek(%jd, %d) failed (%s).", (intmax_t)offset, whence, aki_strerror(errno)); + } + return res; +} + +bool aki_file_truncate(struct aki_file *file, off_t size) +{ + s32 ret = ftruncate(file->fd, size); + if (ret != 0) { + al_log_error("file", "ftruncate(%jd) failed (%s).", (intmax_t)size, aki_strerror(errno)); + return false; + } + file->filesize = size; + return true; +} + +size_t aki_file_get_filesize(struct aki_file *file) +{ + return file->filesize; +} + +#define file_io_loop(call, fail_case) \ + size_t bc = 0; \ + ssize_t res; \ + do { \ + res = call(file->fd, buf, size - bc); \ + if (fail_case) { \ + al_log_error("file", ""#call"() failed (%s).", aki_strerror(errno)); \ + return false; \ + } \ + bc += res; \ + } while (bc < size); \ + return true + +bool aki_file_write(struct aki_file *file, void *buf, size_t size) +{ + file_io_loop(write, (res == -1)); +} + +bool aki_file_read(struct aki_file *file, void *buf, size_t size) +{ + file_io_loop(read, (res == -1)); +} + +void *aki_file_mmap(struct aki_file *file) +{ + void *map = mmap(NULL, file->filesize, PROT_READ | PROT_WRITE, MAP_SHARED, file->fd, 0L); + if (map == MAP_FAILED) { + al_log_error("file", "mmap() failed (%s).", aki_strerror(errno)); + return NULL; + } + return map; +} + +void *aki_file_mremap(struct aki_file *file, size_t size, void *old_map) +{ + printf("old_size: %zu, new_size: %zu\n", file->filesize, size); + void *map = mremap(old_map, file->filesize, size, MREMAP_MAYMOVE); + if (map == MAP_FAILED) { + al_log_error("file", "mremap(%p, %zu, %zu) failed (%s).", old_map, + file->filesize, size, aki_strerror(errno)); + return NULL; + } + return map; +} + +void aki_file_munmap(struct aki_file *file, void *map) +{ + s32 ret = munmap(map, file->filesize); + if (ret != 0) { + al_log_error("file", "munmap(%p, %zu) failed (%s).", map, file->filesize, aki_strerror(errno)); + } +} + +void aki_file_close(struct aki_file *file) +{ + close(file->fd); +} + +bool aki_dir_open(struct aki_dir *dir, str *path) +{ + char *c_str = al_str_to_c_str(path); + dir->dir = opendir(c_str); + al_free(c_str); + if (!dir->dir) { + al_log_error("file", "opendir(%.*s) failed (%s).", AL_STR_PRINTF(path), aki_strerror(errno)); + return false; + } + al_str_clone(&dir->path, path); + return true; +} + +void aki_dir_close(struct aki_dir *dir) +{ + al_str_free(&dir->path); + closedir(dir->dir); +} + +bool aki_dir_exists(str *path) +{ + struct aki_dir dir; + char *c_str = al_str_to_c_str(path); + dir.dir = opendir(c_str); + al_free(c_str); + if (!dir.dir) { + if (errno != ENOENT) { + al_log_error("file", "opendir(%.*s) failed (%s).", AL_STR_PRINTF(path), aki_strerror(errno)); + } + return false; + } + return true; +} + +bool aki_dir_create(str *path) +{ + char *c_str = al_str_to_c_str(path); + s32 ret = mkdir(c_str, 0700); + al_free(c_str); + if (ret == -1) { + al_log_error("file", "mkdir(%.*s) failed (%s).", AL_STR_PRINTF(path), aki_strerror(errno)); + return false; + } + return true; +} + +bool aki_dir_read(struct aki_dir *dir, struct aki_dir_entry *entry) +{ + errno = 0; + entry->entry = readdir(dir->dir); + if (!entry->entry) { + if (errno) { + al_log_error("file", "readdir() failed (%s).", aki_strerror(errno)); + } + return false; + } + switch (entry->entry->d_type) { + case DT_REG: + case DT_UNKNOWN: + entry->type = AKI_ENTRY_FILE; + break; + case DT_DIR: + entry->type = AKI_ENTRY_DIR; + break; + default: + entry->type = AKI_ENTRY_OTHER; + break; + } + al_str_clone(&entry->name, al_str_c(entry->entry->d_name)); + al_str_clone(&entry->path, &dir->path); + al_str_cat(&entry->path, al_str_c("/")); + al_str_cat(&entry->path, &entry->name); + return true; +} + +void aki_dir_entry_free(struct aki_dir_entry *entry) +{ + al_str_free(&entry->name); + al_str_free(&entry->path); +} diff --git a/src/util/file/file_stdio.c b/src/util/file/file_stdio.c new file mode 100644 index 0000000..52d8761 --- /dev/null +++ b/src/util/file/file_stdio.c @@ -0,0 +1,100 @@ +#include + +#include "../error.h" + +#include "file.h" + +bool aki_file_open(struct aki_file *file, str *path, bool create) +{ + char *c_str = al_str_to_c_str(path); + const char *mode = create ? "wb+" : "rb+"; +#ifndef _WIN32 + file->file = fopen(c_str, mode); +#else + errno_t ret = fopen_s(&file->file, c_str, mode); +#endif + al_free(c_str); +#ifndef _WIN32 + if (!file->file) { +#else + if (ret != 0) { +#endif + al_log_error("file_stdio", "fopen(%.*s) failed (%s).", AL_STR_PRINTF(path), aki_strerror(errno)); + return false; + } + off_t pos = aki_file_seek(file, 0, SEEK_END); + if (pos == -1) { + aki_file_close(file); + return false; + } + file->filesize = pos; + rewind(file->file); + return true; +} + +bool aki_file_exists(str *path) +{ + (void)path; + return false; +} + +off_t aki_file_seek(struct aki_file *file, off_t offset, s32 whence) +{ + if (fseek(file->file, offset, whence) != 0) { + al_log_error("file_stdio", "fseek(%jd, %d) failed (%s).", (intmax_t)offset, + whence, aki_strerror(errno)); + return -1; + } + return ftell(file->file); +} + +bool aki_file_truncate(struct aki_file *file, off_t size) +{ + (void)file; + (void)size; + return true; +} + +size_t aki_file_get_filesize(struct aki_file *file) +{ + return file->filesize; +} + +bool aki_file_write(struct aki_file *file, void *buf, size_t size) +{ + size_t ret = fwrite(buf, size, 1, file->file); + if (ret == 0) { + al_log_error("file_stdio", "fwrite(%zu) failed (%s).", size, aki_strerror(errno)); + return false; + } + return true; +} + +bool aki_file_read(struct aki_file *file, void *buf, size_t size) +{ + size_t ret = fread(buf, size, 1, file->file); + if (ret == 0) { + al_log_error("file_stdio", "fread(%zu) failed (%s).", size, aki_strerror(errno)); + return false; + } + return true; +} + +void *aki_file_mmap(struct aki_file *file) +{ + (void)file; + al_assert(false); + return NULL; +} + +void aki_file_close(struct aki_file *file) +{ + fclose(file->file); +} + +bool aki_dir_open(struct aki_dir *dir, str *path) { (void)dir; (void)path; return false; } +void aki_dir_close(struct aki_dir *dir) { (void)dir; } +bool aki_dir_exists(str *path) { (void)path; return false; } +bool aki_dir_create(str *path) { (void)path; return false; } +bool aki_dir_read(struct aki_dir *dir, struct aki_dir_entry *entry) { (void)dir; (void)entry; return false; } +void aki_dir_entry_free(struct aki_dir_entry *entry) { (void)entry; } diff --git a/src/util/file/util.c b/src/util/file/util.c new file mode 100644 index 0000000..e893de7 --- /dev/null +++ b/src/util/file/util.c @@ -0,0 +1,25 @@ +#include "file.h" + +s32 aki_file_read_as_str(struct aki_file *file, str *out) +{ + size_t size = file->filesize; + al_str_sized(out, size); + if (!aki_file_read(file, (void *)out->data, size)) { + al_str_free(out); + return -1; + } + out->len = size; + return size; +} + +s32 aki_file_read_as_c_str(struct aki_file *file, char **out) +{ + size_t size = file->filesize; + *out = al_malloc(size + 1); + if (!aki_file_read(file, (void *)*out, size)) { + al_free(*out); + return -1; + } + (*out)[size] = '\n'; + return size; +} -- cgit v1.2.3-101-g0448