[+] IOHandle::IsWriteEoSOnClose

[+] IOHandle::SetWriteEoSOnClose
[+] IOHandle::HandleCreate::bFlushOnClose
[+] IOHandle::HandleCreate::bWriteEoSOnClose
[*] Unified grug based auto-truncating. Previously we were truncating on the final derefing thread; now, we truncate on the grug thread.
[*] Refactor/Cleanup IOHandle
This commit is contained in:
Reece Wilson 2024-03-27 03:12:49 +00:00
parent 30fa15b726
commit 232a136bfe
17 changed files with 227 additions and 88 deletions

View File

@ -13,10 +13,13 @@
namespace Aurora::IO
{
// Note: A handle is never disposable to prevent IO fd use after close
// You must ensure RAII and/or shared ownership release to dispose of the IO handle.
// This class is only intended to be an handle view; therefore, it is not possible to close the handle.
// You must ensure RAII and/or shared-ownership release to dispose of the IO resource.
// This class is only intended to be a handle view; therefore, it is not possible to close the handle.
//
// You should use the AuIOHandle or AuIO::IOHandle aliases for construction
// Warning: if for some reason you need to wait until any given handle is closed,
// you should ensure the handle is out of scope, then make a call to Aurora::RuntimeWaitForSecondaryTick();
//
// You should use the AuIOHandle or AuIO::IOHandle aliases for SOO construction; although, allocating functions AuIO::IOHandleShared/Unique/New are available.
struct IIOHandle
{
struct HandleCreate
@ -52,10 +55,21 @@ namespace Aurora::IO
bool bAsyncHandle { false };
/**
* Indicates the handle will only ever directly interface with the disk hardware as opposed to leveraging kernel assigned user shared memory
* Indicates the handle will only ever directly interface with the disk hardware/IO stack, as opposed to leveraging kernel assigned shared user memory.
* In this mode, only alignment/chunks of AuUInt32 AuFS::GetLogicalSectorSizeFromPath(const AuString &fileOrDirPath) is guaranteed to be accessible.
*/
bool bDirectIOMode { false };
/**
* Force flush on close?
*/
bool bFlushOnClose { false };
/**
* Auto-truncate?
*/
bool bWriteEoSOnClose { false };
cstatic HandleCreate Create(const AuString &path)
{
HandleCreate create(path);
@ -90,7 +104,9 @@ namespace Aurora::IO
}
inline HandleCreate(const AuString &path) :
path(path)
path(path),
eAdvisoryLevel(FS::EFileAdvisoryLockLevel::eNoSafety),
eMode(FS::EFileOpenMode::eRead)
{
}
};
@ -105,11 +121,11 @@ namespace Aurora::IO
virtual bool InitFromMove(AuUInt64 uOSHandle) = 0;
virtual bool InitFromPair(AuOptionalEx<AuUInt64> optOSReadHandle,
AuOptionalEx<AuUInt64> optOSWriteHandle) = 0;
virtual bool InitFromPair(AuOptional<AuUInt64> optOSReadHandle,
AuOptional<AuUInt64> optOSWriteHandle) = 0;
virtual bool InitFromPairMove(AuOptionalEx<AuUInt64> optOSReadHandle,
AuOptionalEx<AuUInt64> optOSWriteHandle) = 0;
virtual bool InitFromPairMove(AuOptional<AuUInt64> optOSReadHandle,
AuOptional<AuUInt64> optOSWriteHandle) = 0;
virtual bool InitFromStreamEnum(EStandardStream eStream) = 0;
@ -117,15 +133,15 @@ namespace Aurora::IO
virtual AuUInt64 GetOSHandle() const = 0;
virtual AuOptionalEx<AuUInt64> GetOSHandleSafe() const = 0;
virtual AuOptional<AuUInt64> GetOSHandleSafe() const = 0;
virtual AuUInt64 GetOSReadHandle() const = 0;
virtual AuOptionalEx<AuUInt64> GetOSReadHandleSafe() const = 0;
virtual AuOptional<AuUInt64> GetOSReadHandleSafe() const = 0;
virtual AuUInt64 GetOSWriteHandle() const = 0;
virtual AuOptionalEx<AuUInt64> GetOSWriteHandleSafe() const = 0;
virtual AuOptional<AuUInt64> GetOSWriteHandleSafe() const = 0;
virtual bool IsValid() const = 0;
@ -133,12 +149,18 @@ namespace Aurora::IO
virtual bool IsAsync() const = 0;
virtual AuString GetPath() const = 0;
virtual const AuString &GetPath() const = 0;
virtual bool IsFlushOnClose() const = 0;
virtual void SetFlushOnClose(bool bFlushOnClose) = 0;
// aka truncate on close
virtual bool IsWriteEoSOnClose() const = 0;
// aka truncate on close
virtual void SetWriteEoSOnClose(bool bWriteEoSOnClose) = 0;
virtual bool IsFile() const = 0;
virtual bool IsTTY() const = 0;

View File

@ -771,6 +771,33 @@ namespace Aurora
SysUnreachable();
}
void NTWriteEoS(HANDLE hHandle)
{
SetEndOfFile(hHandle);
}
void SysWriteEoS(AuUInt uOSHandle)
{
NTWriteEoS((HANDLE)uOSHandle);
}
void SysCloseHandle(AuUInt uOSHandle)
{
auto pHandle = (void *)uOSHandle;
AuWin32CloseHandle(pHandle);
}
bool SysHandleIsNonZero(AuUInt uOSHandle)
{
return uOSHandle && (void *)uOSHandle != INVALID_HANDLE_VALUE;
}
void SysFlushHandle(AuUInt uOSHandle)
{
auto pHandle = (void *)uOSHandle;
FlushFileBuffers(pHandle);
}
AuUInt64 SysGetFileLength(AuUInt uOSHandle)
{
LARGE_INTEGER length;

View File

@ -1228,6 +1228,8 @@ namespace Aurora
LPCSTR lpProcName
);
void NTWriteEoS(HANDLE hHandle);
static auline bool SysWaitOnAddressNoTimed(const void *pTargetAddress,
const void *pCompareAddress,
AuUInt8 uWordSize)

View File

@ -161,6 +161,40 @@ namespace Aurora
return true;
}
void PosixWriteEoS(int fd)
{
::ftruncate(fd, PosixGetOffset(fd));
}
void SysWriteEoS(AuUInt uOSHandle)
{
PosixWriteEoS(uOSHandle);
}
void SysCloseHandle(AuUInt uOSHandle)
{
::close(uOSHandle);
}
bool SysHandleIsNonZero(AuUInt uOSHandle)
{
#if defined(AURORA_IS_64BIT)
return uOSHandle && (uOSHandle != 0xFFFFFFFFull) && (uOSHandle != 0xFFFFFFFFFFFFFFFFull);
#else
return uOSHandle && (uOSHandle != 0xFFFFFFFF);
#endif
}
void SysFlushHandle(AuUInt uOSHandle)
{
::fsync(uOSHandle);
}
int PosixUnlink(const char *pathname)
{
return ::unlink(pathname);
}
AuUInt64 SysGetFileLength(AuUInt uOSHandle)
{
return PosixGetLength(uOSHandle);

View File

@ -23,4 +23,7 @@ namespace Aurora
AuUInt64 PosixGetLength(int fd);
bool PosixRead (int fd, void *buf, AuUInt32 count, AuUInt32 *pRead);
bool PosixWrite (int fd, const void *buf, AuUInt32 count, AuUInt32 *pWritten);
void PosixWriteEoS (int fd);
int PosixUnlink (const char *pathname);
}

View File

@ -48,6 +48,14 @@ namespace Aurora
AuUInt64 SysGetFileLength(AuUInt uOSHandle);
void SysWriteEoS(AuUInt uOSHandle);
void SysFlushHandle(AuUInt uOSHandle);
void SysCloseHandle(AuUInt uOSHandle);
bool SysHandleIsNonZero(AuUInt uOSHandle);
void *SysAllocateLarge(AuUInt uLength);
void SysAllocateFree(void *pBuffer, AuUInt uLength);

View File

@ -34,7 +34,7 @@ namespace Aurora::Grug
static AuSemaphore gArrows;
static AuBinarySemaphore gArrowsRetarded(false, true, true);
static AuMutex gOtherMutex;
static AuList<AuPair<AuUInt, bool>> gHandlesToClose;
static AuList<AuTuple<AuUInt, bool, bool>> gHandlesToClose;
static AuList<AuThreadPrimitives::IEvent *> gEventsToTrigger;
static void SlowStartupTasks()
@ -189,25 +189,29 @@ namespace Aurora::Grug
toTrigger = AuMove(gEventsToTrigger);
}
for (const auto [uHandle, bFlush] : toClose)
for (const auto [uHandle, bFlush, bWriteEoS] : toClose)
{
#if defined(AURORA_IS_MODERNNT_DERIVED)
auto pHandle = (void *)uHandle;
if (bFlush && pHandle)
if (!SysHandleIsNonZero(uHandle))
{
if (AuIO::IsHandleFile(uHandle))
{
FlushFileBuffers(pHandle);
continue;
}
if (bWriteEoS)
{
SysWriteEoS(uHandle);
}
AuWin32CloseHandle(pHandle);
#elif defined(AURORA_IS_POSIX_DERIVED)
if (bFlush)
{
::fsync(uHandle);
}
::close(uHandle);
#if defined(AURORA_IS_MODERNNT_DERIVED)
if (AuIO::IsHandleFile(uHandle))
#endif
{
SysFlushHandle(uHandle);
}
}
SysCloseHandle(uHandle);
}
for (const auto pEvent : toTrigger)
@ -224,12 +228,12 @@ namespace Aurora::Grug
GrugDoIoWork();
}
void CloseHandle(AuUInt64 handle, bool bFlush)
void CloseHandle(AuUInt64 handle, bool bFlush, bool bWriteEoS)
{
{
AU_DEBUG_MEMCRUNCH;
AU_LOCK_GUARD(gOtherMutex);
gHandlesToClose.push_back(AuMakePair(AuUInt(handle), bFlush));
gHandlesToClose.push_back(AuMakeTuple(AuUInt(handle), bFlush, bWriteEoS));
}
NotifyGrugOfTelemetry();

View File

@ -24,6 +24,6 @@ namespace Aurora::Grug
void InitGrug();
void DeinitGrug();
void CloseHandle(AuUInt64 handle, bool bFlush = false);
void CloseHandle(AuUInt64 handle, bool bFlush = false, bool bWriteEoS = false);
void WaitForGrugTick();
}

View File

@ -40,13 +40,13 @@ namespace Aurora::IO
return AuUInt64(hHandle);
}
void AFileHandle::CloseHandle(AuUInt64 uOSHandle, bool bFlushOnClose)
void AFileHandle::CloseHandle(AuUInt64 uOSHandle, bool bFlushOnClose, bool bWriteEoS)
{
#if 0
HANDLE hHandle = (HANDLE)uOSHandle;
AuWin32CloseHandle(hHandle);
#else
Grug::CloseHandle(uOSHandle, bFlushOnClose);
Grug::CloseHandle(uOSHandle, bFlushOnClose, bWriteEoS);
#endif
}
@ -313,6 +313,8 @@ namespace Aurora::IO
}
this->bIsAsync = create.bAsyncHandle;
this->bShouldWriteEoS = create.bWriteEoSOnClose;
this->bFlushOnClose = create.bFlushOnClose;
this->path = create.path;

View File

@ -85,7 +85,7 @@ namespace Aurora::IO
return 1;
}
void AFileHandle::CloseHandle(AuUInt64 uOSHandle, bool bFlushOnClose)
void AFileHandle::CloseHandle(AuUInt64 uOSHandle, bool bFlushOnClose, bool bWriteEoS)
{
int fd = (int)uOSHandle;
if (fd < 0)
@ -100,7 +100,7 @@ namespace Aurora::IO
}
::close(fd);
#else
Grug::CloseHandle(uOSHandle, bFlushOnClose);
Grug::CloseHandle(uOSHandle, bFlushOnClose, bWriteEoS);
#endif
}
@ -284,6 +284,8 @@ namespace Aurora::IO
};
this->bIsAsync = create.bAsyncHandle;
this->bShouldWriteEoS = create.bWriteEoSOnClose;
this->bFlushOnClose = create.bFlushOnClose;
this->path = create.path;

View File

@ -31,23 +31,28 @@ namespace Aurora::IO
this->SharingStop();
}
if (this->pThat)
{
return;
}
if (this->uOSWriteHandle.HasValue() && this->uOSReadHandle.HasValue() &&
this->uOSReadHandle.Value() == this->uOSWriteHandle.Value())
{
this->CloseHandle(this->uOSReadHandle.Value());
this->CloseHandle(this->uOSReadHandle.Value(), this->bFlushOnClose, this->bShouldWriteEoS);
AuResetMember(this->uOSReadHandle);
AuResetMember(this->uOSWriteHandle);
}
if (this->uOSReadHandle)
{
this->CloseHandle(this->uOSReadHandle.Value());
this->CloseHandle(this->uOSReadHandle.Value(), false, false);
AuResetMember(this->uOSReadHandle);
}
if (this->uOSWriteHandle)
{
this->CloseHandle(this->uOSWriteHandle.Value());
AFileHandle::CloseHandle(this->uOSWriteHandle.Value(), this->bFlushOnClose, this->bShouldWriteEoS);
AuResetMember(this->uOSWriteHandle);
}
}
@ -105,8 +110,8 @@ namespace Aurora::IO
return true;
}
bool AFileHandle::InitFromPair(AuOptionalEx<AuUInt64> optOSReadHandle,
AuOptionalEx<AuUInt64> optOSWriteHandle)
bool AFileHandle::InitFromPair(AuOptional<AuUInt64> optOSReadHandle,
AuOptional<AuUInt64> optOSWriteHandle)
{
if (this->IsValid())
{
@ -144,8 +149,8 @@ namespace Aurora::IO
return true;
}
bool AFileHandle::InitFromPairMove(AuOptionalEx<AuUInt64> uOSReadHandle,
AuOptionalEx<AuUInt64> uOSWriteHandle)
bool AFileHandle::InitFromPairMove(AuOptional<AuUInt64> uOSReadHandle,
AuOptional<AuUInt64> uOSWriteHandle)
{
if (this->IsValid())
{
@ -232,6 +237,16 @@ namespace Aurora::IO
this->bFlushOnClose = bFlushOnClose;
}
bool AFileHandle::IsWriteEoSOnClose() const
{
return this->bShouldWriteEoS;
}
void AFileHandle::SetWriteEoSOnClose(bool bShouldWriteEoS)
{
this->bShouldWriteEoS = bShouldWriteEoS;
}
bool AFileHandle::IsPipe() const
{
bool bIsPipe {};
@ -255,7 +270,7 @@ namespace Aurora::IO
return bIsPipe;
}
AuOptionalEx<AuUInt64> AFileHandle::GetOSHandleSafe() const
AuOptional<AuUInt64> AFileHandle::GetOSHandleSafe() const
{
if (auto write = this->uOSWriteHandle)
{
@ -283,7 +298,7 @@ namespace Aurora::IO
return this->uOSReadHandle.Value();
}
AuOptionalEx<AuUInt64> AFileHandle::GetOSReadHandleSafe() const
AuOptional<AuUInt64> AFileHandle::GetOSReadHandleSafe() const
{
return this->uOSReadHandle;
}
@ -293,7 +308,7 @@ namespace Aurora::IO
return this->uOSWriteHandle.Value();
}
AuOptionalEx<AuUInt64> AFileHandle::GetOSWriteHandleSafe() const
AuOptional<AuUInt64> AFileHandle::GetOSWriteHandleSafe() const
{
return this->uOSWriteHandle;
}
@ -314,7 +329,7 @@ namespace Aurora::IO
return this->bIsAsync;
}
AuString AFileHandle::GetPath() const
const AuString &AFileHandle::GetPath() const
{
return this->path;
}

View File

@ -26,11 +26,11 @@ namespace Aurora::IO
bool InitFromMove(AuUInt64 uOSHandle) override;
bool InitFromPair(AuOptionalEx<AuUInt64> uOSReadHandle,
AuOptionalEx<AuUInt64> uOSWriteHandle) override;
bool InitFromPair(AuOptional<AuUInt64> uOSReadHandle,
AuOptional<AuUInt64> uOSWriteHandle) override;
bool InitFromPairMove(AuOptionalEx<AuUInt64> uOSReadHandle,
AuOptionalEx<AuUInt64> uOSWriteHandle) override;
bool InitFromPairMove(AuOptional<AuUInt64> uOSReadHandle,
AuOptional<AuUInt64> uOSWriteHandle) override;
bool InitFromStreamEnum(EStandardStream eStream) override;
@ -42,15 +42,15 @@ namespace Aurora::IO
AuUInt64 GetOSHandle() const override;
AuOptionalEx<AuUInt64> GetOSHandleSafe() const override;
AuOptional<AuUInt64> GetOSHandleSafe() const override;
AuUInt64 GetOSReadHandle() const override;
AuOptionalEx<AuUInt64> GetOSReadHandleSafe() const override;
AuOptional<AuUInt64> GetOSReadHandleSafe() const override;
AuUInt64 GetOSWriteHandle() const override;
AuOptionalEx<AuUInt64> GetOSWriteHandleSafe() const override;
AuOptional<AuUInt64> GetOSWriteHandleSafe() const override;
bool IsValid() const override;
@ -58,7 +58,7 @@ namespace Aurora::IO
bool IsAsync() const override;
AuString GetPath() const override;
const AuString &GetPath() const override;
bool IsFile() const override;
bool IsTTY() const override;
@ -67,6 +67,9 @@ namespace Aurora::IO
bool IsFlushOnClose() const override;
void SetFlushOnClose(bool bFlushOnClose) override;
bool IsWriteEoSOnClose() const override;
void SetWriteEoSOnClose(bool bShouldWriteEoS) override;
void InitStdIn(bool bSharing = false);
void InitStdOut(bool bError = false, bool bSharing = false);
@ -85,18 +88,17 @@ namespace Aurora::IO
bool ShouldClone();
AuOptionalEx<AuUInt64> uOSWriteHandle;
AuOptionalEx<AuUInt64> uOSReadHandle;
AuOptional<AuUInt64> uOSWriteHandle;
AuOptional<AuUInt64> uOSReadHandle;
AuSPtr<IIOHandle> pThat;
bool bIsAsync {}, bFlushOnClose {};
AuString path;
IPC::IPCPipeImpl *pIPCPipe {};
bool bDirectIO {};
mutable AuOptional<bool> optIsFile;
mutable AuOptional<bool> optIsPipe;
mutable AuOptional<bool> optIsTTY;
mutable AuSPtr<AuString> pIPCString;
AuUInt uThreadId {};
bool bIsAsync {}, bFlushOnClose {}, bShouldWriteEoS {}, bDirectIO {};
protected:
// Implement me:
@ -105,11 +107,11 @@ namespace Aurora::IO
static AuUInt64 DupHandle(AuUInt64 uOSHandle, bool bWriteAccess);
static AuUInt64 DupHandle(AuUInt64 uOSHandle, bool bWriteAccess, bool bShareAccess);
static void CloseHandle(AuUInt64 uOSHandle, bool bFlushOnClose);
static void CloseHandle(AuUInt64 uOSHandle, bool bFlushOnClose, bool bWriteEoS);
inline void CloseHandle(AuUInt64 uOSHandle)
{
CloseHandle(uOSHandle, this->bFlushOnClose);
CloseHandle(uOSHandle, this->bFlushOnClose, false);
}
};
}

View File

@ -406,7 +406,7 @@ namespace Aurora::IO::FS
}
else if (errno == ENOTDIR)
{
if (::unlink(pathExpanded.c_str()) == 0)
if (PosixUnlink(pathExpanded.c_str()) == 0)
{
return true;
}
@ -415,7 +415,7 @@ namespace Aurora::IO::FS
if (S_ISREG(s.st_mode))
{
if (::unlink(pathExpanded.c_str()) == 0)
if (PosixUnlink(pathExpanded.c_str()) == 0)
{
return true;
}

View File

@ -386,7 +386,7 @@ namespace Aurora::IO::FS
return;
}
SetEndOfFile(hHandle);
NTWriteEoS(hHandle);
}
void WinFileStream::Close()
@ -397,10 +397,6 @@ namespace Aurora::IO::FS
bool bDeleteFailed {};
AuString path;
if (this->bShouldWriteEoS)
{
this->WriteEoS();
}
if ((hHandle != INVALID_HANDLE_VALUE) &&
(this->bShouldDelete))
@ -430,6 +426,7 @@ namespace Aurora::IO::FS
// a bit of a hack for problematic NT-like platforms and Windows XP
if (bDeleteFailed)
{
Aurora::RuntimeWaitForSecondaryTick();
AuFS::Remove(path);
}
}
@ -450,7 +447,7 @@ namespace Aurora::IO::FS
{
AU_LOCK_GUARD(this->mutex_);
if (auto pHandle = this->pHandle_)
if (auto &pHandle = this->pHandle_)
{
return pHandle->IsFlushOnClose();
}
@ -464,7 +461,7 @@ namespace Aurora::IO::FS
{
AU_LOCK_GUARD(this->mutex_);
if (auto pHandle = this->pHandle_)
if (auto &pHandle = this->pHandle_)
{
pHandle->SetFlushOnClose(bFlushOnClose);
}
@ -472,12 +469,26 @@ namespace Aurora::IO::FS
bool WinFileStream::IsWriteEoSOnClose() const
{
return this->bShouldWriteEoS;
AU_LOCK_GUARD(this->mutex_);
if (auto &pHandle = this->pHandle_)
{
return pHandle->IsWriteEoSOnClose();
}
else
{
return false;
}
}
void WinFileStream::SetWriteEoSOnClose(bool bShouldWriteEoS)
{
this->bShouldWriteEoS = bShouldWriteEoS;
AU_LOCK_GUARD(this->mutex_);
if (auto &pHandle = this->pHandle_)
{
pHandle->SetWriteEoSOnClose(bShouldWriteEoS);
}
}
AuSPtr<IIOHandle> WinFileStream::GetHandle()

View File

@ -41,7 +41,7 @@ namespace Aurora::IO::FS
private:
AuSPtr<IIOHandle> pHandle_;
bool bShouldDelete {}, bShouldWriteEoS {};
bool bShouldDelete {};
HANDLE hEventHandle_ { INVALID_HANDLE_VALUE };
AuFS::FileReader reader_;
AuFS::FileWriter writer_;

View File

@ -5,9 +5,6 @@
Date: 2021-6-12
Author: Reece
***/
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE
#include <Source/RuntimeInternal.hpp>
#include "FS.hpp"
#include "FileStream.Generic.hpp"
@ -263,16 +260,12 @@ namespace Aurora::IO::FS
auto pHandle = this->pHandle_;
AuResetMember(this->pHandle_);
if (this->bShouldWriteEoS)
{
this->WriteEoS();
}
if (AuExchange(this->bMadeTemporary, false))
{
Aurora::RuntimeWaitForSecondaryTick();
if (pHandle)
{
::unlink(pHandle->GetPath().c_str());
PosixUnlink(pHandle->GetPath().c_str());
}
}
}
@ -281,7 +274,7 @@ namespace Aurora::IO::FS
{
AU_LOCK_GUARD(this->mutex_);
if (auto pHandle = this->pHandle_)
if (auto &pHandle = this->pHandle_)
{
return pHandle->IsFlushOnClose();
}
@ -295,7 +288,7 @@ namespace Aurora::IO::FS
{
AU_LOCK_GUARD(this->mutex_);
if (auto pHandle = this->pHandle_)
if (auto &pHandle = this->pHandle_)
{
pHandle->SetFlushOnClose(bFlushOnClose);
}
@ -303,12 +296,26 @@ namespace Aurora::IO::FS
bool PosixFileStream::IsWriteEoSOnClose() const
{
return this->bShouldWriteEoS;
AU_LOCK_GUARD(this->mutex_);
if (auto &pHandle = this->pHandle_)
{
return pHandle->IsWriteEoSOnClose();
}
else
{
return false;
}
}
void PosixFileStream::SetWriteEoSOnClose(bool bShouldWriteEoS)
{
this->bShouldWriteEoS = bShouldWriteEoS;
AU_LOCK_GUARD(this->mutex_);
if (auto &pHandle = this->pHandle_)
{
pHandle->SetWriteEoSOnClose(bShouldWriteEoS);
}
}
void PosixFileStream::Flush()
@ -328,7 +335,7 @@ namespace Aurora::IO::FS
return;
}
::fsync(fd);
SysFlushHandle(fd);
}
void PosixFileStream::WriteEoS()
@ -348,7 +355,7 @@ namespace Aurora::IO::FS
return;
}
::ftruncate(fd, PosixGetOffset(fd));
PosixWriteEoS(fd);
}
void PosixFileStream::MakeTemporary()

View File

@ -43,11 +43,11 @@ namespace Aurora::IO::FS
AuSPtr<IIOHandle> pHandle_;
AuString path_;
AuMutex mutex_;
bool bMadeTemporary {}, bShouldWriteEoS {};
AuFS::FileReader reader_;
AuFS::FileWriter writer_;
AuFS::FileSeekableReader sreader_;
AuFS::FileSeekableWriter swriter_;
bool bMadeTemporary {};
};
}
#endif