AuroraRuntime/Source/IO/FS/FileStream.NT.cpp

309 lines
8.1 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"
#include "FileAdvisory.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)
{
this->handle_ = handle;
this->path_ = path;
}
AuUInt64 WinFileStream::GetOffset()
{
LARGE_INTEGER distance {};
LARGE_INTEGER pos {};
if (this->handle_ == INVALID_HANDLE_VALUE)
{
SysPushErrorUninitialized();
return 0;
}
if (SetFilePointerEx(this->handle_, distance, &pos, FILE_BEGIN) == 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 (this->handle_ == INVALID_HANDLE_VALUE)
{
SysPushErrorUninitialized();
return false;
}
distance.QuadPart = offset;
if (SetFilePointerEx(this->handle_, distance, &pos, FILE_BEGIN) == 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(this->handle_, &length))
{
SysPushErrorIO();
return 0;
}
return length.QuadPart;
}
bool WinFileStream::Read(const Memory::MemoryViewStreamWrite &parameters)
{
if (this->handle_ == INVALID_HANDLE_VALUE)
{
SysPushErrorUninitialized();
return {};
}
auto length = parameters.length;
parameters.outVariable = 0;
AuUInt64 offset {0};
while (length)
{
DWORD read;
int blockSize = AuMin(AuUInt(kFileCopyBlock), length);
if (!::ReadFile(this->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 (this->handle_ == INVALID_HANDLE_VALUE)
{
SysPushErrorUninitialized();
return 0;
}
auto length = parameters.length;
parameters.outVariable = 0;
AuUInt offset {0};
while (length)
{
DWORD written;
int blockSize = AuMin(AuUInt(kFileCopyBlock), length);
if (!::WriteFile(this->handle_, reinterpret_cast<const char *>(parameters.ptr) + offset, blockSize, &written, NULL))
{
AuLogWarn("WriteFileEx IO Error: 0x{:x}, {}", GetLastError(), this->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 (this->handle_ == INVALID_HANDLE_VALUE)
{
SysPushErrorUninitialized();
return;
}
SetEndOfFile(this->handle_);
}
void WinFileStream::Close()
{
if ((this->handle_ != INVALID_HANDLE_VALUE) &&
(this->bShouldDelete))
{
FILE_DISPOSITION_INFO rm {};
rm.DeleteFile = true;
if (!SetFileInformationByHandle(this->handle_, _FILE_INFO_BY_HANDLE_CLASS::FileDispositionInfo, &rm, sizeof(rm)))
{
SysPushErrorIO("Couldn't delete temporary file {}", this->path_);
}
}
AuWin32CloseHandle(this->handle_);
}
void WinFileStream::Flush()
{
FlushFileBuffers(this->handle_);
}
void WinFileStream::MakeTemporary()
{
this->bShouldDelete = true;
}
AUKN_SYM IFileStream *OpenNew(const AuString &path, EFileOpenMode openMode, EFileAdvisoryLockLevel lock)
{
try
{
auto pathex = NormalizePathRet(path);
if (pathex.empty())
{
return nullptr;
}
auto win32Path = Locale::ConvertFromUTF8(pathex);
if (win32Path.empty())
{
return nullptr;
}
HANDLE fileHandle;
fileHandle = INVALID_HANDLE_VALUE;
switch (openMode)
{
case EFileOpenMode::eRead:
{
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, NtLockAdvisoryToShare(lock), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
break;
}
case EFileOpenMode::eReadWrite:
{
CreateDirectories(pathex, true);
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ, NtLockAdvisoryToShare(lock), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle == INVALID_HANDLE_VALUE)
{
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, NtLockAdvisoryToShare(lock), NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
break;
}
case EFileOpenMode::eWrite:
{
CreateDirectories(pathex, true);
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, NtLockAdvisoryToShare(lock), NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
break;
}
}
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 void OpenRelease(IFileStream *that)
{
AuSafeDelete<WinFileStream *>(that);
}
AUKN_SYM IFileStream *OpenReadNew(const AuString &path, EFileAdvisoryLockLevel level)
{
return OpenNew(path, EFileOpenMode::eRead, level);
}
AUKN_SYM void OpenReadRelease(IFileStream * that)
{
AuSafeDelete<WinFileStream *>(that);
}
AUKN_SYM IFileStream *OpenWriteNew(const AuString &path, EFileAdvisoryLockLevel level)
{
return OpenNew(path, EFileOpenMode::eWrite, level);
}
AUKN_SYM void OpenWriteRelease(IFileStream *that)
{
AuSafeDelete<WinFileStream *>(that);
}
}
#endif