diff --git a/Source/DrangPlatform/Source/win32/fs/dir.c b/Source/DrangPlatform/Source/win32/fs/dir.c new file mode 100644 index 0000000..1f4f069 --- /dev/null +++ b/Source/DrangPlatform/Source/win32/fs/dir.c @@ -0,0 +1,154 @@ +#include "internal.h" +#include "win32/common.h" +#include +#include +#include +#include + +int drang_fs_mkdir(const char *path, drang_fs_permissions_t permissions) +{ + DRANG_BEGIN_TRY() + DRANG_UNUSED(permissions); // Permissions are not used on Windows + + if (!CreateDirectoryA(path, NULL)) { + DRANG_FAIL(win32_error_to_drang(GetLastError())); + } + + DRANG_END_TRY_IGNORE() +} + +int drang_fs_rmdir(const char *path) +{ + DRANG_BEGIN_TRY() + if (!RemoveDirectoryA(path)) { + DRANG_FAIL(win32_error_to_drang(GetLastError())); + } + DRANG_END_TRY_IGNORE() +} + +int drang_fs_opendir(const char *path, drang_fs_directory_t **out_directory) +{ + struct drang_fs_directory *fs_dir = NULL; + char search_path[MAX_PATH]; + DRANG_BEGIN_TRY() + DRANG_FAIL_IF_NULL(path, DRANG_EINVAL); + DRANG_FAIL_IF_NULL(out_directory, DRANG_EINVAL); + + fs_dir = DRANG_TRY_CALLOC_T(struct drang_fs_directory); + snprintf(search_path, MAX_PATH, "%s\\*", path); + fs_dir->handle = FindFirstFileA(search_path, &fs_dir->find_data); + if (fs_dir->handle == INVALID_HANDLE_VALUE) { + DRANG_FAIL(win32_error_to_drang(GetLastError())); + } + fs_dir->first_entry = true; + DRANG_RETURN_IN(out_directory, fs_dir); + + DRANG_CATCH(_) + { + if (fs_dir) { + if (fs_dir->handle != INVALID_HANDLE_VALUE) { + FindClose(fs_dir->handle); + } + drang_free(fs_dir); + } + } + + DRANG_END_TRY() +} + +static int skip_invalid_entries(struct drang_fs_directory *dir) +{ + DRANG_BEGIN_TRY() + + while (strcmp(dir->find_data.cFileName, ".") == 0 || strcmp(dir->find_data.cFileName, "..") == 0) { + if (!FindNextFileA(dir->handle, &dir->find_data)) { + const DWORD err = GetLastError(); + if (err == ERROR_NO_MORE_FILES) { + DRANG_FAIL(DRANG_ENOENT); + } + DRANG_FAIL(win32_error_to_drang(err)); + } + } + + DRANG_END_TRY_IGNORE() +} + +int drang_fs_readdir(drang_fs_directory_t *directory, drang_fs_dir_entry_t *out_entry) +{ + DRANG_BEGIN_TRY() + DRANG_FAIL_IF_NULL(directory, DRANG_EINVAL); + DRANG_FAIL_IF_NULL(out_entry, DRANG_EINVAL); + + if (directory->first_entry) { + directory->first_entry = false; + DRANG_TRY(skip_invalid_entries(directory)); + } else { + if (!FindNextFileA(directory->handle, &directory->find_data)) { + const DWORD err = GetLastError(); + if (err == ERROR_NO_MORE_FILES) { + DRANG_FAIL(DRANG_ENOENT); + } + DRANG_FAIL(win32_error_to_drang(err)); + } + + DRANG_TRY(skip_invalid_entries(directory)); + } + + strncpy(out_entry->name, directory->find_data.cFileName, DRANG_FS_MAX_REL_PATH_SIZE); + out_entry->name[DRANG_FS_MAX_REL_PATH_SIZE - 1] = '\0'; + if (directory->find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + out_entry->type = drang_fs_type_directory; + } else if (directory->find_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + out_entry->type = drang_fs_type_symlink; + } else { + out_entry->type = drang_fs_type_file; + } + + DRANG_END_TRY_IGNORE() +} + +int drang_fs_closedir(drang_fs_directory_t *directory) +{ + DRANG_BEGIN_TRY() + if (directory) { + if (directory->handle != INVALID_HANDLE_VALUE) { + if (!FindClose(directory->handle)) { + DRANG_FAIL(win32_error_to_drang(GetLastError())); + } + } + drang_free(directory); + } + DRANG_END_TRY_IGNORE() +} + +int drang_fs_get_cwd(char *buffer, size_t size, size_t *out_size) +{ + DWORD length = 0; + DRANG_BEGIN_TRY() + DRANG_FAIL_IF_NULL(buffer, DRANG_EINVAL); + + length = GetCurrentDirectoryA((DWORD) size, buffer); + if (length == 0) { + DRANG_FAIL(win32_error_to_drang(GetLastError())); + } + + if (out_size) { + *out_size = length; + } + + DRANG_CHECK(length < size, DRANG_ENOMEM); + + DRANG_END_TRY_IGNORE() +} + +int drang_fs_set_cwd(const char *path) +{ + DRANG_BEGIN_TRY() + DRANG_FAIL_IF_NULL(path, DRANG_EINVAL); + + if (!SetCurrentDirectoryA(path)) { + DRANG_FAIL(win32_error_to_drang(GetLastError())); + } + + DRANG_END_TRY_IGNORE() +} diff --git a/Source/DrangPlatform/Source/win32/fs/internal.h b/Source/DrangPlatform/Source/win32/fs/internal.h index a8da21b..37a6b0a 100644 --- a/Source/DrangPlatform/Source/win32/fs/internal.h +++ b/Source/DrangPlatform/Source/win32/fs/internal.h @@ -11,3 +11,10 @@ struct drang_fs_file drang_fs_mode_t mode; struct drang_rwlock lock; }; + +struct drang_fs_directory +{ + HANDLE handle; + WIN32_FIND_DATAA find_data; + bool first_entry; +}; \ No newline at end of file