AuroraRuntime/Source/IO/FS/FileStream.NT.cpp
2021-11-08 01:15:37 +00:00

241 lines
5.8 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)
{
LogWarn("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)
{
LogWarn("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 = std::min(kFileCopyBlock, length);
if (!::ReadFile(handle_, &reinterpret_cast<char *>(parameters.ptr)[offset], blockSize, &read, NULL))
{
LogWarn("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 = std::min(kFileCopyBlock, length);
if (!::WriteFile(handle_, &reinterpret_cast<const char *>(parameters.ptr)[offset], blockSize, &written, NULL))
{
LogWarn("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::Close()
{
AuWin32CloseHandle(handle_);
}
void WinFileStream::Flush()
{
FlushFileBuffers(handle_);
}
static IFileStream *OpenNew(const AuString &path, bool read)
{
auto pathex = NormalizePathRet(path);
auto win32Path = Locale::ConvertFromUTF8(pathex);
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)
{
LogWarn("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;
}
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