EHS/src/io/File_UNX.cpp
karutoh 1a4a1ecd9c
Some checks failed
Build & Release / Linux-x86_64-Build (push) Successful in 40s
Build & Release / Linux-AARCH64-Build (push) Has been cancelled
First commit.
2024-01-31 22:28:19 -08:00

308 lines
6.5 KiB
C++

#include "ehs/io/File_UNX.h"
#include <cstring>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <cstdio>
namespace ehs
{
File::~File()
{
if (map != MAP_FAILED && munmap(map, mapSize) == -1)
EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(errno) + ".");
if (hdl >= 0 && close(hdl) == -1)
EHS_LOG_INT("Error", 0, "Failed to close file handle with error #" + Str_8::FromNum(errno) + ".");
}
File::File()
: hdl(-1), map(MAP_FAILED), mapSize(0)
{
}
File::File(const Str_8 &filePath, const Mode mode, const Disposition disposition)
: BaseFile(filePath, mode, disposition), hdl(-1), map(MAP_FAILED), mapSize(0)
{
int linuxMode = 0;
switch (mode)
{
case Mode::READ:
linuxMode = O_RDONLY;
break;
case Mode::WRITE:
linuxMode = O_WRONLY;
break;
case Mode::READ_WRITE:
linuxMode = O_RDWR;
break;
}
int linuxDisp = 0;
switch (disposition)
{
case Disposition::CREATE_PERSISTENT:
linuxDisp = O_CREAT;
break;
case Disposition::CREATE:
linuxDisp = O_CREAT | O_EXCL;
break;
case Disposition::OPEN_PERSISTENT:
linuxDisp = O_CREAT;
break;
case Disposition::OPEN:
linuxDisp = 0;
break;
case Disposition::TRUNCATE:
linuxDisp = O_TRUNC;
break;
}
hdl = open64(path, linuxMode | linuxDisp, S_IRUSR | S_IWUSR);
if (hdl == -1)
{
SInt_32 code = errno;
if (code == EEXIST && (disposition == Disposition::CREATE_PERSISTENT || disposition == Disposition::OPEN_PERSISTENT))
{
hdl = open64(path, linuxMode, S_IRUSR | S_IWUSR);
if (hdl == -1)
EHS_LOG_INT("Error", 0, strerror(errno));
}
else
{
if (code == ENOENT)
EHS_LOG_INT("Error", 0, "File at filepath, \"" + filePath + "\" not found.");
else
EHS_LOG_INT("Error", 0, strerror(code));
}
}
}
File::File(File&& file) noexcept
: BaseFile(std::move(file)), hdl(file.hdl), map(file.map), mapSize(file.mapSize)
{
file.hdl = -1;
file.map = MAP_FAILED;
file.mapSize = 0;
}
File::File(const File &file)
: BaseFile(file), hdl(-1), map(MAP_FAILED), mapSize(0)
{
}
File& File::operator=(File&& file) noexcept
{
if (this == &file)
return *this;
BaseFile::operator=(std::move(file));
hdl = file.hdl;
map = file.map;
mapSize = file.mapSize;
file.hdl = -1;
return *this;
}
File& File::operator=(const File &file)
{
if (this == &file)
return *this;
BaseFile::operator=(file);
hdl = -1;
map = MAP_FAILED;
mapSize = 0;
return *this;
}
File::operator const Byte*() const
{
return (const Byte*)map;
}
File::operator Byte*()
{
return (Byte*)map;
}
void File::Release()
{
if (IsMapped() && munmap(map, mapSize) == -1)
EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(errno) + ".");
map = MAP_FAILED;
mapSize = 0;
if (IsValid() && close(hdl) == -1)
EHS_LOG_INT("Error", 0, "Failed to close file handle with error #" + Str_8::FromNum(errno) + ".");
hdl = -1;
}
bool File::IsMapped() const
{
return map != MAP_FAILED;
}
UInt_64 File::MapSize() const
{
return mapSize;
}
void File::Map(const UInt_64 offset, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return;
int linuxMode = 0;
switch (mode)
{
case Mode::READ:
linuxMode = PROT_READ;
break;
case Mode::WRITE:
linuxMode = PROT_WRITE;
break;
case Mode::READ_WRITE:
linuxMode = PROT_READ | PROT_WRITE;
break;
}
map = mmap64(nullptr, size, linuxMode, MAP_SHARED, hdl, (off64_t)offset);
if (map == MAP_FAILED)
{
EHS_LOG_INT("Error", 0, "Failed to map with error #" + Str_8::FromNum(errno) + ".");
return;
}
mapSize = size;
}
void File::Unmap()
{
if (!IsValid() || !IsMapped())
return;
if (munmap(map, mapSize) == -1)
EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(errno) + ".");
map = MAP_FAILED;
mapSize = 0;
}
void File::FlushMap()
{
if (!IsValid() || !IsMapped())
return;
if (msync((void*)map, mapSize, MS_SYNC) == -1)
EHS_LOG_INT("Error", 0, "Failed to flush view with error #" + Str_8::FromNum(errno) + ".");
}
UInt_64 File::Write(const Byte *const data, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return 0;
SInt_64 written = 0;
written = write(hdl, data, size);
if (written == -1)
EHS_LOG_INT("Error", 0, "Failed to write to file, \"" + path + "\", with error #" + Str_8::FromNum(errno) + ".");
return (UInt_64)written;
}
UInt_64 File::Read(Byte *const data, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return 0;
SInt_64 read = 0;
read = ::read(hdl, data, (size_t)size);
if (read == -1)
EHS_LOG_INT("Error", 0, "Failed to read from file, \"" + path + "\", with error #" + Str_8::FromNum(errno) + ".");
return (UInt_64)read;
}
void File::Seek(UInt_64 index)
{
if (!IsValid() || IsMapped())
return;
if (lseek64(hdl, (off64_t)index, SEEK_SET) == -1)
EHS_LOG_INT("Error", 0, "Failed to seek with error #" + Str_8::FromNum(errno) + ".");
}
void File::SeekBeginning()
{
if (!IsValid() || IsMapped())
return;
if (lseek64(hdl, 0, SEEK_SET) == -1)
EHS_LOG_INT("Error", 0, "Failed to seek with error #" + Str_8::FromNum(errno) + ".");
}
void File::SeekEnd()
{
if (!IsValid() || IsMapped())
return;
if (lseek64(hdl, 0, SEEK_END) == -1)
EHS_LOG_INT("Error", 0, "Failed to seek with error #" + Str_8::FromNum(errno) + ".");
}
void File::Truncate(const UInt_64 size)
{
if (!IsValid() || IsMapped())
return;
if (ftruncate64(hdl, (off64_t)size) == -1)
EHS_LOG_INT("Error", 0, "Failed to truncate with error #" + Str_8::FromNum(errno) + ".");
}
UInt_64 File::Size() const
{
struct stat64 info = {};
if (fstat64(hdl, &info) == -1)
EHS_LOG_INT("Error", 0, "Failed to retrieve file size with error #" + Str_8::FromNum(errno) + ".");
return info.st_size;
}
bool File::IsValid() const
{
return hdl >= 0;
}
void File::Rename_32(const Str_32& filePath, const Str_32& newName)
{
Rename_8(UTF::To_8(filePath), UTF::To_8(newName));
}
void File::Rename_16(const Str_16& filePath, const Str_16& newName)
{
Rename_8(UTF::To_8(filePath), UTF::To_8(newName));
}
void File::Rename_8(const Str_8& filePath, const Str_8& newName)
{
UInt_64 index = 0;
Str_8 path;
if (filePath.Find("/", &index, SearchPattern::RIGHT_LEFT) || filePath.Find("\\", &index, SearchPattern::RIGHT_LEFT))
path = filePath.Sub(0, index);
if (rename(filePath, path + newName) == -1)
EHS_LOG_INT("Error", 0, "Failed to rename file with error #" + Str_8::FromNum(errno) + ".");
}
}