mirror of
https://github.com/InoriRus/Kyty.git
synced 2026-08-28 05:06:40 +00:00
Initial commit
This commit is contained in:
@@ -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}")
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "Kyty/Core/Common.h"
|
||||
|
||||
#if KYTY_PLATFORM != KYTY_PLATFORM_LINUX
|
||||
//#error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX"
|
||||
#else
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "Kyty/Core/Common.h"
|
||||
|
||||
#if KYTY_PLATFORM != KYTY_PLATFORM_LINUX
|
||||
//#error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX"
|
||||
#else
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user