#include "ehs/io/File_UNX.h" #include #include #include #include #include #include #include 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) + "."); } }