Initial commit

This commit is contained in:
InoriRus
2021-12-01 19:29:27 +10:00
parent b1e7dcdc5d
commit 43f49c8763
1843 changed files with 1111694 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
file(GLOB sys_src
"src/*.cpp"
)
add_library(sys_obj OBJECT ${sys_src})
add_library(sys STATIC $<TARGET_OBJECTS:sys_obj>)
target_link_libraries(sys core)
get_property(inc_headers TARGET sys PROPERTY INCLUDE_DIRECTORIES)
target_include_directories(sys_obj PRIVATE ${inc_headers})
list(APPEND check_headers
${CMAKE_SOURCE_DIR}/include
)
clang_tidy_check(sys_obj "" "${check_headers}" "${inc_headers}")
include_what_you_use(sys_obj "${inc_headers}")
+7
View File
@@ -0,0 +1,7 @@
#include "Kyty/Core/Common.h"
#if KYTY_PLATFORM != KYTY_PLATFORM_LINUX
//#error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX"
#else
#endif
+7
View File
@@ -0,0 +1,7 @@
#include "Kyty/Core/Common.h"
#if KYTY_PLATFORM != KYTY_PLATFORM_LINUX
//#error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX"
#else
#endif
+297
View File
@@ -0,0 +1,297 @@
#include "Kyty/Sys/SysWindowsDbg.h"
#include "Kyty/Core/Common.h"
#include "Kyty/Core/DbgAssert.h"
#include "Kyty/Sys/SysDbg.h"
// IWYU pragma: no_include <basetsd.h>
// IWYU pragma: no_include <memoryapi.h>
// IWYU pragma: no_include <minwindef.h>
// IWYU pragma: no_include <processthreadsapi.h>
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
//#error "KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS"
#else
#include <windows.h> // IWYU pragma: keep
#if KYTY_COMPILER == KYTY_COMPILER_MSVC
#include <intrin.h>
#endif
#include <psapi.h> // IWYU pragma: keep
namespace Kyty {
#if KYTY_BITNESS == 32
static thread_local sys_dbg_stack_info_t g_stack = {0};
// uintptr_t g_stack_addr = 0;
// bool g_need_break = false;
#endif
#define KYTY_FRAME_SKIP 1
struct FrameS
{
struct FrameS* next;
void* ret_addr;
};
constexpr DWORD READABLE =
(static_cast<DWORD>(PAGE_EXECUTE_READ) | static_cast<DWORD>(PAGE_EXECUTE_READWRITE) | static_cast<DWORD>(PAGE_EXECUTE_WRITECOPY) |
static_cast<DWORD>(PAGE_READONLY) | static_cast<DWORD>(PAGE_READWRITE) | static_cast<DWORD>(PAGE_WRITECOPY));
constexpr DWORD PROTECTED = (static_cast<DWORD>(PAGE_GUARD) | static_cast<DWORD>(PAGE_NOCACHE) | static_cast<DWORD>(PAGE_NOACCESS));
exception_filter_func_t g_exception_filter_func = nullptr;
bool sys_mem_read_allowed(void* ptr)
{
MEMORY_BASIC_INFORMATION mbi;
size_t s = VirtualQuery(ptr, &mbi, sizeof(mbi));
if (s == 0)
{
EXIT_IF(s == 0);
}
return ((mbi.Protect & PROTECTED) == 0u) && ((mbi.State & static_cast<DWORD>(MEM_COMMIT)) != 0u) &&
((mbi.AllocationProtect & READABLE) != 0u);
}
// LONG WINAPI
// VectoredHandlerSkip(struct _EXCEPTION_POINTERS *ExceptionInfo)
//{
// PCONTEXT Context;
//
// g_need_break = true;
//
// Context = ExceptionInfo->ContextRecord;
//#ifdef _AMD64_
// Context->Rip++;
//#else
// Context->Eip++;
//#endif
// return EXCEPTION_CONTINUE_EXECUTION;
//}
#if KYTY_BITNESS == 32
static void stackwalk(void* ebp, void** stack, int* depth, uintptr_t stack_addr, size_t stack_size)
{
frame_t* frame = (frame_t*)ebp;
int d = *depth;
int i;
// printf("1\n");
for (i = 0; i < KYTY_FRAME_SKIP; i++)
{
// if (uintptr_t(frame) <= 0xffff || (uintptr_t(frame) & 0xf0000000)
// || frame->ret_addr == 0
// || (uintptr_t(frame->ret_addr) & 0xf0000000)
// || (uintptr_t(frame->next) & 0xf0000000)) break;
// if (!sys_mem_read_allowed(&frame->next)) break;
if (!(uintptr_t(frame) >= stack_addr && uintptr_t(frame) < stack_addr + stack_size)) break;
frame = frame->next;
}
// printf("2\n");
for (i = 0; i < d; i++)
{
//#ifdef _MSC_VER
// __try
// {
//#endif
// FILE *f = fopen("_sw", "wt");
// printf("%d, %08x\n", i, (uint32_t)frame);
// fflush(stdout);
// fclose(f);
// printf("%d, %08x, %08x, %08x\n", i, (uint32_t)frame,
// (uint32_t)frame->ret_addr, (uint32_t)frame->next);
// if (uintptr_t(frame) <= 0xffff || (uintptr_t(frame) & 0xf0000000)
// || frame->ret_addr == 0
// || (uintptr_t(frame->ret_addr) & 0xf0000000)
// || (uintptr_t(frame->next) & 0xf0000000)) break;
// if (uintptr_t(frame) == 0 || frame->ret_addr == 0 ) break;
// if (!sys_mem_read_allowed(&frame->next) || !sys_mem_read_allowed(&frame->ret_addr)) break;
if (!(uintptr_t(frame) >= stack_addr && uintptr_t(frame) < stack_addr + stack_size)) break;
// if (g_need_break) break;
stack[i] = frame->ret_addr;
frame = frame->next;
//#ifdef _MSC_VER
// } __except(EXCEPTION_EXECUTE_HANDLER)
// {
// break;
// }
//#endif
}
// printf("3\n");
*depth = i;
}
#endif
#if KYTY_BITNESS == 32
void sys_stack_walk(void** stack, int* depth)
{
#if KYTY_COMPILER == KYTY_COMPILER_MSVC
void* ebp = (size_t*)_AddressOfReturnAddress() - 1;
#else
void* ebp = __builtin_frame_address(0);
#endif
// g_need_break = false;
//#ifndef _MSC_VER
// PVOID p = AddVectoredExceptionHandler(1000, VectoredHandlerSkip);
// if (!g_stack_addr) g_stack_addr = (uintptr_t)&depth;
///#endif
if (g_stack.total_size == 0)
{
sys_stack_usage(g_stack);
}
stackwalk(ebp, stack, depth, g_stack.addr, g_stack.total_size);
//#ifndef _MSC_VER
// RemoveVectoredExceptionHandler(p);
//#endif
}
#else
//#include <unwind.h>
// struct unwind_info_t
//{
// void **stack;
// int depth;
// int max_depth;
//};
//_Unwind_Reason_Code trace_fcn(_Unwind_Context *ctx, void *d)
//{
// unwind_info_t *info = (unwind_info_t*)d;
// //printf("\t#%d: program counter at %08x\n", *depth, _Unwind_GetIP(ctx));
// //(*depth)++;
// if (info->depth < info->max_depth)
// {
// void *ptr = (void*)_Unwind_GetIP(ctx);
// info->stack[info->depth] = ptr;
// info->depth++;
// }
// return _URC_NO_REASON;
//}
int WalkStack(int z_stack_depth, void** z_stack_trace)
{
CONTEXT context;
// KNONVOLATILE_CONTEXT_POINTERS NvContext;
PRUNTIME_FUNCTION runtime_function = nullptr;
PVOID handler_data = nullptr;
ULONG64 establisher_frame = 0;
ULONG64 image_base = 0;
RtlCaptureContext(&context);
int frame = 0;
while (true)
{
if (frame >= z_stack_depth)
{
break;
}
z_stack_trace[frame] = reinterpret_cast<void*>(context.Rip);
frame++;
runtime_function = RtlLookupFunctionEntry(context.Rip, &image_base, nullptr);
if (runtime_function == nullptr)
{
break;
}
// RtlZeroMemory(&NvContext, sizeof(KNONVOLATILE_CONTEXT_POINTERS));
RtlVirtualUnwind(0, image_base, context.Rip, runtime_function, &context, &handler_data, &establisher_frame, nullptr /*&NvContext*/);
if (context.Rip == 0u)
{
break;
}
}
return frame;
}
void sys_stack_walk(void** stack, int* depth)
{
// USHORT n = CaptureStackBackTrace(KYTY_FRAME_SKIP, *depth, stack, 0);
int n = WalkStack(*depth, stack);
*depth = n;
// unwind_info_t info = {stack, 0, *depth};
// _Unwind_Backtrace(&trace_fcn, &info);
// *depth = info.depth;
}
#endif
void sys_stack_usage_print(sys_dbg_stack_info_t& stack)
{
printf("stack: (0x%" PRIx64 ", %" PRIu64 ") + (0x%" PRIx64 ", %" PRIu64 ") + (0x%" PRIx64 ", %" PRIu64 ")\n",
static_cast<uint64_t>(stack.reserved_addr), static_cast<uint64_t>(stack.reserved_size), static_cast<uint64_t>(stack.guard_addr),
static_cast<uint64_t>(stack.guard_size), static_cast<uint64_t>(stack.commited_addr), static_cast<uint64_t>(stack.commited_size));
}
void sys_stack_usage(sys_dbg_stack_info_t& s)
{
MEMORY_BASIC_INFORMATION mbi {};
[[maybe_unused]] size_t ss = VirtualQuery(&mbi, &mbi, sizeof(mbi));
EXIT_IF(ss == 0);
PVOID reserved = mbi.AllocationBase;
ss = VirtualQuery(reserved, &mbi, sizeof(mbi));
EXIT_IF(ss == 0);
size_t reserved_size = mbi.RegionSize;
ss = VirtualQuery(static_cast<char*>(reserved) + reserved_size, &mbi, sizeof(mbi));
EXIT_IF(ss == 0);
void* guard_page = mbi.BaseAddress;
size_t guard_page_size = mbi.RegionSize;
ss = VirtualQuery(static_cast<char*>(guard_page) + guard_page_size, &mbi, sizeof(mbi));
EXIT_IF(ss == 0);
void* commited = mbi.BaseAddress;
size_t commited_size = mbi.RegionSize;
s.reserved_addr = reinterpret_cast<uintptr_t>(reserved);
s.reserved_size = reserved_size;
s.guard_addr = reinterpret_cast<uintptr_t>(guard_page);
s.guard_size = guard_page_size;
s.commited_addr = reinterpret_cast<uintptr_t>(commited);
s.commited_size = commited_size;
s.addr = s.reserved_addr;
s.total_size = s.reserved_size + s.guard_size + s.commited_size;
}
void sys_get_code_info(uintptr_t* addr, size_t* size)
{
MODULEINFO info {};
GetModuleInformation(GetCurrentProcess(), GetModuleHandle(nullptr), &info, sizeof(MODULEINFO));
*addr = reinterpret_cast<uintptr_t>(info.lpBaseOfDll);
*size = static_cast<size_t>(info.SizeOfImage);
}
static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exception)
{
g_exception_filter_func(exception->ExceptionRecord->ExceptionAddress);
return EXCEPTION_EXECUTE_HANDLER;
}
void sys_set_exception_filter(exception_filter_func_t func)
{
g_exception_filter_func = func;
SetUnhandledExceptionFilter(ExceptionFilter);
}
} // namespace Kyty
#endif
+642
View File
@@ -0,0 +1,642 @@
#include "Kyty/Sys/SysWindowsFileIO.h"
#include "Kyty/Core/Common.h"
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
//#error "KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS"
#else
#include "Kyty/Core/MemoryAlloc.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/Vector.h"
#include "Kyty/Sys/SysFileIO.h"
#include "Kyty/Sys/SysTimer.h"
#include <windows.h>
// IWYU pragma: no_include <fileapi.h>
// IWYU pragma: no_include <handleapi.h>
// IWYU pragma: no_include <minwinbase.h>
// IWYU pragma: no_include <minwindef.h>
namespace Kyty {
using Core::mem_free;
using Core::mem_realloc;
static inline HANDLE KYTY_INVALID_HANDLE_VALUE()
{
return INVALID_HANDLE_VALUE; // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
}
bool sys_file_io_init()
{
return true;
}
static DWORD get_cache_access_type(sys_file_cache_type_t t)
{
if (t == SYS_FILE_CACHE_RANDOM_ACCESS)
{
return FILE_FLAG_RANDOM_ACCESS;
}
if (t == SYS_FILE_CACHE_SEQUENTIAL_SCAN)
{
return SYS_FILE_CACHE_SEQUENTIAL_SCAN;
}
return SYS_FILE_CACHE_AUTO;
}
void sys_file_read(void* data, uint32_t size, sys_file_t& f, uint32_t* bytes_read)
{
if (f.type == SYS_FILE_FILE)
{
DWORD w = 0;
ReadFile(f.handle, data, size, &w, nullptr);
if (bytes_read != nullptr)
{
*bytes_read = w;
}
} else if (f.type == SYS_FILE_MEMORY_STAT)
{
uint32_t s = size;
if (f.buf->size != 0u)
{
uint32_t l = f.buf->size - (f.buf->ptr - f.buf->base);
if (s > l)
{
s = l;
}
}
std::memcpy(data, f.buf->ptr, s);
f.buf->ptr += s;
if (bytes_read != nullptr)
{
*bytes_read = s;
}
} else if (f.type == SYS_FILE_MEMORY_DYN)
{
uint32_t s = size;
if (f.buf->size != 0u)
{
uint32_t l = f.buf->size - (f.buf->ptr - f.buf->base);
if (s > l)
{
s = l;
}
} else
{
s = 0;
}
std::memcpy(data, f.buf->ptr, s);
f.buf->ptr += s;
if (bytes_read != nullptr)
{
*bytes_read = s;
}
}
}
void sys_file_write(const void* data, uint32_t size, sys_file_t& f, uint32_t* bytes_written)
{
if (f.type == SYS_FILE_FILE)
{
DWORD w = 0;
WriteFile(f.handle, data, size, &w, nullptr);
if (bytes_written != nullptr)
{
*bytes_written = w;
}
} else if (f.type == SYS_FILE_MEMORY_STAT)
{
uint32_t s = size;
if (f.buf->size != 0u)
{
uint32_t l = f.buf->size - (f.buf->ptr - f.buf->base);
if (s > l)
{
s = l;
}
}
std::memcpy(f.buf->ptr, data, s);
f.buf->ptr += s;
if (bytes_written != nullptr)
{
*bytes_written = s;
}
} else if (f.type == SYS_FILE_MEMORY_DYN)
{
uint32_t pos = f.buf->ptr - f.buf->base;
if (f.buf->size < pos + size)
{
f.buf->base = static_cast<uint8_t*>(mem_realloc(f.buf->base, pos + size));
f.buf->ptr = f.buf->base + pos;
f.buf->size = pos + size;
}
std::memcpy(f.buf->ptr, data, size);
f.buf->ptr += size;
if (bytes_written != nullptr)
{
*bytes_written = size;
}
}
}
void sys_file_read_r(void* data, uint32_t size, sys_file_t& f)
{
// DWORD w;
// ReadFile(f, data, size, &w, 0);
sys_file_read(data, size, f);
for (uint32_t i = 0; i < size / 2; i++)
{
char t = (static_cast<char*>(data))[i];
(static_cast<char*>(data))[i] = (static_cast<char*>(data))[size - i - 1];
(static_cast<char*>(data))[size - i - 1] = t;
}
}
void sys_file_write_r(const void* data, uint32_t size, sys_file_t& f)
{
char* data_r = new char[size];
for (uint32_t i = 0; i < size; i++)
{
data_r[i] = (static_cast<const char*>(data))[size - i - 1];
}
sys_file_write(data_r, size, f);
delete[] data_r;
}
void sys_file_write(uint32_t n, sys_file_t& f)
{
sys_file_write(&n, 4, f);
}
void sys_file_write_r(uint32_t n, sys_file_t& f)
{
sys_file_write_r(&n, 4, f);
}
sys_file_t* sys_file_create(const String& file_name)
{
auto* ret = new sys_file_t;
HANDLE h_file = nullptr;
h_file = CreateFileW(reinterpret_cast<LPCWSTR>(file_name.utf16_str().GetData()),
static_cast<DWORD>(GENERIC_READ) | static_cast<DWORD>(GENERIC_WRITE), 0, nullptr, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, nullptr);
ret->handle = h_file;
ret->type = SYS_FILE_FILE;
return ret;
}
sys_file_t* sys_file_open_r(const String& file_name, sys_file_cache_type_t cache_type)
{
auto* ret = new sys_file_t;
HANDLE h_file = nullptr;
h_file = CreateFileW(reinterpret_cast<LPCWSTR>(file_name.utf16_str().GetData()), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
get_cache_access_type(cache_type), nullptr);
if (h_file == KYTY_INVALID_HANDLE_VALUE())
{
ret->type = SYS_FILE_ERROR;
} else
{
ret->type = SYS_FILE_FILE;
}
ret->handle = h_file;
return ret;
}
sys_file_t* sys_file_open(uint8_t* buf, uint32_t buf_size)
{
auto* ret = new sys_file_t;
ret->type = SYS_FILE_MEMORY_STAT;
ret->buf = new sys_file_mem_buf_t;
ret->buf->base = buf;
ret->buf->ptr = buf;
ret->buf->size = buf_size;
return ret;
}
sys_file_t* sys_file_create()
{
auto* ret = new sys_file_t;
ret->type = SYS_FILE_MEMORY_DYN;
ret->buf = new sys_file_mem_buf_t;
ret->buf->base = nullptr;
ret->buf->ptr = nullptr;
ret->buf->size = 0;
return ret;
}
sys_file_t* sys_file_open_w(const String& file_name, sys_file_cache_type_t cache_type)
{
auto* ret = new sys_file_t;
HANDLE h_file = nullptr;
h_file = CreateFileW(reinterpret_cast<LPCWSTR>(file_name.utf16_str().GetData()), GENERIC_WRITE, 0, nullptr, OPEN_EXISTING,
get_cache_access_type(cache_type), nullptr);
if (h_file == KYTY_INVALID_HANDLE_VALUE())
{
ret->type = SYS_FILE_ERROR;
} else
{
ret->type = SYS_FILE_FILE;
}
ret->handle = h_file;
return ret;
}
sys_file_t* sys_file_open_rw(const String& file_name, sys_file_cache_type_t cache_type)
{
auto* ret = new sys_file_t;
HANDLE h_file = nullptr;
h_file = CreateFileW(reinterpret_cast<LPCWSTR>(file_name.utf16_str().GetData()),
static_cast<DWORD>(GENERIC_READ) | static_cast<DWORD>(GENERIC_WRITE), 0, nullptr, OPEN_EXISTING,
get_cache_access_type(cache_type), nullptr);
if (h_file == KYTY_INVALID_HANDLE_VALUE())
{
ret->type = SYS_FILE_ERROR;
} else
{
ret->type = SYS_FILE_FILE;
}
ret->handle = h_file;
return ret;
}
void sys_file_close(sys_file_t* f)
{
if (f->type == SYS_FILE_FILE)
{
CloseHandle(f->handle);
} else if (f->type == SYS_FILE_MEMORY_STAT)
{
delete f->buf;
} else if (f->type == SYS_FILE_MEMORY_DYN)
{
mem_free(f->buf->base);
delete f->buf;
}
// f.type = SYS_FILE_ERROR;
delete f;
}
uint64_t sys_file_size(sys_file_t& f)
{
if (f.type == SYS_FILE_FILE)
{
LARGE_INTEGER s;
GetFileSizeEx(f.handle, &s);
return s.QuadPart;
}
if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN)
{
return f.buf->size;
}
return 0;
}
uint64_t sys_file_size(const String& file_name)
{
LARGE_INTEGER s;
WIN32_FILE_ATTRIBUTE_DATA a;
if (GetFileAttributesExW(reinterpret_cast<LPCWSTR>(file_name.utf16_str().GetData()), GetFileExInfoStandard, &a) == 0)
{
return 0;
}
s.HighPart = static_cast<LONG>(a.nFileSizeHigh);
s.LowPart = a.nFileSizeLow;
return s.QuadPart;
}
bool sys_file_truncate(sys_file_t& f, uint64_t size)
{
bool ok = false;
if (f.type == SYS_FILE_FILE)
{
LARGE_INTEGER s {};
LARGE_INTEGER r {};
s.QuadPart = 0;
SetFilePointerEx(f.handle, s, &r, FILE_CURRENT);
s.QuadPart = static_cast<LONGLONG>(size);
ok = (SetFilePointerEx(f.handle, s, nullptr, FILE_BEGIN) != 0 && SetEndOfFile(f.handle) != 0);
SetFilePointerEx(f.handle, r, nullptr, FILE_BEGIN);
}
return ok;
}
bool sys_file_seek(sys_file_t& f, uint64_t offset)
{
bool ok = true;
if (f.type == SYS_FILE_FILE)
{
LARGE_INTEGER s;
s.QuadPart = static_cast<LONGLONG>(offset);
ok = (SetFilePointerEx(f.handle, s, nullptr, FILE_BEGIN) != 0);
// printf("seek: %u\n", offset);
} else if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN)
{
f.buf->ptr = f.buf->base + offset;
}
return ok;
}
uint64_t sys_file_tell(sys_file_t& f)
{
if (f.type == SYS_FILE_FILE)
{
LARGE_INTEGER s {};
LARGE_INTEGER r {};
s.QuadPart = 0;
SetFilePointerEx(f.handle, s, &r, FILE_CURRENT);
// printf("tell: %u\n", r.QuadPart);
return r.QuadPart;
}
if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN)
{
return f.buf->ptr - f.buf->base;
}
return 0;
}
bool sys_file_is_error(sys_file_t& f)
{
return f.type == SYS_FILE_ERROR || (f.type == SYS_FILE_FILE && f.handle == KYTY_INVALID_HANDLE_VALUE());
}
bool sys_file_is_directory_existing(const String& path)
{
DWORD a = GetFileAttributesW(reinterpret_cast<LPCWSTR>(path.utf16_str().GetData()));
return a != INVALID_FILE_ATTRIBUTES && ((a & static_cast<DWORD>(FILE_ATTRIBUTE_DIRECTORY)) != 0u);
}
bool sys_file_is_file_existing(const String& name)
{
DWORD a = GetFileAttributesW(reinterpret_cast<LPCWSTR>(name.utf16_str().GetData()));
return a != INVALID_FILE_ATTRIBUTES && ((a & static_cast<DWORD>(FILE_ATTRIBUTE_DIRECTORY)) == 0u);
}
bool sys_file_create_directory(const String& path)
{
return CreateDirectoryW(reinterpret_cast<LPCWSTR>(path.utf16_str().GetData()), nullptr) != 0;
}
bool sys_file_delete_directory(const String& path)
{
return RemoveDirectoryW(reinterpret_cast<LPCWSTR>(path.utf16_str().GetData())) != 0;
}
bool sys_file_delete_file(const String& name)
{
return DeleteFileW(reinterpret_cast<LPCWSTR>(name.utf16_str().GetData())) != 0;
}
bool sys_file_flush(sys_file_t& f)
{
if (f.type == SYS_FILE_FILE && f.handle != KYTY_INVALID_HANDLE_VALUE())
{
return (FlushFileBuffers(f.handle) != 0);
}
return false;
}
SysFileTimeStruct sys_file_get_last_access_time_utc(const String& name)
{
SysFileTimeStruct r {};
sys_file_t* f = sys_file_open_r(name);
r.is_invalid = (f->type == SYS_FILE_ERROR || (GetFileTime(f->handle, nullptr, &r.time, nullptr) == 0));
sys_file_close(f);
return r;
}
SysFileTimeStruct sys_file_get_last_write_time_utc(const String& name)
{
SysFileTimeStruct r {};
sys_file_t* f = sys_file_open_r(name);
r.is_invalid = (f->type == SYS_FILE_ERROR || (GetFileTime(f->handle, nullptr, nullptr, &r.time) == 0));
sys_file_close(f);
return r;
}
void sys_file_get_last_access_and_write_time_utc(const String& name, SysFileTimeStruct& a, SysFileTimeStruct& w)
{
// TODO() open file with dwDesiredAccess = 0
// TODO() open directory
sys_file_t* f = sys_file_open_r(name);
a.is_invalid = w.is_invalid = (f->type == SYS_FILE_ERROR || (GetFileTime(f->handle, nullptr, &a.time, &w.time) == 0));
sys_file_close(f);
}
void sys_file_get_last_access_and_write_time_utc(sys_file_t& f, SysFileTimeStruct& a, SysFileTimeStruct& w)
{
if (f.type == SYS_FILE_FILE)
{
a.is_invalid = w.is_invalid = (GetFileTime(f.handle, nullptr, &a.time, &w.time) == 0);
} else if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN)
{
SysTimeStruct t {};
sys_get_system_time_utc(t);
sys_system_to_file_time_utc(t, a);
sys_system_to_file_time_utc(t, w);
} else
{
a.is_invalid = w.is_invalid = true;
}
}
bool sys_file_set_last_access_time_utc(const String& name, SysFileTimeStruct& access)
{
if (access.is_invalid)
{
return false;
}
bool ok = true;
sys_file_t* f = sys_file_open_w(name);
ok = !(f->type == SYS_FILE_ERROR || (SetFileTime(f->handle, nullptr, &access.time, nullptr) == 0));
sys_file_close(f);
return ok;
}
bool sys_file_set_last_write_time_utc(const String& name, SysFileTimeStruct& write)
{
if (write.is_invalid)
{
return false;
}
bool ok = true;
sys_file_t* f = sys_file_open_w(name);
ok = !(f->type == SYS_FILE_ERROR || (SetFileTime(f->handle, nullptr, nullptr, &write.time) == 0));
sys_file_close(f);
return ok;
}
bool sys_file_set_last_access_and_write_time_utc(const String& name, SysFileTimeStruct& access, SysFileTimeStruct& write)
{
if (access.is_invalid || write.is_invalid)
{
return false;
}
bool ok = true;
sys_file_t* f = sys_file_open_w(name);
ok = !(f->type == SYS_FILE_ERROR || (SetFileTime(f->handle, nullptr, &access.time, &write.time) == 0));
sys_file_close(f);
return ok;
}
void sys_file_find_files(const String& path, Vector<sys_file_find_t>& out)
{
String real_path = path.ReplaceChar(U'\\', U'/');
if (!real_path.EndsWith(U"/"))
{
real_path += U"/";
}
String pattern = real_path + U"*";
HANDLE h = nullptr;
WIN32_FIND_DATAW data;
h = FindFirstFileW(reinterpret_cast<LPCWSTR>(pattern.utf16_str().GetData()), &data);
if (h == KYTY_INVALID_HANDLE_VALUE())
{
return;
}
do
{
String file_name = String::FromUtf16(reinterpret_cast<char16_t*>(data.cFileName));
if (file_name == U"." || file_name == U"..")
{
continue;
}
if ((data.dwFileAttributes & static_cast<DWORD>(FILE_ATTRIBUTE_DIRECTORY)) != 0u)
{
sys_file_find_files(real_path + file_name, out);
} else
{
sys_file_find_t r {};
r.path_with_name = real_path + file_name;
r.size = (static_cast<uint64_t>(data.nFileSizeHigh) << 32u) + static_cast<uint64_t>(data.nFileSizeLow);
r.last_access_time.is_invalid = false;
r.last_access_time.time = data.ftLastAccessTime;
r.last_write_time.is_invalid = false;
r.last_write_time.time = data.ftLastWriteTime;
out.Add(r);
}
} while (FindNextFileW(h, &data) != 0);
FindClose(h);
}
void sys_file_get_dents(const String& path, Kyty::Vector<sys_dir_entry_t>& out)
{
String real_path = path.ReplaceChar(U'\\', U'/');
if (!real_path.EndsWith(U"/"))
{
real_path += U"/";
}
String pattern = real_path + U"*";
HANDLE h = nullptr;
WIN32_FIND_DATAW data;
h = FindFirstFileW(reinterpret_cast<LPCWSTR>(pattern.utf16_str().GetData()), &data);
if (h == KYTY_INVALID_HANDLE_VALUE())
{
return;
}
do
{
String file_name = String::FromUtf16(reinterpret_cast<char16_t*>(data.cFileName));
sys_dir_entry_t r {};
r.is_file = ((data.dwFileAttributes & static_cast<DWORD>(FILE_ATTRIBUTE_DIRECTORY)) == 0u);
r.name = file_name;
out.Add(r);
} while (FindNextFileW(h, &data) != 0);
FindClose(h);
}
bool sys_file_copy_file(const String& src, const String& dst)
{
return CopyFileW(reinterpret_cast<LPCWSTR>(src.utf16_str().GetData()), reinterpret_cast<LPCWSTR>(dst.utf16_str().GetData()), FALSE) !=
0;
}
bool sys_file_move_file(const String& src, const String& dst)
{
return MoveFileW(reinterpret_cast<LPCWSTR>(src.utf16_str().GetData()), reinterpret_cast<LPCWSTR>(dst.utf16_str().GetData())) != 0;
}
void sys_file_remove_readonly(const String& name)
{
String::Utf16 s = name.utf16_str();
SetFileAttributesW(reinterpret_cast<LPCWSTR>(s.GetData()),
GetFileAttributesW(reinterpret_cast<LPCWSTR>(s.GetData())) & (~static_cast<DWORD>(FILE_ATTRIBUTE_READONLY)));
}
} // namespace Kyty
#endif