diff options
| -rw-r--r-- | zen/cmds/run.cpp | 2 | ||||
| -rw-r--r-- | zencore/except.cpp | 6 | ||||
| -rw-r--r-- | zencore/filesystem.cpp | 276 | ||||
| -rw-r--r-- | zencore/include/zencore/endian.h | 4 | ||||
| -rw-r--r-- | zencore/include/zencore/except.h | 6 | ||||
| -rw-r--r-- | zencore/include/zencore/filesystem.h | 10 | ||||
| -rw-r--r-- | zencore/include/zencore/intmath.h | 8 | ||||
| -rw-r--r-- | zencore/include/zencore/iobuffer.h | 8 | ||||
| -rw-r--r-- | zencore/include/zencore/logging.h | 56 | ||||
| -rw-r--r-- | zencore/intmath.cpp | 5 | ||||
| -rw-r--r-- | zencore/iobuffer.cpp | 152 | ||||
| -rw-r--r-- | zencore/thread.cpp | 8 | ||||
| -rw-r--r-- | zencore/zencore.cpp | 3 | ||||
| -rw-r--r-- | zenhttp/httpsys.cpp | 6 |
14 files changed, 444 insertions, 106 deletions
diff --git a/zen/cmds/run.cpp b/zen/cmds/run.cpp index e5210f695..97680ed5a 100644 --- a/zen/cmds/run.cpp +++ b/zen/cmds/run.cpp @@ -80,7 +80,7 @@ RunCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) Visitor(const std::filesystem::path& RootPath) : m_RootPath(RootPath) {} - virtual void VisitFile(const std::filesystem::path& Parent, const std::wstring_view& FileName, uint64_t FileSize) override + virtual void VisitFile(const std::filesystem::path& Parent, const path_view& FileName, uint64_t FileSize) override { std::filesystem::path FullPath = Parent / FileName; diff --git a/zencore/except.cpp b/zencore/except.cpp index 9bf043f4a..84e52ab9f 100644 --- a/zencore/except.cpp +++ b/zencore/except.cpp @@ -31,13 +31,13 @@ ThrowLastError(std::string_view Message) std::string GetLastErrorAsString() { - return GetWindowsErrorAsString(zen::GetLastError()); + return GetErrorAsString(zen::GetLastError()); } std::string -GetWindowsErrorAsString(uint32_t Win32ErrorCode) +GetErrorAsString(uint32_t ErrorCode) { - return std::error_code(Win32ErrorCode, std::system_category()).message(); + return std::error_code(ErrorCode, std::system_category()).message(); } #if __cpp_lib_source_location diff --git a/zencore/filesystem.cpp b/zencore/filesystem.cpp index 59300b7ad..afbddcdbd 100644 --- a/zencore/filesystem.cpp +++ b/zencore/filesystem.cpp @@ -7,20 +7,33 @@ #include <zencore/iobuffer.h> #include <zencore/logging.h> #include <zencore/string.h> -#include <zencore/windows.h> +#if ZEN_PLATFORM_WINDOWS +# include <zencore/windows.h> +#endif + +#if ZEN_PLATFORM_WINDOWS +# include <atlbase.h> +# include <atlfile.h> +# include <winioctl.h> +# include <winnt.h> +#else +# include <dirent.h> +# include <fcntl.h> +# include <sys/stat.h> +# include <unistd.h> +#endif -#include <atlbase.h> -#include <atlfile.h> -#include <winioctl.h> -#include <winnt.h> #include <filesystem> +#include <doctest/doctest.h> #include <gsl/gsl-lite.hpp> namespace zen { using namespace std::literals; +#if ZEN_PLATFORM_WINDOWS + static bool DeleteReparsePoint(const wchar_t* Path, DWORD dwReparseTag) { @@ -53,12 +66,6 @@ CreateDirectories(const wchar_t* Dir) return std::filesystem::create_directories(Dir); } -bool -CreateDirectories(const std::filesystem::path& Dir) -{ - return std::filesystem::create_directories(Dir); -} - // Erase all files and directories in a given directory, leaving an empty directory // behind @@ -157,16 +164,46 @@ CleanDirectory(const wchar_t* DirPath) } } +#endif // ZEN_PLATFORM_WINDOWS + +bool +CreateDirectories(const std::filesystem::path& Dir) +{ + return std::filesystem::create_directories(Dir); +} + bool DeleteDirectories(const std::filesystem::path& Dir) { +#if ZEN_PLATFORM_WINDOWS return DeleteDirectories(Dir.c_str()); +#else + std::error_code ErrorCode; + return std::filesystem::remove_all(Dir, ErrorCode); +#endif } bool CleanDirectory(const std::filesystem::path& Dir) { +#if ZEN_PLATFORM_WINDOWS return CleanDirectory(Dir.c_str()); +#else + if (std::filesystem::exists(Dir)) + { + bool Success = true; + + std::error_code ErrorCode; + for (const auto& Item : std::filesystem::directory_iterator(Dir)) + { + Success &= std::filesystem::remove_all(Item, ErrorCode); + } + + return Success; + } + + return CreateDirectories(Dir); +#endif } ////////////////////////////////////////////////////////////////////////// @@ -174,6 +211,7 @@ CleanDirectory(const std::filesystem::path& Dir) bool SupportsBlockRefCounting(std::filesystem::path Path) { +#if ZEN_PLATFORM_WINDOWS ATL::CHandle Handle(CreateFileW(Path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -200,11 +238,15 @@ SupportsBlockRefCounting(std::filesystem::path Path) } return true; +#else + return false; +#endif // ZEN_PLATFORM_WINDOWS } bool CloneFile(std::filesystem::path FromPath, std::filesystem::path ToPath) { +#if ZEN_PLATFORM_WINDOWS ATL::CHandle FromFile(CreateFileW(FromPath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr)); if (FromFile == INVALID_HANDLE_VALUE) { @@ -359,11 +401,16 @@ CloneFile(std::filesystem::path FromPath, std::filesystem::path ToPath) const bool AllOk = (TRUE == SetFileInformationByHandle(TargetFile, FileDispositionInfo, &FileDisposition, sizeof FileDisposition)); return AllOk; +#else + ZEN_ERROR("CloneFile() is not implemented on this platform"); + return false; +#endif // ZEN_PLATFORM_WINDOWS } bool CopyFile(std::filesystem::path FromPath, std::filesystem::path ToPath, const CopyFileOptions& Options) { +#if ZEN_PLATFORM_WINDOWS bool Success = false; if (Options.EnableClone) @@ -395,6 +442,10 @@ CopyFile(std::filesystem::path FromPath, std::filesystem::path ToPath, const Cop } return Success; +#else + ZEN_ERROR("CopyFile() is not implemented on this platform"); + return false; +#endif // ZEN_PLATFORM_WINDOWS } void @@ -402,6 +453,7 @@ WriteFile(std::filesystem::path Path, const IoBuffer* const* Data, size_t Buffer { using namespace fmt::literals; +#if ZEN_PLATFORM_WINDOWS CAtlFile Outfile; HRESULT hRes = Outfile.Create(Path.c_str(), GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS); if (hRes == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) @@ -416,6 +468,20 @@ WriteFile(std::filesystem::path Path, const IoBuffer* const* Data, size_t Buffer zen::ThrowSystemException(hRes, "File open failed for '{}'"_format(Path).c_str()); } +#else + int Fd = open(Path.c_str(), O_WRONLY); + if (Fd < 0) + { + zen::CreateDirectories(Path.parent_path()); + Fd = open(Path.c_str(), O_WRONLY); + } + + if (Fd < 0) + { + ThrowLastError("File open failed for '{}'"_format(Path)); + } +#endif + // TODO: this should be block-enlightened for (size_t i = 0; i < BufferCount; ++i) @@ -427,17 +493,27 @@ WriteFile(std::filesystem::path Path, const IoBuffer* const* Data, size_t Buffer { const uint64_t ChunkSize = zen::Min<uint64_t>(WriteSize, uint64_t(2) * 1024 * 1024 * 1024); +#if ZEN_PLATFORM_WINDOWS hRes = Outfile.Write(DataPtr, gsl::narrow_cast<uint32_t>(WriteSize)); - if (FAILED(hRes)) { zen::ThrowSystemException(hRes, "File write failed for '{}'"_format(Path).c_str()); } +#else + if (write(Fd, DataPtr, WriteSize) != WriteSize) + { + ThrowLastError("File write failed for '{}'"_format(Path)); + } +#endif // ZEN_PLATFORM_WINDOWS WriteSize -= ChunkSize; DataPtr = reinterpret_cast<const uint8_t*>(DataPtr) + ChunkSize; } } + +#if !ZEN_PLATFORM_WINDOWS + close(Fd); +#endif } void @@ -451,6 +527,10 @@ WriteFile(std::filesystem::path Path, IoBuffer Data) FileContents ReadFile(std::filesystem::path Path) { + uint64_t FileSizeBytes; + void* Handle; + +#if ZEN_PLATFORM_WINDOWS ATL::CHandle FromFile(CreateFileW(Path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr)); if (FromFile == INVALID_HANDLE_VALUE) { @@ -464,18 +544,32 @@ ReadFile(std::filesystem::path Path) return FileContents{.ErrorCode = std::error_code(::GetLastError(), std::system_category())}; } - const uint64_t FileSizeBytes = FileSize.EndOfFile.QuadPart; + FileSizeBytes = FileSize.EndOfFile.QuadPart; + Handle = FromFile.Detach(); +#else + int Fd = open(Path.c_str(), O_RDONLY); + if (Fd < 0) + { + return FileContents{.ErrorCode = std::error_code(zen::GetLastError(), std::system_category())}; + } - FileContents Contents; + static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files"); + struct stat Stat; + fstat(Fd, &Stat); - Contents.Data.emplace_back(IoBuffer(IoBuffer::File, FromFile.Detach(), 0, FileSizeBytes)); + FileSizeBytes = Stat.st_size; + Handle = (void*)uintptr_t(Fd); +#endif + FileContents Contents; + Contents.Data.emplace_back(IoBuffer(IoBuffer::File, Handle, 0, FileSizeBytes)); return Contents; } bool ScanFile(std::filesystem::path Path, const uint64_t ChunkSize, std::function<void(const void* Data, size_t Size)>&& ProcessFunc) { +#if ZEN_PLATFORM_WINDOWS ATL::CHandle FromFile(CreateFileW(Path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr)); if (FromFile == INVALID_HANDLE_VALUE) { @@ -502,26 +596,33 @@ ScanFile(std::filesystem::path Path, const uint64_t ChunkSize, std::function<voi } return true; +#else + ZEN_ERROR("ScanFile() is not implemented on this platform"); + return false; +#endif // ZEN_PLATFORM_WINDOWS } std::string ToUtf8(const std::filesystem::path& Path) { +#if ZEN_PLATFORM_WINDOWS return WideToUtf8(Path.native().c_str()); +#else + return Path.string(); +#endif } void FileSystemTraversal::TraverseFileSystem(const std::filesystem::path& RootDir, TreeVisitor& Visitor) { +#if ZEN_PLATFORM_WINDOWS uint64_t FileInfoBuffer[8 * 1024]; FILE_INFO_BY_HANDLE_CLASS FibClass = FileIdBothDirectoryRestartInfo; bool Continue = true; - std::wstring RootDirPath = RootDir.native(); - CAtlFile RootDirHandle; - HRESULT hRes = RootDirHandle.Create(RootDirPath.c_str(), + HRESULT hRes = RootDirHandle.Create(RootDir.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, @@ -581,12 +682,10 @@ FileSystemTraversal::TraverseFileSystem(const std::filesystem::path& RootDir, Tr } else if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DEVICE) { - ZEN_WARN("encountered device node during file system traversal: {} found in {}", WideToUtf8(FileName), RootDir); + ZEN_WARN("encountered device node during file system traversal: {} found in {}", WideToUtf8(FileName), WideToUtf8(RootDir.c_str())); } else { - std::filesystem::path FullPath = RootDir / FileName; - Visitor.VisitFile(RootDir, FileName, DirInfo->EndOfFile.QuadPart); } @@ -600,11 +699,57 @@ FileSystemTraversal::TraverseFileSystem(const std::filesystem::path& RootDir, Tr EntryOffset += NextOffset; } } +#else + using namespace fmt::literals; + + /* Could also implement this using Linux's getdents() syscall */ + + DIR* Dir = opendir(RootDir.c_str()); + if (Dir == nullptr) + { + ThrowLastError("Failed to open directory for traversal: {}"_format(RootDir.c_str())); + } + + for (struct dirent* Entry; Entry = readdir(Dir);) + { + const char* FileName = Entry->d_name; + + struct stat Stat; + std::filesystem::path FullPath = RootDir / FileName; + stat(FullPath.c_str(), &Stat); + + if (S_ISDIR(Stat.st_mode)) + { + if (strcmp(FileName, ".") == 0 || strcmp(FileName, "..") == 0) + { + /* nop */ + } + else if (Visitor.VisitDirectory(RootDir, FileName)) + { + TraverseFileSystem(FullPath, Visitor); + } + } + else if (S_ISREG(Stat.st_mode)) + { + Visitor.VisitFile(RootDir, FileName, Stat.st_size); + } + else + { + ZEN_WARN("encountered non-regular file during file system traversal ({}): {} found in {}", + Stat.st_mode, FileName, RootDir.c_str()); + } + } + + closedir(Dir); +#endif // ZEN_PLATFORM_WINDOWS } + + std::filesystem::path PathFromHandle(void* NativeHandle) { +#if ZEN_PLATFORM_WINDOWS if (NativeHandle == nullptr || NativeHandle == INVALID_HANDLE_VALUE) { return std::filesystem::path(); @@ -620,15 +765,104 @@ PathFromHandle(void* NativeHandle) ZEN_UNUSED(FinalLength); return FullPath; +#elif ZEN_PLATFORM_LINUX + char Buffer[256]; + sprintf(Buffer, "/proc/%d/fd/%d", getpid(), int(uintptr_t(NativeHandle))); + ssize_t BytesRead = readlink(Buffer, Buffer, sizeof(Buffer) - 1); + if (BytesRead <= 0) + return std::filesystem::path(); + + Buffer[BytesRead] = '\0'; + return Buffer; +#else +# error Unimplemented platform +#endif // ZEN_PLATFORM_WINDOWS } std::filesystem::path GetRunningExecutablePath() { +#if ZEN_PLATFORM_WINDOWS TCHAR ExePath[MAX_PATH]; DWORD PathLength = GetModuleFileName(NULL, ExePath, ZEN_ARRAY_COUNT(ExePath)); return {std::wstring_view(ExePath, PathLength)}; +#elif ZEN_PLATFORM_LINUX + char Buffer[256]; + sprintf(Buffer, "/proc/%d/exe", getpid()); + ssize_t BytesRead = readlink(Buffer, Buffer, sizeof(Buffer) - 1); + if (BytesRead < 0) + return {}; + + Buffer[BytesRead] = '\0'; + return Buffer; +#else +# error Unimplemented platform +#endif // ZEN_PLATFORM_WINDOWS +} + + + +////////////////////////////////////////////////////////////////////////// +// +// Testing related code follows... +// + +void +filesystem_forcelink() +{ +} + +TEST_CASE("filesystem") +{ + using namespace std::filesystem; + + // GetExePath + path BinPath = GetRunningExecutablePath(); + CHECK(BinPath.stem() == "zencore-test"); + CHECK(is_regular_file(BinPath)); + + // PathFromHandle + void* Handle; +#if ZEN_PLATFORM_WINDOWS + Handle = CreateFileW(BinPath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, 0, nullptr); + CHECK(Handle != INVALID_HANDLE_VALUE); +#else + int Fd = open(BinPath.c_str(), O_RDONLY); + CHECK(Fd >= 0); + Handle = (void*)uintptr_t(Fd); +#endif + + auto FromHandle = PathFromHandle((void*)uintptr_t(Handle)); + CHECK(equivalent(FromHandle, BinPath)); + +#if ZEN_PLATFORM_WINDOWS + CloseHandle(Handle); +#else + close(int(uintptr_t(Handle))); +#endif + + // Traversal + struct : public FileSystemTraversal::TreeVisitor + { + virtual void VisitFile(const std::filesystem::path& Parent, const path_view& File, uint64_t) override + { + bFoundExpected |= std::filesystem::equivalent(Parent / File, Expected); + } + + virtual bool VisitDirectory(const std::filesystem::path&, const path_view&) override + { + return true; + } + + bool bFoundExpected = false; + std::filesystem::path Expected; + } Visitor; + Visitor.Expected = BinPath; + + FileSystemTraversal().TraverseFileSystem(BinPath.parent_path().parent_path(), Visitor); + CHECK(Visitor.bFoundExpected); } } // namespace zen diff --git a/zencore/include/zencore/endian.h b/zencore/include/zencore/endian.h index d44a27b01..7a9e6b44c 100644 --- a/zencore/include/zencore/endian.h +++ b/zencore/include/zencore/endian.h @@ -2,6 +2,10 @@ #pragma once +#include "zencore.h" + +#include <cstdint> + namespace zen { inline uint16_t diff --git a/zencore/include/zencore/except.h b/zencore/include/zencore/except.h index 08330e4bc..f0e04a795 100644 --- a/zencore/include/zencore/except.h +++ b/zencore/include/zencore/except.h @@ -60,7 +60,7 @@ ZENCORE_API void ThrowLastError(std::string_view Message, const std::source_loca #endif ZENCORE_API std::string GetLastErrorAsString(); -ZENCORE_API std::string GetWindowsErrorAsString(uint32_t Win32ErrorCode); +ZENCORE_API std::string GetErrorAsString(uint32_t ErrorCode); inline void ThrowSystemException(const char* Message) @@ -83,9 +83,9 @@ GetLastError() } inline std::error_code -MakeWin32ErrorCode(uint32_t Win32ErrorCode) noexcept +MakeErrorCode(uint32_t ErrorCode) noexcept { - return std::error_code(Win32ErrorCode, std::system_category()); + return std::error_code(ErrorCode, std::system_category()); } inline std::error_code diff --git a/zencore/include/zencore/filesystem.h b/zencore/include/zencore/filesystem.h index a2d368d6f..66ab37e5c 100644 --- a/zencore/include/zencore/filesystem.h +++ b/zencore/include/zencore/filesystem.h @@ -69,13 +69,19 @@ class FileSystemTraversal public: struct TreeVisitor { - virtual void VisitFile(const std::filesystem::path& Parent, const std::wstring_view& File, uint64_t FileSize) = 0; + using path_view = std::basic_string_view<std::filesystem::path::value_type>; + + virtual void VisitFile(const std::filesystem::path& Parent, const path_view& File, uint64_t FileSize) = 0; // This should return true if we should recurse into the directory - virtual bool VisitDirectory(const std::filesystem::path& Parent, const std::wstring_view& DirectoryName) = 0; + virtual bool VisitDirectory(const std::filesystem::path& Parent, const path_view& DirectoryName) = 0; }; void TraverseFileSystem(const std::filesystem::path& RootDir, TreeVisitor& Visitor); }; +////////////////////////////////////////////////////////////////////////// + +void filesystem_forcelink(); // internal + } // namespace zen diff --git a/zencore/include/zencore/intmath.h b/zencore/include/zencore/intmath.h index b127c8993..7619e1950 100644 --- a/zencore/include/zencore/intmath.h +++ b/zencore/include/zencore/intmath.h @@ -21,7 +21,7 @@ _BitScanReverse(unsigned long* Index, uint32_t Mask) return 0; } - *Index = __builtin_clz(Mask); + *Index = 31 - __builtin_clz(Mask); return 1; } @@ -33,8 +33,8 @@ _BitScanReverse64(unsigned long* Index, uint64_t Mask) return 0; } - *Index = __builtin_clzll(Mask); - return 0; + *Index = 63 - __builtin_clzll(Mask); + return 1; } inline uint8_t @@ -46,7 +46,7 @@ _BitScanForward64(unsigned long* Index, uint64_t Mask) } *Index = __builtin_ctzll(Mask); - return 0; + return 1; } #endif diff --git a/zencore/include/zencore/iobuffer.h b/zencore/include/zencore/iobuffer.h index 517cc7b69..298952dd6 100644 --- a/zencore/include/zencore/iobuffer.h +++ b/zencore/include/zencore/iobuffer.h @@ -7,6 +7,8 @@ #include "refcount.h" #include "zencore.h" +#include <filesystem> + namespace zen { struct IoBufferExtendedCore; @@ -341,9 +343,11 @@ private: class IoBufferBuilder { + using path_char_t = std::filesystem::path::value_type; + public: - ZENCORE_API static IoBuffer MakeFromFile(const wchar_t* FileName, uint64_t Offset = 0, uint64_t Size = ~0ull); - ZENCORE_API static IoBuffer MakeFromTemporaryFile(const wchar_t* FileName); + ZENCORE_API static IoBuffer MakeFromFile(const path_char_t* FileName, uint64_t Offset = 0, uint64_t Size = ~0ull); + ZENCORE_API static IoBuffer MakeFromTemporaryFile(const path_char_t* FileName); ZENCORE_API static IoBuffer MakeFromFileHandle(void* FileHandle, uint64_t Offset = 0, uint64_t Size = ~0ull); inline static IoBuffer MakeCloneFromMemory(const void* Ptr, size_t Sz) { return IoBuffer(IoBuffer::Clone, Ptr, Sz); } }; diff --git a/zencore/include/zencore/logging.h b/zencore/include/zencore/logging.h index 8e6b3a244..412a39415 100644 --- a/zencore/include/zencore/logging.h +++ b/zencore/include/zencore/logging.h @@ -39,44 +39,44 @@ using zen::Log; // Helper macros for logging -#define ZEN_TRACE(fmtstr, ...) \ - do \ - { \ - using namespace std::literals; \ - Log().trace(fmtstr##sv, __VA_ARGS__); \ +#define ZEN_TRACE(fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + Log().trace(fmtstr##sv, ##__VA_ARGS__);\ } while (false) -#define ZEN_DEBUG(fmtstr, ...) \ +#define ZEN_DEBUG(fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + Log().debug(fmtstr##sv, ##__VA_ARGS__);\ + } while (false) + +#define ZEN_INFO(fmtstr, ...) \ do \ { \ using namespace std::literals; \ - Log().debug(fmtstr##sv, __VA_ARGS__); \ + Log().info(fmtstr##sv, ##__VA_ARGS__);\ } while (false) -#define ZEN_INFO(fmtstr, ...) \ - do \ - { \ - using namespace std::literals; \ - Log().info(fmtstr##sv, __VA_ARGS__); \ - } while (false) - -#define ZEN_WARN(fmtstr, ...) \ - do \ - { \ - using namespace std::literals; \ - Log().warn(fmtstr##sv, __VA_ARGS__); \ - } while (false) - -#define ZEN_ERROR(fmtstr, ...) \ +#define ZEN_WARN(fmtstr, ...) \ do \ { \ using namespace std::literals; \ - Log().error(fmtstr##sv, __VA_ARGS__); \ + Log().warn(fmtstr##sv, ##__VA_ARGS__);\ + } while (false) + +#define ZEN_ERROR(fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + Log().error(fmtstr##sv, ##__VA_ARGS__);\ } while (false) -#define ZEN_CRITICAL(fmtstr, ...) \ - do \ - { \ - using namespace std::literals; \ - Log().critical(fmtstr##sv, __VA_ARGS__); \ +#define ZEN_CRITICAL(fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + Log().critical(fmtstr##sv, ##__VA_ARGS__);\ } while (false) diff --git a/zencore/intmath.cpp b/zencore/intmath.cpp index 2acfaebd8..98c345c79 100644 --- a/zencore/intmath.cpp +++ b/zencore/intmath.cpp @@ -1,5 +1,6 @@ // Copyright Epic Games, Inc. All Rights Reserved. +#include <zencore/endian.h> #include <zencore/intmath.h> #include <doctest/doctest.h> @@ -51,6 +52,10 @@ TEST_CASE("intmath") CHECK(CountTrailingZeros64(0x0000'0000'0000'0001ull) == 0); CHECK(CountTrailingZeros64(0x0000'0000'8000'0000ull) == 31); CHECK(CountTrailingZeros64(0x0000'0001'0000'0000ull) == 32); + + CHECK(ByteSwap(uint16_t(0x6d72)) == 0x726d); + CHECK(ByteSwap(uint32_t(0x2741'3965)) == 0x6539'4127); + CHECK(ByteSwap(uint64_t(0x214d'6172'7469'6e21ull)) == 0x216e'6974'7261'4d21ull); } } // namespace zen diff --git a/zencore/iobuffer.cpp b/zencore/iobuffer.cpp index ee06f379e..beb969bc7 100644 --- a/zencore/iobuffer.cpp +++ b/zencore/iobuffer.cpp @@ -4,6 +4,7 @@ #include <doctest/doctest.h> #include <memory.h> +#include <zencore/except.h> #include <zencore/filesystem.h> #include <zencore/fmtutils.h> #include <zencore/logging.h> @@ -11,7 +12,13 @@ #include <zencore/thread.h> #include <system_error> -#include <atlfile.h> +#if ZEN_PLATFORM_WINDOWS +# include <atlfile.h> +#else +# include <sys/stat.h> +# include <sys/mman.h> +#endif + #include <gsl/gsl-lite.hpp> namespace zen { @@ -21,12 +28,14 @@ namespace zen { void* IoBufferCore::AllocateBuffer(size_t InSize, size_t Alignment) { +#if ZEN_PLATFORM_WINDOWS if (((InSize & 0xffFF) == 0) && (Alignment == 0x10000)) { m_Flags |= kLowLevelAlloc; return VirtualAlloc(nullptr, InSize, MEM_COMMIT, PAGE_READWRITE); } else +#endif // ZEN_PLATFORM_WINDOWS { return Memory::Alloc(InSize, Alignment); } @@ -35,11 +44,13 @@ IoBufferCore::AllocateBuffer(size_t InSize, size_t Alignment) void IoBufferCore::FreeBuffer() { +#if ZEN_PLATFORM_WINDOWS if (m_Flags & kLowLevelAlloc) { VirtualFree(const_cast<void*>(m_DataPtr), 0, MEM_DECOMMIT); } else +#endif // ZEN_PLATFORM_WINDOWS { return Memory::Free(const_cast<void*>(m_DataPtr)); } @@ -151,17 +162,29 @@ IoBufferExtendedCore::~IoBufferExtendedCore() { if (m_MappedPointer) { +#if ZEN_PLATFORM_WINDOWS UnmapViewOfFile(m_MappedPointer); +#else + uint64_t MapSize = ~uint64_t(uintptr_t(m_MmapHandle)); + munmap(m_MappedPointer, MapSize); +#endif } +#if ZEN_PLATFORM_WINDOWS if (m_Flags & kOwnsMmap) { CloseHandle(m_MmapHandle); } +#endif if (m_Flags & kOwnsFile) { +#if ZEN_PLATFORM_WINDOWS BOOL Success = CloseHandle(m_FileHandle); +#else + int Fd = int(uintptr_t(m_FileHandle)); + bool Success = (close(Fd) == 0); +#endif if (!Success) { @@ -172,7 +195,7 @@ IoBufferExtendedCore::~IoBufferExtendedCore() m_DataPtr = nullptr; } -RwLock g_MappingLock; +static RwLock g_MappingLock; void IoBufferExtendedCore::Materialize() const @@ -191,6 +214,11 @@ IoBufferExtendedCore::Materialize() const if (m_MmapHandle) return; + const uint64_t MapOffset = m_FileOffset & ~0xffffull; + const uint64_t MappedOffsetDisplacement = m_FileOffset - MapOffset; + const uint64_t MapSize = m_DataBytes + MappedOffsetDisplacement; + +#if ZEN_PLATFORM_WINDOWS m_MmapHandle = CreateFileMapping(m_FileHandle, /* lpFileMappingAttributes */ nullptr, /* flProtect */ PAGE_READONLY, @@ -206,20 +234,28 @@ IoBufferExtendedCore::Materialize() const m_Flags |= kOwnsMmap; - const uint64_t MapOffset = m_FileOffset & ~0xffffull; - const uint64_t MappedOffsetDisplacement = m_FileOffset - MapOffset; - const uint64_t MapSize = m_DataBytes + MappedOffsetDisplacement; - void* MappedBase = MapViewOfFile(m_MmapHandle, /* dwDesiredAccess */ FILE_MAP_READ, /* FileOffsetHigh */ uint32_t(MapOffset >> 32), /* FileOffsetLow */ uint32_t(MapOffset & 0xffFFffFFu), /* dwNumberOfBytesToMap */ MapSize); +#else + m_MmapHandle = (void*)uintptr_t(~MapSize); // ~ so it's never null (assuming MapSize >= 0) + m_Flags |= kOwnsMmap; + + void* MappedBase = mmap( + /* addr */ nullptr, + /* length */ MapSize, + /* prot */ PROT_READ, + /* flags */ MAP_SHARED|MAP_NORESERVE, + /* fd */ int(uintptr_t(m_FileHandle)), + /* offset */ MapOffset); +#endif // ZEN_PLATFORM_WINDOWS if (MappedBase == nullptr) { throw std::system_error( - std::error_code(::GetLastError(), std::system_category()), + std::error_code(zen::GetLastError(), std::system_category()), "MapViewOfFile failed (offset {:#x}, size {:#x}) file: '{}'"_format(MapOffset, MapSize, zen::PathFromHandle(m_FileHandle))); } @@ -315,49 +351,72 @@ IoBufferBuilder::MakeFromFileHandle(void* FileHandle, uint64_t Offset, uint64_t } IoBuffer -IoBufferBuilder::MakeFromFile(const wchar_t* FileName, uint64_t Offset, uint64_t Size) +IoBufferBuilder::MakeFromFile(const path_char_t* FileName, uint64_t Offset, uint64_t Size) { + uint64_t FileSize; + +#if ZEN_PLATFORM_WINDOWS CAtlFile DataFile; HRESULT hRes = DataFile.Create(FileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING); - if (SUCCEEDED(hRes)) + if (FAILED(hRes)) { - ULONGLONG FileSize; - DataFile.GetSize(FileSize); + return {}; + } - // TODO: should validate that offset is in range + DataFile.GetSize((ULONGLONG&)FileSize); +#else + int Fd = open(FileName, O_RDONLY); + if (Fd < 0) + { + return {}; + } + + static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files"); + struct stat Stat; + fstat(Fd, &Stat); + FileSize = Stat.st_size; +#endif // ZEN_PLATFORM_WINDOWS - if (Size == ~0ull) + // TODO: should validate that offset is in range + + if (Size == ~0ull) + { + Size = FileSize - Offset; + } + else + { + // Clamp size + if ((Offset + Size) > FileSize) { Size = FileSize - Offset; } - else - { - // Clamp size - if ((Offset + Size) > FileSize) - { - Size = FileSize - Offset; - } - } + } - if (Size) - { - return IoBuffer(IoBuffer::File, DataFile.Detach(), Offset, Size); - } - else - { - // For an empty file, we may as well just return an empty memory IoBuffer - return IoBuffer(IoBuffer::Wrap, "", 0); - } + if (Size) + { +#if ZEN_PLATFORM_WINDOWS + void* Fd = DataFile.Detach(); +#endif + return IoBuffer(IoBuffer::File, (void*)uintptr_t(Fd), Offset, Size); } - return {}; +#if !ZEN_PLATFORM_WINDOWS + close(Fd); +#endif + + // For an empty file, we may as well just return an empty memory IoBuffer + return IoBuffer(IoBuffer::Wrap, "", 0); } IoBuffer -IoBufferBuilder::MakeFromTemporaryFile(const wchar_t* FileName) +IoBufferBuilder::MakeFromTemporaryFile(const path_char_t* FileName) { + uint64_t FileSize; + void* Handle; + +#if ZEN_PLATFORM_WINDOWS CAtlFile DataFile; // We need to open with DELETE since this is used for the case @@ -366,18 +425,33 @@ IoBufferBuilder::MakeFromTemporaryFile(const wchar_t* FileName) HRESULT hRes = DataFile.Create(FileName, GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_DELETE, OPEN_EXISTING); - if (SUCCEEDED(hRes)) + if (FAILED(hRes)) { - ULONGLONG FileSize; - DataFile.GetSize(FileSize); + return {}; + } - IoBuffer Iob(IoBuffer::File, DataFile.Detach(), 0, FileSize); - Iob.m_Core->SetIsWholeFile(true); + DataFile.GetSize((ULONGLONG&)FileSize); - return Iob; + Handle = DataFile.Detach(); +#else + int Fd = open(FileName, O_RDONLY); + if (Fd < 0) + { + return {}; } - return {}; + static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files"); + struct stat Stat; + fstat(Fd, &Stat); + FileSize = Stat.st_size; + + Handle = (void*)uintptr_t(Fd); +#endif // ZEN_PLATFORM_WINDOWS + + IoBuffer Iob(IoBuffer::File, Handle, 0, FileSize); + Iob.m_Core->SetIsWholeFile(true); + + return Iob; } ////////////////////////////////////////////////////////////////////////// diff --git a/zencore/thread.cpp b/zencore/thread.cpp index 598466bb4..620ea3bff 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -54,6 +54,8 @@ RwLock::ReleaseExclusive() #endif } +////////////////////////////////////////////////////////////////////////// + Event::Event() { m_EventHandle = CreateEvent(nullptr, true, false, nullptr); @@ -93,6 +95,8 @@ Event::Wait(int TimeoutMs) return (Result == WAIT_OBJECT_0); } +////////////////////////////////////////////////////////////////////////// + NamedEvent::NamedEvent(std::u8string_view EventName) : Event(nullptr) { using namespace std::literals; @@ -160,6 +164,8 @@ NamedMutex::Exists(std::string_view MutexName) return true; } +////////////////////////////////////////////////////////////////////////// + ProcessHandle::ProcessHandle() = default; void @@ -255,6 +261,8 @@ ProcessHandle::Wait(int TimeoutMs) return false; } +////////////////////////////////////////////////////////////////////////// + bool IsProcessRunning(int pid) { diff --git a/zencore/zencore.cpp b/zencore/zencore.cpp index f179880e4..f9b19ba9d 100644 --- a/zencore/zencore.cpp +++ b/zencore/zencore.cpp @@ -16,6 +16,8 @@ #include <zencore/compactbinarypackage.h> #include <zencore/compositebuffer.h> #include <zencore/compress.h> +#include <zencore/filesystem.h> +#include <zencore/intmath.h> #include <zencore/iobuffer.h> #include <zencore/memory.h> #include <zencore/refcount.h> @@ -85,6 +87,7 @@ zencore_forcelinktests() zen::blake3_forcelink(); zen::compositebuffer_forcelink(); zen::compress_forcelink(); + zen::filesystem_forcelink(); zen::intmath_forcelink(); zen::iobuffer_forcelink(); zen::memory_forcelink(); diff --git a/zenhttp/httpsys.cpp b/zenhttp/httpsys.cpp index c2d4ef14c..d70c88271 100644 --- a/zenhttp/httpsys.cpp +++ b/zenhttp/httpsys.cpp @@ -417,7 +417,7 @@ HttpMessageResponseRequest::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfB if (IoResult) { - ZEN_WARN("response aborted due to error: '{}'", GetWindowsErrorAsString(IoResult)); + ZEN_WARN("response aborted due to error: '{}'", GetErrorAsString(IoResult)); // if one transmit failed there's really no need to go on return nullptr; @@ -555,7 +555,7 @@ HttpMessageResponseRequest::IssueRequest(std::error_code& ErrorCode) ZEN_ERROR("failed to send HTTP response (error: '{}'), request URL: {}", SendResult, HttpReq->pRawUrl); - ErrorCode = MakeWin32ErrorCode(SendResult); + ErrorCode = MakeErrorCode(SendResult); } else { @@ -1236,7 +1236,7 @@ InitialRequestHandler::IssueRequest(std::error_code& ErrorCode) // CleanupHttpIoRequest(pIoRequest); - ErrorCode = MakeWin32ErrorCode(HttpApiResult); + ErrorCode = MakeErrorCode(HttpApiResult); ZEN_ERROR("HttpReceiveHttpRequest failed, error {}", ErrorCode.message()); |