Skip to content

Commit

Permalink
Revert "Native Branch: Replace parts of IO::Filesystem with C++17 `…
Browse files Browse the repository at this point in the history
…std::filesystem`" (vmangos#2757)
  • Loading branch information
ratkosrb authored Sep 7, 2024
1 parent d9f17f6 commit 1d18a61
Show file tree
Hide file tree
Showing 16 changed files with 154 additions and 6,469 deletions.
2 changes: 1 addition & 1 deletion src/realmd/ClientPatchCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ void ClientPatchCache::LoadPatchesInfo()

for (const std::string& filePath : IO::Filesystem::GetAllFilesInFolder(fullFolderPath, IO::Filesystem::OutputFilePath::FullFilePath))
{
auto fileHandle = IO::Filesystem::TryOpenFileReadonly(filePath);
auto fileHandle = IO::Filesystem::TryOpenFileReadonly(filePath, IO::Filesystem::FileOpenFlags::HintSequentialRead);
if (fileHandle)
{
sLog.Out(LOG_BASIC, LOG_LVL_DEBUG, "[PatchCache] Calculate hash of %s", filePath.c_str());
Expand Down
1 change: 0 additions & 1 deletion src/shared/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ set (shared_SRCS
IO/Timer/impl/unix/TimerHandle.cpp
IO/Timer/AsyncSystemTimer.h
IO/Filesystem/FileSystem.h
IO/Filesystem/FileSystem.cpp
IO/Filesystem/FileHandle.h
IO/Filesystem/impl/windows/FileSystem.cpp
IO/Filesystem/impl/windows/FileHandle.cpp
Expand Down
23 changes: 0 additions & 23 deletions src/shared/EnumFlag.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,6 @@

#include <type_traits>

/* Example usage:
// In header
enum class MyCoolFlags
{
None = 0,
FlagA = (1 << 0),
FlagB = (1 << 0),
FlagC = (1 << 0),
FlagD = (1 << 0),
FlagE = (1 << 0),
};
DEFINE_ENUM_FLAG(MyCoolFlags);
// In CPP file
void MyCoolFunction(EnumFlag<MyCoolFlags> flags)
{
if (flags.HasFlag(MyCoolFlags::FlagA))
// Do something
}
*/

template<typename T>
constexpr bool IsEnumFlag(T) { return false; }

Expand Down
22 changes: 0 additions & 22 deletions src/shared/IO/Filesystem/FileSystem.cpp

This file was deleted.

9 changes: 8 additions & 1 deletion src/shared/IO/Filesystem/FileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
#include "FileHandle.h"

namespace IO { namespace Filesystem {
enum class FileOpenFlags
{
None = 0,
HintSequentialRead = (1 << 0), // Hint to the OS, that the file will be read sequentially. (The OS will read ahead and preload the file into memory)
};
DEFINE_ENUM_FLAG(FileOpenFlags);

enum class OutputFilePath
{
JustFileName,
Expand All @@ -18,7 +25,7 @@ namespace IO { namespace Filesystem {
/// 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
[[nodiscard("You need to use the file handle, otherwise the file will close immediately again")]]
std::unique_ptr<IO::Filesystem::FileHandleReadonly> TryOpenFileReadonly(std::string const& filePath);
std::unique_ptr<IO::Filesystem::FileHandleReadonly> TryOpenFileReadonly(std::string const& filePath, EnumFlag<FileOpenFlags> flags = IO::Filesystem::FileOpenFlags::None);

/// Will convert a partial path like "./data/myCoolFile.txt" to a complete absolute path like "/home/user/data/myCoolFile.txt"
[[nodiscard]]
Expand Down
97 changes: 92 additions & 5 deletions src/shared/IO/Filesystem/impl/unix/FileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,108 @@
#include "IO/Filesystem/FileHandle.h"
#include "Log.h"
#include "IO/SystemErrorToString.h"

#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.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)
std::unique_ptr<IO::Filesystem::FileHandleReadonly> IO::Filesystem::TryOpenFileReadonly(std::string const& filePath, EnumFlag<FileOpenFlags> flags)
{
int nativeFlags = O_RDONLY;
IO::Native::FileHandle nativeFileHandle = ::open(filePath.c_str(), nativeFlags);
IO::Native::FileHandle fileHandle = ::open(filePath.c_str(), nativeFlags);

if (nativeFileHandle == -1) {
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;
}

return std::make_unique<FileHandleReadonly>(filePath, nativeFileHandle);
#if defined(__linux__)
// Tell Kernel: we might need the file in the near future, please preload it into mem
if (::posix_fadvise(fileHandle, 0, 0, POSIX_FADV_WILLNEED) != 0)
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "Failed to set WILLNEED hint for file");

if (flags.HasFlag(FileOpenFlags::HintSequentialRead))
{
// Tell Kernel: to preallocate and load memory pages while reading
if (::posix_fadvise(fileHandle, 0, 0, POSIX_FADV_SEQUENTIAL) != 0)
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "Failed to set SEQUENTIAL hint for file");
}
#elif defined(__APPLE__)
{ // Tell Kernel: we might need the file in the near future, please preload it into mem
struct radvisory radv;
radv.ra_offset = 0; // 0 = start of file
radv.ra_count = 0; // 0 = means read whole file if possible
if (::fcntl(fileHandle, F_RDADVISE, &radv) == -1)
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "Failed to set RDADVISE hint for file");
}

if (flags.HasFlag(FileOpenFlags::HintSequentialRead))
{
// Tell Kernel: to preallocate and load memory pages while reading
if (::fcntl(fileHandle, F_RDAHEAD, 1) == -1)
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "Failed to set SEQUENTIAL hint for file");
}
#else
#warning "IO::Filesystem::TryOpenFileReadonly(...) hints are not supported on your platform"
#endif

return std::unique_ptr<FileHandleReadonly>(new FileHandleReadonly(filePath, 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;
}
57 changes: 53 additions & 4 deletions src/shared/IO/Filesystem/impl/windows/FileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@
/// 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)
std::unique_ptr<IO::Filesystem::FileHandleReadonly> IO::Filesystem::TryOpenFileReadonly(std::string const& filePath, EnumFlag<FileOpenFlags> flags)
{
IO::Native::FileHandle nativeFileHandle = CreateFileA(
DWORD nativeFlags = FILE_ATTRIBUTE_NORMAL;
if (flags.HasFlag(FileOpenFlags::HintSequentialRead))
{
nativeFlags |= FILE_FLAG_SEQUENTIAL_SCAN;
}

HANDLE nativeFileHandle = CreateFileA(
filePath.c_str(),
GENERIC_READ,
FILE_SHARE_READ, // Share mode: allow other processes to read
nullptr, // Security attributes
OPEN_EXISTING, // Open exising file. Fail if it does not exist
FILE_ATTRIBUTE_NORMAL, // Normal open, without any special flags
nativeFlags,
nullptr // Template file handle (would be used when creating a new file and copy the attributes)
);

Expand All @@ -26,5 +32,48 @@ std::unique_ptr<IO::Filesystem::FileHandleReadonly> IO::Filesystem::TryOpenFileR
return nullptr;
}

return std::make_unique<FileHandleReadonly>(filePath, nativeFileHandle);
return std::unique_ptr<FileHandleReadonly>(new FileHandleReadonly(filePath, nativeFileHandle));
}

/// 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)
{
char fullPath[MAX_PATH];
if (::GetFullPathNameA(partialPath.c_str(), MAX_PATH, fullPath, nullptr) == 0)
throw std::runtime_error("ToAbsolutePath -> ::GetFullPathNameA() failed " + std::to_string(GetLastError()));

return std::string(fullPath);
}

/// 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;

// Construct the search path
std::string searchPath = folderPath + "\\*";

WIN32_FIND_DATAA fileData;
HANDLE hFind = ::FindFirstFileA(searchPath.c_str(), &fileData);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
if (!(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) // Somehow Windows detects .MPQ files as FILE_ATTRIBUTE_ARCHIVE? Thus, we can't use FILE_ATTRIBUTE_NORMAL
{
std::string filePath = filePathOption == OutputFilePath::FullFilePath
? IO::Filesystem::ToAbsolutePath(folderPath + "\\" + fileData.cFileName)
: fileData.cFileName;

files.emplace_back(filePath);
}

} while (::FindNextFileA(hFind, &fileData));

::FindClose(hFind);
}

return files;
}
13 changes: 0 additions & 13 deletions src/shared/nonstd/filesystem.h

This file was deleted.

19 changes: 0 additions & 19 deletions src/shared/nonstd/ghc-filesystem-cpp11-backport/LICENSE

This file was deleted.

16 changes: 0 additions & 16 deletions src/shared/nonstd/ghc-filesystem-cpp11-backport/README.md

This file was deleted.

Loading

0 comments on commit 1d18a61

Please sign in to comment.