forked from vmangos/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
NativeIO: Add Linux support (vmangos#2696)
* Create NativeAliases.h * IO::Networking moved some files around * `IocpOperationTask` as member of `AsyncSocket` to avoid `new` memory allocation * Native IO: Able to compile empty impl on linux * Fix windows build * Native IO: Linux add fs support * Native IO: Linux, able to connect * Fix uninitialized `m_sessionDurationTimeout` * Fix SO_REUSEADDR on linux * Sortof impl of unix epoll AsyncSocket * Add own implementation of `AsyncSystemTimer` * Code Style * Native IO: Add all other Write handlers * NativeIO: Linux add EPOLLRDHUP for disconnect requests * Fix windows build * NativeIO: Windows Code Style * Fix EnumFlags * Update comment
- Loading branch information
Showing
39 changed files
with
1,548 additions
and
647 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
#include "IO/Filesystem/FileHandle.h" | ||
#include "Log.h" | ||
#include "IO/SystemErrorToString.h" | ||
#include <sys/param.h> | ||
|
||
IO::Filesystem::FileHandle::FileHandle(IO::Native::FileHandle nativeFileHandle) : m_nativeFileHandle(nativeFileHandle) | ||
{ | ||
} | ||
|
||
IO::Filesystem::FileHandle::~FileHandle() | ||
{ | ||
sLog.Out(LOG_NETWORK, LOG_LVL_DETAIL, "Destructor called ~FileHandle: No references left"); | ||
::close(m_nativeFileHandle); | ||
} | ||
|
||
uint64_t IO::Filesystem::FileHandle::GetTotalFileSize() const | ||
{ | ||
struct stat file_stat; | ||
|
||
if (fstat(m_nativeFileHandle, &file_stat) == -1) | ||
throw std::runtime_error("GetTotalFileSize -> ::fstat() Failed: " + SystemErrorToString(errno)); | ||
|
||
return file_stat.st_size; | ||
} | ||
|
||
std::chrono::system_clock::time_point IO::Filesystem::FileHandle::GetLastModifyDate() const | ||
{ | ||
struct stat file_stat; | ||
|
||
if (fstat(m_nativeFileHandle, &file_stat) == -1) | ||
throw std::runtime_error("GetLastModifyDate -> ::fstat() Failed: " + SystemErrorToString(errno)); | ||
|
||
uint64_t unixSecs = file_stat.st_mtime; | ||
|
||
std::chrono::system_clock::time_point result(std::chrono::duration_cast<std::chrono::system_clock::time_point::duration>(std::chrono::seconds(unixSecs))); | ||
return result; | ||
} | ||
|
||
std::string IO::Filesystem::FileHandle::GetAbsoluteFilePath() const | ||
{ | ||
char filePath[PATH_MAX]; | ||
#if defined(__linux__) | ||
// I really hate LINUX, there is no universal way to get a file path | ||
// Everyone on the internet recommends the following approach. | ||
// (Which can fail if we dont have access to the virtual-"/proc"-fs). | ||
|
||
char pathToLink[PATH_MAX]; | ||
snprintf(pathToLink, sizeof(pathToLink), "/proc/self/fd/%d", m_nativeFileHandle); | ||
|
||
ssize_t len = ::readlink(pathToLink, filePath, sizeof(filePath) - 1); | ||
if (len == -1) | ||
throw std::runtime_error("GetAbsoluteFilePath -> ::readlink() Failed: " + SystemErrorToString(errno)); | ||
filePath[len] = '\0'; | ||
|
||
#elif defined(MACOS) | ||
if (fcntl(m_nativeFileHandle, F_GETPATH, filePath) == -1) | ||
throw std::runtime_error("::fstat(GetLastModifyDate) Failed: " + SystemErrorToString(errno)); | ||
#else | ||
#error "How to implement FileHandle::GetAbsoluteFilePath() on your OS?" | ||
#endif | ||
|
||
return filePath; | ||
} | ||
|
||
uint64_t IO::Filesystem::FileHandleReadonly::ReadSync(uint8_t* dest, uint64_t amountToRead) | ||
{ | ||
uint64_t leftToRead = amountToRead; | ||
while (leftToRead > 0) | ||
{ | ||
size_t amountToReadThisCycle = (size_t) std::min(leftToRead, ((uint64_t) std::numeric_limits<size_t>::max()) - 1); | ||
|
||
ssize_t actuallyReadThisCycle = ::read(m_nativeFileHandle, dest, amountToReadThisCycle); | ||
if (actuallyReadThisCycle == -1) | ||
{ | ||
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "[ERROR] ReadSync -> ::read() Error: %s", SystemErrorToCString(errno)); | ||
return 0; | ||
} | ||
leftToRead -= actuallyReadThisCycle; | ||
|
||
if (actuallyReadThisCycle != amountToReadThisCycle) | ||
{ | ||
break; | ||
} | ||
} | ||
return amountToRead - leftToRead; | ||
} | ||
|
||
std::unique_ptr<IO::Filesystem::FileHandleReadonly> IO::Filesystem::FileHandleReadonly::DuplicateFileHandle() | ||
{ | ||
IO::Native::FileHandle newNativeFileHandle = ::dup(m_nativeFileHandle); | ||
|
||
if (newNativeFileHandle == -1) | ||
throw std::runtime_error("DuplicateFileHandle -> ::dup() Failed: " + SystemErrorToString(errno)); | ||
|
||
return std::make_unique<FileHandleReadonly>(newNativeFileHandle); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
#include "IO/Filesystem/FileSystem.h" | ||
#include "IO/Filesystem/FileHandle.h" | ||
#include "Log.h" | ||
#include "IO/SystemErrorToString.h" | ||
#include <limits.h> | ||
#include <unistd.h> | ||
#include <dirent.h> | ||
|
||
/// This function will open a file in read shared and binary mode | ||
/// You have to check the resulting pointer for nullptr! | ||
/// If the file does not exists or you dont have permission to open it the ptr will be null | ||
std::unique_ptr<IO::Filesystem::FileHandleReadonly> IO::Filesystem::TryOpenFileReadonly(std::string const& filePath, EnumFlag<FileOpenFlags> flags) | ||
{ | ||
int nativeFlags = O_RDONLY; | ||
IO::Native::FileHandle fileHandle = ::open(filePath.c_str(), nativeFlags); | ||
|
||
if (fileHandle == -1) { | ||
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "Unable to open file. Error %s on file: %s", SystemErrorToCString(errno), filePath.c_str()); | ||
return nullptr; | ||
} | ||
|
||
if (::posix_fadvise(fileHandle, 0, 0, POSIX_FADV_WILLNEED) != 0) // Tell Kernel: we might need the file in the near future, please preload it into mem | ||
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "Failed to set WILLNEED hint for file"); | ||
|
||
if (flags.HasFlag(FileOpenFlags::HintSequentialRead)) | ||
{ | ||
if (posix_fadvise(fileHandle, 0, 0, POSIX_FADV_SEQUENTIAL) != 0) // Tell Kernel: to preallocate and load memory pages while reading | ||
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "Failed to set SEQUENTIAL hint for file"); | ||
} | ||
|
||
return std::unique_ptr<FileHandleReadonly>(new FileHandleReadonly(fileHandle)); | ||
} | ||
|
||
/// Will convert a partial path like "./data/myCoolFile.txt" to a complete absolute path like "/home/user/data/myCoolFile.txt" | ||
std::string IO::Filesystem::ToAbsolutePath(std::string const& partialPath) | ||
{ | ||
// There is no absolute/canonicalize path function in linux. | ||
// There is :realpath, but it requires the file/folder to be present | ||
|
||
if (partialPath.find('/') == 0) | ||
return partialPath; // already absolute | ||
|
||
std::string trimmedPath = (partialPath.find("./") == 0) | ||
? partialPath.substr(2) // starts with "relative from CWD path" | ||
: partialPath; | ||
|
||
char temp[PATH_MAX]; | ||
if (::getcwd(temp, sizeof(temp)) == nullptr) | ||
throw std::runtime_error("ToAbsolutePath -> ::getcwd(...) Failed: " + SystemErrorToString(errno)); | ||
|
||
// TODO: Find a way to canonicalize_filepath without reimplementing it by my own | ||
// TODO: For own impl: Keep in mind all the stuff that can be included like "../abc/../.\.\//d" or "./abc\./.conf/bash.config" | ||
std::string completePath = std::string(temp) + "/" + trimmedPath; | ||
return completePath; | ||
} | ||
|
||
/// Returns all files in a folder, non-recursively. | ||
/// if OutputFilePath::JustFileName the path will be based on the folderPath e.g. "myCoolFile.txt" | ||
/// if OutputFilePath::FullFilePath the path will be absolute e.g. "/home/user/data/myCoolFile.txt" | ||
std::vector<std::string> IO::Filesystem::GetAllFilesInFolder(std::string const& folderPath, IO::Filesystem::OutputFilePath filePathOption) | ||
{ | ||
std::vector<std::string> files; | ||
DIR* dir = opendir(folderPath.c_str()); | ||
if (dir == nullptr) | ||
return files; | ||
|
||
std::string safeFolderPath = (folderPath.rfind('/') == (folderPath.size() - 1)) | ||
? folderPath // folder already ends with / | ||
: folderPath + "/"; | ||
|
||
struct dirent* entry; | ||
while ((entry = readdir(dir)) != nullptr) | ||
{ | ||
std::string fullFilePath = safeFolderPath + entry->d_name; // we need the fullFilePath to check if it's a file via ::stat(...) | ||
struct stat info{}; | ||
if (::stat(fullFilePath.c_str(), &info) == 0 && S_ISREG(info.st_mode)) // S_ISREG means IsRegularFile | ||
{ | ||
std::string filePath = filePathOption == OutputFilePath::FullFilePath | ||
? fullFilePath | ||
: entry->d_name; | ||
|
||
files.emplace_back(filePath); | ||
} | ||
} | ||
::closedir(dir); | ||
return files; | ||
} |
Oops, something went wrong.