#define _FILE_OFFSET_BITS 64 #define _LARGEFILE64_SOURCE #include #include "FS.hpp" #include "FileStream.Generic.hpp" #include #include #include #if !defined(_AURUNTIME_GENERICFILESTREAM) namespace Aurora::IO::FS { static const AuUInt64 kFileCopyBlock = 0x4000; // 16KiB static bool PosixLseek63(int fd, AuUInt64 offset, int whence, AuUInt64 *pOffset) { if (offset > std::numeric_limits::max()) { SysPushErrorIO("int overflow exploit?"); return false; } #if defined(AURORA_IS_LINUX_DERIVED) auto ret = lseek64(fd, offset, whence); #elif defined(AURORA_IS_64BIT) static_assert(std::numeric_limits::max() >= std::numeric_limits::max(), "unsupported posix os"); auto ret = lseek(fd, offset, whence); #else #error accient 32-bit posix operating systems require 64-bit file awareness #endif if (ret < 0) { LogWarn("PosixLseek63 IO Error %i", ret); SysPushErrorIO("PosixLseek63: %i", ret); return false; } if (pOffset) { *pOffset = ret; } return true; } static AuUInt64 PosixGetOffset(int fd) { AuUInt64 ret; if (!PosixLseek63(fd, 0, SEEK_SET, &ret)) { return 0; } return ret; } static bool PosixSetOffset(int fd, AuUInt64 offset) { return PosixLseek63(fd, offset, SEEK_SET, nullptr); } static AuUInt64 PosixGetLength(int fd) { AuUInt64 ret {}, old {}; bool status {}; if (!PosixLseek63(fd, 0, SEEK_SET, &old)) { return 0; } status = PosixLseek63(fd, 0, SEEK_END, &ret); status &= PosixLseek63(fd, old, SEEK_SET, nullptr); return status ? ret : 0; } static bool PosixRead(int fd, void *buf, AuUInt32 count, AuUInt32 *pRead) { auto ret = read(fd, buf, count); if (ret < 0) { LogWarn("PosixRead IO Error %i", ret); SysPushErrorIO("PosixRead: %i", ret); return false; } if (pRead) { *pRead = ret; } return true; } static bool PosixWrite(int fd, const void *buf, AuUInt32 count, AuUInt32 *pWritten) { auto ret = write(fd, buf, count); if (ret < 0) { LogWarn("PosixWrite IO Error %i", ret); SysPushErrorIO("PosixWrite: %i", ret); return false; } if (pWritten) { *pWritten = ret; } return true; } PosixFileStream::~PosixFileStream() { Close(); } void PosixFileStream::Init(int handle, const AuString &path) { handle_ = handle; path_ = path; } AuUInt64 PosixFileStream::GetOffset() { if (handle_ == -1) { SysPushErrorUninitialized(); return 0; } return PosixGetOffset(handle_); } bool PosixFileStream::SetOffset(AuUInt64 offset) { if (handle_ == -1) { SysPushErrorUninitialized(); return 0; } return PosixSetOffset(handle_, offset); } AuUInt64 PosixFileStream::GetLength() { if (handle_ == -1) { SysPushErrorUninitialized(); return 0; } return PosixGetLength(handle_); } bool PosixFileStream::Read(const Memory::MemoryViewStreamWrite ¶meters) { if (handle_ == -1) { SysPushErrorUninitialized(); return 0; } auto length = parameters.length; AuUInt offset {0}; while (length) { AuUInt32 read; int blockSize = std::min(kFileCopyBlock, length); if (!PosixRead(handle_, &reinterpret_cast(parameters.ptr)[offset], blockSize, &read)) { SysPushErrorNested("File Error: {}", path_); break; } if (read == 0) { break; } offset += read; length -= read; } if (!offset) { return false; } parameters.outVariable = offset; return true; } bool PosixFileStream::Write(const Memory::MemoryViewStreamRead ¶meters) { if (handle_ == -1) { SysPushErrorUninitialized(); return 0; } auto length = parameters.length; AuUInt offset {0}; while (length) { AuUInt32 written; int blockSize = std::min(kFileCopyBlock, length); if (!PosixWrite(handle_, &reinterpret_cast(parameters.ptr)[offset], blockSize, &written)) { SysPushErrorNested("File Error: {}", path_); return false; } if (written != blockSize) { SysPushErrorIO(); SysPushErrorNested("File Error: {}", path_); break; } offset += written; length -= written; } if (!offset) { return false; } parameters.outVariable = offset; return true; } void PosixFileStream::Close() { int handle; if ((handle = std::exchange(handle_, -1)) != -1) { ::close(handle); } } void PosixFileStream::Flush() { fsync(handle_); } static IFileStream *OpenNew(const AuString &path, bool read) { auto pathex = NormalizePathRet(path); if (!read) { CreateDirectories(pathex, true); } auto fileHandle = open(pathex.c_str(), read ? O_RDONLY : O_RDWR); if (fileHandle < 0) { LogWarn("Couldn't open file: {}", path); SysPushErrorIO("Couldn't open file: {}", path); return nullptr; } auto stream = _new PosixFileStream(); if (!stream) { close(fileHandle); return nullptr; } stream->Init(fileHandle, pathex); return stream; } AUKN_SYM IFileStream *OpenReadNew(const AuString &path) { return OpenNew(path, true); } AUKN_SYM void OpenReadRelease(IFileStream * that) { SafeDelete(that); } AUKN_SYM IFileStream *OpenWriteNew(const AuString &path) { return OpenNew(path, false); } AUKN_SYM void OpenWriteRelease(IFileStream * that) { SafeDelete(that); } } #endif