308 lines
6.5 KiB
C++
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) + ".");
|
||
|
}
|
||
|
}
|