296 lines
6.5 KiB
C++
296 lines
6.5 KiB
C++
#define _FILE_OFFSET_BITS 64
|
|
#define _LARGEFILE64_SOURCE
|
|
|
|
#include <RuntimeInternal.hpp>
|
|
#include "FS.hpp"
|
|
#include "FileStream.Generic.hpp"
|
|
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
|
|
#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<off_t>::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<off_t>::max() >= std::numeric_limits<AuInt64>::max(), "unsupported posix os");
|
|
auto ret = lseek(fd, offset, whence);
|
|
#else
|
|
#error accient 32-bit posix operating systems require 64-bit file awareness
|
|
#end
|
|
|
|
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_);
|
|
}
|
|
|
|
AuUInt64 PosixFileStream::GetLength()
|
|
{
|
|
if (handle_ == -1)
|
|
{
|
|
SysPushErrorUninitialized();
|
|
return 0;
|
|
}
|
|
|
|
return PosixGetLength(handle_);
|
|
}
|
|
|
|
AuUInt64 PosixFileStream::Read(void *in, AuUInt64 length)
|
|
{
|
|
if (handle_ == -1)
|
|
{
|
|
SysPushErrorUninitialized();
|
|
return 0;
|
|
}
|
|
|
|
AuUInt64 offset {0};
|
|
while (length)
|
|
{
|
|
AuUInt32 read;
|
|
|
|
int blockSize = std::min(kFileCopyBlock, length);
|
|
|
|
if (!PosixRead(handle_, &reinterpret_cast<char *>(in)[offset], blockSize, &read))
|
|
{
|
|
SysPushErrorNested("File Error: {}", path);
|
|
break;
|
|
}
|
|
|
|
if (read == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
offset += read;
|
|
length -= read;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
AuUInt64 PosixFileStream::Write(const void *out, AuUInt64 length)
|
|
{
|
|
if (handle_ == -1)
|
|
{
|
|
SysPushErrorUninitialized();
|
|
return 0;
|
|
}
|
|
|
|
AuUInt64 offset {0};
|
|
while (length)
|
|
{
|
|
AuUInt32 written;
|
|
|
|
int blockSize = std::min(kFileCopyBlock, length);
|
|
|
|
if (!PosixWrite(handle_, &reinterpret_cast<const char *>(out)[offset], blockSize, &written))
|
|
{
|
|
SysPushErrorNested("File Error: {}", path);
|
|
return offset;
|
|
}
|
|
|
|
if (written != blockSize)
|
|
{
|
|
SysPushErrorIO();
|
|
SysPushErrorNested("File Error: {}", path);
|
|
return offset;
|
|
}
|
|
|
|
offset += written;
|
|
length -= written;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
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<PosixFileStream *>(that);
|
|
}
|
|
|
|
AUKN_SYM IFileStream *OpenWriteNew(const AuString &path)
|
|
{
|
|
return OpenNew(path, false);
|
|
}
|
|
|
|
AUKN_SYM void OpenWriteRelease(IFileStream * that)
|
|
{
|
|
SafeDelete<PosixFileStream *>(that);
|
|
}
|
|
}
|
|
#endif |