362 lines
9.9 KiB
C++
362 lines
9.9 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_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 (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 ¶meters)
|
|
{
|
|
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 ¶meters)
|
|
{
|
|
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))
|
|
{
|
|
SysPushErrorIO("WriteFileEx IO Error: 0x{:x}, {}", GetLastError(), this->path_);
|
|
return false;
|
|
}
|
|
|
|
if (!written)
|
|
{
|
|
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;
|
|
}
|
|
|
|
HANDLE WinFileStream::GetHandle()
|
|
{
|
|
return this->handle_;
|
|
}
|
|
|
|
static IFileStream *OpenNewEx(const AuString &path, EFileOpenMode openMode, EFileAdvisoryLockLevel lock, bool bCheck)
|
|
{
|
|
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;
|
|
|
|
auto dwShare = NtLockAdvisoryToShare(lock);
|
|
|
|
switch (openMode)
|
|
{
|
|
case EFileOpenMode::eRead:
|
|
{
|
|
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, dwShare, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
break;
|
|
}
|
|
case EFileOpenMode::eReadWrite:
|
|
{
|
|
CreateDirectories(pathex, true);
|
|
|
|
if (bCheck)
|
|
{
|
|
fileHandle = ::CreateFileW(win32Path.c_str(),
|
|
GENERIC_WRITE | GENERIC_READ | DELETE,
|
|
NULL,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ | DELETE, dwShare, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (fileHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ | DELETE, dwShare, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case EFileOpenMode::eWrite:
|
|
{
|
|
CreateDirectories(pathex, true);
|
|
|
|
if (bCheck)
|
|
{
|
|
fileHandle = ::CreateFileW(win32Path.c_str(),
|
|
GENERIC_WRITE | DELETE,
|
|
NULL,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | FILE_READ_ATTRIBUTES | DELETE, dwShare, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (fileHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | DELETE, dwShare, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (fileHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
SysPushErrorIO("Invalid filepath, couldn't open: {}", 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 *CreateNew(const AuString &path)
|
|
{
|
|
return OpenNewEx(path, EFileOpenMode::eWrite, EFileAdvisoryLockLevel::eBlockReadWrite, true);
|
|
}
|
|
|
|
AUKN_SYM void CreateRelease(IFileStream *that)
|
|
{
|
|
AuSafeDelete<WinFileStream *>(that);
|
|
}
|
|
|
|
AUKN_SYM IFileStream *OpenNew(const AuString &path, EFileOpenMode openMode, EFileAdvisoryLockLevel lock)
|
|
{
|
|
return OpenNewEx(path, openMode, lock, false);
|
|
}
|
|
|
|
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 |