summaryrefslogtreecommitdiff
path: root/src/util/file
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/file')
-rw-r--r--src/util/file/file.c0
-rw-r--r--src/util/file/file.h82
-rw-r--r--src/util/file/file_linux.c203
-rw-r--r--src/util/file/file_stdio.c100
-rw-r--r--src/util/file/util.c25
5 files changed, 410 insertions, 0 deletions
diff --git a/src/util/file/file.c b/src/util/file/file.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/util/file/file.c
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 <stdio.h>
+#else
+#ifndef _WIN32
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#endif
+#endif
+
+#include <al/str.h>
+
+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 <sys/mman.h>
+#include <al/log.h>
+
+#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 <al/log.h>
+
+#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;
+}