summaryrefslogtreecommitdiff
path: root/source/kit/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/kit/file.c')
-rw-r--r--source/kit/file.c234
1 files changed, 206 insertions, 28 deletions
diff --git a/source/kit/file.c b/source/kit/file.c
index c82ef35..7b80e67 100644
--- a/source/kit/file.c
+++ b/source/kit/file.c
@@ -7,19 +7,21 @@
enum { PATH_BUF_SIZE = 4096 };
#if defined(_WIN32) && !defined(__CYGWIN__)
-# include <stdint.h>
-
# ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN 1
+# define WIN32_LEAN_AND_MEAN
# endif
-
-# include <Windows.h>
-
-# include <Shlwapi.h>
+# ifndef NOMINMAX
+# define NOMINMAX
+# endif
+# include <windows.h>
+# include <shlwapi.h>
#else
# include <dirent.h>
+# include <sys/mman.h>
# include <sys/stat.h>
+# include <fcntl.h>
# include <unistd.h>
+# include <limits.h>
#endif
#ifdef __APPLE__
@@ -227,7 +229,7 @@ kit_str_t kit_path_take(kit_str_t path, i64 count) {
}
#if defined(_WIN32) && !defined(__CYGWIN__)
-static void win32_prepare_path_(WCHAR *buf, kit_str_t path) {
+static void kit_win32_prepare_path_(WCHAR *buf, kit_str_t path) {
assert(path.size == 0 || path.values != NULL);
assert(path.size + 5 < PATH_BUF_SIZE);
@@ -246,9 +248,9 @@ static void win32_prepare_path_(WCHAR *buf, kit_str_t path) {
}
# define PREPARE_PATH_BUF_ \
WCHAR buf[PATH_BUF_SIZE]; \
- win32_prepare_path_(buf, path)
+ kit_win32_prepare_path_(buf, path)
#else
-static void unix_prepare_path_(char *buf, kit_str_t path) {
+static void kit_unix_prepare_path_(char *buf, kit_str_t path) {
assert(path.size == 0 || path.values != NULL);
assert(path.size + 1 < PATH_BUF_SIZE);
@@ -258,20 +260,20 @@ static void unix_prepare_path_(char *buf, kit_str_t path) {
}
# define PREPARE_PATH_BUF_ \
char buf[PATH_BUF_SIZE]; \
- unix_prepare_path_(buf, path)
+ kit_unix_prepare_path_(buf, path)
#endif
-kit_status_t kit_file_create_folder(kit_str_t path) {
+kit_status_t kit_folder_create(kit_str_t path) {
PREPARE_PATH_BUF_;
#if defined(_WIN32) && !defined(__CYGWIN__)
return CreateDirectoryW(buf, NULL) ? KIT_OK
: KIT_ERROR_MKDIR_FAILED;
#else
- return mkdir(buf, 0755) == 0 ? KIT_OK : KIT_ERROR_MKDIR_FAILED;
+ return mkdir(buf, 0775) == 0 ? KIT_OK : KIT_ERROR_MKDIR_FAILED;
#endif
}
-kit_status_t kit_file_create_folder_recursive(kit_str_t path) {
+kit_status_t kit_folder_create_recursive(kit_str_t path) {
i64 i;
for (i = 0;; i++) {
@@ -280,7 +282,7 @@ kit_status_t kit_file_create_folder_recursive(kit_str_t path) {
if (type == KIT_PATH_FILE)
return KIT_ERROR_FILE_ALREADY_EXISTS;
if (type == KIT_PATH_NONE) {
- kit_status_t s = kit_file_create_folder(part);
+ kit_status_t s = kit_folder_create(part);
if (s != KIT_OK)
return s;
}
@@ -300,7 +302,7 @@ kit_status_t kit_file_remove(kit_str_t path) {
#endif
}
-kit_status_t kit_file_remove_folder(kit_str_t path) {
+kit_status_t kit_folder_remove(kit_str_t path) {
PREPARE_PATH_BUF_;
#if defined(_WIN32) && !defined(__CYGWIN__)
return RemoveDirectoryW(buf) ? KIT_OK : KIT_ERROR_RMDIR_FAILED;
@@ -315,27 +317,41 @@ kit_status_t kit_file_remove_recursive(kit_str_t path,
i64 i;
switch (type) {
- case KIT_PATH_FILE: return kit_file_remove(path);
+ case KIT_PATH_FILE: {
+ kit_status_t s = kit_file_remove(path);
+ assert(s == KIT_OK);
+ return s;
+ }
case KIT_PATH_FOLDER: {
- kit_path_list_t list = kit_file_enum_folder(path, alloc);
+ kit_path_list_t list = kit_folder_enum(path, alloc);
+
+ assert(list.status == KIT_OK);
if (list.status != KIT_OK) {
kit_path_list_destroy(list);
return list.status;
}
+
for (i = 0; i < list.files.size; i++) {
- str_t s = { .size = list.files.values[i].size,
- .values = list.files.values[i].values };
- kit_file_remove_recursive(s, alloc);
+ str_builder_t full_path = kit_path_join(
+ path, WRAP_STR(list.files.values[i]), alloc);
+ kit_status_t s = kit_file_remove_recursive(
+ WRAP_STR(full_path), alloc);
+ DA_DESTROY(full_path);
+ assert(s == KIT_OK);
}
+
kit_path_list_destroy(list);
- return kit_file_remove_folder(path);
+
+ kit_status_t s = kit_folder_remove(path);
+ assert(s == KIT_OK);
+ return s;
}
default:;
}
- return KIT_ERROR_FILE_DO_NOT_EXIST;
+ return KIT_ERROR_FILE_DOES_NOT_EXIST;
}
kit_path_type_t kit_path_type(kit_str_t path) {
@@ -393,8 +409,8 @@ kit_file_info_t kit_file_info(kit_str_t path) {
if (stat(buf, &info) == 0 && S_ISREG(info.st_mode)) {
result.size = (i64) info.st_size;
# ifndef st_mtime
- /* No support for nanosecond timestamps.
- */
+ // No support for nanosecond timestamps.
+ //
result.time_modified_sec = (i64) info.st_mtime;
# else
result.time_modified_sec = (i64) info.st_mtim.tv_sec;
@@ -405,12 +421,12 @@ kit_file_info_t kit_file_info(kit_str_t path) {
}
#endif
- result.status = KIT_ERROR_FILE_DO_NOT_EXIST;
+ result.status = KIT_ERROR_FILE_DOES_NOT_EXIST;
return result;
}
-kit_path_list_t kit_file_enum_folder(kit_str_t path,
- kit_allocator_t *alloc) {
+kit_path_list_t kit_folder_enum(kit_str_t path,
+ kit_allocator_t *alloc) {
PREPARE_PATH_BUF_;
kit_path_list_t result = { .status = KIT_OK };
@@ -499,3 +515,165 @@ void kit_path_list_destroy(kit_path_list_t list) {
DA_DESTROY(list.files.values[i]);
DA_DESTROY(list.files);
}
+
+kit_mapped_file_t kit_file_map(kit_str_t path, i64 size, i32 mode) {
+ assert(size > 0);
+ assert(path.size > 0);
+ assert(path.size <= PATH_MAX);
+ assert(path.values != NULL);
+
+ kit_mapped_file_t mf;
+ memset(&mf, 0, sizeof mf);
+
+ if (size <= 0) {
+ mf.status = KIT_ERROR_INVALID_SIZE;
+ return mf;
+ }
+
+ if (path.size <= 0) {
+ mf.status = KIT_ERROR_INVALID_ARGUMENT;
+ return mf;
+ }
+
+ if (path.size > PATH_MAX) {
+ mf.status = KIT_ERROR_PATH_TOO_LONG;
+ return mf;
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ char buf[MAX_PATH + 1];
+ memcpy(buf, path.values, path.size);
+ buf[path.size] = '\0';
+
+ HANDLE file = CreateFileA(
+ buf, GENERIC_READ | GENERIC_WRITE,
+ mode == FILE_MAP_SHARED ? FILE_SHARE_READ | FILE_SHARE_WRITE
+ : 0,
+ NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (file == INVALID_HANDLE_VALUE) {
+ mf.status = KIT_ERROR_OPEN_FAILED;
+ return mf;
+ }
+
+ LONG high = (LONG) (size >> 32);
+
+ if (SetFilePointer(file, (LONG) size, &high, FILE_BEGIN) ==
+ INVALID_SET_FILE_POINTER) {
+ CloseHandle(file);
+ assert(0);
+ mf.status = KIT_ERROR_TRUNCATE_FAILED;
+ return mf;
+ }
+
+ if (!SetEndOfFile(file)) {
+ CloseHandle(file);
+ assert(0);
+ mf.status = KIT_ERROR_TRUNCATE_FAILED;
+ return mf;
+ }
+
+ HANDLE map = CreateFileMappingA(file, NULL, PAGE_READWRITE,
+ (DWORD) (size >> 32), (DWORD) size,
+ NULL);
+
+ if (map == INVALID_HANDLE_VALUE) {
+ CloseHandle(file);
+ assert(0);
+ mf.status = KIT_ERROR_MAP_FAILED;
+ return mf;
+ }
+
+ void *p = MapViewOfFile(map, FILE_MAP_ALL_ACCESS, 0, 0,
+ (SIZE_T) size);
+
+ if (p == NULL) {
+ CloseHandle(map);
+ CloseHandle(file);
+ assert(0);
+ mf.status = KIT_ERROR_MAP_FAILED;
+ return mf;
+ }
+
+ mf.status = KIT_OK;
+ mf.size = size;
+ mf.bytes = p;
+ mf._file = file;
+ mf._map = map;
+#else
+ char buf[PATH_MAX + 1];
+ memcpy(buf, path.values, path.size);
+ buf[path.size] = '\0';
+
+ i32 fd = open(buf, O_RDWR | O_CREAT, 0664);
+
+ if (fd == -1) {
+ mf.status = KIT_ERROR_OPEN_FAILED;
+ return mf;
+ }
+
+ if (ftruncate(fd, size) == -1) {
+ close(fd);
+ assert(0);
+ mf.status = KIT_ERROR_TRUNCATE_FAILED;
+ return mf;
+ }
+
+ void *p = mmap(
+ NULL, size, PROT_READ | PROT_WRITE,
+ mode == KIT_FILE_MAP_SHARED ? MAP_SHARED : MAP_PRIVATE, fd, 0);
+
+ if (p == MAP_FAILED) {
+ close(fd);
+ assert(0);
+ mf.status = KIT_ERROR_MAP_FAILED;
+ return mf;
+ }
+
+ mf.status = KIT_OK;
+ mf.size = size;
+ mf.bytes = (u8 *) p;
+ mf._fd = fd;
+#endif
+
+ return mf;
+}
+
+kit_status_t kit_file_sync(kit_mapped_file_t *mf) {
+ assert(mf != NULL);
+
+ if (mf == NULL)
+ return KIT_ERROR_INVALID_ARGUMENT;
+
+ kit_status_t status = KIT_OK;
+
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ if (msync(mf->bytes, mf->size, MS_SYNC) != 0)
+ status |= KIT_ERROR_SYNC_FAILED;
+#endif
+
+ return status;
+}
+
+kit_status_t kit_file_unmap(kit_mapped_file_t *mf) {
+ assert(mf != NULL);
+
+ if (mf == NULL)
+ return KIT_ERROR_INVALID_ARGUMENT;
+
+ kit_status_t status = KIT_OK;
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (!UnmapViewOfFile(mf->bytes))
+ status |= KIT_ERROR_UNMAP_FAILED;
+ if (!CloseHandle(mf->_map) || !CloseHandle(mf->_file))
+ status |= KIT_ERROR_CLOSE_FAILED;
+#else
+ if (munmap(mf->bytes, mf->size) != 0)
+ status |= KIT_ERROR_UNMAP_FAILED;
+ if (close(mf->_fd) != 0)
+ status |= KIT_ERROR_CLOSE_FAILED;
+#endif
+
+ return status;
+}