feature: implement Win32 directory handling functions including mkdir, rmdir, opendir, readdir, closedir, getcwd, and setcwd

This commit is contained in:
MechSlayer 2025-09-09 20:16:27 +02:00
parent c43748d1d4
commit f766cdb21e
2 changed files with 161 additions and 0 deletions

View file

@ -0,0 +1,154 @@
#include "internal.h"
#include "win32/common.h"
#include <drang/alloc.h>
#include <drang/error.h>
#include <drang/fs.h>
#include <stdio.h>
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()
}

View file

@ -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;
};