feature: implement Win32 file handling functions including open, close, read, write, and permissions management
This commit is contained in:
parent
7cd3fe2905
commit
053f4f9043
4 changed files with 500 additions and 0 deletions
35
Source/DrangPlatform/Source/win32/common.c
Normal file
35
Source/DrangPlatform/Source/win32/common.c
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
#include "common.h"
|
||||||
|
#include <drang/error.h>
|
||||||
|
int win32_error_to_drang(const DWORD error)
|
||||||
|
{
|
||||||
|
switch (error) {
|
||||||
|
case ERROR_SUCCESS:
|
||||||
|
return DRANG_EOK;
|
||||||
|
case ERROR_FILE_NOT_FOUND:
|
||||||
|
case ERROR_PATH_NOT_FOUND:
|
||||||
|
case ERROR_INVALID_DRIVE:
|
||||||
|
return DRANG_ENOENT;
|
||||||
|
case ERROR_ACCESS_DENIED:
|
||||||
|
case ERROR_SHARING_VIOLATION:
|
||||||
|
case ERROR_LOCK_VIOLATION:
|
||||||
|
return DRANG_EPERM;
|
||||||
|
case ERROR_ALREADY_EXISTS:
|
||||||
|
case ERROR_FILE_EXISTS:
|
||||||
|
return DRANG_EBUSY;
|
||||||
|
case ERROR_NOT_ENOUGH_MEMORY:
|
||||||
|
case ERROR_OUTOFMEMORY:
|
||||||
|
return DRANG_ENOMEM;
|
||||||
|
case ERROR_DISK_FULL:
|
||||||
|
return DRANG_ENOSPC;
|
||||||
|
case ERROR_INVALID_PARAMETER:
|
||||||
|
return DRANG_EINVAL;
|
||||||
|
case ERROR_WRITE_PROTECT:
|
||||||
|
return DRANG_EROFS;
|
||||||
|
case ERROR_IO_DEVICE:
|
||||||
|
case ERROR_IO_PENDING:
|
||||||
|
return DRANG_EIO;
|
||||||
|
case ERROR_CRC:
|
||||||
|
default:
|
||||||
|
return DRANG_EPLATFORM; // Unknown or unhandled error
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Source/DrangPlatform/Source/win32/common.h
Normal file
11
Source/DrangPlatform/Source/win32/common.h
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <drang/platform.h>
|
||||||
|
|
||||||
|
|
||||||
|
DRANG_BEGIN_DECLS
|
||||||
|
|
||||||
|
DRANG_PLATFORM_API int win32_error_to_drang(DWORD error);
|
||||||
|
|
||||||
|
DRANG_END_DECLS
|
||||||
438
Source/DrangPlatform/Source/win32/fs/file.c
Normal file
438
Source/DrangPlatform/Source/win32/fs/file.c
Normal file
|
|
@ -0,0 +1,438 @@
|
||||||
|
#include "drang/sync.h"
|
||||||
|
#include "internal.h"
|
||||||
|
#include "win32/common.h"
|
||||||
|
#include <drang/alloc.h>
|
||||||
|
#include <drang/error.h>
|
||||||
|
|
||||||
|
static void mode_to_access(drang_fs_mode_t mode, DWORD *out_access, DWORD *out_creation)
|
||||||
|
{
|
||||||
|
DWORD access = 0;
|
||||||
|
DWORD creation = 0;
|
||||||
|
if (mode & drang_fs_mode_read) {
|
||||||
|
access |= GENERIC_READ;
|
||||||
|
}
|
||||||
|
if (mode & drang_fs_mode_write) {
|
||||||
|
access |= GENERIC_WRITE;
|
||||||
|
}
|
||||||
|
if (mode & drang_fs_mode_append) {
|
||||||
|
access |= FILE_APPEND_DATA;
|
||||||
|
}
|
||||||
|
if (mode & drang_fs_mode_create) {
|
||||||
|
if (mode & drang_fs_mode_exclusive) {
|
||||||
|
creation = CREATE_NEW;
|
||||||
|
} else {
|
||||||
|
creation = OPEN_ALWAYS;
|
||||||
|
}
|
||||||
|
} else if (mode & drang_fs_mode_truncate) {
|
||||||
|
creation = TRUNCATE_EXISTING;
|
||||||
|
} else {
|
||||||
|
creation = OPEN_EXISTING;
|
||||||
|
}
|
||||||
|
*out_access = access;
|
||||||
|
*out_creation = creation;
|
||||||
|
}
|
||||||
|
|
||||||
|
int drang_fs_open(const char *path, drang_fs_mode_t mode, drang_fs_file_t **out_file)
|
||||||
|
{
|
||||||
|
struct drang_fs_file *file = NULL;
|
||||||
|
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(path, DRANG_EINVAL);
|
||||||
|
DRANG_FAIL_IF_NULL(out_file, DRANG_EINVAL);
|
||||||
|
|
||||||
|
DWORD access = 0;
|
||||||
|
DWORD creation = 0;
|
||||||
|
mode_to_access(mode, &access, &creation);
|
||||||
|
handle = CreateFileA(path,
|
||||||
|
access,
|
||||||
|
0, //TODO: Implement sharing
|
||||||
|
NULL,
|
||||||
|
creation,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL);
|
||||||
|
if (handle == INVALID_HANDLE_VALUE) {
|
||||||
|
DRANG_FAIL(win32_error_to_drang(GetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
file = DRANG_TRY_CALLOC_T(struct drang_fs_file);
|
||||||
|
file->handle = handle;
|
||||||
|
file->mode = mode;
|
||||||
|
DRANG_TRY(drang_rwlock_init(&file->lock));
|
||||||
|
*out_file = file;
|
||||||
|
|
||||||
|
DRANG_CATCH(_)
|
||||||
|
{
|
||||||
|
if (handle != INVALID_HANDLE_VALUE) {
|
||||||
|
CloseHandle(handle);
|
||||||
|
}
|
||||||
|
if (file) {
|
||||||
|
drang_rwlock_fini(&file->lock);
|
||||||
|
drang_free(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DRANG_END_TRY()
|
||||||
|
}
|
||||||
|
|
||||||
|
int drang_fs_close(drang_fs_file_t *file)
|
||||||
|
{
|
||||||
|
bool locked = false;
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(file, DRANG_EINVAL);
|
||||||
|
|
||||||
|
DRANG_TRY(drang_rwlock_wrlock(&file->lock));
|
||||||
|
locked = true;
|
||||||
|
if (file->handle != INVALID_HANDLE_VALUE) {
|
||||||
|
DRANG_CHECK(CloseHandle(file->handle), win32_error_to_drang(GetLastError()));
|
||||||
|
file->handle = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
drang_rwlock_fini(&file->lock);
|
||||||
|
locked = false;
|
||||||
|
drang_free(file);
|
||||||
|
|
||||||
|
DRANG_CATCH(_)
|
||||||
|
{
|
||||||
|
if (locked) {
|
||||||
|
drang_rwlock_wrunlock(&file->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DRANG_END_TRY()
|
||||||
|
}
|
||||||
|
|
||||||
|
int drang_fs_read(drang_fs_file_t *file, void *buffer, size_t count, size_t size, size_t *bytes_read)
|
||||||
|
{
|
||||||
|
bool locked = false;
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(file, DRANG_EINVAL);
|
||||||
|
DRANG_FAIL_IF_NULL(buffer, DRANG_EINVAL);
|
||||||
|
if (count == 0 || size == 0) {
|
||||||
|
if (bytes_read)
|
||||||
|
*bytes_read = 0;
|
||||||
|
DRANG_RETURN();
|
||||||
|
}
|
||||||
|
DRANG_CHECK(file->mode & drang_fs_mode_read, DRANG_EPERM);
|
||||||
|
|
||||||
|
DRANG_TRY(drang_rwlock_rdlock(&file->lock));
|
||||||
|
locked = true;
|
||||||
|
DWORD total_bytes = 0;
|
||||||
|
DRANG_CHECK(!DRANG_MUL_OVERFLOW(count, size, &total_bytes), DRANG_EOVERFLOW);
|
||||||
|
|
||||||
|
DWORD read_bytes = 0;
|
||||||
|
if (!ReadFile(file->handle, buffer, total_bytes, &read_bytes, NULL)) {
|
||||||
|
DRANG_FAIL(win32_error_to_drang(GetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_read) {
|
||||||
|
*bytes_read = (size_t) read_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
drang_rwlock_rdunlock(&file->lock);
|
||||||
|
locked = false;
|
||||||
|
|
||||||
|
DRANG_CATCH(_)
|
||||||
|
{
|
||||||
|
if (locked) {
|
||||||
|
drang_rwlock_rdunlock(&file->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DRANG_END_TRY()
|
||||||
|
}
|
||||||
|
|
||||||
|
int drang_fs_write(drang_fs_file_t *file, const void *buffer, size_t count, size_t size, size_t *bytes_written)
|
||||||
|
{
|
||||||
|
bool locked = false;
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(file, DRANG_EINVAL);
|
||||||
|
DRANG_FAIL_IF_NULL(buffer, DRANG_EINVAL);
|
||||||
|
if (count == 0 || size == 0) {
|
||||||
|
if (bytes_written)
|
||||||
|
*bytes_written = 0;
|
||||||
|
DRANG_RETURN();
|
||||||
|
}
|
||||||
|
DRANG_CHECK(file->mode & (drang_fs_mode_write | drang_fs_mode_append), DRANG_EPERM);
|
||||||
|
DRANG_TRY(drang_rwlock_wrlock(&file->lock));
|
||||||
|
locked = true;
|
||||||
|
DWORD total_bytes = 0;
|
||||||
|
DRANG_CHECK(!DRANG_MUL_OVERFLOW(count, size, &total_bytes), DRANG_EOVERFLOW);
|
||||||
|
if (file->mode & drang_fs_mode_append) {
|
||||||
|
const LARGE_INTEGER zero = {0};
|
||||||
|
if (!SetFilePointerEx(file->handle, zero, NULL, FILE_END)) {
|
||||||
|
DRANG_FAIL(win32_error_to_drang(GetLastError()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DWORD written_bytes = 0;
|
||||||
|
if (!WriteFile(file->handle, buffer, total_bytes, &written_bytes, NULL)) {
|
||||||
|
DRANG_FAIL(win32_error_to_drang(GetLastError()));
|
||||||
|
}
|
||||||
|
if (bytes_written) {
|
||||||
|
*bytes_written = (size_t) written_bytes;
|
||||||
|
}
|
||||||
|
drang_rwlock_wrunlock(&file->lock);
|
||||||
|
locked = false;
|
||||||
|
DRANG_CATCH(_)
|
||||||
|
{
|
||||||
|
if (locked) {
|
||||||
|
drang_rwlock_wrunlock(&file->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DRANG_END_TRY()
|
||||||
|
}
|
||||||
|
|
||||||
|
int drang_fs_seek(drang_fs_file_t *file, int64_t offset, drang_seek_origin_t origin)
|
||||||
|
{
|
||||||
|
bool locked = false;
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(file, DRANG_EINVAL);
|
||||||
|
DRANG_TRY(drang_rwlock_wrlock(&file->lock));
|
||||||
|
locked = true;
|
||||||
|
DWORD move_method = 0;
|
||||||
|
switch (origin) {
|
||||||
|
case drang_seek_origin_begin:
|
||||||
|
move_method = FILE_BEGIN;
|
||||||
|
break;
|
||||||
|
case drang_seek_origin_current:
|
||||||
|
move_method = FILE_CURRENT;
|
||||||
|
break;
|
||||||
|
case drang_seek_origin_end:
|
||||||
|
move_method = FILE_END;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LARGE_INTEGER li;
|
||||||
|
li.QuadPart = offset;
|
||||||
|
if (!SetFilePointerEx(file->handle, li, NULL, move_method)) {
|
||||||
|
DRANG_FAIL(win32_error_to_drang(GetLastError()));
|
||||||
|
}
|
||||||
|
drang_rwlock_wrunlock(&file->lock);
|
||||||
|
locked = false;
|
||||||
|
DRANG_CATCH(_)
|
||||||
|
{
|
||||||
|
if (locked) {
|
||||||
|
drang_rwlock_wrunlock(&file->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DRANG_END_TRY()
|
||||||
|
}
|
||||||
|
|
||||||
|
int drang_fs_tell(drang_fs_file_t *file, uint64_t *position)
|
||||||
|
{
|
||||||
|
bool locked = false;
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(file, DRANG_EINVAL);
|
||||||
|
DRANG_FAIL_IF_NULL(position, DRANG_EINVAL);
|
||||||
|
DRANG_TRY(drang_rwlock_rdlock(&file->lock));
|
||||||
|
locked = true;
|
||||||
|
LARGE_INTEGER zero = {0};
|
||||||
|
LARGE_INTEGER pos = {0};
|
||||||
|
if (!SetFilePointerEx(file->handle, zero, &pos, FILE_CURRENT)) {
|
||||||
|
DRANG_FAIL(win32_error_to_drang(GetLastError()));
|
||||||
|
}
|
||||||
|
*position = (uint64_t) pos.QuadPart;
|
||||||
|
drang_rwlock_rdunlock(&file->lock);
|
||||||
|
locked = false;
|
||||||
|
DRANG_CATCH(_)
|
||||||
|
{
|
||||||
|
if (locked) {
|
||||||
|
drang_rwlock_rdunlock(&file->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DRANG_END_TRY()
|
||||||
|
}
|
||||||
|
|
||||||
|
int drang_fs_flush(drang_fs_file_t *file)
|
||||||
|
{
|
||||||
|
bool locked = false;
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(file, DRANG_EINVAL);
|
||||||
|
DRANG_CHECK(file->mode & (drang_fs_mode_write | drang_fs_mode_append), DRANG_EPERM);
|
||||||
|
DRANG_TRY(drang_rwlock_wrlock(&file->lock));
|
||||||
|
locked = true;
|
||||||
|
if (!FlushFileBuffers(file->handle)) {
|
||||||
|
DRANG_FAIL(win32_error_to_drang(GetLastError()));
|
||||||
|
}
|
||||||
|
drang_rwlock_wrunlock(&file->lock);
|
||||||
|
locked = false;
|
||||||
|
DRANG_CATCH(_)
|
||||||
|
{
|
||||||
|
if (locked) {
|
||||||
|
drang_rwlock_wrunlock(&file->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DRANG_END_TRY()
|
||||||
|
}
|
||||||
|
int drang_fs_truncate(drang_fs_file_t *file, uint64_t size)
|
||||||
|
{
|
||||||
|
bool locked = false;
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(file, DRANG_EINVAL);
|
||||||
|
DRANG_CHECK(file->mode & drang_fs_mode_write, DRANG_EPERM);
|
||||||
|
DRANG_TRY(drang_rwlock_wrlock(&file->lock));
|
||||||
|
locked = true;
|
||||||
|
LARGE_INTEGER li;
|
||||||
|
li.QuadPart = (LONGLONG) size;
|
||||||
|
if (!SetFilePointerEx(file->handle, li, NULL, FILE_BEGIN)) {
|
||||||
|
DRANG_FAIL(win32_error_to_drang(GetLastError()));
|
||||||
|
}
|
||||||
|
if (!SetEndOfFile(file->handle)) {
|
||||||
|
DRANG_FAIL(win32_error_to_drang(GetLastError()));
|
||||||
|
}
|
||||||
|
drang_rwlock_wrunlock(&file->lock);
|
||||||
|
locked = false;
|
||||||
|
DRANG_CATCH(_)
|
||||||
|
{
|
||||||
|
if (locked) {
|
||||||
|
drang_rwlock_wrunlock(&file->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DRANG_END_TRY()
|
||||||
|
}
|
||||||
|
|
||||||
|
int drang_fs_create(const char *path, drang_fs_permissions_t permissions)
|
||||||
|
{
|
||||||
|
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||||
|
DRANG_UNUSED(permissions);
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(path, DRANG_EINVAL);
|
||||||
|
|
||||||
|
// Create the file with CREATE_NEW to fail if it already exists
|
||||||
|
handle = CreateFileA(path,
|
||||||
|
GENERIC_WRITE, // Need write access to create
|
||||||
|
0, // No sharing during creation
|
||||||
|
NULL, // Default security attributes
|
||||||
|
CREATE_NEW, // Fail if file already exists
|
||||||
|
FILE_ATTRIBUTE_NORMAL, // Normal file attributes
|
||||||
|
NULL); // No template file
|
||||||
|
|
||||||
|
DRANG_CHECK(handle != INVALID_HANDLE_VALUE, win32_error_to_drang(GetLastError()));
|
||||||
|
|
||||||
|
// Close the file handle immediately since we're just creating an empty file
|
||||||
|
CloseHandle(handle);
|
||||||
|
|
||||||
|
// Note: Windows doesn't support Unix-style permissions directly.
|
||||||
|
// The permissions parameter is ignored on Windows as documented behavior
|
||||||
|
// may vary between platforms. For a full implementation, we could use
|
||||||
|
// SetFileSecurity() with ACLs, but that's complex and not typically needed.
|
||||||
|
|
||||||
|
DRANG_CATCH(_)
|
||||||
|
{
|
||||||
|
if (handle != INVALID_HANDLE_VALUE) {
|
||||||
|
CloseHandle(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DRANG_END_TRY()
|
||||||
|
}
|
||||||
|
|
||||||
|
int drang_fs_remove(const char *path)
|
||||||
|
{
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(path, DRANG_EINVAL);
|
||||||
|
|
||||||
|
if (!DeleteFileA(path)) {
|
||||||
|
DRANG_FAIL(win32_error_to_drang(GetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// No cleanup needed for this function
|
||||||
|
DRANG_END_TRY_IGNORE()
|
||||||
|
}
|
||||||
|
|
||||||
|
int drang_fs_move(const char *old_path, const char *new_path)
|
||||||
|
{
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(old_path, DRANG_EINVAL);
|
||||||
|
DRANG_FAIL_IF_NULL(new_path, DRANG_EINVAL);
|
||||||
|
if (!MoveFileA(old_path, new_path)) {
|
||||||
|
DRANG_FAIL(win32_error_to_drang(GetLastError()));
|
||||||
|
}
|
||||||
|
DRANG_END_TRY_IGNORE()
|
||||||
|
}
|
||||||
|
|
||||||
|
bool drang_fs_exists(const char *path)
|
||||||
|
{
|
||||||
|
if (path == NULL)
|
||||||
|
return false;
|
||||||
|
const DWORD attrs = GetFileAttributesA(path);
|
||||||
|
if (attrs == INVALID_FILE_ATTRIBUTES) {
|
||||||
|
false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int drang_fs_stat(const char *path, struct drang_fs_stat *out_stat)
|
||||||
|
{
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(path, DRANG_EINVAL);
|
||||||
|
DRANG_FAIL_IF_NULL(out_stat, DRANG_EINVAL);
|
||||||
|
|
||||||
|
WIN32_FILE_ATTRIBUTE_DATA file_data;
|
||||||
|
if (!GetFileAttributesExA(path, GetFileExInfoStandard, &file_data)) {
|
||||||
|
DRANG_FAIL(win32_error_to_drang(GetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine file type
|
||||||
|
if (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||||
|
out_stat->type = drang_fs_type_directory;
|
||||||
|
out_stat->size = 0; // Directories have no size
|
||||||
|
} else if (file_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||||
|
// This might be a symlink, but we need to check further
|
||||||
|
out_stat->type = drang_fs_type_symlink;
|
||||||
|
out_stat->size = ((uint64_t)file_data.nFileSizeHigh << 32) | file_data.nFileSizeLow;
|
||||||
|
} else {
|
||||||
|
out_stat->type = drang_fs_type_file;
|
||||||
|
out_stat->size = ((uint64_t)file_data.nFileSizeHigh << 32) | file_data.nFileSizeLow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert Windows permissions to Unix-style permissions
|
||||||
|
// Windows doesn't have the same permission model, so we'll approximate
|
||||||
|
out_stat->permissions = DRANG_FS_PERM_USER_READ | DRANG_FS_PERM_GROUP_READ | DRANG_FS_PERM_OTHER_READ;
|
||||||
|
|
||||||
|
if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
|
||||||
|
out_stat->permissions |= DRANG_FS_PERM_USER_WRITE | DRANG_FS_PERM_GROUP_WRITE | DRANG_FS_PERM_OTHER_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For directories and executables, add execute permissions
|
||||||
|
if ((file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
|
||||||
|
(strlen(path) > 4 &&
|
||||||
|
(_stricmp(path + strlen(path) - 4, ".exe") == 0 ||
|
||||||
|
_stricmp(path + strlen(path) - 4, ".bat") == 0 ||
|
||||||
|
_stricmp(path + strlen(path) - 4, ".cmd") == 0))) {
|
||||||
|
out_stat->permissions |= DRANG_FS_PERM_USER_EXEC | DRANG_FS_PERM_GROUP_EXEC | DRANG_FS_PERM_OTHER_EXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert FILETIME to Unix timestamp (seconds since epoch)
|
||||||
|
// Windows FILETIME is 100-nanosecond intervals since January 1, 1601
|
||||||
|
// Unix timestamp is seconds since January 1, 1970
|
||||||
|
const uint64_t WINDOWS_EPOCH_DIFF = 11644473600ULL; // Seconds between 1601 and 1970
|
||||||
|
|
||||||
|
// Convert creation time
|
||||||
|
uint64_t created_100ns = ((uint64_t)file_data.ftCreationTime.dwHighDateTime << 32) |
|
||||||
|
file_data.ftCreationTime.dwLowDateTime;
|
||||||
|
out_stat->created_time = (created_100ns / 10000000ULL) - WINDOWS_EPOCH_DIFF;
|
||||||
|
|
||||||
|
// Convert modification time
|
||||||
|
uint64_t modified_100ns = ((uint64_t)file_data.ftLastWriteTime.dwHighDateTime << 32) |
|
||||||
|
file_data.ftLastWriteTime.dwLowDateTime;
|
||||||
|
out_stat->modified_time = (modified_100ns / 10000000ULL) - WINDOWS_EPOCH_DIFF;
|
||||||
|
|
||||||
|
// Convert access time
|
||||||
|
uint64_t accessed_100ns = ((uint64_t)file_data.ftLastAccessTime.dwHighDateTime << 32) |
|
||||||
|
file_data.ftLastAccessTime.dwLowDateTime;
|
||||||
|
out_stat->accessed_time = (accessed_100ns / 10000000ULL) - WINDOWS_EPOCH_DIFF;
|
||||||
|
|
||||||
|
DRANG_END_TRY_IGNORE()
|
||||||
|
}
|
||||||
|
|
||||||
|
int drang_fs_set_permissions(const char *path, drang_fs_permissions_t permissions)
|
||||||
|
{
|
||||||
|
DRANG_BEGIN_TRY()
|
||||||
|
DRANG_FAIL_IF_NULL(path, DRANG_EINVAL);
|
||||||
|
|
||||||
|
// Windows doesn't support Unix-style permissions directly.
|
||||||
|
// The permissions parameter is ignored on Windows as documented behavior
|
||||||
|
// may vary between platforms. For a full implementation, we could use
|
||||||
|
// SetFileSecurity() with ACLs, but that's complex and not typically needed.
|
||||||
|
DRANG_UNUSED(permissions);
|
||||||
|
|
||||||
|
DRANG_END_TRY_IGNORE()
|
||||||
|
}
|
||||||
16
Source/DrangPlatform/Source/win32/fs/internal.h
Normal file
16
Source/DrangPlatform/Source/win32/fs/internal.h
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
#include <drang/fs.h>
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include "../sync/internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct drang_fs_file
|
||||||
|
{
|
||||||
|
HANDLE handle;
|
||||||
|
drang_fs_mode_t mode;
|
||||||
|
struct drang_rwlock lock;
|
||||||
|
|
||||||
|
};
|
||||||
Loading…
Add table
Add a link
Reference in a new issue