diff options
Diffstat (limited to 'source/kit/file.c')
-rw-r--r-- | source/kit/file.c | 234 |
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; +} |