AuroraRuntime/Source/IO/FS/FileStream.NT.cpp
Reece e5e36bd887 Large Commit
[*] Fix deadlock in the async subsystem (NoLockShutdown vs Shutdown in exception handler)
[+] Added ProccessMap NT variant
[+] Added ToolHelp image profiling
[*] Improved exception awareness
[*] Delegated SpawnThread to isolated TU, ready for reuse for RunAs and XNU Open - now with horrible evil alloc that could fail
[+] Added header for future api 'UtilRun'
[*] Improve NT core detection
[*] Changed small affinity bitmap to AuUInt64 instead of AuUInt32
[+] Added data structure to hold cpuids/affinity masks
[+] Implemented logger sinks
[+] Implemented logger glue logic
[*] Began migrating older loggers to sink-based default devices
[*] Minor refactors
[*] Improved internal exception discarding, not yet nothrow capable
[*] Minor create directory fix
2022-01-24 18:43:53 +00:00

268 lines
6.3 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: FileStream.NT.cpp
Date: 2021-6-12
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "FS.hpp"
#include "FileStream.NT.hpp"
#if !defined(_AURUNTIME_GENERICFILESTREAM)
namespace Aurora::IO::FS
{
static const AuUInt64 kFileCopyBlock = 0xFFFF; // 64KiB, 1k iterations to max out 64MB/s disk, 2k iteration to make out 128MB/s disk, is this number still way too low? cpu go brr
WinFileStream::~WinFileStream()
{
Close();
}
void WinFileStream::Init(HANDLE handle, const AuString &path)
{
handle_ = handle;
path_ = path;
}
AuUInt64 WinFileStream::GetOffset()
{
LARGE_INTEGER distance {};
LARGE_INTEGER pos {};
if (handle_ == INVALID_HANDLE_VALUE)
{
SysPushErrorUninitialized();
return 0;
}
if (SetFilePointerEx(handle_, distance, &pos, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
{
AuLogWarn("SetFilePointerEx IO Error: 0x{:x}, {}", GetLastError(), path_);
SysPushErrorIO();
return 0;
}
return pos.QuadPart;
}
bool WinFileStream::SetOffset(AuUInt64 offset)
{
LARGE_INTEGER distance {};
LARGE_INTEGER pos {};
if (handle_ == INVALID_HANDLE_VALUE)
{
SysPushErrorUninitialized();
return false;
}
distance.QuadPart = offset;
if (SetFilePointerEx(handle_, distance, &pos, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
{
AuLogWarn("SetFilePointerEx IO Error: 0x{:x}, {}", GetLastError(), path_);
SysPushErrorIO();
return false;
}
return true;
}
AuUInt64 WinFileStream::GetLength()
{
LARGE_INTEGER length;
if (handle_ == INVALID_HANDLE_VALUE)
{
SysPushErrorUninitialized();
return 0;
}
if (!GetFileSizeEx(handle_, &length))
{
SysPushErrorIO();
return 0;
}
return length.QuadPart;
}
bool WinFileStream::Read(const Memory::MemoryViewStreamWrite &parameters)
{
if (handle_ == INVALID_HANDLE_VALUE)
{
SysPushErrorUninitialized();
return {};
}
auto length = parameters.length;
AuUInt64 offset {0};
while (length)
{
DWORD read;
int blockSize = AuMin(kFileCopyBlock, length);
if (!::ReadFile(handle_, reinterpret_cast<char *>(parameters.ptr) + offset, blockSize, &read, NULL))
{
AuLogWarn("ReadFile IO Error: 0x{:x}, {}", GetLastError(), path_);
SysPushErrorIO();
return false;
}
if (read == 0)
{
break;
}
offset += read;
length -= read;
}
if (!offset)
{
return false;
}
parameters.outVariable = offset;
return true;
}
bool WinFileStream::Write(const Memory::MemoryViewStreamRead &parameters)
{
if (handle_ == INVALID_HANDLE_VALUE)
{
SysPushErrorUninitialized();
return 0;
}
auto length = parameters.length;
AuUInt offset {0};
while (length)
{
DWORD written;
int blockSize = AuMin(kFileCopyBlock, length);
if (!::WriteFile(handle_, reinterpret_cast<const char *>(parameters.ptr) + offset, blockSize, &written, NULL))
{
AuLogWarn("WriteFileEx IO Error: 0x{:x}, {}", GetLastError(), path_);
SysPushErrorIO();
return false;
}
if (written != blockSize)
{
SysPushErrorIO();
parameters.outVariable = offset;
return true;
}
offset += written;
length -= written;
}
if (!offset)
{
return false;
}
parameters.outVariable = offset;
return true;
}
void WinFileStream::WriteEoS()
{
if (handle_ == INVALID_HANDLE_VALUE)
{
SysPushErrorUninitialized();
return;
}
SetEndOfFile(handle_);
}
void WinFileStream::Close()
{
AuWin32CloseHandle(handle_);
}
void WinFileStream::Flush()
{
FlushFileBuffers(handle_);
}
static IFileStream *OpenNew(const AuString &path, bool read)
{
try
{
auto pathex = NormalizePathRet(path);
if (pathex.empty())
{
return nullptr;
}
auto win32Path = Locale::ConvertFromUTF8(pathex);
if (win32Path.empty())
{
return nullptr;
}
HANDLE fileHandle;
if (read)
{
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
else
{
CreateDirectories(pathex, true);
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
if (fileHandle == INVALID_HANDLE_VALUE)
{
AuLogWarn("Missing file: {}", path);
SysPushErrorIO("Missing file: {}", path);
return nullptr;
}
auto stream = _new WinFileStream();
if (!stream)
{
CloseHandle(fileHandle);
return nullptr;
}
stream->Init(fileHandle, pathex);
return stream;
}
catch (...)
{
return nullptr;
}
}
AUKN_SYM IFileStream *OpenReadNew(const AuString &path)
{
return OpenNew(path, true);
}
AUKN_SYM void OpenReadRelease(IFileStream * that)
{
SafeDelete<WinFileStream *>(that);
}
AUKN_SYM IFileStream *OpenWriteNew(const AuString &path)
{
return OpenNew(path, false);
}
AUKN_SYM void OpenWriteRelease(IFileStream * that)
{
SafeDelete<WinFileStream *>(that);
}
}
#endif