[+] 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:
Reece Wilson 2023-02-04 19:43:01 +00:00
parent 7d46679969
commit f43251c8fc
43 changed files with 1379 additions and 148 deletions

View File

@ -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 &times);
/**
* @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

View File

@ -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);

View File

@ -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;
};
}

View 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, ())
);
}

View File

@ -19,6 +19,8 @@
#include "NetHostname.hpp"
#include "NetError.hpp"
#include "ISocketChannelEventListener.hpp"
#include "ISocketBase.hpp"
#include "ISocket.hpp"
#include "ISocketStats.hpp"

View File

@ -16,6 +16,7 @@ namespace Aurora::Logging
{
struct DirectoryLogger
{
AuUInt32 uMaxLogsOrZeroBeforeCompress {};
AuUInt32 uMaxLogsOrZeroBeforeDelete {};
AuUInt32 uMaxCumulativeFileSizeInMiBOrZeroBeforeDelete {};
AuUInt32 uMaxCumulativeFileSizeInMiBOrZeroBeforeCompress {};

View File

@ -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_ ||

View File

@ -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);
}

View File

@ -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({});
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -100,7 +100,7 @@ namespace Aurora::Compression
have))
{
this->pReader_.reset();
SysPushErrorIO("Memory Error");
SysPushErrorIO("Compression Out of Overhead");
return AuMakePair(read, 0);
}

View File

@ -106,6 +106,7 @@ namespace Aurora::Compression
{
if (!Write(this->pBufferOut_.get(), frameS2Ptr))
{
SysPushErrorIO("Compression Out of Overhead");
return {};
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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);
}
}

View 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 &times)
{
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;
}
}

View 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

View 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 &times)
{
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;
}
}

View 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
***/

View 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);
}
}

View 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

View 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);
}
}

View 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

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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_;

View File

@ -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);
}
}

View File

@ -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_;

View File

@ -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();
}

View File

@ -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));

View File

@ -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_;

View File

@ -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_;

View File

@ -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();

View File

@ -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)