[+] AuNet::ISocketChannelEventListener
[+] AuFS::UpdateTimes [+] AuFS::UpdateFileTimes [+] AuFS::CompressEx [*] AuFS::Compress now rejects files that look to be already compressed [+] AuFS::DecompressEx [+] AuFS::Create [+] AuFS::WriteNewFile [+] AuFS::WriteNewString [+] AuFs::FileAttrsList [+] AuFs::FileAttrsGet [+] AuFs::FileAttrsSet [+] DirectoryLogger::uMaxLogsOrZeroBeforeCompress [+] ISocketChannel.AddEventListener [+] ISocketChannel.AddEventListener [+] DirectoryLogger.uMaxLogsOrZeroBeforeCompress [*] Fix UNIX regression [*] Fix up stream socket channel realloc IPC [*] Fix shutdown regression in pretty much everything thanks to 8ff81df1's dumbass fix (fixes fence regression on shutdown) [*] Fix DirDeleterEx formatting of reported failed paths [*] Fix up file not truncated if already exists bugs. Extended and alternative apis added. [*] Fix ICompressionStream::ReadEx returning the wrong read value [+] Legacy compression API can now self-correct once newer stream processor objects are added
This commit is contained in:
parent
7d46679969
commit
f43251c8fc
@ -7,6 +7,8 @@
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
#include <Aurora/Compression/ECompressionType.hpp>
|
||||
|
||||
namespace Aurora::IO::FS
|
||||
{
|
||||
struct IReadDir;
|
||||
@ -61,6 +63,14 @@ namespace Aurora::IO::FS
|
||||
*/
|
||||
AUKN_SYM bool WriteFile(const AuString &path, const Memory::MemoryViewRead &blob);
|
||||
|
||||
/**
|
||||
* @brief Same as WriteFile except fails if the file already exists
|
||||
* @param path
|
||||
* @param blob
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM bool WriteNewFile(const AuString &path, const Memory::MemoryViewRead &blob);
|
||||
|
||||
/**
|
||||
* @brief Writes a UTF-8 string onto disk with a BOM
|
||||
* The directory structure may or may not exist for the write operation to succeed.
|
||||
@ -70,6 +80,14 @@ namespace Aurora::IO::FS
|
||||
*/
|
||||
AUKN_SYM bool WriteString(const AuString &path, const AuString &str);
|
||||
|
||||
/**
|
||||
* @brief Same as WriteString except fails if the file already exists
|
||||
* @param path
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM bool WriteNewString(const AuString &path, const AuString &str);
|
||||
|
||||
/**
|
||||
* @brief Returns a bytebuffer (does not write into) of a binary files contents
|
||||
* @param path An Aurora path as defined in the README
|
||||
@ -176,9 +194,59 @@ namespace Aurora::IO::FS
|
||||
* @param path = ur mother
|
||||
*/
|
||||
AUKN_SYM bool Compress(const AuString &path, AuInt8 level = 17);
|
||||
|
||||
AUKN_SYM bool CompressEx(const AuString &path, const AuString &suffix, Compression::ECompressionType type, AuInt8 level);
|
||||
|
||||
AUKN_SYM bool Decompress(const AuString &path);
|
||||
|
||||
AUKN_SYM bool DecompressEx(const AuString &path, const AuString &suffix, Compression::ECompressionType type);
|
||||
|
||||
struct UpdateTimes
|
||||
{
|
||||
AuOptionalEx<AuInt64> createdNs;
|
||||
AuOptionalEx<AuInt64> modifiedNs;
|
||||
AuOptionalEx<AuInt64> accessedNs;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param times
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM bool UpdateFileTimes(const AuString &path, const UpdateTimes ×);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM AuList<AuString> FileAttrsList(const AuString &path);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param path
|
||||
* @param attr
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM AuResult<Memory::ByteBuffer> FileAttrsGet(const AuString &path, const AuString &attr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param path
|
||||
* @param attr
|
||||
* @param view
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM bool FileAttrsSet(const AuString &path, const AuString &attr, const Memory::MemoryViewRead &view);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param path
|
||||
* @param attr
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM bool FileAttrsDel(const AuString &path, const AuString &attr);
|
||||
|
||||
/**
|
||||
* @brief Normalizes an arbitrary string of in
|
||||
* @param out
|
||||
|
@ -9,6 +9,10 @@
|
||||
|
||||
namespace Aurora::IO::FS
|
||||
{
|
||||
// WARNING: there are no truncate write modes. IFileStream::WriteEoS must be called by the caller of Open[Write]s.
|
||||
|
||||
AUKN_SHARED_API(Create, IFileStream, const AuString &path);
|
||||
|
||||
AUKN_SHARED_API(OpenRead, IFileStream, const AuString &path, EFileAdvisoryLockLevel successPostAdvisoryLevel = EFileAdvisoryLockLevel::eBlockWrite);
|
||||
|
||||
AUKN_SHARED_API(OpenWrite, IFileStream, const AuString &path, EFileAdvisoryLockLevel successPostAdvisoryLevel = EFileAdvisoryLockLevel::eBlockReadWrite);
|
||||
|
@ -15,7 +15,8 @@ namespace Aurora::IO::Protocol
|
||||
namespace Aurora::IO::Net
|
||||
{
|
||||
struct ISocket;
|
||||
|
||||
struct ISocketChannelEventListener;
|
||||
|
||||
struct ISocketChannel : Protocol::IProtocolBaseReader, Protocol::IProtocolBaseWriter
|
||||
{
|
||||
/**
|
||||
@ -205,5 +206,17 @@ namespace Aurora::IO::Net
|
||||
* @return
|
||||
*/
|
||||
virtual AuSPtr<ISocketStats> GetSendStats() = 0;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param pListener
|
||||
*/
|
||||
virtual void AddEventListener(const AuSPtr<ISocketChannelEventListener> &pListener) = 0;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param pListener
|
||||
*/
|
||||
virtual void RemoveEventListener(const AuSPtr<ISocketChannelEventListener> &pListener) = 0;
|
||||
};
|
||||
}
|
18
Include/Aurora/IO/Net/ISocketChannelEventListener.hpp
Normal file
18
Include/Aurora/IO/Net/ISocketChannelEventListener.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: ISocketChannelEventListener.hpp
|
||||
Date: 2023-1-30
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::IO::Net
|
||||
{
|
||||
AUKN_INTERFACE(ISocketChannelEventListener,
|
||||
// return false to remove
|
||||
AUI_METHOD(bool, OnData, ()),
|
||||
AUI_METHOD(void, OnRejected, ()),
|
||||
AUI_METHOD(void, OnComplete, ())
|
||||
);
|
||||
}
|
@ -19,6 +19,8 @@
|
||||
#include "NetHostname.hpp"
|
||||
#include "NetError.hpp"
|
||||
|
||||
#include "ISocketChannelEventListener.hpp"
|
||||
|
||||
#include "ISocketBase.hpp"
|
||||
#include "ISocket.hpp"
|
||||
#include "ISocketStats.hpp"
|
||||
|
@ -16,6 +16,7 @@ namespace Aurora::Logging
|
||||
{
|
||||
struct DirectoryLogger
|
||||
{
|
||||
AuUInt32 uMaxLogsOrZeroBeforeCompress {};
|
||||
AuUInt32 uMaxLogsOrZeroBeforeDelete {};
|
||||
AuUInt32 uMaxCumulativeFileSizeInMiBOrZeroBeforeDelete {};
|
||||
AuUInt32 uMaxCumulativeFileSizeInMiBOrZeroBeforeCompress {};
|
||||
|
@ -623,26 +623,8 @@ namespace Aurora::Async
|
||||
|
||||
void ThreadPool::Shutdown()
|
||||
{
|
||||
// Always do this
|
||||
auto trySelfPid = AuAsync::GetCurrentWorkerPId();
|
||||
|
||||
{
|
||||
AU_LOCK_GUARD(this->rwlock_->AsWritable());
|
||||
|
||||
for (auto &[groupId, group] : this->threads_)
|
||||
{
|
||||
for (auto &[id, worker] : group->workers)
|
||||
{
|
||||
worker->shuttingdown = true;
|
||||
|
||||
if (group->cvWorkMutex && group->cvVariable)
|
||||
{
|
||||
group->cvVariable->Broadcast();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update shutting down flag
|
||||
{
|
||||
if (AuAtomicTestAndSet(&this->shuttingdown_, 0) != 0)
|
||||
@ -650,7 +632,7 @@ namespace Aurora::Async
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Noting
|
||||
// 1) that StopSched may lockup under a writable lock
|
||||
// -> we will terminate a thread that may be dispatching a sys pump event
|
||||
@ -698,8 +680,6 @@ namespace Aurora::Async
|
||||
{
|
||||
if (group->cvWorkMutex && group->cvVariable)
|
||||
{
|
||||
// TODO (urgent)
|
||||
//AU_LOCK_GUARD(group->cvWorkMutex);
|
||||
bool bLocked = group->cvWorkMutex->TryLock();
|
||||
worker->shuttingdown = true;
|
||||
group->cvVariable->Broadcast();
|
||||
@ -731,7 +711,7 @@ namespace Aurora::Async
|
||||
thread->Exit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ThreadPool::Exiting()
|
||||
{
|
||||
return this->shuttingdown_ ||
|
||||
|
@ -30,17 +30,24 @@ namespace Aurora::Compression
|
||||
{
|
||||
auto toRead = destination.length ? AuUInt32(destination.length - this->pOutputBuffer_->RemainingBytes()) : 10 * 1024;
|
||||
|
||||
if (Ingest_s(toRead).second == 0)
|
||||
// TODO: I was trying to get out of stream memory to explode less with real code. bIngestUntilEOS users are usually lazy decompressors
|
||||
// This was just to give a chance to yield, because theres no API to process after end of write condition; we always ended up failing.
|
||||
// ...
|
||||
// I think this rate limiter can be removed. Something else was the primary factor.
|
||||
toRead = AuMin<AuUInt32>(toRead, 1024 * 10);
|
||||
|
||||
auto realPair = Ingest_s(toRead);
|
||||
dwRead += realPair.first;
|
||||
|
||||
if (realPair.second == 0)
|
||||
{
|
||||
if (!this->pOutputBuffer_->RemainingBytes(true))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
//if (!this->pOutputBuffer_->RemainingBytes(true))
|
||||
//{
|
||||
// return {};
|
||||
//}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
dwRead += toRead;
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,6 +68,7 @@ namespace Aurora::Compression
|
||||
{
|
||||
return this->pOutputBuffer_->RemainingBytes();
|
||||
}
|
||||
|
||||
return this->pOutputBuffer_->Read(destination.ptr, destination.length, destination.ptr == nullptr);
|
||||
}
|
||||
|
||||
@ -88,7 +96,7 @@ namespace Aurora::Compression
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
return Ingest_s(dwBytesFromUnprocessedInputSource);
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ namespace Aurora::Compression
|
||||
{
|
||||
struct BaseStream : ICompressionStream, protected IngestableReadBase
|
||||
{
|
||||
inline BaseStream(AuUInt32 bufferSize = 4096 * 4) : _outbufferOwned(bufferSize, true), uBufferSize_(bufferSize)
|
||||
inline BaseStream(AuUInt32 bufferSize = 4096 * 64) : _outbufferOwned(bufferSize, true), uBufferSize_(bufferSize)
|
||||
{
|
||||
SetBuffer({});
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
namespace Aurora::Compression
|
||||
{
|
||||
static const AuUInt64 kChunkSize = 32 * 1024;
|
||||
static const AuUInt64 kChunkSize = 128 * 1024;
|
||||
|
||||
/// * compression type + bits -> internal zlib windowBits
|
||||
static bool CompressionLevelFromExternalApi(const DecompressInfo &info, AuInt8 &out)
|
||||
|
@ -105,7 +105,7 @@ namespace Aurora::Compression
|
||||
have))
|
||||
{
|
||||
this->pReader_.reset();
|
||||
SysPushErrorIO("Memory Error");
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
return AuMakePair(read, 0);
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ namespace Aurora::Compression
|
||||
have))
|
||||
{
|
||||
this->pReader_.reset();
|
||||
SysPushErrorIO("Memory Error");
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -183,7 +183,7 @@ namespace Aurora::Compression
|
||||
have))
|
||||
{
|
||||
this->pReader_.reset();
|
||||
SysPushErrorIO("Memory Error");
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ namespace Aurora::Compression
|
||||
if (!Write(reinterpret_cast<const AuUInt8 *>(this->dout_),
|
||||
have))
|
||||
{
|
||||
SysPushErrorIO("Memory Error");
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
this->pReader_.reset();
|
||||
return AuMakePair(read, 0);
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ namespace Aurora::Compression
|
||||
have))
|
||||
{
|
||||
this->pReader_.reset();
|
||||
SysPushErrorIO("Memory Error");
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
return AuMakePair(read, 0);
|
||||
}
|
||||
|
||||
@ -143,7 +143,7 @@ namespace Aurora::Compression
|
||||
have))
|
||||
{
|
||||
this->pReader_.reset();
|
||||
SysPushErrorIO("Memory Error");
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -171,7 +171,7 @@ namespace Aurora::Compression
|
||||
have))
|
||||
{
|
||||
this->pReader_.reset();
|
||||
SysPushErrorIO("Memory Error");
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
return false;
|
||||
}
|
||||
} while (this->ctx_.avail_out == 0);
|
||||
|
@ -100,7 +100,7 @@ namespace Aurora::Compression
|
||||
have))
|
||||
{
|
||||
this->pReader_.reset();
|
||||
SysPushErrorIO("Memory Error");
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
return AuMakePair(read, 0);
|
||||
}
|
||||
|
||||
|
@ -106,6 +106,7 @@ namespace Aurora::Compression
|
||||
{
|
||||
if (!Write(this->pBufferOut_.get(), frameS2Ptr))
|
||||
{
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -125,6 +125,7 @@ namespace Aurora::Compression
|
||||
if (!Write(reinterpret_cast<const AuUInt8 *>(this->dout_),
|
||||
AuUInt32(output.pos)))
|
||||
{
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
this->pReader_.reset();
|
||||
return AuMakePair(read, 0);
|
||||
}
|
||||
@ -169,6 +170,7 @@ namespace Aurora::Compression
|
||||
if (!Write(reinterpret_cast<const AuUInt8 *>(this->dout_),
|
||||
AuUInt32(output.pos)))
|
||||
{
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
this->pReader_.reset();
|
||||
return false;
|
||||
}
|
||||
@ -199,6 +201,7 @@ namespace Aurora::Compression
|
||||
if (!Write(reinterpret_cast<const AuUInt8 *>(this->dout_),
|
||||
AuUInt32(output.pos)))
|
||||
{
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ namespace Aurora::Compression
|
||||
if (!Write(reinterpret_cast<const AuUInt8 *>(output.dst),
|
||||
AuUInt32(output.pos)))
|
||||
{
|
||||
SysPushErrorIO("Compression Out of Overhead");
|
||||
this->pReader_.reset();
|
||||
return AuMakePair(read, 0);
|
||||
}
|
||||
|
@ -819,6 +819,186 @@ namespace Aurora::Compression
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool DecompressNoOldAssReferenceImpl(const CompressionPipe &stream, const DecompressInfo &meta2)
|
||||
{
|
||||
if (!stream.pWritePipe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!stream.pReadPipe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DecompressInfo meta3 = meta2;
|
||||
meta3.uInternalStreamSize = kChunkSize * 10; // stupid, but required for BaseStream::Write to not blow up. not optimizing old apis.
|
||||
auto pCompressor = DecompressorUnique(stream.pReadPipe, meta3);
|
||||
if (!pCompressor)
|
||||
{
|
||||
SysPushErrorGeneric("No decompressor / inflator");
|
||||
return false;
|
||||
}
|
||||
|
||||
AuByteBuffer buffer(kChunkSize * 2, true);
|
||||
|
||||
AuStreamReadWrittenPair_t pair;
|
||||
do
|
||||
{
|
||||
auto view = buffer.GetNextLinearRead();
|
||||
view.length = AuMin(view.length, kChunkSize / 2);
|
||||
auto pair = pCompressor->ReadEx(AuMemory::MemoryViewWrite(buffer), true);
|
||||
|
||||
while (pair.first || pair.second)
|
||||
{
|
||||
buffer.writePtr += pair.second;
|
||||
|
||||
{
|
||||
AuUInt copy;
|
||||
auto err = AuIO::WriteAll(stream.pWritePipe.get(), AuMemory::MemoryViewStreamRead(buffer, copy));
|
||||
if (err != AuIO::EStreamError::eErrorNone)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer.readPtr += copy;
|
||||
}
|
||||
|
||||
if (buffer.writePtr == buffer.readPtr)
|
||||
{
|
||||
buffer.readPtr = buffer.writePtr = buffer.base;
|
||||
}
|
||||
|
||||
pair = pCompressor->ReadEx(AuMemory::MemoryViewWrite(buffer), true);
|
||||
}
|
||||
|
||||
// debugging cope loops
|
||||
#if 0
|
||||
while (buffer.readPtr != buffer.writePtr)
|
||||
{
|
||||
{
|
||||
AuUInt copy;
|
||||
auto err = AuIO::WriteAll(stream.pWritePipe.get(), AuMemory::MemoryViewStreamRead(buffer, copy));
|
||||
if (err != AuIO::EStreamError::eErrorNone)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer.readPtr += copy;
|
||||
}
|
||||
}
|
||||
|
||||
for (AuUInt i = 0;
|
||||
i < 5 && (!(pair.first || pair.second));
|
||||
i++)
|
||||
{
|
||||
pair = pCompressor->ReadEx(AuMemory::MemoryViewWrite(buffer), true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
while (pair.first || pair.second);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CompressNoOldAssReferenceImpl(const CompressionPipe &stream, const CompressInfo &meta2)
|
||||
{
|
||||
if (!stream.pWritePipe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!stream.pReadPipe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CompressInfo meta3 = meta2;
|
||||
meta3.uInternalStreamSize = kChunkSize / 2;
|
||||
auto pCompressor = CompressorUnique(stream.pReadPipe, meta3);
|
||||
if (!pCompressor)
|
||||
{
|
||||
SysPushErrorGeneric("No compressor / deflator");
|
||||
return false;
|
||||
}
|
||||
|
||||
AuByteBuffer buffer(kChunkSize / 2, true);
|
||||
|
||||
AuStreamReadWrittenPair_t pair;
|
||||
do
|
||||
{
|
||||
auto view = buffer.GetNextLinearRead();
|
||||
view.length = AuMin(view.length, kChunkSize / 2);
|
||||
auto pair = pCompressor->ReadEx(AuMemory::MemoryViewWrite(buffer), true);
|
||||
|
||||
while (pair.first || pair.second)
|
||||
{
|
||||
buffer.writePtr += pair.second;
|
||||
|
||||
{
|
||||
AuUInt copy;
|
||||
auto err = AuIO::WriteAll(stream.pWritePipe.get(), AuMemory::MemoryViewStreamRead(buffer, copy));
|
||||
if (err != AuIO::EStreamError::eErrorNone)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer.readPtr += copy;
|
||||
}
|
||||
|
||||
if (buffer.writePtr == buffer.readPtr)
|
||||
{
|
||||
buffer.readPtr = buffer.writePtr = buffer.base;
|
||||
}
|
||||
|
||||
pair = pCompressor->ReadEx(AuMemory::MemoryViewWrite(buffer), true);
|
||||
}
|
||||
}
|
||||
while (pair.first || pair.second);
|
||||
|
||||
pCompressor->Flush();
|
||||
|
||||
pCompressor->Finish();
|
||||
|
||||
do
|
||||
{
|
||||
if (buffer.writePtr == buffer.readPtr)
|
||||
{
|
||||
buffer.readPtr = buffer.writePtr = buffer.base;
|
||||
}
|
||||
|
||||
auto view = buffer.GetNextLinearRead();
|
||||
view.length = AuMin(view.length, kChunkSize / 2);
|
||||
auto pair = pCompressor->ReadEx(AuMemory::MemoryViewWrite(buffer), false);
|
||||
|
||||
while (pair.first || pair.second)
|
||||
{
|
||||
buffer.writePtr += pair.second;
|
||||
|
||||
{
|
||||
AuUInt copy;
|
||||
auto err = AuIO::WriteAll(stream.pWritePipe.get(), AuMemory::MemoryViewStreamRead(buffer, copy));
|
||||
if (err != AuIO::EStreamError::eErrorNone)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer.readPtr += copy;
|
||||
}
|
||||
|
||||
if (buffer.writePtr == buffer.readPtr)
|
||||
{
|
||||
buffer.readPtr = buffer.writePtr = buffer.base;
|
||||
}
|
||||
|
||||
pair = pCompressor->ReadEx(AuMemory::MemoryViewWrite(buffer), false);
|
||||
}
|
||||
}
|
||||
while (pair.first || pair.second);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AUKN_SYM bool Compress(const CompressionPipe &stream, const CompressInfo &info)
|
||||
{
|
||||
CompressInfo meta = info;
|
||||
@ -826,11 +1006,13 @@ namespace Aurora::Compression
|
||||
|
||||
if (!stream.pReadPipe)
|
||||
{
|
||||
SysPushErrorArg();
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!stream.pWritePipe)
|
||||
{
|
||||
SysPushErrorArg();
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -856,7 +1038,7 @@ namespace Aurora::Compression
|
||||
//case ECompressionType::eLZMA:
|
||||
// return CompressLZMA(stream, info);
|
||||
default:
|
||||
return false;
|
||||
return CompressNoOldAssReferenceImpl(stream, info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -897,7 +1079,7 @@ namespace Aurora::Compression
|
||||
//case ECompressionType::eLZMA:
|
||||
// return DecompressLZMA(pipe);
|
||||
default:
|
||||
return false;
|
||||
return DecompressNoOldAssReferenceImpl(pipe, meta2);
|
||||
}
|
||||
}
|
||||
}
|
@ -154,11 +154,21 @@ namespace Aurora::IO::FS
|
||||
{
|
||||
for (const auto &str : pObj->failedPaths)
|
||||
{
|
||||
auto normalizedUserDir = string + "/" + str;
|
||||
auto normalizedUserDir = string + "/" ;
|
||||
auto normalizedUserDir2 = normalizedUserDir + str;
|
||||
|
||||
if (AuFS::FileExists(normalizedUserDir) ||
|
||||
AuFS::DirExists(normalizedUserDir))
|
||||
if (AuFS::FileExists(normalizedUserDir2) ||
|
||||
AuFS::DirExists(normalizedUserDir2))
|
||||
{
|
||||
if (AuEndsWith(normalizedUserDir, "//") ||
|
||||
AuEndsWith(normalizedUserDir, "\\/"))
|
||||
{
|
||||
normalizedUserDir.pop_back();
|
||||
normalizedUserDir[normalizedUserDir.size() - 1] = '/';
|
||||
}
|
||||
|
||||
normalizedUserDir += str;
|
||||
|
||||
failingPaths.push_back(normalizedUserDir);
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ namespace Aurora::IO::FS
|
||||
return true;
|
||||
}
|
||||
|
||||
AUKN_SYM bool WriteFile(const AuString &path, const Memory::MemoryViewRead &blob)
|
||||
static bool WriteFileEx(const AuString &path, const Memory::MemoryViewRead &blob, bool bCheck)
|
||||
{
|
||||
bool status;
|
||||
size_t offset;
|
||||
@ -192,18 +192,50 @@ namespace Aurora::IO::FS
|
||||
|
||||
CreateDirectories(pathNormalized, true);
|
||||
|
||||
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||
if (bCheck)
|
||||
{
|
||||
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
fileHandle = ::CreateFileW(win32Path.c_str(),
|
||||
GENERIC_WRITE,
|
||||
NULL,
|
||||
NULL,
|
||||
CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||
else
|
||||
{
|
||||
AuThreading::ContextYield();
|
||||
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
}
|
||||
fileHandle = ::CreateFileW(win32Path.c_str(),
|
||||
GENERIC_WRITE | GENERIC_READ,
|
||||
NULL,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fileHandle = ::CreateFileW(win32Path.c_str(),
|
||||
GENERIC_WRITE,
|
||||
NULL,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
AuThreading::ContextYield();
|
||||
fileHandle = ::CreateFileW(win32Path.c_str(),
|
||||
GENERIC_WRITE | GENERIC_READ,
|
||||
NULL,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
}
|
||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
SysPushErrorIO("Couldn't open handle: {}", path);
|
||||
@ -236,11 +268,24 @@ namespace Aurora::IO::FS
|
||||
|
||||
status = true;
|
||||
|
||||
::SetEndOfFile(fileHandle);
|
||||
::FlushFileBuffers(fileHandle);
|
||||
|
||||
out:
|
||||
AuWin32CloseHandle(fileHandle);
|
||||
return status;
|
||||
}
|
||||
|
||||
AUKN_SYM bool WriteFile(const AuString &path, const Memory::MemoryViewRead &blob)
|
||||
{
|
||||
return WriteFileEx(path, blob, false);
|
||||
}
|
||||
|
||||
AUKN_SYM bool WriteNewFile(const AuString &path, const Memory::MemoryViewRead &blob)
|
||||
{
|
||||
return WriteFileEx(path, blob, true);
|
||||
}
|
||||
|
||||
AUKN_SYM bool ReadFile(const AuString &path, AuByteBuffer &buffer)
|
||||
{
|
||||
std::wstring win32Path;
|
||||
@ -258,14 +303,20 @@ namespace Aurora::IO::FS
|
||||
return false;
|
||||
}
|
||||
|
||||
auto fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
auto fileHandle = ::CreateFileW(win32Path.c_str(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
SysPushErrorIO("Couldn't open handle: {}", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GetFileSizeEx(fileHandle, &length))
|
||||
if (!::GetFileSizeEx(fileHandle, &length))
|
||||
{
|
||||
SysPushErrorIO();
|
||||
goto out;
|
||||
@ -307,7 +358,7 @@ namespace Aurora::IO::FS
|
||||
{
|
||||
try
|
||||
{
|
||||
DWORD dwAttrib = GetFileAttributesW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str());
|
||||
DWORD dwAttrib = ::GetFileAttributesW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str());
|
||||
return ((dwAttrib != INVALID_FILE_ATTRIBUTES) &&
|
||||
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
@ -321,7 +372,7 @@ namespace Aurora::IO::FS
|
||||
{
|
||||
try
|
||||
{
|
||||
DWORD dwAttrib = GetFileAttributesW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str());
|
||||
DWORD dwAttrib = ::GetFileAttributesW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str());
|
||||
return ((dwAttrib != INVALID_FILE_ATTRIBUTES) &&
|
||||
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
@ -374,8 +425,8 @@ namespace Aurora::IO::FS
|
||||
auto destPathNormalized = NormalizePathRet(dest);
|
||||
CreateDirectories(destPathNormalized, true);
|
||||
|
||||
return MoveFileW(Locale::ConvertFromUTF8(srcPathNormalized).c_str(),
|
||||
Locale::ConvertFromUTF8(destPathNormalized).c_str());
|
||||
return ::MoveFileW(Locale::ConvertFromUTF8(srcPathNormalized).c_str(),
|
||||
Locale::ConvertFromUTF8(destPathNormalized).c_str());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@ -391,8 +442,8 @@ namespace Aurora::IO::FS
|
||||
auto destPathNormalized = NormalizePathRet(dest);
|
||||
CreateDirectories(destPathNormalized, true);
|
||||
|
||||
return CopyFileW(Locale::ConvertFromUTF8(srcPathNormalized).c_str(),
|
||||
Locale::ConvertFromUTF8(destPathNormalized).c_str(), true);
|
||||
return ::CopyFileW(Locale::ConvertFromUTF8(srcPathNormalized).c_str(),
|
||||
Locale::ConvertFromUTF8(destPathNormalized).c_str(), true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@ -406,7 +457,7 @@ namespace Aurora::IO::FS
|
||||
|
||||
stat = {};
|
||||
|
||||
if (!GetFileAttributesExW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str(), GetFileExInfoStandard, &data))
|
||||
if (!::GetFileAttributesExW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str(), GetFileExInfoStandard, &data))
|
||||
{
|
||||
stat.bExists = false;
|
||||
return false;
|
||||
|
@ -211,27 +211,48 @@ namespace Aurora::IO::FS
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AUKN_SYM bool WriteFile(const AuString &path, const Memory::MemoryViewRead &blob)
|
||||
|
||||
static bool WriteFileEx(const AuString &path, const Memory::MemoryViewRead &blob, bool bCheck)
|
||||
{
|
||||
auto file = OpenWriteUnique(path);
|
||||
SysCheckReturn(file, false);
|
||||
auto pFile = OpenWriteUnique(path);
|
||||
SysCheckReturn(pFile, false);
|
||||
|
||||
if (bCheck)
|
||||
{
|
||||
if (pFile->GetLength())
|
||||
{
|
||||
SysPushErrorIO("File exists: {}", path);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
AuUInt written = blob.length;
|
||||
if (!file->Write(Memory::MemoryViewStreamRead(blob, written)))
|
||||
if (!pFile->Write(Memory::MemoryViewStreamRead(blob, written)))
|
||||
{
|
||||
SysPushErrorMem();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
pFile->WriteEoS();
|
||||
|
||||
if (written != blob.length)
|
||||
{
|
||||
{
|
||||
SysPushErrorIO();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
AUKN_SYM bool WriteFile(const AuString &path, const Memory::MemoryViewRead &blob)
|
||||
{
|
||||
return WriteFileEx(path, blob, false);
|
||||
}
|
||||
|
||||
AUKN_SYM bool WriteNewFile(const AuString &path, const Memory::MemoryViewRead &blob)
|
||||
{
|
||||
return WriteFileEx(path, blob, true);
|
||||
}
|
||||
|
||||
AUKN_SYM bool ReadFile(const AuString &path, AuByteBuffer &buffer)
|
||||
{
|
||||
@ -324,7 +345,7 @@ namespace Aurora::IO::FS
|
||||
{
|
||||
auto normalizedDestPath = NormalizePathRet(dest);
|
||||
CreateDirectories(destPathNormalized, true);
|
||||
return rename(NormalizePathRet(src).c_str(), destPathNormalized.c_str()) != -1;
|
||||
return ::rename(NormalizePathRet(src).c_str(), destPathNormalized.c_str()) != -1;
|
||||
}
|
||||
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
@ -336,29 +357,29 @@ namespace Aurora::IO::FS
|
||||
|
||||
int input, output;
|
||||
|
||||
if ((input = open(normalizedSrcPath.c_str(), O_RDONLY | O_CLOEXEC)) == -1)
|
||||
if ((input = ::open(normalizedSrcPath.c_str(), O_RDONLY | O_CLOEXEC)) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
struct stat fileinfo = { 0 };
|
||||
if (fstat(input, &fileinfo) != 0)
|
||||
if (::fstat(input, &fileinfo) != 0)
|
||||
{
|
||||
close(input);
|
||||
::close(input);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((output = creat(normalizedDestPath.c_str(), fileinfo.st_mode)) == -1)
|
||||
if ((output = ::creat(normalizedDestPath.c_str(), fileinfo.st_mode)) == -1)
|
||||
{
|
||||
close(input);
|
||||
::close(input);
|
||||
return false;
|
||||
}
|
||||
|
||||
off_t bytesCopied = 0;
|
||||
auto result = sendfile(output, input, &bytesCopied, fileinfo.st_size) != -1;
|
||||
auto result = ::sendfile(output, input, &bytesCopied, fileinfo.st_size) != -1;
|
||||
|
||||
close(input);
|
||||
close(output);
|
||||
::close(input);
|
||||
::close(output);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -420,7 +441,7 @@ namespace Aurora::IO::FS
|
||||
{
|
||||
if (ENOENT != errno)
|
||||
{
|
||||
AuLogWarn("Critical IO error while stating file (errno: {}, path: {})", errno, path);
|
||||
SysPushErrorIO("Critical IO error while stating file (errno: {}, path: {})", errno, path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -432,7 +453,7 @@ namespace Aurora::IO::FS
|
||||
|
||||
if (!stat.bExists)
|
||||
{
|
||||
AuLogWarn("Missing attribute type in stat mode {} (of path {})", s.st_mode, path);
|
||||
SysPushErrorIO("Missing attribute type in stat mode {} (of path {})", s.st_mode, path);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -263,7 +263,7 @@ namespace Aurora::IO::FS
|
||||
|
||||
return Locale::Encoding::DecodeUTF8(fileBuffer.data(), fileBuffer.size(), buffer, Locale::ECodePage::eUTF8).first != 0;
|
||||
}
|
||||
|
||||
|
||||
AUKN_SYM bool WriteString(const AuString &path, const AuString &str)
|
||||
{
|
||||
char bom[3]
|
||||
@ -271,20 +271,48 @@ namespace Aurora::IO::FS
|
||||
'\xEF', '\xBB', '\xBF'
|
||||
};
|
||||
|
||||
auto stream = FS::OpenWriteUnique(path);
|
||||
if (!stream)
|
||||
auto pStream = FS::OpenWriteUnique(path);
|
||||
if (!pStream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool ok {};
|
||||
ok = stream->Write(AuMemoryViewStreamRead{bom});
|
||||
ok &= stream->Write(AuMemoryViewStreamRead{str});
|
||||
stream->Flush();
|
||||
ok = pStream->Write(AuMemoryViewStreamRead { bom });
|
||||
ok &= pStream->Write(AuMemoryViewStreamRead { str });
|
||||
pStream->Flush();
|
||||
pStream->WriteEoS();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
AUKN_SYM bool WriteNewString(const AuString &path, const AuString &str)
|
||||
{
|
||||
char bom[3]
|
||||
{
|
||||
'\xEF', '\xBB', '\xBF'
|
||||
};
|
||||
|
||||
auto pStream = FS::OpenWriteUnique(path);
|
||||
if (!pStream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pStream->GetLength())
|
||||
{
|
||||
SysPushErrorIO("File exists: {}", path);
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ok {};
|
||||
ok = pStream->Write(AuMemoryViewStreamRead { bom });
|
||||
ok &= pStream->Write(AuMemoryViewStreamRead { str });
|
||||
pStream->Flush();
|
||||
pStream->WriteEoS();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
AUKN_SYM bool NormalizePath(AuString &out, const AuString &in)
|
||||
{
|
||||
|
@ -16,10 +16,25 @@ namespace Aurora::IO::FS
|
||||
static auto const kCompressionType = AuCompression::ECompressionType::eZSTD;
|
||||
static const AuString kStringSuffix = ".zst";
|
||||
|
||||
AUKN_SYM bool Compress(const AuString &path, AuInt8 level)
|
||||
static bool CompressEx2(const AuString &path, const AuString &suffix, AuCompression::ECompressionType type, AuInt8 level, bool bCheck)
|
||||
{
|
||||
static const auto kCompressionReadChunks = kFileCopyBlock;
|
||||
|
||||
if (suffix.empty())
|
||||
{
|
||||
SysPushErrorInvalidArgPos2();
|
||||
return {};
|
||||
}
|
||||
|
||||
if (bCheck)
|
||||
{
|
||||
if (AuEndsWith(path, suffix))
|
||||
{
|
||||
SysPushErrorIO("File path (\"{}\") ends in {}, yet was requested to be compressed. A user or a developer is probably being stupid.", path, suffix);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto pFileSrc = OpenReadShared(path, EFileAdvisoryLockLevel::eBlockWrite);
|
||||
if (!pFileSrc)
|
||||
{
|
||||
@ -27,16 +42,16 @@ namespace Aurora::IO::FS
|
||||
return {};
|
||||
}
|
||||
|
||||
auto pFileDest = OpenWriteShared(path + kStringSuffix, EFileAdvisoryLockLevel::eBlockReadWrite);
|
||||
auto pFileDest = OpenWriteShared(path + suffix, EFileAdvisoryLockLevel::eBlockReadWrite);
|
||||
if (!pFileDest)
|
||||
{
|
||||
SysPushErrorIO("Couldn't open compression destination path: {}.{}", path, kStringSuffix);
|
||||
SysPushErrorIO("Couldn't open compression destination path: {}{}", path, suffix);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (pFileDest->GetLength())
|
||||
{
|
||||
SysPushErrorIO("File exists");
|
||||
SysPushErrorIO("File ({}) exists", path);
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -56,7 +71,7 @@ namespace Aurora::IO::FS
|
||||
return {};
|
||||
}
|
||||
|
||||
AuCompression::CompressInfo compress { kCompressionType };
|
||||
AuCompression::CompressInfo compress { type };
|
||||
compress.uCompressionLevel = level;
|
||||
compress.uInternalStreamSize = kCompressionReadChunks * 2;
|
||||
auto pCompressor = AuCompression::CompressorUnique(pFileStream, compress);
|
||||
@ -132,14 +147,30 @@ namespace Aurora::IO::FS
|
||||
return qwTotalRead == qwLength;
|
||||
}
|
||||
|
||||
AUKN_SYM bool Decompress(const AuString &path)
|
||||
AUKN_SYM bool CompressEx(const AuString &path, const AuString &suffix, AuCompression::ECompressionType type, AuInt8 level)
|
||||
{
|
||||
return CompressEx2(path, kStringSuffix, kCompressionType, level, false);
|
||||
}
|
||||
|
||||
AUKN_SYM bool Compress(const AuString &path, AuInt8 level)
|
||||
{
|
||||
return CompressEx2(path, kStringSuffix, kCompressionType, level, true);
|
||||
}
|
||||
|
||||
AUKN_SYM bool DecompressEx(const AuString &path, const AuString &suffix, AuCompression::ECompressionType type)
|
||||
{
|
||||
static const auto kCompressionReadChunks = kFileCopyBlock;
|
||||
|
||||
auto pFileSrc = OpenReadShared(path + kStringSuffix, EFileAdvisoryLockLevel::eBlockWrite);
|
||||
if (suffix.empty())
|
||||
{
|
||||
SysPushErrorInvalidArgPos2();
|
||||
return {};
|
||||
}
|
||||
|
||||
auto pFileSrc = OpenReadShared(path + suffix, EFileAdvisoryLockLevel::eBlockWrite);
|
||||
if (!pFileSrc)
|
||||
{
|
||||
SysPushErrorIO("Couldn't open compression source path: {}.{}", path, kStringSuffix);
|
||||
SysPushErrorIO("Couldn't open compression source path: {}{}", path, suffix);
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -152,7 +183,7 @@ namespace Aurora::IO::FS
|
||||
|
||||
if (pFileDest->GetLength())
|
||||
{
|
||||
SysPushErrorIO("File exists");
|
||||
SysPushErrorIO("File exists path: {}", path);
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -172,7 +203,7 @@ namespace Aurora::IO::FS
|
||||
return {};
|
||||
}
|
||||
|
||||
AuCompression::DecompressInfo decompress{ kCompressionType };
|
||||
AuCompression::DecompressInfo decompress{ type };
|
||||
decompress.uInternalStreamSize = kCompressionReadChunks * 5;
|
||||
auto pDecompressor = AuCompression::DecompressorUnique(pFileStream, decompress);
|
||||
if (!pDecompressor)
|
||||
@ -221,4 +252,9 @@ namespace Aurora::IO::FS
|
||||
|
||||
return qwTotalRead == qwLength;
|
||||
}
|
||||
|
||||
AUKN_SYM bool Decompress(const AuString &path)
|
||||
{
|
||||
return DecompressEx(path, kStringSuffix, kCompressionType);
|
||||
}
|
||||
}
|
80
Source/IO/FS/FSTimes.NT.cpp
Normal file
80
Source/IO/FS/FSTimes.NT.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: FSTimes.NT.cpp
|
||||
Date: 2023-2-4
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "FS.hpp"
|
||||
#include "FSTimes.NT.hpp"
|
||||
#include <Source/Time/Time.hpp>
|
||||
|
||||
namespace Aurora::IO::FS
|
||||
{
|
||||
const FILETIME *ConvertFileTime(FILETIME *temp, AuOptionalEx<AuInt64> time)
|
||||
{
|
||||
if (!time)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto word = AuTime::ConvertTimestampNs(time.value());
|
||||
temp->dwLowDateTime = AuBitsToLower(word);
|
||||
temp->dwHighDateTime = AuBitsToHigher(word);
|
||||
return temp;
|
||||
}
|
||||
|
||||
AUKN_SYM bool UpdateFileTimes(const AuString &path, const UpdateTimes ×)
|
||||
{
|
||||
HANDLE hFile;
|
||||
FILETIME created;
|
||||
FILETIME modified;
|
||||
FILETIME access;
|
||||
|
||||
auto pathex = NormalizePathRet(path);
|
||||
if (pathex.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto win32Path = Locale::ConvertFromUTF8(pathex);
|
||||
if (win32Path.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
hFile = ::CreateFileW(win32Path.c_str(),
|
||||
GENERIC_WRITE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (!AuFS::FileExists(pathex))
|
||||
{
|
||||
SysPushErrorIO("Missing file: {}", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
SysPushErrorIO("Couoldn't open a handle for: {}", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bRet = ::SetFileTime(hFile,
|
||||
ConvertFileTime(&created, times.createdNs),
|
||||
ConvertFileTime(&access, times.accessedNs),
|
||||
ConvertFileTime(&modified, times.modifiedNs));
|
||||
if (!bRet)
|
||||
{
|
||||
SysPushErrorIO();
|
||||
}
|
||||
|
||||
AuWin32CloseHandle(hFile);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
}
|
8
Source/IO/FS/FSTimes.NT.hpp
Normal file
8
Source/IO/FS/FSTimes.NT.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: FSTimes.NT.hpp
|
||||
Date: 2023-2-4
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
80
Source/IO/FS/FSTimes.Unix.cpp
Normal file
80
Source/IO/FS/FSTimes.Unix.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: FSTimes.Unix.cpp
|
||||
Date: 2023-2-4
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "FS.hpp"
|
||||
#include "FSTimes.Unix.hpp"
|
||||
#include <Source/Time/Time.hpp>
|
||||
#include <sys/time.h>
|
||||
#include <utime.h>
|
||||
|
||||
namespace Aurora::IO::FS
|
||||
{
|
||||
void ConvertFileTime(timeval *temp,
|
||||
AuInt64 alternative,
|
||||
AuOptionalEx<AuInt64> time)
|
||||
{
|
||||
timespec ts;
|
||||
|
||||
if (!time)
|
||||
{
|
||||
time = alternative;
|
||||
}
|
||||
|
||||
AuTime::auabsns2ts(&ts, time.value());
|
||||
|
||||
temp->tv_sec = ts.tv_sec;
|
||||
temp->tv_usec = ts.tv_nsec / 1'000ull;
|
||||
}
|
||||
|
||||
AUKN_SYM bool UpdateFileTimes(const AuString &path, const UpdateTimes ×)
|
||||
{
|
||||
if (times.createdNs)
|
||||
{
|
||||
SysPushErrorArg("Cannot modify a files' created timestamp under UNIX");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pathex = NormalizePathRet(path);
|
||||
if (pathex.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Stat auStat;
|
||||
if (!times.accessedNs ||
|
||||
!times.modifiedNs)
|
||||
{
|
||||
if (!AuFS::StatFile(pathex, auStat))
|
||||
{
|
||||
SysPushErrorArg("Cannot stat file of a attr-poke suspect");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AuFS::FileExists(pathex))
|
||||
{
|
||||
SysPushErrorIO("Missing file: {}", path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
timeval timeVals[2];
|
||||
|
||||
ConvertFileTime(&timeVals[0], auStat.accessed, times.accessedNs);
|
||||
ConvertFileTime(&timeVals[1], auStat.modified, times.modifiedNs);
|
||||
|
||||
bool bRet = ::utimes(pathex.c_str(), timeVals) == 0;
|
||||
if (!bRet)
|
||||
{
|
||||
SysPushErrorIO();
|
||||
}
|
||||
|
||||
return bRet;
|
||||
}
|
||||
}
|
7
Source/IO/FS/FSTimes.Unix.hpp
Normal file
7
Source/IO/FS/FSTimes.Unix.hpp
Normal file
@ -0,0 +1,7 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: FSTimes.Unix.hpp
|
||||
Date: 2023-2-4
|
||||
Author: Reece
|
||||
***/
|
116
Source/IO/FS/FileAttrs.NT.cpp
Normal file
116
Source/IO/FS/FileAttrs.NT.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: FileAttrs.NT.cpp
|
||||
Date: 2023-2-4
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "FS.hpp"
|
||||
#include "FileAttrs.NT.hpp"
|
||||
|
||||
namespace Aurora::IO::FS
|
||||
{
|
||||
AUKN_SYM AuList<AuString> FileAttrsList(const AuString &path)
|
||||
{
|
||||
AuList<AuString> names;
|
||||
WIN32_FIND_STREAM_DATA data;
|
||||
|
||||
auto pathex = NormalizePathRet(path);
|
||||
if (pathex.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto win32Path = Locale::ConvertFromUTF8(pathex);
|
||||
if (win32Path.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto hIterationHandle = ::FindFirstStreamW(win32Path.c_str(),
|
||||
FindStreamInfoStandard,
|
||||
&data,
|
||||
0);
|
||||
if (hIterationHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (!AuFS::FileExists(pathex))
|
||||
{
|
||||
SysPushErrorIO("Missing file: {}", path);
|
||||
return {};
|
||||
}
|
||||
|
||||
SysPushErrorIO("Couoldn't open a handle for: {}", path);
|
||||
return {};
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
AuString currentName;
|
||||
|
||||
currentName = AuLocale::ConvertFromWChar(data.cStreamName, wcsnlen_s(data.cStreamName, AuArraySize(data.cStreamName)));
|
||||
if (currentName.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// meh, noise. doesnt prevent an explicit read for this attribute.
|
||||
if (currentName == "::$DATA")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/a82e9105-2405-4e37-b2c3-28c773902d85
|
||||
// Seems like NTFS docs
|
||||
// "A file's data is an attribute; the "Data Attribute" known as $DATA"
|
||||
// ok, so, let's drop this suffix?
|
||||
|
||||
if (AuEndsWith(currentName, "$DATA"))
|
||||
{
|
||||
currentName.resize(currentName.size() - 5);
|
||||
}
|
||||
}
|
||||
|
||||
int endRemoval = currentName.size() > 1 && currentName[currentName.size() - 1] == ':';
|
||||
if (currentName[0] == ':')
|
||||
{
|
||||
auto endLen = currentName.size() - 1;
|
||||
AuMemmove(currentName.data(), currentName.data() + 1, endLen);
|
||||
currentName.resize(endLen - endRemoval);
|
||||
}
|
||||
else if (endRemoval)
|
||||
{
|
||||
currentName.pop_back();
|
||||
}
|
||||
|
||||
names.push_back(currentName);
|
||||
}
|
||||
while (::FindNextStreamW(hIterationHandle, &data));
|
||||
::FindClose(hIterationHandle);
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
AUKN_SYM AuResult<Memory::ByteBuffer> FileAttrsGet(const AuString &path, const AuString &attr)
|
||||
{
|
||||
AuByteBuffer temp;
|
||||
|
||||
if (!AuFS::ReadFile(path + ":" + attr, temp))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return AuMove(temp);
|
||||
}
|
||||
|
||||
AUKN_SYM bool FileAttrsSet(const AuString &path, const AuString &attr, const Memory::MemoryViewRead &view)
|
||||
{
|
||||
return AuFS::WriteFile(path + ":" + attr, view);
|
||||
}
|
||||
|
||||
AUKN_SYM bool FileAttrsDel(const AuString &path, const AuString &attr)
|
||||
{
|
||||
return AuFS::Remove(path + ":" + attr) || AuFS::FileExists(path);
|
||||
}
|
||||
}
|
9
Source/IO/FS/FileAttrs.NT.hpp
Normal file
9
Source/IO/FS/FileAttrs.NT.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: FileAttrs.NT.hpp
|
||||
Date: 2023-2-4
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
123
Source/IO/FS/FileAttrs.Unix.cpp
Normal file
123
Source/IO/FS/FileAttrs.Unix.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: FileAttrs.Unix.cpp
|
||||
Date: 2023-2-4
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "FS.hpp"
|
||||
#include "FileAttrs.Unix.hpp"
|
||||
#include <sys/types.h>
|
||||
#include <sys/xattr.h>
|
||||
|
||||
namespace Aurora::IO::FS
|
||||
{
|
||||
AUKN_SYM AuList<AuString> FileAttrsList(const AuString &path)
|
||||
{
|
||||
static const auto kLength = 10 * 1024;
|
||||
AuString buffer;
|
||||
|
||||
auto srcPath = NormalizePathRet(path);
|
||||
if (pathex.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!AuTryResize(buffer, kLength))
|
||||
{
|
||||
SysPushErrorMemory();
|
||||
return {};
|
||||
}
|
||||
|
||||
auto length = ::listxattr(srcPath.c_str(), attr.c_str(), buffer.data(), buffer.size(), 0 /*no follow symlinks*/);
|
||||
if (length < 0)
|
||||
{
|
||||
SysPushErrorIO("Error listing attributes");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!AuTryResize(buffer, length))
|
||||
{
|
||||
SysPushErrorMemory();
|
||||
return {};
|
||||
}
|
||||
|
||||
return AuSplitString(buffer, "\00");
|
||||
}
|
||||
|
||||
AUKN_SYM AuResult<AuByteBuffer> FileAttrsGet(const AuString &path, const AuString &attr)
|
||||
{
|
||||
AuByteBuffer buffer;
|
||||
|
||||
auto srcPath = NormalizePathRet(path);
|
||||
if (pathex.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto length = ::getxattr(srcPath.c_str(), attr.c_str(), nullptr, 0, 0 /*no follow symlinks*/);
|
||||
if (length < 0)
|
||||
{
|
||||
SysPushErrorIO("Error reading attribute");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!length)
|
||||
{
|
||||
return AuMove(buffer);
|
||||
}
|
||||
|
||||
if (!AuTryResize(buffer, length))
|
||||
{
|
||||
SysPushErrorMemory();
|
||||
return {};
|
||||
}
|
||||
|
||||
length = ::getxattr(srcPath.c_str(), attr.c_str(), buffer.base, length, 0 /*no follow symlinks*/);
|
||||
if (length < 0)
|
||||
{
|
||||
SysPushErrorIO("Error reading attribute");
|
||||
return {};
|
||||
}
|
||||
|
||||
buffer.writePtr += length;
|
||||
|
||||
return AuMove(buffer);
|
||||
}
|
||||
|
||||
AUKN_SYM bool FileAttrsSet(const AuString &path, const AuString &attr, const Memory::MemoryViewRead &view)
|
||||
{
|
||||
auto srcPath = NormalizePathRet(path);
|
||||
if (pathex.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::setxattr(srcPath.c_str(), attr.c_str(), view.ptr, view.length, XATTR_CREATE) == -1)
|
||||
{
|
||||
if (errno == EEXIST)
|
||||
{
|
||||
if (::setxattr(srcPath.c_str(), attr.c_str(), view.ptr, view.length, XATTR_REPLACE) == -1)
|
||||
{
|
||||
SysPushErrorIO();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AUKN_SYM bool FileAttrsDel(const AuString &path, const AuString &attr)
|
||||
{
|
||||
auto srcPath = NormalizePathRet(path);
|
||||
if (pathex.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (::removexattr(srcPath.c_str(), attr.c_str()) == 0) ||
|
||||
(errno == ENODATA);
|
||||
}
|
||||
}
|
9
Source/IO/FS/FileAttrs.Unix.hpp
Normal file
9
Source/IO/FS/FileAttrs.Unix.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: FileAttrs.Unix.hpp
|
||||
Date: 2023-2-4
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
@ -151,8 +151,7 @@ namespace Aurora::IO::FS
|
||||
|
||||
if (!::WriteFile(this->handle_, reinterpret_cast<const char *>(parameters.ptr) + offset, blockSize, &written, NULL))
|
||||
{
|
||||
AuLogWarn("WriteFileEx IO Error: 0x{:x}, {}", GetLastError(), this->path_);
|
||||
SysPushErrorIO();
|
||||
SysPushErrorIO("WriteFileEx IO Error: 0x{:x}, {}", GetLastError(), this->path_);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -217,7 +216,7 @@ namespace Aurora::IO::FS
|
||||
return this->handle_;
|
||||
}
|
||||
|
||||
AUKN_SYM IFileStream *OpenNew(const AuString &path, EFileOpenMode openMode, EFileAdvisoryLockLevel lock)
|
||||
static IFileStream *OpenNewEx(const AuString &path, EFileOpenMode openMode, EFileAdvisoryLockLevel lock, bool bCheck)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -237,30 +236,61 @@ namespace Aurora::IO::FS
|
||||
|
||||
fileHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
auto dwShare = NtLockAdvisoryToShare(lock);
|
||||
|
||||
switch (openMode)
|
||||
{
|
||||
case EFileOpenMode::eRead:
|
||||
{
|
||||
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, NtLockAdvisoryToShare(lock), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, dwShare, 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)
|
||||
|
||||
if (bCheck)
|
||||
{
|
||||
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, NtLockAdvisoryToShare(lock), NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
fileHandle = ::CreateFileW(win32Path.c_str(),
|
||||
GENERIC_WRITE | GENERIC_READ,
|
||||
NULL,
|
||||
NULL,
|
||||
CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ, dwShare, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, dwShare, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case EFileOpenMode::eWrite:
|
||||
{
|
||||
CreateDirectories(pathex, true);
|
||||
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | FILE_READ_ATTRIBUTES, NtLockAdvisoryToShare(lock), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||
|
||||
if (bCheck)
|
||||
{
|
||||
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, NtLockAdvisoryToShare(lock), NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
fileHandle = ::CreateFileW(win32Path.c_str(),
|
||||
GENERIC_WRITE,
|
||||
NULL,
|
||||
NULL,
|
||||
CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | FILE_READ_ATTRIBUTES, dwShare, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, dwShare, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -268,8 +298,7 @@ namespace Aurora::IO::FS
|
||||
|
||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
AuLogWarn("Missing file: {}", path);
|
||||
SysPushErrorIO("Missing file: {}", path);
|
||||
SysPushErrorIO("Invalid filepath, couldn't open: {}", path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -289,6 +318,21 @@ namespace Aurora::IO::FS
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -302,7 +302,7 @@ namespace Aurora::IO::FS
|
||||
return this->handle_;
|
||||
}
|
||||
|
||||
static IFileStream *OpenNew(const AuString &path, EFileOpenMode openMode, EFileAdvisoryLockLevel lock)
|
||||
static IFileStream *OpenNewEx(const AuString &path, EFileOpenMode openMode, EFileAdvisoryLockLevel lock, bool bCheck)
|
||||
{
|
||||
auto pathex = NormalizePathRet(path);
|
||||
|
||||
@ -311,6 +311,15 @@ namespace Aurora::IO::FS
|
||||
CreateDirectories(pathex, true);
|
||||
}
|
||||
|
||||
if (bCheck)
|
||||
{
|
||||
if (FileExists(path))
|
||||
{
|
||||
SysPushErrorIO("Couldn't open file: {}. Already exists.", path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto fileHandle = ::open(pathex.c_str(),
|
||||
(openMode == EFileOpenMode::eRead ? O_RDONLY : (O_RDWR | O_CREAT)) | O_CLOEXEC,
|
||||
0664);
|
||||
@ -327,6 +336,15 @@ namespace Aurora::IO::FS
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (bCheck)
|
||||
{
|
||||
if (PosixGetLength(fileHandle))
|
||||
{
|
||||
SysPushErrorIO("Couldn't open file: {}. Already exists.", path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto stream = _new PosixFileStream();
|
||||
if (!stream)
|
||||
{
|
||||
@ -345,6 +363,21 @@ namespace Aurora::IO::FS
|
||||
return stream;
|
||||
}
|
||||
|
||||
AUKN_SYM IFileStream *CreateNew(const AuString &path)
|
||||
{
|
||||
return OpenNewEx(path, EFileOpenMode::eWrite, EFileAdvisoryLockLevel::eBlockReadWrite, true);
|
||||
}
|
||||
|
||||
AUKN_SYM void CreateRelease(IFileStream *that)
|
||||
{
|
||||
AuSafeDelete<PosixFileStream *>(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<PosixFileStream *>(that);
|
||||
@ -352,7 +385,7 @@ namespace Aurora::IO::FS
|
||||
|
||||
AUKN_SYM IFileStream *OpenReadNew(const AuString &path, EFileAdvisoryLockLevel level)
|
||||
{
|
||||
return OpenNew(path, EFileOpenMode::eRead, level);
|
||||
return OpenNewEx(path, EFileOpenMode::eRead, level, false);
|
||||
}
|
||||
|
||||
AUKN_SYM void OpenReadRelease(IFileStream * that)
|
||||
@ -362,7 +395,7 @@ namespace Aurora::IO::FS
|
||||
|
||||
AUKN_SYM IFileStream *OpenWriteNew(const AuString &path, EFileAdvisoryLockLevel level)
|
||||
{
|
||||
return OpenNew(path, EFileOpenMode::eWrite, level);
|
||||
return OpenNewEx(path, EFileOpenMode::eWrite, level, false);
|
||||
}
|
||||
|
||||
AUKN_SYM void OpenWriteRelease(IFileStream *that)
|
||||
|
@ -311,6 +311,8 @@ namespace Aurora::IO::Net
|
||||
|
||||
this->error_ = error;
|
||||
|
||||
this->RejectAllListeners();
|
||||
|
||||
if (this->pSocketDriver_)
|
||||
{
|
||||
try
|
||||
@ -334,7 +336,7 @@ namespace Aurora::IO::Net
|
||||
}
|
||||
|
||||
this->error_ = error;
|
||||
|
||||
|
||||
if (this->pSocketDriver_)
|
||||
{
|
||||
try
|
||||
@ -347,9 +349,35 @@ namespace Aurora::IO::Net
|
||||
}
|
||||
}
|
||||
|
||||
RejectAllListeners();
|
||||
|
||||
this->Shutdown();
|
||||
}
|
||||
|
||||
void SocketBase::RejectAllListeners()
|
||||
{
|
||||
AU_LOCK_GUARD(this->socketChannel_.spinLock);
|
||||
|
||||
for (const auto &pListener : this->socketChannel_.eventListeners)
|
||||
{
|
||||
pListener->OnRejected();
|
||||
}
|
||||
|
||||
this->socketChannel_.eventListeners.clear();
|
||||
}
|
||||
|
||||
void SocketBase::CompleteAllListeners()
|
||||
{
|
||||
AU_LOCK_GUARD(this->socketChannel_.spinLock);
|
||||
|
||||
for (const auto &pListener : this->socketChannel_.eventListeners)
|
||||
{
|
||||
pListener->OnComplete();
|
||||
}
|
||||
|
||||
this->socketChannel_.eventListeners.clear();
|
||||
}
|
||||
|
||||
void SocketBase::SendOnData()
|
||||
{
|
||||
auto pReadableBuffer = this->socketChannel_.AsReadableByteBuffer();
|
||||
@ -383,7 +411,36 @@ namespace Aurora::IO::Net
|
||||
this->SendErrorBeginShutdown({});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
AuList<AuSPtr<ISocketChannelEventListener>> listeners;
|
||||
AuList<AuSPtr<ISocketChannelEventListener>> listenersToEvict;
|
||||
{
|
||||
AU_LOCK_GUARD(this->socketChannel_.spinLock);
|
||||
listeners = this->socketChannel_.eventListeners;
|
||||
}
|
||||
|
||||
if (AuTryReserve(listenersToEvict, listeners.size()))
|
||||
{
|
||||
for (const auto &pListener : listeners)
|
||||
{
|
||||
if (!pListener->OnData())
|
||||
{
|
||||
pListener->OnComplete();
|
||||
listenersToEvict.push_back(pListener);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
AU_LOCK_GUARD(this->socketChannel_.spinLock);
|
||||
for (const auto &pListener : listenersToEvict)
|
||||
{
|
||||
AuTryRemove(this->socketChannel_.eventListeners, pListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->ToChannel()->ScheduleOutOfFrameWrite();
|
||||
|
||||
auto uHeadDelta = pReadableBuffer ? (pReadableBuffer->readPtr - pStartOffset) : 0;
|
||||
@ -485,6 +542,15 @@ namespace Aurora::IO::Net
|
||||
|
||||
this->pWorker_->RemoveSocket(this);
|
||||
|
||||
if (this->bHasErrored_)
|
||||
{
|
||||
this->RejectAllListeners();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->CompleteAllListeners();
|
||||
}
|
||||
|
||||
if (this->pSocketDriver_)
|
||||
{
|
||||
try
|
||||
|
@ -73,6 +73,9 @@ namespace Aurora::IO::Net
|
||||
void SendErrorBeginShutdown(const NetError &error);
|
||||
void SendOnData();
|
||||
|
||||
void RejectAllListeners();
|
||||
void CompleteAllListeners();
|
||||
|
||||
virtual AuSPtr<ISocketChannel> ToChannel() override;
|
||||
|
||||
|
||||
@ -120,6 +123,9 @@ namespace Aurora::IO::Net
|
||||
protected:
|
||||
AuUInt osHandle_ {};
|
||||
|
||||
friend struct NetWriteQueue;
|
||||
friend struct SocketChannelOutput;
|
||||
|
||||
NetEndpoint remoteEndpoint_;
|
||||
NetEndpoint localEndpoint_;
|
||||
|
||||
|
@ -178,6 +178,36 @@ namespace Aurora::IO::Net
|
||||
return this->recvStats_;
|
||||
}
|
||||
|
||||
void SocketChannel::AddEventListener(const AuSPtr<ISocketChannelEventListener> &pListener)
|
||||
{
|
||||
AU_LOCK_GUARD(this->spinLock);
|
||||
|
||||
auto pWorker = this->pParent_->ToWorkerEx();
|
||||
if (pWorker->IsOnThread() && this->AsReadableByteBuffer()->GetNextLinearRead().length)
|
||||
{
|
||||
if (!pListener->OnData())
|
||||
{
|
||||
pListener->OnComplete();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this->eventListeners.push_back(pListener);
|
||||
}
|
||||
|
||||
void SocketChannel::RemoveEventListener(const AuSPtr<ISocketChannelEventListener> &pListener)
|
||||
{
|
||||
AU_LOCK_GUARD(this->spinLock);
|
||||
|
||||
bool bSuccess = AuTryRemove(this->eventListeners, pListener);
|
||||
|
||||
auto pWorker = this->pParent_->ToWorkerEx();
|
||||
if (pWorker->IsOnThread() && bSuccess)
|
||||
{
|
||||
pListener->OnRejected();
|
||||
}
|
||||
}
|
||||
|
||||
bool SocketChannel::IsValid()
|
||||
{
|
||||
return bool(this->outputChannel.IsValid()) &&
|
||||
@ -381,6 +411,7 @@ namespace Aurora::IO::Net
|
||||
{
|
||||
pCallbackOptional->OnSuccess((void *)nullptr);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -388,50 +419,173 @@ namespace Aurora::IO::Net
|
||||
{
|
||||
if (!this->outputChannel.CanResize())
|
||||
{
|
||||
if (pCallbackOptional)
|
||||
{
|
||||
pCallbackOptional->OnFailure((void *)nullptr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
AuByteBuffer newBuffer(uBytes, true, false);
|
||||
if (!(newBuffer.IsValid()))
|
||||
{
|
||||
SysPushErrorMemory();
|
||||
if (pCallbackOptional)
|
||||
{
|
||||
pCallbackOptional->OnFailure((void *)nullptr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto &byteBufferRef = this->outputChannel.GetByteBuffer();
|
||||
auto oldReadHead = byteBufferRef.readPtr;
|
||||
|
||||
if (!newBuffer.WriteFrom(byteBufferRef))
|
||||
{
|
||||
SysPushErrorMemory();
|
||||
AuByteBuffer newBuffer(uBytes, false, false);
|
||||
if (!(newBuffer.IsValid()))
|
||||
{
|
||||
SysPushErrorMemory();
|
||||
if (pCallbackOptional)
|
||||
{
|
||||
pCallbackOptional->OnFailure((void *)nullptr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this->outputChannel.GetByteBuffer().readPtr = oldReadHead;
|
||||
auto &byteBufferRef = this->outputChannel.GetByteBuffer();
|
||||
auto oldReadHead = byteBufferRef.readPtr;
|
||||
|
||||
if (!newBuffer.WriteFrom(byteBufferRef))
|
||||
{
|
||||
SysPushErrorMemory();
|
||||
|
||||
this->outputChannel.GetByteBuffer().readPtr = oldReadHead;
|
||||
|
||||
if (pCallbackOptional)
|
||||
{
|
||||
pCallbackOptional->OnFailure((void *)nullptr);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
byteBufferRef = AuMove(newBuffer);
|
||||
|
||||
if (pCallbackOptional)
|
||||
{
|
||||
pCallbackOptional->OnFailure((void *)nullptr);
|
||||
pCallbackOptional->OnSuccess((void *)nullptr);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
byteBufferRef = AuMove(newBuffer);
|
||||
}
|
||||
|
||||
if (bInput)
|
||||
{
|
||||
SysPushErrorUnimplemented("Cannot resize a TCP clients input stream now");
|
||||
AU_LOCK_GUARD(this->spinLock);
|
||||
|
||||
if (bOutput)
|
||||
{
|
||||
if (this->uBytesOutputBufferRetarget)
|
||||
{
|
||||
if (this->pRetargetOutput)
|
||||
{
|
||||
this->pRetargetOutput->OnFailure((void *)nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
this->uBytesOutputBufferRetarget = uBytes;
|
||||
this->pRetargetOutput = pCallbackOptional;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->uBytesInputBufferRetarget)
|
||||
{
|
||||
if (this->pRetargetInput)
|
||||
{
|
||||
this->pRetargetInput->OnFailure((void *)nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
this->uBytesInputBufferRetarget = uBytes;
|
||||
this->pRetargetInput = pCallbackOptional;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SocketChannel::DoReallocWriteTick()
|
||||
{
|
||||
AU_LOCK_GUARD(this->spinLock);
|
||||
|
||||
if (!this->uBytesOutputBufferRetarget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pCallbackOptional)
|
||||
AuByteBuffer newBuffer(this->uBytesOutputBufferRetarget, true, false);
|
||||
if (!(newBuffer.IsValid()))
|
||||
{
|
||||
pCallbackOptional->OnSuccess((void *)nullptr);
|
||||
SysPushErrorMemory();
|
||||
if (this->pRetargetOutput)
|
||||
{
|
||||
this->pRetargetOutput->OnFailure((void *)nullptr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto &byteBufferRef = this->outputChannel.GetByteBuffer();
|
||||
auto oldReadHead = byteBufferRef.readPtr;
|
||||
auto oldWriteHead = byteBufferRef.writePtr;
|
||||
|
||||
if (!newBuffer.WriteFrom(byteBufferRef))
|
||||
{
|
||||
SysPushErrorMemory();
|
||||
|
||||
this->outputChannel.GetByteBuffer().readPtr = oldReadHead;
|
||||
this->outputChannel.GetByteBuffer().writePtr = oldWriteHead;
|
||||
|
||||
if (this->pRetargetOutput)
|
||||
{
|
||||
this->pRetargetOutput->OnFailure((void *)nullptr);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
byteBufferRef = AuMove(newBuffer);
|
||||
|
||||
this->uBytesOutputBufferRetarget = 0;
|
||||
|
||||
if (this->pRetargetOutput)
|
||||
{
|
||||
this->pRetargetOutput->OnSuccess((void *)nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void SocketChannel::DoReallocReadTick()
|
||||
{
|
||||
AU_LOCK_GUARD(this->spinLock);
|
||||
|
||||
if (!this->uBytesInputBufferRetarget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AuByteBuffer newBuffer(this->uBytesInputBufferRetarget, true, false);
|
||||
if (!(newBuffer.IsValid()))
|
||||
{
|
||||
SysPushErrorMemory();
|
||||
if (this->pRetargetInput)
|
||||
{
|
||||
this->pRetargetInput->OnFailure((void *)nullptr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto byteBufferRef = this->inputChannel.AsReadableByteBuffer();
|
||||
auto oldReadHead = byteBufferRef->readPtr;
|
||||
auto oldWriteHead = byteBufferRef->writePtr;
|
||||
|
||||
if (!newBuffer.WriteFrom(*byteBufferRef.get()))
|
||||
{
|
||||
SysPushErrorMemory();
|
||||
|
||||
byteBufferRef->readPtr = oldReadHead;
|
||||
byteBufferRef->writePtr = oldWriteHead;
|
||||
|
||||
if (this->pRetargetInput)
|
||||
{
|
||||
this->pRetargetInput->OnFailure((void *)nullptr);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
byteBufferRef.get()->operator=(AuMove(newBuffer));
|
||||
|
||||
this->uBytesInputBufferRetarget = 0;
|
||||
|
||||
if (this->pRetargetInput)
|
||||
{
|
||||
this->pRetargetInput->OnSuccess((void *)nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,10 @@ namespace Aurora::IO::Net
|
||||
|
||||
AuSPtr<ISocketStats> GetSendStats() override;
|
||||
|
||||
void AddEventListener(const AuSPtr<ISocketChannelEventListener> &pListener) override;
|
||||
|
||||
void RemoveEventListener(const AuSPtr<ISocketChannelEventListener> &pListener) override;
|
||||
|
||||
SocketStats & GetSendStatsEx();
|
||||
SocketStats & GetRecvStatsEx();
|
||||
|
||||
@ -93,9 +97,19 @@ namespace Aurora::IO::Net
|
||||
AuUInt uBytesInputBuffer { 0 };
|
||||
AuUInt uBytesOutputBuffer { 0 };
|
||||
|
||||
AuUInt uBytesInputBufferRetarget { 0 };
|
||||
AuSPtr<AuAsync::PromiseCallback<AuNullS, AuNullS>> pRetargetInput;
|
||||
AuUInt uBytesOutputBufferRetarget { 0 };
|
||||
AuSPtr<AuAsync::PromiseCallback<AuNullS, AuNullS>> pRetargetOutput;
|
||||
|
||||
void DoReallocWriteTick();
|
||||
void DoReallocReadTick();
|
||||
|
||||
AuSPtr<Protocol::IProtocolStack> pRecvProtocol;
|
||||
AuSPtr<Protocol::IProtocolStack> pSendProtocol;
|
||||
|
||||
AuThreadPrimitives::SpinLock spinLock;
|
||||
AuList<AuSPtr<ISocketChannelEventListener>> eventListeners;
|
||||
|
||||
private:
|
||||
SocketBase * pParent_;
|
||||
|
@ -27,6 +27,8 @@ namespace Aurora::IO::Net
|
||||
return;
|
||||
}
|
||||
|
||||
AuStaticCast<SocketChannel>(this->pParent_->ToChannel())->DoReallocReadTick();
|
||||
|
||||
struct DispatchLater : IIOProcessorWorkUnit
|
||||
{
|
||||
inline DispatchLater(const AuSPtr<SocketChannelInput> &parent) :
|
||||
@ -56,6 +58,7 @@ namespace Aurora::IO::Net
|
||||
auto temp = AuMakeShared<DispatchLater>(AuSPtr<SocketChannelInput>(this->pParent_->SharedFromThis(), this));
|
||||
if (!(temp && this->pParent_->ToWorker()->ToProcessor()->SubmitIOWorkItem(temp)))
|
||||
{
|
||||
SysPushErrorIO("Preemptively running tick. low resource?");
|
||||
AuStaticCast<IOPipeWork>(this->pNetReader)->Tick_Any();
|
||||
AuStaticCast<IOPipeWork>(this->pNetReader)->Tick_FrameEpilogue();
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ namespace Aurora::IO::Net
|
||||
pNetWriteTransaction_(stream),
|
||||
outputBuffer_(kDefaultBufferSize, true)
|
||||
{
|
||||
this->outputWriteQueue_.pBase = pParent;
|
||||
}
|
||||
|
||||
bool SocketChannelOutput::IsValid()
|
||||
@ -173,6 +174,15 @@ namespace Aurora::IO::Net
|
||||
}
|
||||
}
|
||||
|
||||
if (this->outputWriteQueue_.IsEmpty())
|
||||
{
|
||||
if (this->pParent_)// &&
|
||||
///this->outputBuffer_.outputChannel.AsWritableByteBuffer()->GetNextLinearRead().length == 0)
|
||||
{
|
||||
this->pParent_->socketChannel_.DoReallocWriteTick();
|
||||
}
|
||||
}
|
||||
|
||||
if (auto pFrameToSend = this->outputWriteQueue_.Dequeue())
|
||||
{
|
||||
this->pNetWriteTransaction_->SetCallback(AuSPtr<IAsyncFinishedSubscriber>(this->pParent_->SharedFromThis(), this));
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
namespace Aurora::IO::Net
|
||||
{
|
||||
struct SocketBase;
|
||||
struct NetWriteQueue
|
||||
{
|
||||
bool Push(const AuSPtr<AuMemoryViewRead> &read);
|
||||
@ -16,6 +17,7 @@ namespace Aurora::IO::Net
|
||||
AuSPtr<AuMemoryViewRead> Dequeue();
|
||||
bool IsEmpty();
|
||||
|
||||
SocketBase *pBase {};
|
||||
private:
|
||||
AuList<AuTuple<AuUInt, AuSPtr<AuMemoryViewRead>>> views_;
|
||||
AuMemoryViewRead current_;
|
||||
|
@ -252,6 +252,16 @@ namespace Aurora::IO::Net
|
||||
return AuSPtr<ISocketStats>(this->pParent_->SharedFromThis(), &this->sendStats_);
|
||||
}
|
||||
|
||||
void NetDatagramSocketServerChannel::AddEventListener(const AuSPtr<ISocketChannelEventListener> &pListener)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NetDatagramSocketServerChannel::RemoveEventListener(const AuSPtr<ISocketChannelEventListener> &pListener)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SocketStats &NetDatagramSocketServerChannel::GetSendStatsEx()
|
||||
{
|
||||
return this->sendStats_;
|
||||
|
@ -66,6 +66,10 @@ namespace Aurora::IO::Net
|
||||
|
||||
AuSPtr<ISocketStats> GetSendStats() override;
|
||||
|
||||
void AddEventListener(const AuSPtr<ISocketChannelEventListener> &pListener) override;
|
||||
|
||||
void RemoveEventListener(const AuSPtr<ISocketChannelEventListener> &pListener) override;
|
||||
|
||||
SocketStats &GetSendStatsEx();
|
||||
SocketStats &GetRecvStatsEx();
|
||||
|
||||
|
@ -41,6 +41,26 @@ namespace Aurora::Logging::Sinks
|
||||
|
||||
doScan();
|
||||
|
||||
if (logger.uMaxLogsOrZeroBeforeCompress)
|
||||
{
|
||||
if (fileMeta.size() > logger.uMaxLogsOrZeroBeforeCompress)
|
||||
{
|
||||
for (AuUInt i = logger.uMaxLogsOrZeroBeforeCompress; i < fileMeta.size(); i++)
|
||||
{
|
||||
auto path = baseLogPath + "/" + fileMeta[i].first;
|
||||
|
||||
if (AuEndsWith(path, ".zst")) continue;
|
||||
|
||||
if (AuIOFS::Compress(path))
|
||||
{
|
||||
AuIOFS::Remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
doScan();
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.uMaxFileTimeInDeltaMSOrZeroBeforeCompress)
|
||||
{
|
||||
auto qwMaxTime = AuTime::CurrentClockMS() - logger.uMaxFileTimeInDeltaMSOrZeroBeforeCompress;
|
||||
@ -51,6 +71,9 @@ namespace Aurora::Logging::Sinks
|
||||
if (qwMaxTime > fileMeta[i].second.modified)
|
||||
{
|
||||
auto path = baseLogPath + "/" + fileMeta[i].first;
|
||||
|
||||
if (AuEndsWith(path, ".zst")) continue;
|
||||
|
||||
if (AuIOFS::Compress(path))
|
||||
{
|
||||
AuIOFS::Remove(path);
|
||||
@ -85,6 +108,9 @@ namespace Aurora::Logging::Sinks
|
||||
}
|
||||
|
||||
auto path = baseLogPath + "/" + fileMeta[i].first;
|
||||
|
||||
if (AuEndsWith(path, ".zst")) continue;
|
||||
|
||||
if (AuIOFS::Compress(path))
|
||||
{
|
||||
AuIOFS::Remove(path);
|
||||
@ -99,7 +125,7 @@ namespace Aurora::Logging::Sinks
|
||||
doScan();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (logger.uMaxLogsOrZeroBeforeDelete)
|
||||
{
|
||||
if (fileMeta.size() > logger.uMaxLogsOrZeroBeforeDelete)
|
||||
|
Loading…
Reference in New Issue
Block a user