diff options
Diffstat (limited to 'libs/usvfs/src/shared')
28 files changed, 0 insertions, 5099 deletions
diff --git a/libs/usvfs/src/shared/CMakeLists.txt b/libs/usvfs/src/shared/CMakeLists.txt deleted file mode 100644 index b1a7c05..0000000 --- a/libs/usvfs/src/shared/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -find_package(Boost CONFIG REQUIRED COMPONENTS algorithm interprocess filesystem) -find_package(spdlog CONFIG REQUIRED) - -file(GLOB sources "*.cpp" "*.h") -source_group("" FILES ${sources}) - -add_library(shared STATIC ${sources}) -target_link_libraries(shared - PUBLIC - Boost::algorithm Boost::interprocess comsuppw - Boost::filesystem spdlog::spdlog_header_only) -target_include_directories(shared - PUBLIC ${PROJECT_SOURCE_DIR}/include/usvfs ${CMAKE_CURRENT_SOURCE_DIR}) -target_precompile_headers(shared PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/pch.h) -target_compile_options(shared PUBLIC /FI"pch.h") -target_compile_definitions(shared PUBLIC - SPDLOG_USE_STD_FORMAT SPDLOG_NO_NAME SPDLOG_NO_REGISTRY_MUTEX - BOOST_INTERPROCESS_SHARED_DIR_FUNC BOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE - NOMINMAX _WINDOWS _UNICODE UNICODE - _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR -) diff --git a/libs/usvfs/src/shared/addrtools.h b/libs/usvfs/src/shared/addrtools.h deleted file mode 100644 index b888ebf..0000000 --- a/libs/usvfs/src/shared/addrtools.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include "windows_sane.h" - -namespace usvfs::shared -{ - -#ifdef _M_AMD64 -typedef DWORD64 REGWORD; -#elif _M_IX86 -typedef DWORD REGWORD; -#endif - -inline LPVOID AddrAdd(LPVOID address, size_t offset) -{ - return reinterpret_cast<LPVOID>(reinterpret_cast<LPBYTE>(address) + offset); -} - -inline std::ptrdiff_t AddrDiff(LPVOID lhs, LPVOID rhs) -{ - return reinterpret_cast<LPBYTE>(lhs) - reinterpret_cast<LPBYTE>(rhs); -} - -// implicitly cast pointer to void*, from there cast to target type. -// This is supposed to be safer than directly reinterpret-casting -template <typename T> -inline T void_ptr_cast(void* ptr) -{ - return reinterpret_cast<T>(ptr); -} - -template <> -inline int64_t void_ptr_cast(void* ptr) -{ - return reinterpret_cast<int64_t>(ptr); -} - -template <> -inline uint64_t void_ptr_cast(void* ptr) -{ - return reinterpret_cast<uint64_t>(ptr); -} - -} // namespace usvfs::shared diff --git a/libs/usvfs/src/shared/directory_tree.cpp b/libs/usvfs/src/shared/directory_tree.cpp deleted file mode 100644 index 33d7ae1..0000000 --- a/libs/usvfs/src/shared/directory_tree.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "directory_tree.h" -#include "tree_container.h" - -namespace usvfs::shared -{ - -fs::path::iterator nextIter(const fs::path::iterator& iter, - const fs::path::iterator& end) -{ - fs::path::iterator next = iter; - advanceIter(next, end); - return next; -} - -void advanceIter(fs::path::iterator& iter, const fs::path::iterator& end) -{ - if (iter == end) { - return; - } - - ++iter; - while (iter != end && (iter->wstring() == L"/" || iter->wstring() == L"\\" || - iter->wstring() == L".")) - ++iter; -} - -} // namespace usvfs::shared diff --git a/libs/usvfs/src/shared/directory_tree.h b/libs/usvfs/src/shared/directory_tree.h deleted file mode 100644 index 1712071..0000000 --- a/libs/usvfs/src/shared/directory_tree.h +++ /dev/null @@ -1,650 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include "exceptionex.h" -#include "logging.h" -#include "shared_memory.h" -#include "stringutils.h" -#include "wildcard.h" - -// simplify unit tests by allowing access to private members -#ifndef PRIVATE -#define PRIVATE private -#endif // PRIVATE - -namespace usvfs::shared -{ - -template <typename T, typename U> -struct SHMDataCreator -{ - static T create(const U& source, const VoidAllocatorT& allocator) - { - return T(source, allocator); - } -}; - -template <typename T, typename U> -T createData(const U& source, const VoidAllocatorT& allocator) -{ - return SHMDataCreator<T, U>::create(source, allocator); -} - -template <typename T> -T createDataEmpty(const VoidAllocatorT& allocator); - -template <typename T> -void dataAssign(T& destination, const T& source); - -// crappy little workaround for fs::path iterating over path separators -fs::path::iterator nextIter(const fs::path::iterator& iter, - const fs::path::iterator& end); - -void advanceIter(fs::path::iterator& iter, const fs::path::iterator& end); - -// decomposes a path into its components -// -class DecomposablePath -{ -public: - explicit DecomposablePath(std::string s) : m_s(std::move(s)), m_begin(0), m_end(0) - { - m_end = nextSeparator(m_begin); - } - - // move to the next component, returns false when there are no more components - // - bool next() - { - for (;;) { - if (m_end >= m_s.size()) { - // done - m_begin = m_end; - return false; - } - - // move begin to one past the last separator found - m_begin = m_end + 1; - - // find the next separator - m_end = nextSeparator(m_begin); - - // check for components that should be ignored: - // - empty, happens when the path ends with a separator - // - slashes, happens with consecutive separators - // - dot, unnecessary - const auto c = current(); - if (!c.empty() && c != "\\" && c != "/" && c != ".") { - return true; - } - } - } - - // checks if next() would return false - // - bool peekNext() const - { - auto copy = *this; - return copy.next(); - } - - // the current component, empty when next() returned false - // - std::string_view current() const { return {m_s.data() + m_begin, m_end - m_begin}; } - -private: - const std::string m_s; - std::size_t m_begin, m_end; - - // finds the next path separator - // - std::size_t nextSeparator(std::size_t from) const - { - while (from < m_s.size()) { - if (m_s[from] == '/' || m_s[from] == '\\') { - break; - } - - ++from; - } - - return from; - } -}; - -namespace bi = boost::interprocess; -namespace bmi = boost::multi_index; - -typedef uint8_t TreeFlags; - -static const TreeFlags FLAG_DIRECTORY = 0x01; -static const TreeFlags FLAG_DUMMY = 0x02; -static const TreeFlags FLAG_FIRSTUSERFLAG = 0x10; - -struct MissingThrowT -{}; -static const MissingThrowT MissingThrow = MissingThrowT(); - -template <typename NodeDataT> -class TreeContainer; - -template <typename T1, typename T2, typename Alloc> -struct mutable_pair -{ - typedef T1 first_type; - typedef T2 second_type; - - mutable_pair(Alloc alloc) : first(T1(alloc)), second(T2(alloc)) {} - - mutable_pair(const T1& f, const T2& s) : first(f), second(s) {} - - mutable_pair(const std::pair<T1, T2>& p) : first(p.first), second(p.second) {} - - T1 first; - mutable T2 second; -}; - -template <typename Key, typename T, typename Compare, typename Allocator, - typename Element = mutable_pair<Key, T, Allocator>> -using mimap = bmi::multi_index_container< - Element, - bmi::indexed_by< - bmi::ordered_unique<bmi::member<Element, Key, &Element::first>, Compare>>, - typename Allocator::template rebind<Element>::other>; - -/** - * a representation of a directory tree in memory. - * This class is designed to be stored in shared memory. - */ -template <typename NodeDataT> -class DirectoryTree -{ - template <typename T> - friend class TreeContainer; - -public: - struct CILess - { - template <typename U, typename V> - bool operator()(const U& lhs, const V& rhs) const - { - const size_t lhsLength = getLength(lhs); - const size_t rhsLength = getLength(rhs); - - const auto r = - _strnicmp(getCharPtr(lhs), getCharPtr(rhs), std::min(lhsLength, rhsLength)); - - if (r == 0) { - return lhsLength < rhsLength; - } - - return (r < 0); - } - - private: - const char* getCharPtr(const StringT& s) const { return s.c_str(); } - - const char* getCharPtr(const std::string& s) const { return s.c_str(); } - - const char* getCharPtr(const char* s) const { return s; } - - const char* getCharPtr(std::string_view s) const { return s.data(); } - - size_t getLength(const StringT& s) const { return s.size(); } - - size_t getLength(const std::string& s) const { return s.size(); } - - size_t getLength(const char* s) const { return strlen(s); } - - size_t getLength(std::string_view s) const { return s.size(); } - }; - - typedef DirectoryTree<NodeDataT> NodeT; - typedef bi::deleter<NodeT, SegmentManagerT> DeleterT; - typedef NodeDataT DataT; - - typedef bi::shared_ptr<NodeT, VoidAllocatorT, DeleterT> NodePtrT; - typedef bi::weak_ptr<NodeT, VoidAllocatorT, DeleterT> WeakPtrT; - - typedef bi::allocator<std::pair<const StringT, NodePtrT>, SegmentManagerT> - NodeEntryAllocatorT; - - typedef mimap<StringT, NodePtrT, CILess, NodeEntryAllocatorT> NodeMapT; - typedef typename NodeMapT::iterator file_iterator; - typedef typename NodeMapT::const_iterator const_file_iterator; - - typedef std::function<void(const NodePtrT&)> VisitorFunction; - - DirectoryTree() = delete; - DirectoryTree(const NodeT& reference) = delete; - DirectoryTree(NodeT&& reference) = delete; - NodeT& operator=(NodeT reference) = delete; - - /** - * @brief construct a new node to be inserted in an existing tree - **/ - DirectoryTree(std::string_view name, TreeFlags flags, const NodePtrT& parent, - const NodeDataT& data, const VoidAllocatorT& allocator) - : m_Parent(parent), m_Name(name.begin(), name.end(), allocator), m_Data(data), - m_Nodes(allocator), m_Flags(flags) - {} - - ~DirectoryTree() { m_Nodes.clear(); } - - /** - * @return parent node - */ - NodePtrT parent() const { return m_Parent.lock(); } - - /** - * @return the full path to the node - */ - fs::path path() const - { - if (m_Parent.lock().get() == nullptr) { - if (m_Name.size() == 0) { - return fs::path(); - } else { - return fs::path(m_Name.c_str()) / "\\"; - } - } else { - return m_Parent.lock()->path() / m_Name.c_str(); - } - } - - /** - * @return data connected to this node - **/ - const NodeDataT& data() const { return m_Data; } - - /** - * @return name of this node - */ - std::string name() const { return m_Name.c_str(); } - - /** - * @brief setFlag change a flag for this node - * @param enabled new state for the specified flag - */ - void setFlag(TreeFlags flag, bool enabled = true) - { - m_Flags = enabled ? m_Flags | flag : m_Flags & ~flag; - } - - /** - * @return true if the specified flag is set, false otherwise - */ - bool hasFlag(TreeFlags flag) const { return (m_Flags & flag) != 0; } - - /** - * @return true if this node is a directory, false if it's a regular file - */ - bool isDirectory() const { return hasFlag(FLAG_DIRECTORY); } - - /** - * @return the number of subnodes (directly) below this one - */ - size_t numNodes() const { return m_Nodes.size(); } - - /** - * @return number of nodes in this (sub-)tree including this one - */ - size_t numNodesRecursive() const - { - size_t result = numNodes() + 1; - - for (const auto& node : m_Nodes) { - result += node.second->numNodesRecursive(); - } - - return result; - } - - /** - * @brief find a node by its path - * @param path the path to look up - * @return a pointer to the node or a null ptr - */ - NodePtrT findNode(const fs::path& path) - { - fs::path::iterator iter = path.begin(); - if (iter == path.end()) { - return NodePtrT(); - } - return findNode(path, iter); - } - - /** - * @brief find a node by its path - * @param path the path to look up - * @return a pointer to the node or a null ptr - */ - const NodePtrT findNode(const fs::path& path) const - { - fs::path::iterator iter = path.begin(); - if (iter == path.end()) { - return NodePtrT(); - } - return findNode(path, iter); - } - - /** - * @brief visit the nodes along the specified path (in order) calling the visitor for - * each - * @param path the path to visit - * @param visitor a function called for each node - */ - void visitPath(const fs::path& path, const VisitorFunction& visitor) const - { - fs::path::iterator iter = path.begin(); - if (iter == path.end()) { - return; - } - visitPath(path, iter, visitor); - } - - /** - * @brief retrieve a node by the specified name - * @param name name of the node - * @return the node found or an empty pointer if no such node was found - */ - NodePtrT node(std::string_view name, MissingThrowT) const - { - auto iter = m_Nodes.find(name); - - if (iter != m_Nodes.end()) { - return iter->second; - } else { - USVFS_THROW_EXCEPTION(node_missing_error()); - } - } - - /** - * @brief retrieve a node by the specified name - * @param name name of the node - * @return the node found or an empty pointer if no such node was found - */ - NodePtrT node(std::string_view name) - { - auto iter = m_Nodes.find(name); - - if (iter != m_Nodes.end()) { - return iter->second; - } else { - return NodePtrT(); - } - } - - /** - * @brief retrieve a node by the specified name - * @param name name of the node - * @return the node found or an empty pointer if no such node was found - */ - const NodePtrT node(std::string_view name, MissingThrowT) - { - auto iter = m_Nodes.find(name); - - if (iter != m_Nodes.end()) { - return iter->second; - } else { - USVFS_THROW_EXCEPTION(node_missing_error()); - } - } - - /** - * @brief retrieve a node by the specified name - * @param name name of the node - * @return the node found or an empty pointer if no such node was found - */ - const NodePtrT node(std::string_view name) const - { - auto iter = m_Nodes.find(name); - - if (iter != m_Nodes.end()) { - return iter->second; - } else { - return NodePtrT(); - } - } - - /** - * @brief test if a node by the specified name exists - * @param name name of the node - * @return true if the node exists, false otherwise - */ - bool exists(std::string_view name) const - { - return m_Nodes.find(name) != m_Nodes.end(); - } - - /** - * @brief find all matches for a pattern - * @param pattern the pattern to look for - * @return a vector of the found nodes - */ - std::vector<NodePtrT> find(const std::string& pattern) const - { - // determine if there is a prefix in the pattern that indicates a specific - // directory. - size_t fixedPart = pattern.find_first_of("*?"); - - if (fixedPart == 0) - fixedPart = std::string::npos; - if (fixedPart != std::string::npos) - fixedPart = pattern.find_last_of(R"(\/)", fixedPart); - - std::vector<NodePtrT> result; - - if (fixedPart != std::string::npos) { - // if there is a prefix, search for the node representing that path and - // search only on that - NodePtrT node = findNode(fs::path(pattern.substr(0, fixedPart))); - if (node.get() != nullptr) { - node->findLocal(result, pattern.substr(fixedPart + 1)); - } - } else { - findLocal(result, pattern); - } - - return result; - } - - /** - * @return an iterator to the first leaf - **/ - file_iterator filesBegin() { return m_Nodes.begin(); } - - /** - * @return a const iterator to the first leaf - **/ - const_file_iterator filesBegin() const { return m_Nodes.begin(); } - - /** - * @return an iterator one past the last leaf - **/ - file_iterator filesEnd() { return m_Nodes.end(); } - - /** - * @return a const iterator one past the last leaf - **/ - const_file_iterator filesEnd() const { return m_Nodes.end(); } - - /** - * @brief erase the leaf at the specified iterator - * @return an iterator to the following file - **/ - file_iterator erase(file_iterator iter) { return m_Nodes.erase(iter); } - - /** - * @brief clear all nodes - */ - void clear() { m_Nodes.clear(); } - - void removeFromTree() - { - if (auto par = parent()) { - spdlog::get("usvfs")->info("remove from tree {}", m_Name.c_str()); - auto self = par->m_Nodes.find(m_Name.c_str()); - if (self != par->m_Nodes.end()) { - par->erase(self); - } else { - // trying to remove a node that does not exist, most likely because it was - // already removed in a lower level call. this is known to happen when MoveFile - // has the MOVEFILE_COPY_ALLOWED flag and moving a mapped file. - spdlog::get("usvfs")->warn("Failed to remove inexisting node from tree: {}", - m_Name.c_str()); - } - } - } - - PRIVATE : void set(StringT key, const NodePtrT& value) - { - auto res = m_Nodes.emplace(std::move(key), value); - if (!res.second) { - res.first->second = value; - } - } - - WeakPtrT findRoot() const - { - if (m_Parent.lock().get() == nullptr) { - return m_Self; - } else { - return m_Parent.lock()->findRoot(); - } - } - - NodePtrT findNode(const fs::path& name, fs::path::iterator& iter) - { - if (iter == name.end()) { - return NodePtrT(); - } - - std::string l = iter->string(); - auto subNode = m_Nodes.find(iter->string()); - advanceIter(iter, name.end()); - - if (iter == name.end()) { - // last name component, should be a local node - if (subNode != m_Nodes.end()) { - return subNode->second; - } else { - return NodePtrT(); - } - } else { - if (subNode != m_Nodes.end()) { - return subNode->second->findNode(name, iter); - } else { - return NodePtrT(); - } - } - } - - const NodePtrT findNode(const fs::path& name, fs::path::iterator& iter) const - { - if (iter == name.end()) { - return NodePtrT(); - } - - auto subNode = m_Nodes.find(iter->string()); - advanceIter(iter, name.end()); - - if (iter == name.end()) { - // last name component, should be a local node - if (subNode != m_Nodes.end()) { - return subNode->second; - } else { - return NodePtrT(); - } - } else { - if (subNode != m_Nodes.end()) { - return subNode->second->findNode(name, iter); - } else { - return NodePtrT(); - } - } - } - - void visitPath(const fs::path& path, fs::path::iterator& iter, - const VisitorFunction& visitor) const - { - if (iter == path.end()) { - return; - } - - auto subNode = m_Nodes.find(iter->string()); - - if (subNode != m_Nodes.end()) { - visitor(subNode->second); - advanceIter(iter, path.end()); - if (iter != path.end()) { - subNode->second->visitPath(path, iter, visitor); - } - } - } - - void findLocal(std::vector<NodePtrT>& output, const std::string& pattern) const - { - for (auto iter = m_Nodes.begin(); iter != m_Nodes.end(); ++iter) { - LPCSTR remainder = nullptr; - - if (pattern.size() > 1 && (pattern[0] == '*') && - ((pattern[1] == '/') || (pattern[1] == '\\')) && - iter->second->isDirectory()) { - // the star may represent a directory (one directory level, not - // multiple!), search in subdirectory - iter->second->findLocal(output, pattern.substr(1)); - } else if ((remainder = wildcard::PartialMatch(iter->second->name().c_str(), - pattern.c_str())) != nullptr) { - if ((*remainder == '\0') || (strcmp(remainder, "*") == 0)) { - NodePtrT node = iter->second; - output.push_back(node); - } - - if (iter->second->isDirectory()) { - iter->second->findLocal(output, remainder); - } - } - } - } - - PRIVATE : TreeFlags m_Flags; - - WeakPtrT m_Parent; - WeakPtrT m_Self; - - StringT m_Name; - NodeDataT m_Data; - - NodeMapT m_Nodes; -}; - -template <typename NodeDataT> -void dumpTree(std::ostream& stream, const DirectoryTree<NodeDataT>& tree, int level = 0) -{ - stream << std::string(level, ' ') << tree.name() << " -> " << tree.data() << "\n"; - for (auto iter = tree.filesBegin(); iter != tree.filesEnd(); ++iter) { - dumpTree<NodeDataT>(stream, *iter->second, level + 1); - } -} - -} // namespace usvfs::shared diff --git a/libs/usvfs/src/shared/exceptionex.cpp b/libs/usvfs/src/shared/exceptionex.cpp deleted file mode 100644 index 4a814b5..0000000 --- a/libs/usvfs/src/shared/exceptionex.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "exceptionex.h" -#include "winapi.h" -#include <spdlog/spdlog.h> - -namespace usvfs::shared -{ - -std::string windows_error::constructMessage(const std::string& input, int inErrorCode) -{ - std::ostringstream finalMessage; - finalMessage << input; - - LPSTR buffer = nullptr; - - DWORD errorCode = inErrorCode != -1 ? inErrorCode : GetLastError(); - - // TODO: the message is not english? - if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&buffer, 0, nullptr) == 0) { - finalMessage << " (errorcode " << errorCode << ")"; - } else { - LPSTR lastChar = buffer + strlen(buffer) - 2; - *lastChar = '\0'; - finalMessage << " (" << buffer << " [" << errorCode << "])"; - LocalFree(buffer); // allocated by FormatMessage - } - - SetLastError( - errorCode); // restore error code because FormatMessage might have modified it - return finalMessage.str(); -} - -} // namespace usvfs::shared - -void logExtInfo(const std::exception& e, LogLevel logLevel) -{ - std::string content; - - if (const std::string* msg = boost::get_error_info<ex_msg>(e)) { - content = *msg; - } - - if (const DWORD* errorCode = boost::get_error_info<ex_win_errcode>(e)) { - content = std::string("error: ") + winapi::ex::ansi::errorString(*errorCode); - } - - switch (logLevel) { - case LogLevel::Debug: - spdlog::get("usvfs")->debug(content); - break; - case LogLevel::Info: - spdlog::get("usvfs")->info(content); - break; - case LogLevel::Warning: - spdlog::get("usvfs")->warn(content); - break; - case LogLevel::Error: - spdlog::get("usvfs")->error(content); - break; - } -} diff --git a/libs/usvfs/src/shared/exceptionex.h b/libs/usvfs/src/shared/exceptionex.h deleted file mode 100644 index 4c298a5..0000000 --- a/libs/usvfs/src/shared/exceptionex.h +++ /dev/null @@ -1,99 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include "logging.h" -#include <boost/exception/all.hpp> -#include <stdexcept> - -typedef boost::error_info<struct tag_message, DWORD> ex_win_errcode; -typedef boost::error_info<struct tag_message, std::string> ex_msg; - -struct std_boost_exception : virtual boost::exception, virtual std::exception -{ - const char* what() const noexcept override - { - return boost::diagnostic_information_what(*this); - } -}; - -struct incompatibility_error : std_boost_exception -{}; -struct usage_error : std_boost_exception -{}; -struct data_error : std_boost_exception -{}; -struct file_not_found_error : std_boost_exception -{}; -struct timeout_error : std_boost_exception -{}; -struct unknown_error : std_boost_exception -{}; -struct node_missing_error : std_boost_exception -{}; - -#define USVFS_THROW_EXCEPTION(x) BOOST_THROW_EXCEPTION(x) - -void logExtInfo(const std::exception& e, LogLevel logLevel = LogLevel::Warning); - -namespace usvfs::shared -{ - -class windows_error : public std::runtime_error -{ -public: - windows_error(const std::string& message, int errorcode = GetLastError()) - : runtime_error(constructMessage(message, errorcode)), m_ErrorCode(errorcode) - {} - - int getErrorCode() const { return m_ErrorCode; } - -private: - int m_ErrorCode; - - std::string constructMessage(const std::string& input, int errorcode); -}; - -class guard -{ -public: - explicit guard(std::function<void()> f) : m_f(std::move(f)) {} - - ~guard() - { - if (m_f) { - m_f(); - } - } - - guard(const guard&); - guard& operator=(const guard&); - -private: - std::function<void()> m_f; -}; - -} // namespace usvfs::shared - -#define CONCATENATE_DIRECT(s1, s2) s1##s2 -#define CONCATENATE(s1, s2) CONCATENATE_DIRECT(s1, s2) -#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__) -#define ON_BLOCK_EXIT(f) usvfs::shared::guard ANONYMOUS_VARIABLE(guard)(f) diff --git a/libs/usvfs/src/shared/formatters.h b/libs/usvfs/src/shared/formatters.h deleted file mode 100644 index 3d0e47e..0000000 --- a/libs/usvfs/src/shared/formatters.h +++ /dev/null @@ -1,158 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2024. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <format> -#include <type_traits> - -#include "ntdll_declarations.h" - -// formatters for standard types - -namespace usvfs::log -{ -std::string to_string(LPCWSTR value); -std::string to_string(PCUNICODE_STRING value); -} // namespace usvfs::log - -template <class Enum, class CharT> - requires std::is_enum_v<Enum> -struct std::formatter<Enum, CharT> : std::formatter<std::underlying_type_t<Enum>, CharT> -{ - template <class FmtContext> - FmtContext::iterator format(Enum v, FmtContext& ctx) const - { - return std::formatter<std::underlying_type_t<Enum>, CharT>::format( - static_cast<std::underlying_type_t<Enum>>(v), ctx); - } -}; - -template <> -struct std::formatter<LPCWSTR, char> : std::formatter<std::string, char> -{ - template <class FmtContext> - FmtContext::iterator format(LPCWSTR v, FmtContext& ctx) const - { - return std::formatter<std::string, char>::format(usvfs::log::to_string(v), ctx); - } -}; - -template <> -struct std::formatter<std::wstring, char> : std::formatter<LPCWSTR, char> -{ - template <class FmtContext> - FmtContext::iterator format(const std::wstring& v, FmtContext& ctx) const - { - return std::formatter<LPCWSTR, char>::format(v.c_str(), ctx); - } -}; - -template <> -struct std::formatter<PCUNICODE_STRING, char> : std::formatter<std::string, char> -{ - template <class FmtContext> - FmtContext::iterator format(PCUNICODE_STRING v, FmtContext& ctx) const - { - return std::formatter<std::string, char>::format(usvfs::log::to_string(v), ctx); - } -}; - -template <> -struct std::formatter<UNICODE_STRING, char> : std::formatter<std::string, char> -{ - template <class FmtContext> - FmtContext::iterator format(UNICODE_STRING v, FmtContext& ctx) const - { - return std::formatter<std::string, char>::format(usvfs::log::to_string(&v), ctx); - } -}; - -template <class Pointer> - requires(std::is_pointer_v<Pointer> && !std::is_same_v<Pointer, const char*> && - !std::is_same_v<Pointer, char*> && !std::is_same_v<Pointer, const void*> && - !std::is_same_v<Pointer, void*>) -struct std::formatter<Pointer, char> : std::formatter<const void*, char> -{ - template <class FmtContext> - FmtContext::iterator format(Pointer v, FmtContext& ctx) const - { - return std::formatter<const void*, char>::format(v, ctx); - } -}; - -namespace usvfs::log -{ - -/** - * a small helper class to wrap any object. The whole point is to give us a way - * to ensure our own operator<< is used in addParam calls - */ -template <typename T> -class Wrap -{ -public: - explicit Wrap(const T& data) : m_Data(data) {} - Wrap(Wrap<T>&& reference) : m_Data(std::move(reference.m_Data)) {} - - Wrap(const Wrap<T>& reference) = delete; - Wrap<T>& operator=(const Wrap<T>& reference) = delete; - -private: - friend struct ::std::formatter<Wrap<T>, char>; - const T& m_Data; -}; - -template <typename T> -Wrap<T> wrap(const T& data) -{ - return Wrap<T>(data); -} - -} // namespace usvfs::log - -template <> -struct std::formatter<usvfs::log::Wrap<DWORD>, char> : std::formatter<DWORD, char> -{ - template <class FmtContext> - FmtContext::iterator format(const usvfs::log::Wrap<DWORD>& v, FmtContext& ctx) const - { - return std::format_to(ctx.out(), "{:x}", v.m_Data); - } -}; - -template <> -struct std::formatter<usvfs::log::Wrap<NTSTATUS>, char> : std::formatter<NTSTATUS, char> -{ - template <class FmtContext> - FmtContext::iterator format(const usvfs::log::Wrap<NTSTATUS>& v, - FmtContext& ctx) const - { - switch (v.m_Data) { - case 0x00000000: - return std::format_to(ctx.out(), "ok"); - case 0xC0000022: - return std::format_to(ctx.out(), "access denied"); - case 0xC0000035: - return std::format_to(ctx.out(), "exists already"); - } - return std::format_to(ctx.out(), "err {:x}", v.m_Data); - } -}; diff --git a/libs/usvfs/src/shared/loghelpers.cpp b/libs/usvfs/src/shared/loghelpers.cpp deleted file mode 100644 index bfcabf1..0000000 --- a/libs/usvfs/src/shared/loghelpers.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include <format> - -#include "formatters.h" -#include "loghelpers.h" -#include "stringcast.h" -#include "stringutils.h" - -namespace ush = usvfs::shared; - -namespace usvfs::log -{ - -// this is declared in formatters but is defined here to avoid a whole .cpp -// file for two small functions -// -// comments from old code, taken as is: -// -// TODO this does not correctly support surrogate pairs since the size used here -// is the number of 16-bit characters in the buffer whereas toNarrow expects the -// actual number of characters. It will always underestimate though, so worst -// case scenario we truncate the string -// -std::string to_string(LPCWSTR value) -{ - if (value == nullptr) { - return "<null>"; - } - try { - return ush::string_cast<std::string>(value, ush::CodePage::UTF8); - } catch (const std::exception& e) { - return std::format("<err: {}>", e.what()); - } -} -std::string to_string(PCUNICODE_STRING value) -{ - try { - return ush::string_cast<std::string>(value->Buffer, ush::CodePage::UTF8, - value->Length / sizeof(WCHAR)); - } catch (const std::exception& e) { - return std::format("<err: {}>", e.what()); - } -} - -spdlog::level::level_enum ConvertLogLevel(LogLevel level) -{ - switch (level) { - case LogLevel::Debug: - return spdlog::level::debug; - case LogLevel::Info: - return spdlog::level::info; - case LogLevel::Warning: - return spdlog::level::warn; - case LogLevel::Error: - return spdlog::level::err; - default: - return spdlog::level::debug; - } -} - -LogLevel ConvertLogLevel(spdlog::level::level_enum level) -{ - switch (level) { - case spdlog::level::debug: - return LogLevel::Debug; - case spdlog::level::info: - return LogLevel::Info; - case spdlog::level::warn: - return LogLevel::Warning; - case spdlog::level::err: - return LogLevel::Error; - default: - return LogLevel::Debug; - } -} - -} // namespace usvfs::log diff --git a/libs/usvfs/src/shared/loghelpers.h b/libs/usvfs/src/shared/loghelpers.h deleted file mode 100644 index 071ad9d..0000000 --- a/libs/usvfs/src/shared/loghelpers.h +++ /dev/null @@ -1,123 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include "dllimport.h" -#include "formatters.h" -#include "ntdll_declarations.h" -#include "shmlogger.h" -#include "stringutils.h" - -namespace usvfs::log -{ - -enum class DisplayStyle : uint8_t -{ - Hex = 0x01 -}; - -class CallLoggerDummy -{ -public: - template <typename T> - CallLoggerDummy& addParam(const char*, const T&, uint8_t style = 0) - { - return *this; - } -}; - -class CallLogger -{ -public: - explicit CallLogger(const char* function) - { - const char* namespaceend = strrchr(function, ':'); - - if (namespaceend != nullptr) { - function = namespaceend + 1; - } - - m_Message = function; - } - - ~CallLogger() - { - try { - static std::shared_ptr<spdlog::logger> log = spdlog::get("hooks"); - log->debug("{}", m_Message); - } catch (...) { - // suppress all exceptions in destructor - } - } - - template <typename T> - CallLogger& addParam(const char* name, const T& value, uint8_t style = 0); - -private: - std::string m_Message; -}; - -template <typename T> -CallLogger& CallLogger::addParam(const char* name, const T& value, uint8_t style) -{ - static bool enabled = spdlog::get("hooks")->should_log(spdlog::level::debug); - typedef std::underlying_type<DisplayStyle>::type DSType; - - if (enabled) { - if constexpr (std::is_pointer_v<T>) { - if (value == nullptr) { - std::format_to(std::back_inserter(m_Message), "[{}=<null>]", name); - } else { - std::format_to(std::back_inserter(m_Message), "[{}={}]", name, value); - } - } else if constexpr (std::is_integral_v<T>) { - if (style & static_cast<DSType>(DisplayStyle::Hex)) { - std::format_to(std::back_inserter(m_Message), "[{}={:x}]", name, value); - } else { - std::format_to(std::back_inserter(m_Message), "[{}={}]", name, value); - } - } else { - std::format_to(std::back_inserter(m_Message), "[{}={}]", name, value); - } - } - - return *this; -} - -spdlog::level::level_enum ConvertLogLevel(LogLevel level); -LogLevel ConvertLogLevel(spdlog::level::level_enum level); - -} // namespace usvfs::log - -// prefer the short variant of the function name, without signature. -// Fall back to the portable boost macro -#ifdef __FUNCTION__ -#define __MYFUNC__ __FUNCTION__ -#else -#define __MYFUNC__ BOOST_CURRENT_FUNCTION -#endif - -#define LOG_CALL() usvfs::log::CallLogger(__MYFUNC__) - -#define PARAM(val) addParam(#val, val) -#define PARAMHEX(val) \ - addParam(#val, val, static_cast<uint8_t>(usvfs::log::DisplayStyle::Hex)) -#define PARAMWRAP(val) addParam(#val, usvfs::log::wrap(val)) diff --git a/libs/usvfs/src/shared/ntdll_declarations.cpp b/libs/usvfs/src/shared/ntdll_declarations.cpp deleted file mode 100644 index b4bf0f5..0000000 --- a/libs/usvfs/src/shared/ntdll_declarations.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "ntdll_declarations.h" -#include <cassert> - -#define LOAD_EXT(mod, name) \ - name = reinterpret_cast<name##_type>(::GetProcAddress(mod, #name)); \ - assert(name != nullptr) - -NtQueryDirectoryFile_type NtQueryDirectoryFile; -NtQueryDirectoryFileEx_type NtQueryDirectoryFileEx; -NtQueryFullAttributesFile_type NtQueryFullAttributesFile; -NtQueryAttributesFile_type NtQueryAttributesFile; -NtQueryObject_type NtQueryObject; -NtQueryInformationFile_type NtQueryInformationFile; -NtQueryInformationByName_type NtQueryInformationByName; -NtOpenFile_type NtOpenFile; -NtCreateFile_type NtCreateFile; -NtClose_type NtClose; -RtlDoesFileExists_U_type RtlDoesFileExists_U; -RtlDosPathNameToRelativeNtPathName_U_WithStatus_type - RtlDosPathNameToRelativeNtPathName_U_WithStatus; -RtlReleaseRelativeName_type RtlReleaseRelativeName; -RtlGetVersion_type RtlGetVersion; -NtTerminateProcess_type NtTerminateProcess; - -static bool ntdll_initialized; - -void ntdll_declarations_init() -{ - if (!ntdll_initialized) { - HMODULE ntDLLMod = GetModuleHandleW(L"ntdll.dll"); - - LOAD_EXT(ntDLLMod, NtQueryDirectoryFile); - LOAD_EXT(ntDLLMod, NtQueryDirectoryFileEx); - LOAD_EXT(ntDLLMod, NtQueryFullAttributesFile); - LOAD_EXT(ntDLLMod, NtQueryAttributesFile); - LOAD_EXT(ntDLLMod, NtQueryObject); - LOAD_EXT(ntDLLMod, NtQueryInformationFile); - LOAD_EXT(ntDLLMod, NtQueryInformationByName); - LOAD_EXT(ntDLLMod, NtCreateFile); - LOAD_EXT(ntDLLMod, NtOpenFile); - LOAD_EXT(ntDLLMod, NtClose); - LOAD_EXT(ntDLLMod, RtlDoesFileExists_U); - LOAD_EXT(ntDLLMod, RtlDosPathNameToRelativeNtPathName_U_WithStatus); - LOAD_EXT(ntDLLMod, RtlReleaseRelativeName); - LOAD_EXT(ntDLLMod, RtlGetVersion); - LOAD_EXT(ntDLLMod, NtTerminateProcess); - - ntdll_initialized = true; - } -} - -static struct __Initializer -{ - __Initializer() { ntdll_declarations_init(); } -} __initializer; diff --git a/libs/usvfs/src/shared/ntdll_declarations.h b/libs/usvfs/src/shared/ntdll_declarations.h deleted file mode 100644 index 813ad8c..0000000 --- a/libs/usvfs/src/shared/ntdll_declarations.h +++ /dev/null @@ -1,612 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include "windows_sane.h" - -#pragma warning(push) -#pragma warning(disable : 4201) - -typedef LONG NTSTATUS; - -typedef struct _IO_STATUS_BLOCK -{ - union - { - NTSTATUS Status; - PVOID Pointer; - } DUMMYUNIONNAME; - - ULONG_PTR Information; -} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; - -typedef struct _FILE_DIRECTORY_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - WCHAR FileName[1]; -} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; - -typedef struct _FILE_FULL_DIR_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - WCHAR FileName[1]; -} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION; - -typedef struct _FILE_ID_FULL_DIR_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - LARGE_INTEGER FileId; - WCHAR FileName[1]; -} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION; - -typedef struct _FILE_BOTH_DIR_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - CCHAR ShortNameLength; - WCHAR ShortName[12]; - WCHAR FileName[1]; -} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; - -typedef struct _FILE_ID_BOTH_DIR_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - CCHAR ShortNameLength; - WCHAR ShortName[12]; - LARGE_INTEGER FileId; - WCHAR FileName[1]; -} FILE_ID_BOTH_DIR_INFORMATION, *PFILE_ID_BOTH_DIR_INFORMATION; - -typedef struct _FILE_BASIC_INFORMATION -{ - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - ULONG FileAttributes; -} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; - -typedef struct _FILE_RENAME_INFORMATION -{ -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS1) - union - { - BOOLEAN ReplaceIfExists; // FileRenameInformation - ULONG Flags; // FileRenameInformationEx - } DUMMYUNIONNAME; -#else - BOOLEAN ReplaceIfExists; -#endif - HANDLE RootDirectory; - ULONG FileNameLength; - WCHAR FileName[1]; -} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION; - -typedef struct _FILE_STANDARD_INFORMATION -{ - LARGE_INTEGER AllocationSize; - LARGE_INTEGER EndOfFile; - ULONG NumberOfLinks; - BOOLEAN DeletePending; - BOOLEAN Directory; -} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; - -typedef struct _FILE_NAMES_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - ULONG FileNameLength; - WCHAR FileName[1]; -} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; - -typedef struct _FILE_INTERNAL_INFORMATION -{ - LARGE_INTEGER IndexNumber; -} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; - -typedef struct _FILE_EA_INFORMATION -{ - ULONG EaSize; -} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; - -typedef struct _FILE_ACCESS_INFORMATION -{ - ACCESS_MASK AccessFlags; -} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION; - -typedef struct _FILE_POSITION_INFORMATION -{ - LARGE_INTEGER CurrentByteOffset; -} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; - -typedef struct _FILE_MODE_INFORMATION -{ - ULONG Mode; -} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; - -typedef struct _FILE_ALIGNMENT_INFORMATION -{ - ULONG AlignmentRequirement; -} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION; - -typedef struct _FILE_NAME_INFORMATION -{ - ULONG FileNameLength; - WCHAR FileName[1]; -} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; - -typedef struct _FILE_ID_EXTD_DIR_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - ULONG ReparsePointTag; - FILE_ID_128 FileId; - WCHAR FileName[1]; -} FILE_ID_EXTD_DIR_INFORMATION, *PFILE_ID_EXTD_DIR_INFORMATION; - -typedef struct _FILE_ID_EXTD_BOTH_DIR_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - ULONG ReparsePointTag; - FILE_ID_128 FileId; - CCHAR ShortNameLength; - WCHAR ShortName[12]; - WCHAR FileName[1]; -} FILE_ID_EXTD_BOTH_DIR_INFORMATION, *PFILE_ID_EXTD_BOTH_DIR_INFORMATION; - -typedef struct _FILE_ID_64_EXTD_DIR_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - ULONG ReparsePointTag; - LARGE_INTEGER FileId; - WCHAR FileName[1]; -} FILE_ID_64_EXTD_DIR_INFORMATION, *PFILE_ID_64_EXTD_DIR_INFORMATION; - -typedef struct _FILE_ID_64_EXTD_BOTH_DIR_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - ULONG ReparsePointTag; - LARGE_INTEGER FileId; - CCHAR ShortNameLength; - WCHAR ShortName[12]; - WCHAR FileName[1]; -} FILE_ID_64_EXTD_BOTH_DIR_INFORMATION, *PFILE_ID_64_EXTD_BOTH_DIR_INFORMATION; - -typedef struct _FILE_ID_ALL_EXTD_DIR_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - ULONG ReparsePointTag; - LARGE_INTEGER FileId; - FILE_ID_128 FileId128; - WCHAR FileName[1]; -} FILE_ID_ALL_EXTD_DIR_INFORMATION, *PFILE_ID_ALL_EXTD_DIR_INFORMATION; - -typedef struct _FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - ULONG ReparsePointTag; - LARGE_INTEGER FileId; - FILE_ID_128 FileId128; - CCHAR ShortNameLength; - WCHAR ShortName[12]; - WCHAR FileName[1]; -} FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION, *PFILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION; - -typedef struct _FILE_ALL_INFORMATION -{ - FILE_BASIC_INFORMATION BasicInformation; - FILE_STANDARD_INFORMATION StandardInformation; - FILE_INTERNAL_INFORMATION InternalInformation; - FILE_EA_INFORMATION EaInformation; - FILE_ACCESS_INFORMATION AccessInformation; - FILE_POSITION_INFORMATION PositionInformation; - FILE_MODE_INFORMATION ModeInformation; - FILE_ALIGNMENT_INFORMATION AlignmentInformation; - FILE_NAME_INFORMATION NameInformation; -} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; - -typedef struct _FILE_OBJECTID_INFORMATION -{ - LONGLONG FileReference; - UCHAR ObjectId[16]; - union - { - struct - { - UCHAR BirthVolumeId[16]; - UCHAR BirthObjectId[16]; - UCHAR DomainId[16]; - }; - UCHAR ExtendedInfo[48]; - }; -} FILE_OBJECTID_INFORMATION, *PFILE_OBJECTID_INFORMATION; - -typedef struct _FILE_REPARSE_POINT_INFORMATION -{ - LONGLONG FileReference; - ULONG Tag; -} FILE_REPARSE_POINT_INFORMATION, *PFILE_REPARSE_POINT_INFORMATION; - -// copied from ntstatus.h -#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) -#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) -#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) -#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) -#define STATUS_NO_SUCH_FILE ((NTSTATUS)0xC000000FL) - -#define SL_RESTART_SCAN 0x01 -#define SL_RETURN_SINGLE_ENTRY 0x02 -#define SL_INDEX_SPECIFIED 0x04 -#define SL_RETURN_ON_DISK_ENTRIES_ONLY 0x08 - -#define SL_QUERY_DIRECTORY_MASK 0x0b - -typedef enum _FILE_INFORMATION_CLASS -{ - FileDirectoryInformation = 1, - FileFullDirectoryInformation = 2, - FileBothDirectoryInformation = 3, - FileStandardInformation = 5, - FileNameInformation = 9, - FileRenameInformation = 10, - FileNamesInformation = 12, - FileAllInformation = 18, - FileObjectIdInformation = 29, - FileReparsePointInformation = 33, - FileIdBothDirectoryInformation = 37, - FileIdFullDirectoryInformation = 38, - FileNormalizedNameInformation = 48, - FileIdExtdDirectoryInformation = 60, - FileIdExtdBothDirectoryInformation = 63, - FileId64ExtdDirectoryInformation = 78, - FileId64ExtdBothDirectoryInformation = 79, - FileIdAllExtdDirectoryInformation = 80, - FileIdAllExtdBothDirectoryInformation = 81 -} FILE_INFORMATION_CLASS, - *PFILE_INFORMATION_CLASS; - -typedef enum _MODE -{ - KernelMode, - UserMode, - MaximumMode -} MODE; - -typedef struct _IO_STATUS_BLOCK IO_STATUS_BLOCK; - -typedef struct _IO_STATUS_BLOCK* PIO_STATUS_BLOCK; -// typedef VOID (NTAPI *PIO_APC_ROUTINE )(__in PVOID ApcContext, __in -// PIO_STATUS_BLOCK IoStatusBlock, __in ULONG Reserved); -typedef VOID(NTAPI* PIO_APC_ROUTINE)(PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, - ULONG Reserved); -typedef enum _FILE_INFORMATION_CLASS FILE_INFORMATION_CLASS; - -typedef struct _UNICODE_STRING -{ - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; -} UNICODE_STRING, *PUNICODE_STRING; -typedef const UNICODE_STRING* PCUNICODE_STRING; - -typedef struct _OBJECT_ATTRIBUTES -{ - ULONG Length; - HANDLE RootDirectory; - PUNICODE_STRING ObjectName; - ULONG Attributes; - PVOID SecurityDescriptor; - PVOID SecurityQualityOfService; -} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; - -typedef enum _POOL_TYPE -{ - NonPagedPool, - NonPagedPoolExecute = NonPagedPool, - PagedPool, - NonPagedPoolMustSucceed = NonPagedPool + 2, - DontUseThisType, - NonPagedPoolCacheAligned = NonPagedPool + 4, - PagedPoolCacheAligned, - NonPagedPoolCacheAlignedMustS = NonPagedPool + 6, - MaxPoolType, - NonPagedPoolBase = 0, - NonPagedPoolBaseMustSucceed = NonPagedPoolBase + 2, - NonPagedPoolBaseCacheAligned = NonPagedPoolBase + 4, - NonPagedPoolBaseCacheAlignedMustS = NonPagedPoolBase + 6, - NonPagedPoolSession = 32, - PagedPoolSession = NonPagedPoolSession + 1, - NonPagedPoolMustSucceedSession = PagedPoolSession + 1, - DontUseThisTypeSession = NonPagedPoolMustSucceedSession + 1, - NonPagedPoolCacheAlignedSession = DontUseThisTypeSession + 1, - PagedPoolCacheAlignedSession = NonPagedPoolCacheAlignedSession + 1, - NonPagedPoolCacheAlignedMustSSession = PagedPoolCacheAlignedSession + 1, - NonPagedPoolNx = 512, - NonPagedPoolNxCacheAligned = NonPagedPoolNx + 4, - NonPagedPoolSessionNx = NonPagedPoolNx + 32 -} POOL_TYPE; - -typedef struct _OBJECT_TYPE_INITIALIZER -{ - WORD Length; - UCHAR ObjectTypeFlags; - ULONG CaseInsensitive : 1; - ULONG UnnamedObjectsOnly : 1; - ULONG UseDefaultObject : 1; - ULONG SecurityRequired : 1; - ULONG MaintainHandleCount : 1; - ULONG MaintainTypeList : 1; - ULONG ObjectTypeCode; - ULONG InvalidAttributes; - GENERIC_MAPPING GenericMapping; - ULONG ValidAccessMask; - POOL_TYPE PoolType; - ULONG DefaultPagedPoolCharge; - ULONG DefaultNonPagedPoolCharge; - PVOID DumpProcedure; - LONG* OpenProcedure; - PVOID CloseProcedure; - PVOID DeleteProcedure; - LONG* ParseProcedure; - LONG* SecurityProcedure; - LONG* QueryNameProcedure; - UCHAR* OkayToCloseProcedure; -} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER; - -typedef CCHAR KPROCESSOR_MODE; - -typedef struct _OBJECT_HANDLE_INFORMATION -{ - ULONG HandleAttributes; - ACCESS_MASK GrantedAccess; -} OBJECT_HANDLE_INFORMATION, *POBJECT_HANDLE_INFORMATION; - -typedef struct _OBJECT_NAME_INFORMATION -{ - UNICODE_STRING Name; -} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; - -typedef enum _OBJECT_INFORMATION_CLASS -{ - ObjectBasicInformation = 0, - ObjectNameInformation = 1, - ObjectTypeInformation = 2 -} OBJECT_INFORMATION_CLASS; - -typedef struct _RTL_RELATIVE_NAME -{ - UNICODE_STRING RelativeName; - HANDLE ContainingDirectory; - void* CurDirRef; -} RTL_RELATIVE_NAME, *PRTL_RELATIVE_NAME; - -typedef struct _FILE_NETWORK_OPEN_INFORMATION -{ - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER AllocationSize; - LARGE_INTEGER EndOfFile; - ULONG FileAttributes; -} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; - -#define FILE_DIRECTORY_FILE 0x00000001 -#define FILE_WRITE_THROUGH 0x00000002 -#define FILE_SEQUENTIAL_ONLY 0x00000004 -#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 -#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 -#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 -#define FILE_NON_DIRECTORY_FILE 0x00000040 -#define FILE_CREATE_TREE_CONNECTION 0x00000080 -#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 -#define FILE_NO_EA_KNOWLEDGE 0x00000200 -#define FILE_OPEN_REMOTE_INSTANCE 0x00000400 -#define FILE_RANDOM_ACCESS 0x00000800 -#define FILE_DELETE_ON_CLOSE 0x00001000 -#define FILE_OPEN_BY_FILE_ID 0x00002000 -#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 -#define FILE_NO_COMPRESSION 0x00008000 -#define FILE_OPEN_REQUIRING_OPLOCK 0x00010000 -#define FILE_DISALLOW_EXCLUSIVE 0x00020000 -#define FILE_SESSION_AWARE 0x00040000 -#define FILE_RESERVE_OPFILTER 0x00100000 -#define FILE_OPEN_REPARSE_POINT 0x00200000 -#define FILE_OPEN_NO_RECALL 0x00400000 -#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 -#define FILE_CONTAINS_EXTENDED_CREATE_INFORMATION 0x10000000 - -// Nt - -using NtQueryDirectoryFile_type = NTSTATUS(WINAPI*)(HANDLE, HANDLE, PIO_APC_ROUTINE, - PVOID, PIO_STATUS_BLOCK, PVOID, - ULONG, FILE_INFORMATION_CLASS, - BOOLEAN, PUNICODE_STRING, BOOLEAN); -using NtQueryDirectoryFileEx_type = NTSTATUS(WINAPI*)(HANDLE, HANDLE, PIO_APC_ROUTINE, - PVOID, PIO_STATUS_BLOCK, PVOID, - ULONG, FILE_INFORMATION_CLASS, - ULONG, PUNICODE_STRING); - -using NtQueryFullAttributesFile_type = - NTSTATUS(WINAPI*)(POBJECT_ATTRIBUTES, PFILE_NETWORK_OPEN_INFORMATION); -using NtQueryAttributesFile_type = NTSTATUS(WINAPI*)(POBJECT_ATTRIBUTES, - PFILE_BASIC_INFORMATION); - -using NtQueryObject_type = NTSTATUS(WINAPI*)( - HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, - PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); -using NtQueryInformationFile_type = NTSTATUS(WINAPI*)( - HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, - ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); - -using NtQueryInformationByName_type = NTSTATUS(WINAPI*)( - HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, - ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); - -using NtOpenFile_type = NTSTATUS(WINAPI*)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, - PIO_STATUS_BLOCK, ULONG, ULONG); -using NtCreateFile_type = NTSTATUS(WINAPI*)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, - PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, - ULONG, ULONG, ULONG, PVOID, ULONG); - -using NtClose_type = NTSTATUS(WINAPI*)(HANDLE); - -using NtTerminateProcess_type = NTSTATUS(WINAPI*)(HANDLE ProcessHandle, - NTSTATUS ExitStatus); - -// Rtl - -using RtlDoesFileExists_U_type = NTSYSAPI BOOLEAN(NTAPI*)(PCWSTR); -using RtlDosPathNameToRelativeNtPathName_U_WithStatus_type = - NTSTATUS(NTAPI*)(PCWSTR DosFileName, PUNICODE_STRING NtFileName, PWSTR* FilePath, - PRTL_RELATIVE_NAME RelativeName); -using RtlReleaseRelativeName_type = void(NTAPI*)(PRTL_RELATIVE_NAME RelativeName); -using RtlGetVersion_type = NTSTATUS(NTAPI*)(PRTL_OSVERSIONINFOW); - -extern NtQueryDirectoryFile_type NtQueryDirectoryFile; -extern NtQueryDirectoryFileEx_type NtQueryDirectoryFileEx; -extern NtQueryFullAttributesFile_type NtQueryFullAttributesFile; -extern NtQueryAttributesFile_type NtQueryAttributesFile; -extern NtQueryObject_type NtQueryObject; -extern NtQueryInformationFile_type NtQueryInformationFile; -extern NtQueryInformationByName_type NtQueryInformationByName; -extern NtOpenFile_type NtOpenFile; -extern NtCreateFile_type NtCreateFile; -extern NtClose_type NtClose; -extern NtTerminateProcess_type NtTerminateProcess; -extern RtlDoesFileExists_U_type RtlDoesFileExists_U; -extern RtlDosPathNameToRelativeNtPathName_U_WithStatus_type - RtlDosPathNameToRelativeNtPathName_U_WithStatus; -extern RtlReleaseRelativeName_type RtlReleaseRelativeName; -extern RtlGetVersion_type RtlGetVersion; - -// ensures ntdll functions have been initialized (only needed during static objects -// initialization) -void ntdll_declarations_init(); - -#pragma warning(pop) diff --git a/libs/usvfs/src/shared/pch.cpp b/libs/usvfs/src/shared/pch.cpp deleted file mode 100644 index 1d9f38c..0000000 --- a/libs/usvfs/src/shared/pch.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "pch.h" diff --git a/libs/usvfs/src/shared/pch.h b/libs/usvfs/src/shared/pch.h deleted file mode 100644 index e787f68..0000000 --- a/libs/usvfs/src/shared/pch.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -#include <algorithm> -#include <atomic> -#include <bitset> -#include <cassert> -#include <codecvt> -#include <cstddef> -#include <cstdint> -#include <cstring> -#include <ctime> -#include <exception> -#include <format> -#include <functional> -#include <future> -#include <iomanip> -#include <ios> -#include <limits> -#include <map> -#include <memory> -#include <mutex> -#include <regex> -#include <shared_mutex> -#include <sstream> -#include <stdexcept> -#include <string> -#include <thread> -#include <type_traits> -#include <utility> -#include <vector> - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -// clang-format off -#define WIN32_LEAN_AND_MEAN -#include <Windows.h> -#include <ShlObj.h> -#include <comutil.h> -#include <Psapi.h> -#include <shellapi.h> -#include <shlwapi.h> -#include <fileapi.h> -#include <DbgHelp.h> -// clang-format on - -#define BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI 1 -#include <boost/algorithm/string.hpp> -#include <boost/algorithm/string/case_conv.hpp> -#include <boost/any.hpp> -#include <boost/container/flat_set.hpp> -#include <boost/container/map.hpp> -#include <boost/container/scoped_allocator.hpp> -#include <boost/container/slist.hpp> -#include <boost/container/string.hpp> -#include <boost/container/vector.hpp> -#include <boost/current_function.hpp> -#include <boost/dll/runtime_symbol_info.hpp> -#include <boost/filesystem.hpp> -#include <boost/filesystem/detail/utf8_codecvt_facet.hpp> -#include <boost/filesystem/operations.hpp> -#include <boost/filesystem/path.hpp> -#include <boost/format.hpp> -#include <boost/interprocess/ipc/message_queue.hpp> -#include <boost/interprocess/managed_windows_shared_memory.hpp> -#include <boost/interprocess/offset_ptr.hpp> -#include <boost/interprocess/smart_ptr/deleter.hpp> -#include <boost/interprocess/smart_ptr/shared_ptr.hpp> -#include <boost/interprocess/smart_ptr/weak_ptr.hpp> -#include <boost/interprocess/sync/named_mutex.hpp> -#include <boost/lexical_cast.hpp> -#include <boost/locale.hpp> -#include <boost/multi_index/member.hpp> -#include <boost/multi_index/ordered_index.hpp> -#include <boost/multi_index_container.hpp> -#include <boost/predef.h> -#include <boost/static_assert.hpp> -#include <boost/thread.hpp> -#include <boost/thread/shared_lock_guard.hpp> -#include <boost/thread/shared_mutex.hpp> -#include <boost/tokenizer.hpp> -#include <boost/type_traits.hpp> - -#include <spdlog/spdlog.h> - -namespace fs = boost::filesystem; diff --git a/libs/usvfs/src/shared/shared_memory.h b/libs/usvfs/src/shared/shared_memory.h deleted file mode 100644 index 28da34b..0000000 --- a/libs/usvfs/src/shared/shared_memory.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ - -#pragma once - -namespace bi = boost::interprocess; -namespace bc = boost::container; - -namespace usvfs::shared -{ - -template <typename T> -using OffsetPtrT = bi::offset_ptr<T, std::int32_t, std::uint64_t>; - -using VoidPointerT = OffsetPtrT<void>; - -// important: the windows shared memory mechanism, unlike other implementations, -// automatically removes the SHM object when there are no more "subscribers". -// MO currently depends on that feature! - -// managed_windows_shared_memory apparently doesn't support sharing between -// 64bit and 32bit processes -using managed_windows_shared_memory = bi::basic_managed_windows_shared_memory< - char, bi::rbtree_best_fit<bi::mutex_family, VoidPointerT, 8>, bi::iset_index>; - -using SharedMemoryT = managed_windows_shared_memory; -using SegmentManagerT = SharedMemoryT::segment_manager; - -using VoidAllocatorT = boost::container::scoped_allocator_adaptor< - boost::interprocess::allocator<void, SegmentManagerT>>; -using CharAllocatorT = VoidAllocatorT::rebind<char>::other; - -using StringT = bc::basic_string<char, std::char_traits<char>, CharAllocatorT>; - -} // namespace usvfs::shared diff --git a/libs/usvfs/src/shared/shmlogger.cpp b/libs/usvfs/src/shared/shmlogger.cpp deleted file mode 100644 index 66512de..0000000 --- a/libs/usvfs/src/shared/shmlogger.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma warning(disable : 4714) -#pragma warning(disable : 4503) -#pragma warning(push, 3) -#include "shmlogger.h" -#pragma warning(pop) - -#pragma warning(disable : 4996) - -using namespace boost::interprocess; -using namespace boost::posix_time; - -SHMLogger* SHMLogger::s_Instance = nullptr; - -SHMLogger::owner_t SHMLogger::owner; -SHMLogger::client_t SHMLogger::client; - -SHMLogger::SHMLogger(owner_t, const std::string& queueName) - : m_QueueName(queueName), - m_LogQueue(create_only, queueName.c_str(), MESSAGE_COUNT, MESSAGE_SIZE), - m_DroppedMessages(0) -{ - if (s_Instance != nullptr) { - throw std::runtime_error("duplicate shm logger instantiation"); - } else { - s_Instance = this; - } -} - -SHMLogger::SHMLogger(client_t, const std::string& queueName) - : m_QueueName(queueName), m_LogQueue(open_only, queueName.c_str()), - m_DroppedMessages(0) -{ - if (s_Instance != nullptr) { - throw std::runtime_error("duplicate shm logger instantiation"); - } else { - s_Instance = this; - } -} - -SHMLogger::~SHMLogger() -{ - s_Instance = nullptr; - message_queue_interop::remove(m_QueueName.c_str()); -} - -SHMLogger& SHMLogger::create(const char* instanceName) -{ - if (s_Instance != nullptr) { - throw std::runtime_error("duplicate shm logger instantiation"); - } else { - std::string queueName = std::string("__shm_sink_") + instanceName; - message_queue::remove(queueName.c_str()); - new SHMLogger(owner, queueName); - atexit([]() { - delete s_Instance; - }); - } - return *s_Instance; -} - -SHMLogger& SHMLogger::open(const char* instanceName) -{ - if (s_Instance != nullptr) { - throw std::runtime_error("duplicate shm logger instantiation"); - } else { - new SHMLogger(client, std::string("__shm_sink_") + instanceName); - } - return *s_Instance; -} - -void SHMLogger::free() -{ - if (s_Instance != nullptr) { - SHMLogger* temp = s_Instance; - s_Instance = nullptr; - delete temp; - } -} - -bool SHMLogger::tryGet(char* buffer, size_t bufferSize) -{ - message_queue_interop::size_type receivedSize; - unsigned int prio; - bool res = m_LogQueue.try_receive(buffer, static_cast<unsigned int>(bufferSize), - receivedSize, prio); - if (res) { - buffer[std::min(bufferSize - 1, static_cast<size_t>(receivedSize))] = '\0'; - } - return res; -} - -void SHMLogger::get(char* buffer, size_t bufferSize) -{ - message_queue_interop::size_type receivedSize; - unsigned int prio; - m_LogQueue.receive(buffer, static_cast<unsigned int>(bufferSize), receivedSize, prio); - buffer[std::min(bufferSize - 1, static_cast<size_t>(receivedSize))] = '\0'; -} - -usvfs::sinks::shm_sink::shm_sink(const char* queueName) - : m_LogQueue(open_only, (std::string("__shm_sink_") + queueName).c_str()), - m_DroppedMessages(0) -{} - -void usvfs::sinks::shm_sink::flush_() {} - -void usvfs::sinks::shm_sink::sink_it_(const spdlog::details::log_msg& msg) -{ - int droppedMessages = m_DroppedMessages.load(std::memory_order_relaxed); - if (droppedMessages > 0) { - auto dropMessage = std::format("{} debug messages dropped", droppedMessages); - if (m_LogQueue.try_send(dropMessage.c_str(), - static_cast<unsigned int>(dropMessage.size()), 0)) { - m_DroppedMessages.store(0, std::memory_order_relaxed); - } - } - - std::string message{msg.payload}; - - // blacklist %USERNAME% because PII - static const std::string username = std::string(getenv("USERNAME")); - boost::algorithm::ireplace_all(message, std::string("\\") + username, "\\USERNAME"); - boost::algorithm::ireplace_all(message, std::string("/") + username, "/USERNAME"); - - if (message.length() > SHMLogger::MESSAGE_SIZE) { - std::vector<std::string> splitVec; - boost::split(splitVec, message, boost::is_any_of("\r\n"), boost::token_compress_on); - for (const std::string& line : splitVec) { - output(msg.level, line); - } - } else { - output(msg.level, message); - } -} - -void usvfs::sinks::shm_sink::output(spdlog::level::level_enum lev, - const std::string& message) -{ - bool sent = true; - - // spdlog auto-append line breaks which we don't need. Probably would be - // better to not write the breaks to begin with? - size_t count = std::min(message.find_last_not_of("\r\n") + 1, - static_cast<size_t>(m_LogQueue.get_max_msg_size())); - - // depending on the log level, drop less important messages if the receiver - // can't keep up - switch (lev) { - case spdlog::level::trace: - case spdlog::level::debug: - case spdlog::level::info: { - // m_LogQueue.send(message.c_str(), count, 0); - sent = m_LogQueue.try_send(message.c_str(), static_cast<unsigned int>(count), 0); - } break; - case spdlog::level::err: - case spdlog::level::critical: { - m_LogQueue.send(message.c_str(), static_cast<unsigned int>(count), 0); - } break; - default: { - boost::posix_time::ptime time = - microsec_clock::universal_time() + boost::posix_time::milliseconds(200); - sent = m_LogQueue.timed_send(message.c_str(), static_cast<unsigned int>(count), 0, - time); - } break; - } - - if (!sent) { - m_DroppedMessages.fetch_add(1, std::memory_order_relaxed); - } -} - -void __cdecl boost::interprocess::ipcdetail::get_shared_dir(std::string& shared_dir) -{ - PWSTR path; - if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_ProgramData, 0, NULL, &path))) { - _bstr_t bPath(path); - shared_dir = (char*)bPath; - shared_dir += "\\USVFS"; - } else { - shared_dir = "C:\\ProgramData\\USVFS"; - } - boost::filesystem::path boostPath(shared_dir); - if (!boost::filesystem::exists(boostPath)) - boost::filesystem::create_directories(boostPath); -} diff --git a/libs/usvfs/src/shared/shmlogger.h b/libs/usvfs/src/shared/shmlogger.h deleted file mode 100644 index 158f941..0000000 --- a/libs/usvfs/src/shared/shmlogger.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <spdlog/details/null_mutex.h> -#include <spdlog/sinks/base_sink.h> - -#include "logging.h" -#include "shared_memory.h" -#include "windows_sane.h" - -typedef boost::interprocess::message_queue_t<usvfs::shared::VoidPointerT> - message_queue_interop; - -namespace usvfs::sinks -{ -class shm_sink : public spdlog::sinks::base_sink<spdlog::details::null_mutex> -{ -public: - shm_sink(const char* queueName); - -protected: - void sink_it_(const spdlog::details::log_msg& msg) override; - void output(spdlog::level::level_enum lev, const std::string& message); - void flush_() override; - -private: - message_queue_interop m_LogQueue; - std::atomic<int> m_DroppedMessages; -}; - -} // namespace usvfs::sinks - -class SHMLogger -{ -public: - static const size_t MESSAGE_COUNT = 1024; - static const size_t MESSAGE_SIZE = 512; - - static SHMLogger& create(const char* instanceName); - static SHMLogger& open(const char* instanceName); - static void free(); - - static bool isInstantiated() { return s_Instance != nullptr; } - - static inline SHMLogger& instance() - { - if (s_Instance == nullptr) { - throw std::runtime_error("shm logger not instantiated"); - } - - return *s_Instance; - } - - void log(LogLevel logLevel, const std::string& message); - bool tryGet(char* buffer, size_t bufferSize); - void get(char* buffer, size_t bufferSize); - -private: - struct owner_t - {}; - static owner_t owner; - - struct client_t - {}; - static client_t client; - -private: - SHMLogger(owner_t, const std::string& instanceName); - SHMLogger(client_t, const std::string& instanceName); - - SHMLogger(const SHMLogger&) = delete; - SHMLogger& operator=(const SHMLogger&) = delete; - - ~SHMLogger(); - -private: - static SHMLogger* s_Instance; - - message_queue_interop m_LogQueue; - - std::string m_SHMName; - std::string m_LockName; - std::string m_QueueName; - - std::atomic<int> m_DroppedMessages; -}; diff --git a/libs/usvfs/src/shared/stringcast.cpp b/libs/usvfs/src/shared/stringcast.cpp deleted file mode 100644 index 47822d5..0000000 --- a/libs/usvfs/src/shared/stringcast.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "stringcast.h" - -namespace usvfs::shared -{ - -UINT windowsCP(CodePage codePage) -{ - switch (codePage) { - case CodePage::LOCAL: - return CP_ACP; - case CodePage::UTF8: - return CP_UTF8; - case CodePage::LATIN1: - return 850; - } - // this should not be possible in practice - throw std::runtime_error("unsupported codePage"); -} - -} // namespace usvfs::shared diff --git a/libs/usvfs/src/shared/stringcast.h b/libs/usvfs/src/shared/stringcast.h deleted file mode 100644 index 0ce56d1..0000000 --- a/libs/usvfs/src/shared/stringcast.h +++ /dev/null @@ -1,170 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include "exceptionex.h" - -namespace usvfs::shared -{ - -enum class CodePage -{ - LOCAL, - LATIN1, - UTF8 -}; - -template <typename ToT, typename FromT> -class string_cast_impl -{ -public: - static ToT cast(const FromT& source, CodePage codePage, size_t sourceLength); -}; - -template <typename ToT, typename FromT> -ToT string_cast(FromT source, CodePage codePage = CodePage::LOCAL, - size_t sourceLength = std::numeric_limits<size_t>::max()) -{ - return string_cast_impl<ToT, FromT>::cast(source, codePage, sourceLength); -} - -template <typename ToT, typename CharT> -class string_cast_impl<ToT, std::basic_string<CharT>> -{ -public: - static ToT cast(const std::basic_string<CharT>& source, CodePage codePage, - size_t sourceLength) - { - return string_cast_impl<ToT, const CharT*>::cast(source.c_str(), codePage, - sourceLength); - } -}; - -template <typename ToT, typename CharT> -class string_cast_impl<ToT, CharT*> -{ - BOOST_STATIC_ASSERT(!boost::is_base_and_derived<ToT, CharT>::value); - -public: - static ToT cast(CharT* source, CodePage codePage, size_t sourceLength) - { - return string_cast_impl<ToT, const CharT*>::cast(source, codePage, sourceLength); - } -}; - -template <typename ToT, typename CharT, int N> -class string_cast_impl<ToT, CharT[N]> -{ -public: - static ToT cast(CharT (&source)[N], CodePage codePage, size_t sourceLength) - { - return string_cast_impl<ToT, const CharT*>::cast(source, codePage, sourceLength); - } -}; - -UINT windowsCP(CodePage codePage); - -template <> -class string_cast_impl<std::string, const wchar_t*> -{ -public: - static std::string cast(const wchar_t* const& source, CodePage codePage, - size_t sourceLength) - { - std::string result; - - if (sourceLength == std::numeric_limits<size_t>::max()) { - sourceLength = wcslen(source); - } - - if (sourceLength > 0) { - // use utf8 or local 8-bit encoding depending on user choice - UINT cp = windowsCP(codePage); - // preflight to find out the required buffer size - int outLength = WideCharToMultiByte(cp, 0, source, static_cast<int>(sourceLength), - nullptr, 0, nullptr, nullptr); - if (outLength == 0) { - throw windows_error("string conversion failed"); - } - result.resize(outLength); - outLength = WideCharToMultiByte(cp, 0, source, static_cast<int>(sourceLength), - &result[0], outLength, nullptr, nullptr); - if (outLength == 0) { - throw windows_error("string conversion failed"); - } - // fix output string length (i.e. in case of unconvertible characters - while (result[outLength - 1] == L'\0') { - result.resize(--outLength); - } - } - - return result; - } -}; - -template <> -class string_cast_impl<std::wstring, const char*> -{ -public: - static std::wstring cast(const char* const& source, CodePage codePage, - size_t sourceLength) - { - std::wstring result; - - if (sourceLength == std::numeric_limits<size_t>::max()) { - sourceLength = strlen(source); - } - - if (sourceLength > 0) { - // use utf8 or local 8-bit encoding depending on user choice - UINT cp = windowsCP(codePage); - // preflight to find out the required source size - int outLength = MultiByteToWideChar(cp, 0, source, static_cast<int>(sourceLength), - &result[0], 0); - if (outLength == 0) { - throw windows_error("string conversion failed"); - } - result.resize(outLength); - outLength = MultiByteToWideChar(cp, 0, source, static_cast<int>(sourceLength), - &result[0], outLength); - if (outLength == 0) { - throw windows_error("string conversion failed"); - } - while (result[outLength - 1] == L'\0') { - result.resize(--outLength); - } - } - - return result; - } -}; - -template <> -class string_cast_impl<std::wstring, const wchar_t*> -{ -public: - static std::wstring cast(const wchar_t* const& source, CodePage, size_t) - { - return std::wstring(source); - } -}; - -} // namespace usvfs::shared diff --git a/libs/usvfs/src/shared/stringutils.cpp b/libs/usvfs/src/shared/stringutils.cpp deleted file mode 100644 index 2ddbf64..0000000 --- a/libs/usvfs/src/shared/stringutils.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "stringutils.h" -#include "windows_sane.h" - -namespace usvfs::shared -{ - -void strncpy_sz(char* dest, const char* src, size_t destSize) -{ - if (destSize > 0) { - strncpy(dest, src, destSize - 1); - dest[destSize - 1] = '\0'; - } -} - -void wcsncpy_sz(wchar_t* dest, const wchar_t* src, size_t destSize) -{ - if ((destSize > 0) && (dest != nullptr)) { - wcsncpy(dest, src, destSize - 1); - dest[destSize - 1] = L'\0'; - } -} - -bool startswith(const wchar_t* string, const wchar_t* subString) -{ - while ((*string != '\0') && (*subString != '\0')) { - if (towlower(*string) != towlower(*subString)) { - return false; - } - ++string; - ++subString; - } - - return *subString == '\0'; -} - -static fs::path normalize(const fs::path& path) -{ - fs::path result; - - boost::locale::generator gen; - auto loc = gen("en_US.UTF-8"); - for (fs::path::iterator iter = path.begin(); iter != path.end(); ++iter) { - if (*iter == "..") { - result = result.parent_path(); - } else if (*iter != ".") { - result /= boost::to_lower_copy(iter->string(), loc); - } // single dot is ignored - } - return result; -} - -fs::path make_relative(const fs::path& fromIn, const fs::path& toIn) -{ - // converting path to lower case to make iterator comparison work correctly - // on case-insenstive filesystems - fs::path from(fs::absolute(fromIn)); - fs::path to(fs::absolute(toIn)); - - // find common base - fs::path::const_iterator fromIter(from.begin()); - fs::path::const_iterator toIter(to.begin()); - - // TODO the following equivalent test is probably quite expensive as new - // paths are created for each iteration but the case sensitivity depends on - // the fs - while ((fromIter != from.end()) && (toIter != to.end()) && - (boost::iequals(fromIter->string(), toIter->string()))) { - ++fromIter; - ++toIter; - } - - // Navigate backwards in directory to reach previously found base - fs::path result; - for (; fromIter != from.end(); ++fromIter) { - if (*fromIter != ".") { - result /= ".."; - } - } - - // Now navigate down the directory branch - for (; toIter != to.end(); ++toIter) { - result /= *toIter; - } - return result; -} - -std::string to_hex(void* bufferIn, size_t bufferSize) -{ - unsigned char* buffer = static_cast<unsigned char*>(bufferIn); - std::ostringstream temp; - temp << std::hex; - for (size_t i = 0; i < bufferSize; ++i) { - temp << std::setfill('0') << std::setw(2) << (unsigned int)buffer[i]; - if ((i % 16) == 15) { - temp << "\n"; - } else { - temp << " "; - } - } - return temp.str(); -} - -std::wstring to_upper(const std::wstring& input) -{ - std::wstring result; - result.resize(input.size()); - ::LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, input.c_str(), - static_cast<int>(input.size()), &result[0], - static_cast<int>(result.size())); - return result; -} - -std::string byte_string(std::size_t n) -{ - auto s = std::to_string(n); - auto p = s.size(); - - while (p > 3) { - p -= 3; - s.insert(p, 1, ','); - } - - return s + " B"; -} - -} // namespace usvfs::shared diff --git a/libs/usvfs/src/shared/stringutils.h b/libs/usvfs/src/shared/stringutils.h deleted file mode 100644 index 64d0af7..0000000 --- a/libs/usvfs/src/shared/stringutils.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -namespace usvfs::shared -{ - -void strncpy_sz(char* dest, const char* src, size_t destSize); -void wcsncpy_sz(wchar_t* dest, const wchar_t* src, size_t destSize); - -bool startswith(const wchar_t* string, const wchar_t* subString); - -// Return path when appended to a_From will resolve to same as a_To -fs::path make_relative(const fs::path& from, const fs::path& to); - -std::string to_hex(void* bufferIn, size_t bufferSize); - -// convert unicode string to upper-case (locale invariant) -std::wstring to_upper(const std::wstring& input); - -// formats a number with thousand separators and B at the end -// -std::string byte_string(std::size_t n); - -class FormatGuard -{ - std::ostream& m_Stream; - std::ios::fmtflags m_Flags; - -public: - FormatGuard(std::ostream& stream) : m_Stream(stream), m_Flags(stream.flags()) {} - - ~FormatGuard() { m_Stream.flags(m_Flags); } - - FormatGuard(const FormatGuard&) = delete; - FormatGuard& operator=(FormatGuard&) = delete; -}; - -} // namespace usvfs::shared diff --git a/libs/usvfs/src/shared/tree_container.h b/libs/usvfs/src/shared/tree_container.h deleted file mode 100644 index a2f61fa..0000000 --- a/libs/usvfs/src/shared/tree_container.h +++ /dev/null @@ -1,630 +0,0 @@ -#pragma once - -#include "directory_tree.h" -#include "shared_memory.h" - -namespace usvfs::shared -{ - -// smart pointer to DirectoryTrees (only intended for top-level nodes). This -// will transparently switch to new shared memory regions in case they get -// reallocated -// -// -// reassign() is called from a variety of places when the current chunk of -// shared memory is full or is marked as being outdated; its job is to either -// find another chunk that may have been created by another process or to create -// a brand new one -// -// -// if there is only a single process hooked, it will slowly fill up the shared -// memory when adding files, eventually throw a bi::bad_alloc and end up in -// reassign(); a new block will be allocated, the data copied over, and the old -// block will be deallocated -// -// -// when multiple processes are involved, things are more complicated -// -// two processes A and B will start by using the same shared memory, but they -// have their own pointer to it that's local to the process (the `m_TreeMeta` -// member variable) -// -// so when process A fills up the shared memory and reallocates it, process B -// is still pointing to the old shared memory; only when process B does some -// operation that accesses the file tree will the pointer be checked and -// adjusted to point to the new shared memory -// -// in this example, when process A ran out of memory, it set `outdated` to -// `true` in the shared memory block, allocated a new one and copied the data -// over, but it did not deallocate the block because process B is still -// pointing to it -// -// when process B tries to access the block, it checks `outdated` (see get()); -// if it's true, it means that it's pointing to an outdated shared memory block -// and must find the new one that process A created -// -// the new block is not necessarily the very next name, it is possible for -// process A to burn through a series of blocks quickly when adding a bunch of -// new files, and these blocks will all have been deallocated by the time -// process B tries to find the newest one -// -// so when a process sees its block as outdated, it will try to open a bunch of -// names until one exists that is not outdated; if it can't find the block -// (shouldn't happen), it will just create a new one -// -template <typename TreeT> -class TreeContainer -{ -public: - /** - * @brief Constructor - * @param SHMName name of the shared memory holding the tree. This should contain the - * running number - * @param size initial size in bytes of the container. since the tree is resized by - * doubling this should be a power of two. 64k is supposed to be the page size on - * windows so smaller allocations make little sense - * @note size can't be too small. If initial allocations fail automatic growing won't - * work - */ - TreeContainer(const std::string& SHMName, size_t size = 64 * 1024) - : m_TreeMeta(nullptr), m_SHMName(SHMName) - { - std::locale global_loc = std::locale(); - std::locale loc(global_loc, new fs::detail::utf8_codecvt_facet); - fs::path::imbue(loc); - - // append _1 to the name if it doesn't end with _N already - std::regex pattern(R"exp((.*_)(\d+))exp"); - std::smatch match; - std::string shmName(m_SHMName.c_str()); - regex_match(shmName, match, pattern); - - if (match.size() != 3) { - m_SHMName += "_1"; - } - - // creates a new memory block if this is the first process to run or attach - // to an already existing one - createOrOpen(m_SHMName, size); - - spdlog::get("usvfs")->info("attached to {0} with {1} nodes, size {2}", m_SHMName, - m_TreeMeta->tree->numNodesRecursive(), - byte_string(m_SHM->get_size())); - } - - TreeContainer(const TreeContainer&) = delete; - TreeContainer& operator=(const TreeContainer&) = delete; - - ~TreeContainer() - { - if (unassign(m_SHM, m_TreeMeta)) { - bi::shared_memory_object::remove(m_SHMName.c_str()); - } - } - - /** - * @return retrieve an allocator that can be used to create objects in this tree - */ - VoidAllocatorT allocator() { return VoidAllocatorT(m_SHM->get_segment_manager()); } - - template <typename... Arguments> - typename TreeT::DataT create(Arguments&&... args) - { - return TreeT::DataT(std::forward<Arguments>(args)..., allocator()); - } - - TreeT* operator->() { return get(); } - - /** - * @return raw pointer to the managed tree - */ - TreeT* get() - { - if (m_TreeMeta->outdated) { - reassign(); - } - - return m_TreeMeta->tree.get(); - } - - /** - * @return raw const pointer to the managed tree - */ - const TreeT* get() const - { - if (m_TreeMeta->outdated) { - // safe const_cast, TreeContainer are never created const - const_cast<TreeContainer<TreeT>*>(this)->reassign(); - } - - return m_TreeMeta->tree.get(); - } - - const TreeT* operator->() const { return get(); } - - /** - * @return current name of the managed shared memory - */ - std::string shmName() const { return m_SHMName; } - - void clear() { m_TreeMeta->tree->clear(); } - - /** - * @brief add a new file to the tree - * - * @param name name of the file, expected to be relative to this directory - * @param data the file data to attach - * @param flags flags for this files - * @param overwrite if true, the new leaf will overwrite an existing one that compares - *as "equal" - * @return pointer to the new node or a null ptr - **/ - template <typename T> - typename TreeT::NodePtrT addFile(const fs::path& name, const T& data, - TreeFlags flags = 0, bool overwrite = true) - { - for (;;) { - DecomposablePath dp(name.string()); - - try { - return addNode(m_TreeMeta->tree.get(), dp, data, overwrite, flags, allocator()); - } catch (const bi::bad_alloc&) { - } - - reassign(); - } - } - - /** - * @brief add a new directory to the tree - * - * @param name name of the file, expected to be relative to this directory - * @param data the file data to attach - * @param flags flags for this files - * @param overwrite if true, the new leaf will overwrite an existing one that compares - *as "equal" - * @return pointer to the new node or a null ptr - **/ - template <typename T> - typename TreeT::NodePtrT addDirectory(const fs::path& name, const T& data, - TreeFlags flags = 0, bool overwrite = true) - { - for (;;) { - DecomposablePath dp(name.string()); - - try { - return addNode(m_TreeMeta->tree.get(), dp, data, overwrite, - flags | FLAG_DIRECTORY, allocator()); - } catch (const bi::bad_alloc&) { - } - - reassign(); - } - } - - void getBuffer(void*& buffer, size_t& bufferSize) const - { - buffer = m_SHM->get_address(); - bufferSize = m_SHM->get_size(); - } - -private: - struct TreeMeta - { - TreeMeta(const typename TreeT::DataT& data, SegmentManagerT* segmentManager) - : tree(segmentManager->construct<TreeT>(bi::anonymous_instance)( - "", true, TreeT::NodePtrT(), data, VoidAllocatorT(segmentManager))), - referenceCount(0), // reference count only set on top level node - outdated(false) - {} - - OffsetPtrT<TreeT> tree; - long referenceCount; - bool outdated; - bi::interprocess_mutex mutex; - }; - - std::string m_SHMName; - std::shared_ptr<SharedMemoryT> m_SHM; - TreeMeta* m_TreeMeta; - - typename TreeT::DataT createEmpty() - { - return createDataEmpty<typename TreeT::DataT>(allocator()); - } - - template <typename T> - TreeT* createSubNode(const VoidAllocatorT& allocator, std::string_view name, - unsigned long flags, const T& data) - { - auto* manager = allocator.get_segment_manager(); - - return manager->construct<TreeT>(bi::anonymous_instance)( - name, flags, TreeT::NodePtrT(), - createData<typename TreeT::DataT, T>(data, allocator), manager); - } - - typename TreeT::NodePtrT createSubPtr(TreeT* subNode) - { - SharedMemoryT::segment_manager* manager = m_SHM->get_segment_manager(); - return TreeT::NodePtrT(subNode, allocator(), TreeT::DeleterT(manager)); - } - - template <typename T> - typename TreeT::NodePtrT addNode(TreeT* base, DecomposablePath& path, const T& data, - bool overwrite, unsigned int flags, - const VoidAllocatorT& allocator) - { - if (!path.peekNext()) { - typename TreeT::NodePtrT newNode = base->node(path.current()); - - if (!newNode) { - // last name component, should be the filename - TreeT* node = createSubNode(allocator, path.current(), flags, data); - newNode = createSubPtr(node); - newNode->m_Self = TreeT::WeakPtrT(newNode); - newNode->m_Parent = base->m_Self; - base->set(StringT(path.current(), allocator), newNode); - return newNode; - } else if (overwrite) { - newNode->m_Data = createData<typename TreeT::DataT, T>(data, allocator); - newNode->m_Flags = static_cast<usvfs::shared::TreeFlags>(flags); - return newNode; - } else { - // the node is already in the tree, overwrite is false, nothing to do - return {}; - } - } else { - // not last component, continue search in child node - auto subNode = base->m_Nodes.find(path.current()); - - if (subNode == base->m_Nodes.end()) { - typename TreeT::NodePtrT newNode = createSubPtr(createSubNode( - allocator, path.current(), FLAG_DIRECTORY | FLAG_DUMMY, createEmpty())); - - subNode = - base->m_Nodes.emplace(StringT(path.current(), allocator), newNode).first; - subNode->second->m_Self = TreeT::WeakPtrT(subNode->second); - subNode->second->m_Parent = base->m_Self; - } - - path.next(); - - return addNode(subNode->second.get().get(), path, data, overwrite, flags, - allocator); - } - } - - /** - * @brief copy content of one tree to a different tree (in a different shared memory - * segment - * @param destination - * @param reference - * @note at the time this is called, destination needs to refer to the shm of - * "destination" so that objects can be allocated in the new tree - */ - void copyTree(TreeT* destination, const TreeT* reference) - { - VoidAllocatorT allocator = VoidAllocatorT(m_SHM->get_segment_manager()); - destination->m_Flags = reference->m_Flags; - dataAssign(destination->m_Data, reference->m_Data); - destination->m_Name.assign(reference->m_Name.c_str()); - - for (const auto& kv : reference->m_Nodes) { - TreeT* newNode = createSubNode(allocator, "", true, createEmpty()); - typename TreeT::NodePtrT newNodePtr = createSubPtr(newNode); - - // need to set self BEFORE recursively copying the subtree, otherwise - // how would we assign parent pointers? - newNode->m_Self = newNodePtr; - - TreeT* source = reinterpret_cast<TreeT*>(kv.second.get().get()); - copyTree(newNode, source); - destination->set(newNode->m_Name, newNodePtr); - newNode->m_Parent = destination->m_Self; - } - } - - int increaseRefCount(TreeMeta* treeMeta) - { - bi::scoped_lock<bi::interprocess_mutex> lock(treeMeta->mutex); - return ++treeMeta->referenceCount; - } - - int decreaseRefCount(TreeMeta* treeMeta) - { - bi::scoped_lock<bi::interprocess_mutex> lock(treeMeta->mutex); - return --treeMeta->referenceCount; - } - - // see activateSHM() for return value - // - std::optional<std::string> createOrOpen(const std::string& SHMName, size_t size) - { - SharedMemoryT* newSHM = openSHM(SHMName); - - if (newSHM) { - spdlog::get("usvfs")->info("{} opened in process {}", SHMName, - ::GetCurrentProcessId()); - } else { - newSHM = createSHM(SHMName, size); - - if (newSHM) { - spdlog::get("usvfs")->info("{} created in process {}", SHMName, - ::GetCurrentProcessId()); - } - } - - if (!newSHM) { - spdlog::get("usvfs")->error("failed to create or open {} in process {}", SHMName, - ::GetCurrentProcessId()); - - throw std::exception("no shm instance"); - } - - return activateSHM(newSHM, SHMName); - } - - // see activateSHM() for return value - // - SharedMemoryT* createSHM(const std::string& SHMName, size_t size) - { - try { - return new SharedMemoryT(bi::create_only, SHMName.c_str(), - static_cast<unsigned int>(size)); - } catch (const bi::interprocess_exception&) { - } - - return nullptr; - } - - // see activateSHM() for return value - // - SharedMemoryT* openSHM(const std::string& SHMName) - { - try { - return new SharedMemoryT(bi::open_only, SHMName.c_str()); - } catch (const bi::interprocess_exception&) { - } - - return nullptr; - } - - // makes the given shm current, returns the name of the previous shm block - // if it is now unused and must be destroyed; if the block is still used by - // another process, returns empty - // - // see reassign() - // - std::optional<std::string> activateSHM(SharedMemoryT* shm, const std::string& SHMName) - { - std::shared_ptr<SharedMemoryT> oldSHM = m_SHM; - - m_SHM.reset(shm); - std::pair<TreeMeta*, SharedMemoryT::size_type> res = m_SHM->find<TreeMeta>("Meta"); - - if (res.first == nullptr) { - res.first = m_SHM->construct<TreeMeta>("Meta")(createEmpty(), - m_SHM->get_segment_manager()); - if (res.first == nullptr) { - USVFS_THROW_EXCEPTION(bi::bad_alloc()); - } - if (m_TreeMeta != nullptr) { - copyTree(res.first->tree.get(), m_TreeMeta->tree.get()); - } - } - - increaseRefCount(res.first); - - std::optional<std::string> deadSHMName; - - if (oldSHM.get() != nullptr) { - const bool lastUser = unassign(oldSHM, m_TreeMeta); - if (lastUser) { - deadSHMName = m_SHMName; - } - } - - m_TreeMeta = res.first; - m_SHMName = SHMName; - - return deadSHMName; - } - - static std::string followupName(const std::string& currentName) - { - std::regex pattern(R"exp((.*_)(\d+))exp"); - std::smatch match; - regex_match(currentName, match, pattern); - - if (match.size() != 3) { - USVFS_THROW_EXCEPTION(usage_error() << ex_msg("shared memory name invalid")); - } - - const int count = boost::lexical_cast<int>(match[2]); - return match[1].str() + std::to_string(count + 1); - } - - bool unassign(const std::shared_ptr<SharedMemoryT>& shm, TreeMeta* tree) - { - if (tree == nullptr) { - return true; - } - - if (decreaseRefCount(tree) == 0) { - shm->get_segment_manager()->destroy_ptr(tree); - return true; - } else { - return false; - } - } - - // re-entrancy: every time a process switches to a new shared memory block, it - // will know whether it was the last process to have a handle to it; when that - // happens, the block will be destroyed to avoid leaking it - // - // destroying these blocks is somewhat dangerous: it ends up in boost, which - // will try to access the filesystem to see if the name of the shared memory - // corresponds to a file on the drive, which can call hooked functions and end - // up right back here - // - // (note that in usvfs, only the shared memory for the log file uses a real - // file on the filesystem, see shmlogger.cpp; all the tree stuff uses - // anonymous, memory mapped files that live in the Windows pagefile) - // - // so the old blocks can be destroyed, but only after all the shenanigans with - // finding the correct shared memory block are over and `m_TreeMeta` points to - // a valid block, so all the names of the dead shared memory blocks are kept - // in a vector and deallocated at the very end - // - void reassign() - { - // list of all the shared memory blocks that are now unused and can be - // destroyed - std::vector<std::string> deadSHMNames; - - if (m_TreeMeta->outdated) { - // this block was marked as outdated, which should only happen when - // another process has ran out of memory and started allocating blocks - // with higher numbers - - spdlog::get("usvfs")->info("tree {0} is outdated, looking for another one", - m_SHMName); - - if (findNewerBlock(deadSHMNames)) { - // the new block was found and activated - return; - } - } else { - // this block isn't outdated, so reassign() was called because a bad_alloc - // exception was thrown - spdlog::get("usvfs")->info( - "ran out of memory in tree {0}, will create another one", m_SHMName); - } - - // either the block is full or it's outdated, but no higher block was found; - // just create a new one - - createNewBlock(deadSHMNames); - - // remove the old shared memory blocks; this can be recursive and call - // reassign() again, but it's safe at this point - for (const std::string& name : deadSHMNames) { - spdlog::get("usvfs")->info("destroying {0}", name); - bi::shared_memory_object::remove(name.c_str()); - } - } - - // tries a series of shm names above the current one in the hope of finding - // the most recent one - // - // if the new block was found and activated correctly, returns true - // - // when findNewerBlock() returns false, this container will either still be - // pointing to the same, outdated block as it started with, or it might have - // moved up to another outdated block, but it will always be pointing to - // a valid block in memory - // - bool findNewerBlock(std::vector<std::string>& deadSHMNames) - { - // how many blocks are checked above the current one; it's unlikely there - // will ever be more than 15 to 20 blocks allocated, but this is high - // because it's really the only way to keep processes connected to the same - // shm block, so processes must not fail to find the next one - constexpr int Tries = 100; - - std::string nextName = m_SHMName; - - for (int i = 0; i < Tries; ++i) { - // the shm name is something like "mod_organizer_3", which becomes - // "mod_organizer_4" - nextName = followupName(nextName); - spdlog::get("usvfs")->info("opening {0}", nextName); - - // open the shm, see if it exists - SharedMemoryT* shm = openSHM(nextName); - - if (!shm) { - // this is not necessarily an error, another process might have created - // a bunch of blocks and destroyed them before this process had a chance - // to see them, so just keep going - spdlog::get("usvfs")->info("{0} doesn't exist", nextName); - continue; - } - - spdlog::get("usvfs")->info("{0} exists, activating", nextName); - const auto deadSHMName = activateSHM(shm, nextName); - - // if this process was the last user of the previous block, it must be - // deallocated, but only after this whole thing is finished, because it - // can end up calling reassign() again - if (deadSHMName) { - spdlog::get("usvfs")->info("will destroy {0}", *deadSHMName); - deadSHMNames.push_back(*deadSHMName); - } - - // another process might have already created this block, run out of - // memory and created more, so make sure to only stop when finding a block - // that's not outdated - if (m_TreeMeta->outdated) { - spdlog::get("usvfs")->info("{0} is also outdated", nextName); - } else { - // shm opened correctly, activated and not outdated, done - spdlog::get("usvfs")->info("{0} not outdated, taking it, size now {1}", - nextName, byte_string(m_SHM->get_size())); - - return true; - } - } - - // this block is outdated, but no other valid block was found above; this - // shouldn't happen, but just create a new block to make sure programs can - // still run - - spdlog::get("usvfs")->error( - "found no existing tree above {0}, will create a new one", m_SHMName); - - return false; - } - - // creates a new block and activates it, throws on failure - // - void createNewBlock(std::vector<std::string>& deadSHMNames) - { - // the current block is now considered stale, so make sure other processes - // are aware of it and try to find the new block - // - // todo: there really should be some synchronization here, another process - // can pick up this flag before the next block has been created - m_TreeMeta->outdated = true; - - // the shm name is something like "mod_organizer_3", which becomes - // "mod_organizer_4" - const std::string nextName = followupName(m_SHMName); - spdlog::get("usvfs")->info("creating {0}", nextName); - - SharedMemoryT* shm = createSHM(nextName, m_SHM->get_size() * 2); - - if (!shm) { - // this shouldn't happen - spdlog::get("usvfs")->error("failed to create {0}", nextName); - throw std::exception("cannot create block"); - } - - spdlog::get("usvfs")->info("{0} created, activating", nextName); - const auto deadSHMName = activateSHM(shm, nextName); - - // if this process was the last user of the previous block, it must be - // deallocated, but only after this whole thing is finished, because it - // can end up calling reassign() again - if (deadSHMName) { - spdlog::get("usvfs")->info("will destroy {0}", *deadSHMName); - deadSHMNames.push_back(*deadSHMName); - } - - spdlog::get("usvfs")->info("tree {0} size now {1}", m_SHMName, - byte_string(m_SHM->get_size())); - } -}; - -} // namespace usvfs::shared diff --git a/libs/usvfs/src/shared/unicodestring.cpp b/libs/usvfs/src/shared/unicodestring.cpp deleted file mode 100644 index f997e7f..0000000 --- a/libs/usvfs/src/shared/unicodestring.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "unicodestring.h" -#include "logging.h" -#include "stringcast.h" -#include "stringutils.h" - -namespace usvfs -{ - -UnicodeString::UnicodeString(LPCWSTR string, size_t length) -{ - if (length == std::string::npos) { - length = wcslen(string); - } - m_Buffer.resize(length + 1); - memcpy(m_Buffer.data(), string, length * sizeof(wchar_t)); - update(); -} - -UnicodeString::UnicodeString(const std::wstring& string) -{ - m_Buffer.resize(string.length() + 1); - memcpy(m_Buffer.data(), string.data(), string.length() * sizeof(wchar_t)); - update(); -} - -UnicodeString& UnicodeString::operator=(const std::wstring& string) -{ - m_Buffer.resize(string.length() + 1); - memcpy(m_Buffer.data(), string.data(), string.length() * sizeof(wchar_t)); - update(); - return *this; -} - -UnicodeString& UnicodeString::appendPath(PUNICODE_STRING path) -{ - if (path != nullptr && path->Buffer && path->Length) { - auto appendAt = size(); - if (appendAt) { - m_Buffer.resize(m_Buffer.size() + path->Length / sizeof(WCHAR) + 1); - m_Buffer[appendAt++] = L'\\'; - } else - m_Buffer.resize(path->Length / sizeof(WCHAR) + 1); - memcpy(&m_Buffer[appendAt], path->Buffer, path->Length); - update(); - } - - return *this; -} - -void UnicodeString::update() -{ - m_Data.Length = static_cast<USHORT>(size() * sizeof(WCHAR)); - m_Data.MaximumLength = static_cast<USHORT>((m_Buffer.capacity() - 1) * sizeof(WCHAR)); - m_Data.Buffer = m_Buffer.data(); -} - -} // namespace usvfs diff --git a/libs/usvfs/src/shared/unicodestring.h b/libs/usvfs/src/shared/unicodestring.h deleted file mode 100644 index 77071ad..0000000 --- a/libs/usvfs/src/shared/unicodestring.h +++ /dev/null @@ -1,110 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include "ntdll_declarations.h" -#include "windows_sane.h" - -#include "formatters.h" - -namespace usvfs -{ - -/** - * @brief C++ wrapper for the windows UNICODE_STRING structure - */ -class UnicodeString -{ -public: - UnicodeString() : m_Buffer(1) { update(); } - - UnicodeString(const UnicodeString& other) : m_Buffer(other.m_Buffer) { update(); } - - UnicodeString(UnicodeString&& other) : m_Buffer(std::move(other.m_Buffer)) - { - update(); - } - - UnicodeString(const std::wstring& string); - UnicodeString(LPCWSTR string, size_t length = std::string::npos); - - UnicodeString& operator=(const std::wstring& string); - - UnicodeString& operator=(const UnicodeString& other) - { - m_Buffer = other.m_Buffer; - update(); - return *this; - } - - UnicodeString& operator=(UnicodeString&& other) - { - m_Buffer = std::move(other.m_Buffer); - update(); - return *this; - } - - /** - * @brief convert to a WinNt Api-style unicode string. This is only valid as long - * as the string isn't modified - */ - explicit operator PUNICODE_STRING() { return &m_Data; } - - /** - * @brief convert to a Win32 Api-style unicode string. This is only valid as long - * as the string isn't modified - */ - explicit operator LPCWSTR() const { return m_Data.Buffer; } - - /** - * @return length of the string in 16-bit words (not including zero termination) - */ - size_t size() const { return m_Buffer.size() - 1; } - - wchar_t operator[](size_t pos) const { return m_Buffer[pos]; } - - UnicodeString& appendPath(PUNICODE_STRING path); - -private: - friend struct ::std::formatter<UnicodeString, char>; - - void update(); - - UNICODE_STRING m_Data; - std::vector<wchar_t> m_Buffer; -}; - -} // namespace usvfs - -template <> -struct std::formatter<usvfs::UnicodeString, char> - : std::formatter<PCUNICODE_STRING, char> -{ - template <class FmtContext> - FmtContext::iterator format(const usvfs::UnicodeString& v, FmtContext& ctx) const - { - if (v.size() == 0) { - return std::format_to(ctx.out(), "<empty string>"); - } else { - return std::formatter<PCUNICODE_STRING, char>::format(&v.m_Data, ctx); - } - } -}; diff --git a/libs/usvfs/src/shared/wildcard.cpp b/libs/usvfs/src/shared/wildcard.cpp deleted file mode 100644 index a2efe6d..0000000 --- a/libs/usvfs/src/shared/wildcard.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "wildcard.h" -#include "logging.h" -#include "windows_sane.h" - -static bool IsInnerMatch(LPCWSTR pszString, LPCWSTR pszMatch) -{ - while (*pszMatch != L'\0') { - if ((*pszMatch == L'?') || (*pszMatch == L'>')) { - if (!*pszString) { - // ? must match exactly one character - return false; - } - - ++pszString; - ++pszMatch; - } else if ((*pszMatch == L'*') || (*pszMatch == L'<')) { - if (IsInnerMatch(pszString, pszMatch + 1)) { - // * may match empty string or we may have matched something already - return true; - } - - return *pszString && IsInnerMatch(pszString + 1, pszMatch); - - // the rest of the string can't be matched - } else { - if (CharUpperW(MAKEINTRESOURCEW(MAKELONG(*pszString++, 0))) != - CharUpperW(MAKEINTRESOURCEW(MAKELONG(*pszMatch++, 0)))) { - // regular chars compare - return false; - } - } - } - - return !*pszString && !*pszMatch; -} - -static LPCSTR InnerMatch(LPCSTR pszString, LPCSTR pszMatch) -{ - // We have a special case where string is empty ("") and the mask is "*". - // We need to handle this too. So we can't test on !*pszString here. - // The loop breaks when the match string is exhausted. - while (*pszString != '\0') { - // Single wildcard character - if ((*pszMatch == '?') || (*pszMatch == '>')) { - // can't match directory separator - if ((*pszString == '\\') || (*pszString == '/')) - return nullptr; - - // Matches any character except empty string - if (*pszString == '\0') { - // string consumed, part of the pattern is left - return pszMatch; - } - - // OK next - ++pszString; - ++pszMatch; - } else if ((*pszMatch == '*') || (*pszMatch == '<')) { - // * doesn't match directory separators - if ((*pszString == '\\') || (*pszString == '/')) { - ++pszMatch; - continue; - } - - // Need to do some tricks. - - // 1. The wildcard * is ignored. - // So just an empty string matches. This is done by recursion. - // Because we eat one character from the match string, the - // recursion will stop. - { - LPCSTR remainder = InnerMatch(pszString, pszMatch + 1); - if (remainder != nullptr) { - // we have a match and the * replaces no other character - return remainder; - } - } - - // 2. Chance we eat the next character and try it again, with a - // wildcard * match. This is done by recursion. Because we eat - // one character from the string, the recursion will stop. - if (*pszString != '\0') { - LPCSTR remainder = InnerMatch(pszString + 1, pszMatch); - if (remainder != nullptr) { - return remainder; - } - } - - // Nothing worked with this wildcard. - return nullptr; - } else { - // Standard compare of 2 chars. Note that *pszSring might be 0 - // here, but then we never get a match on *pszMask that has always - // a value while inside this loop. - if (CharUpperA(MAKEINTRESOURCEA(MAKELONG(*pszString++, 0))) != - CharUpperA(MAKEINTRESOURCEA(MAKELONG(*pszMatch++, 0)))) - return nullptr; - } - } - - // successful match if the input string was completely consumed - if (*pszString == '\0') { - while ((*pszMatch == '*') || (*pszMatch == '<')) { - ++pszMatch; - } - return pszMatch; - } else { - return nullptr; - } -} - -namespace usvfs::shared::wildcard -{ - -bool Match(LPCWSTR pszString, LPCWSTR pszMatch) -{ - if (*pszString == L'.') { - // cmd.exe seems to ignore - return Match(pszString + 1, pszMatch); - } else { - size_t len = wcslen(pszMatch); - if ((len > 2) && (wcscmp(pszMatch + len - 2, L".*") == 0)) { - // cmd.exe seems to completely ignore .* at the end. - std::wstring temp(pszMatch, pszMatch + len - 2); - return IsInnerMatch(pszString, temp.c_str()); - } - return IsInnerMatch(pszString, pszMatch); - } -} - -bool Match(LPCSTR pszString, LPCSTR pszMatch) -{ - if (*pszString == '.') { - // cmd.exe seems to ignore - return Match(pszString + 1, pszMatch); - } else { - size_t len = strlen(pszMatch); - LPCSTR res = nullptr; - if ((len > 2) && (strcmp(pszMatch + len - 2, ".*") == 0)) { - // cmd.exe seems to completely ignore .* at the end. - std::string temp(pszMatch, pszMatch + len - 2); - res = InnerMatch(pszString, temp.c_str()); - } else { - res = InnerMatch(pszString, pszMatch); - } - return ((res != nullptr) && (*res == '\0')); - } -} - -LPCSTR PartialMatch(LPCSTR pszString, LPCSTR pszMatch) -{ - if (*pszString == '.') { - // cmd.exe seems to ignore dots at the start - return PartialMatch(pszString + 1, pszMatch); - } else { - size_t len = strlen(pszMatch); - if ((len > 2) && (strcmp(pszMatch + len - 2, ".*") == 0)) { - // in cmd.exe there seems to be no difference between <something>* and - // <something>*.* - std::string temp(pszMatch, pszMatch + len - 2); - LPCSTR pos = InnerMatch(pszString, temp.c_str()); - if (pos != nullptr) { - if (*pos == '\0') { - return pszMatch + strlen(pszMatch); - } else { - return pszMatch + (pos - temp.c_str()); - } - } - } - return InnerMatch(pszString, pszMatch); - } -} - -} // namespace usvfs::shared::wildcard diff --git a/libs/usvfs/src/shared/wildcard.h b/libs/usvfs/src/shared/wildcard.h deleted file mode 100644 index bf5b4a3..0000000 --- a/libs/usvfs/src/shared/wildcard.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -/// Wildcard matching code -/// by Martin Richter -/// licensed under The Code Project Open License (CPOL) - -#pragma once - -#include "windows_sane.h" - -namespace usvfs::shared::wildcard -{ - -/** - * @brief match string to wildcard windows-style - * @param pszString Input string to match - * @param pszMatch Match mask that may contain wildcards like ? and * - * @note A ? sign matches any character, except an empty string. - * @note A * sign matches any string inclusive an empty string. - * @note Characters are compared caseless. - * @return true if the string matches the pattern - */ -bool Match(LPCWSTR pszString, LPCWSTR pszMatch); - -/** - * @brief match string to wildcard windows-style - * @param pszString Input string to match - * @param pszMatch Match mask that may contain wildcards like ? and * - * @note A ? sign matches any character, except an empty string. - * @note A * sign matches any string inclusive an empty string. - * @note Characters are compared caseless. - * @return true if the string matches the pattern - */ -bool Match(LPCSTR pszString, LPCSTR pszMatch); - -/** - * @brief match string to wildcard windows-style - * @param pszString Input string to match - * @param pszMatch Match mask that may contain wildcards like ? and * - * @note A ? sign matches any character, except an empty string. - * @note A * sign matches any string inclusive an empty string. - * @note Characters are compared caseless. - * @return the "not-consumed" remainder of the pattern. If this points to a - * zero terminator, this was a full match. - * Returns nullptr if no match is possible - */ -LPCSTR PartialMatch(LPCSTR pszString, LPCSTR pszMatch); - -} // namespace usvfs::shared::wildcard diff --git a/libs/usvfs/src/shared/winapi.cpp b/libs/usvfs/src/shared/winapi.cpp deleted file mode 100644 index e28a13c..0000000 --- a/libs/usvfs/src/shared/winapi.cpp +++ /dev/null @@ -1,490 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "winapi.h" -#include "exceptionex.h" -#include "logging.h" -#include "ntdll_declarations.h" -#include "stringcast.h" -#include "stringutils.h" -#include "unicodestring.h" - -namespace winapi::ansi -{ - -std::string getModuleFileName(HMODULE module, HANDLE process) -{ - std::wstring result = wide::getModuleFileName(module, process); - return usvfs::shared::string_cast<std::string>(result); -} - -std::string getCurrentDirectory() -{ - std::string result; - DWORD required = GetCurrentDirectoryA(0, nullptr); - if (required == 0UL) { - throw usvfs::shared::windows_error("failed to determine current working directory"); - } - result.resize(required); - GetCurrentDirectoryA(required, &result[0]); - result.resize(required - 1); - return result; -} - -std::pair<std::string, std::string> getFullPathName(LPCSTR fileName) -{ - static const int INIT_SIZE = 128; - std::string result; - result.resize(INIT_SIZE); - LPSTR filePart = nullptr; - DWORD requiredSize = GetFullPathNameA(fileName, INIT_SIZE, &result[0], &filePart); - if (requiredSize >= INIT_SIZE) { - result.resize(requiredSize); - GetFullPathNameA(fileName, requiredSize, &result[0], &filePart); - } - if (requiredSize != 0UL) { - return std::make_pair(result, std::string(filePart != nullptr ? filePart : "")); - } else { - return make_pair(result, std::string()); - } -} - -} // namespace winapi::ansi - -namespace winapi::wide -{ - -std::wstring getModuleFileName(HMODULE module, HANDLE process) -{ - std::wstring result; - result.resize(64); - DWORD rc = 0UL; - - while ((rc = (process == INVALID_HANDLE_VALUE) - ? ::GetModuleFileNameW(module, &result[0], - static_cast<DWORD>(result.size())) - : ::GetModuleFileNameExW(process, module, &result[0], - static_cast<DWORD>(result.size()))) == - result.size()) { - result.resize(result.size() * 2); - } - - if (rc == 0UL) { - if (::GetLastError() == ERROR_PARTIAL_COPY) { -#if BOOST_ARCH_X86_64 - return L"unknown (32-bit process)"; -#else - return L"unknown (64-bit process)"; -#endif - } else { - throw usvfs::shared::windows_error("failed to retrieve module file name"); - } - } - - result.resize(rc); - - return result; -} - -std::pair<std::wstring, std::wstring> getFullPathName(LPCWSTR fileName) -{ - wchar_t buf1[MAX_PATH]; - std::vector<wchar_t> buf2; - wchar_t* result = buf1; - LPWSTR filePart = nullptr; - DWORD requiredSize = GetFullPathNameW(fileName, MAX_PATH, result, &filePart); - if (requiredSize >= MAX_PATH) { - buf2.resize(requiredSize); - result = &buf2[0]; - requiredSize = GetFullPathNameW(fileName, requiredSize, result, &filePart); - } - return make_pair(std::wstring(result, requiredSize), - std::wstring((requiredSize && filePart) ? filePart : L"")); -} - -std::wstring getCurrentDirectory() -{ - // really great api this (::GetCurrentDirectoryW) - // - if it succeeds, returns size in characters WITHOUT zero termination - // - if it fails due to buffer too small, returns size in characters WITH zero - // termination - // - if it fails for other reasons, returns 0 - std::wstring result; - DWORD required = GetCurrentDirectoryW(0, nullptr); - if (required == 0UL) { - throw usvfs::shared::windows_error("failed to determine current working directory"); - } - result.resize(required); - GetCurrentDirectoryW(required, &result[0]); - result.resize(required - 1); - return result; -} - -std::wstring getKnownFolderPath(REFKNOWNFOLDERID folderID) -{ - PWSTR writablePath; - - ::SHGetKnownFolderPath(folderID, 0, nullptr, &writablePath); - - ON_BLOCK_EXIT([writablePath]() { - ::CoTaskMemFree(writablePath); - }); - - return std::wstring(writablePath); -} - -} // namespace winapi::wide - -namespace winapi::ex -{ - -std::pair<uintptr_t, uintptr_t> getSectionRange(HANDLE moduleHandle) -{ - std::pair<uintptr_t, uintptr_t> result; - bool found = false; - uintptr_t exeModule = reinterpret_cast<uintptr_t>(moduleHandle); - if (exeModule == 0) { - throw std::runtime_error("failed to determine address range of executable"); - } - - std::pair<uintptr_t, uintptr_t> totalRange{UINT_MAX, 0}; - - PIMAGE_DOS_HEADER dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(exeModule); - PIMAGE_NT_HEADERS ntHeader = - reinterpret_cast<PIMAGE_NT_HEADERS>(exeModule + dosHeader->e_lfanew); - PIMAGE_SECTION_HEADER sectionHeader = - reinterpret_cast<PIMAGE_SECTION_HEADER>(ntHeader + 1); - for (int i = 0; i < ntHeader->FileHeader.NumberOfSections && !found; ++i) { - if (memcmp(sectionHeader->Name, ".text", 5) == 0) { - result.first = exeModule + sectionHeader->VirtualAddress; - result.second = result.first + sectionHeader->Misc.VirtualSize; - found = true; - } else { - uintptr_t start = exeModule + sectionHeader->VirtualAddress; - totalRange.first = std::min(totalRange.first, start); - totalRange.second = std::max<uintptr_t>(totalRange.second, - start + sectionHeader->Misc.VirtualSize); - } - ++sectionHeader; - } - - if (!found) { - return totalRange; - } - - return result; -} - -OSVersion getOSVersion() -{ - RTL_OSVERSIONINFOEXW versionInfo; - ZeroMemory(&versionInfo, sizeof(RTL_OSVERSIONINFOEXW)); - versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); - RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo); - - OSVersion result; - result.major = versionInfo.dwMajorVersion; - result.minor = versionInfo.dwMinorVersion; - result.build = versionInfo.dwBuildNumber; - result.platformid = versionInfo.dwPlatformId; - result.servicpack = - versionInfo.wServicePackMajor << 16 | versionInfo.wServicePackMinor; - return result; -} - -} // namespace winapi::ex - -namespace winapi::ex::ansi -{ - -std::string errorString(DWORD errorCode) -{ - std::ostringstream finalMessage; - - LPSTR buffer = nullptr; - - DWORD currentErrorCode = GetLastError(); - - errorCode = - errorCode != std::numeric_limits<DWORD>::max() ? errorCode : currentErrorCode; - - // TODO: the message is not english? - if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - nullptr, errorCode, - 0 //, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) - , - (LPSTR)&buffer, 0, nullptr) == 0) { - finalMessage << "(unknown error [" << errorCode << "])"; - } else { - if (buffer != nullptr) { - size_t end = strlen(buffer) - 1; - while ((buffer[end] == '\n') || (buffer[end] == '\r')) { - buffer[end--] = '\0'; - } - finalMessage << "(" << buffer << " [" << errorCode << "])"; - LocalFree(buffer); // allocated by FormatMessage - } - } - - SetLastError(currentErrorCode); // restore error code because FormatMessage might - // have modified it - return finalMessage.str(); -} - -std::string toString(const FILETIME& time) -{ - SYSTEMTIME temp; - FileTimeToSystemTime(&time, &temp); - std::ostringstream stream; - stream << temp.wYear << "-" << temp.wMonth << "-" << temp.wDay << temp.wHour << ":" - << temp.wMinute << ":" << temp.wSecond; - return stream.str(); -} - -LPCSTR GetBaseName(LPCSTR string) -{ - LPCSTR result = string + strlen(string) - 1; - while (result > string) { - if ((*result == '\\') || (*result == '/')) { - ++result; - break; - } else { - --result; - } - } - return result; -} - -} // namespace winapi::ex::ansi - -namespace winapi::ex::wide -{ - -bool fileExists(LPCWSTR fileName, bool* isDirectory) -{ - DWORD attrib = GetFileAttributesW(fileName); - - if (attrib == INVALID_FILE_ATTRIBUTES) { - return false; - } else { - if (isDirectory != nullptr) { - *isDirectory = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; - } - return true; - } -} - -std::wstring errorString(DWORD errorCode) -{ - std::wostringstream finalMessage; - - LPWSTR buffer = nullptr; - - DWORD currentErrorCode = GetLastError(); - - errorCode = - errorCode != std::numeric_limits<DWORD>::max() ? errorCode : currentErrorCode; - - // TODO: the message is not english? - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - nullptr, errorCode, - 0 //, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) - , - (LPWSTR)&buffer, 0, nullptr) == 0) { - finalMessage << L"(unknown error [" << errorCode << "])"; - } else { - if (buffer != nullptr) { - size_t end = wcslen(buffer) - 1; - while ((buffer[end] == L'\n') || (buffer[end] == L'\r')) { - buffer[end--] = L'\0'; - } - finalMessage << L"(" << buffer << L" [" << errorCode << L"])"; - LocalFree(buffer); // allocated by FormatMessage - } - } - - SetLastError(currentErrorCode); // restore error code because FormatMessage might - // have modified it - return finalMessage.str(); -} - -std::wstring toString(const FILETIME& time) -{ - SYSTEMTIME temp; - FileTimeToSystemTime(&time, &temp); - std::wostringstream stream; - stream << temp.wYear << "-" << temp.wMonth << "-" << temp.wDay << temp.wHour << ":" - << temp.wMinute << ":" << temp.wSecond; - return stream.str(); -} - -LPCWSTR GetBaseName(LPCWSTR string) -{ - LPCWSTR result; - if ((string == nullptr) || (string[0] == L'\0')) { - result = string; - } else { - result = string + wcslen(string) - 1; - } - - while (result > string) { - if ((*result == L'\\') || (*result == L'/')) { - ++result; - break; - } else { - --result; - } - } - return result; -} - -LPWSTR GetBaseName(LPWSTR path) -{ - LPCWSTR result = GetBaseName(static_cast<LPCWSTR>(path)); - return const_cast<LPWSTR>(result); -} - -std::wstring getSectionName(PVOID addressIn, HANDLE process) -{ - if (process == nullptr) { - process = GetCurrentProcess(); - } - HMODULE modules[1024]; - intptr_t address = reinterpret_cast<intptr_t>(addressIn); - DWORD required; - if (::EnumProcessModules(process, modules, sizeof(modules), &required)) { - for (DWORD i = 0; i < (std::min<DWORD>(1024UL, required) / sizeof(HMODULE)); ++i) { - std::pair<intptr_t, intptr_t> range = getSectionRange(modules[i]); - if ((address > range.first) && (address < range.second)) { - try { - return winapi::wide::getModuleFileName(modules[i], process); - } catch (const std::exception&) { - return std::wstring(L"unknown"); - } - } - } - } - return std::wstring(L"unknown"); -} - -std::vector<FileResult> quickFindFiles(LPCWSTR directoryName, LPCWSTR pattern) -{ - std::vector<FileResult> result; - - static const unsigned int BUFFER_SIZE = 1024; - - HANDLE hdl = CreateFileW(directoryName, GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - - ON_BLOCK_EXIT([hdl]() { - CloseHandle(hdl); - }); - - uint8_t buffer[BUFFER_SIZE]; - - NTSTATUS res = STATUS_SUCCESS; // status success - while (res == STATUS_SUCCESS) { - IO_STATUS_BLOCK status; - - res = NtQueryDirectoryFile( - hdl, nullptr, nullptr, nullptr, &status, buffer, BUFFER_SIZE, - FileFullDirectoryInformation, FALSE, - static_cast<PUNICODE_STRING>(usvfs::UnicodeString(pattern)), FALSE); - if (res == STATUS_SUCCESS) { - FILE_FULL_DIR_INFORMATION* info = - reinterpret_cast<FILE_FULL_DIR_INFORMATION*>(buffer); - void* endPos = buffer + status.Information; - while (info < endPos) { - FileResult file; - file.fileName = - std::wstring(info->FileName, info->FileNameLength / sizeof(wchar_t)); - file.attributes = info->FileAttributes; - - result.push_back(file); - if (info->NextEntryOffset == 0) { - break; - } else { - info = reinterpret_cast<FILE_FULL_DIR_INFORMATION*>( - reinterpret_cast<uint8_t*>(info) + info->NextEntryOffset); - } - } - } - } - - return result; -} - -bool createPath(boost::filesystem::path path, LPSECURITY_ATTRIBUTES securityAttributes) -{ - // sanity and guaranteed recursion end: - if (!path.has_relative_path()) - throw usvfs::shared::windows_error( - "createPath() refusing to create non-existing top level path: " + - path.string()); - - DWORD attr = GetFileAttributesW(path.c_str()); - DWORD err = GetLastError(); - if (attr != INVALID_FILE_ATTRIBUTES) { - if (attr & FILE_ATTRIBUTE_DIRECTORY) - return false; // if directory already exists all is good - else - throw usvfs::shared::windows_error("createPath() called on a file: " + - path.string()); - } - if (err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND) - throw usvfs::shared::windows_error( - "createPath() GetFileAttributesW failed on: " + path.string(), err); - - if (err != ERROR_FILE_NOT_FOUND) // ERROR_FILE_NOT_FOUND means parent directory - // already exists - createPath(path.parent_path(), - securityAttributes); // otherwise create parent directory (recursively) - - BOOL res = CreateDirectoryW(path.c_str(), securityAttributes); - if (!res) { - err = GetLastError(); - throw usvfs::shared::windows_error( - "createPath() CreateDirectoryW failed on: " + path.string(), err); - } - return true; -} - -std::wstring getWindowsBuildLab(bool ex) -{ - HKEY hKey = nullptr; - auto res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", 0, - KEY_READ, &hKey); - if (res != ERROR_SUCCESS || !hKey) - return L"Opening HKLM Windows NT\\CurrentVersion failed?!"; - WCHAR buf[200]; - DWORD size = static_cast<DWORD>(sizeof(buf)); - res = RegQueryValueExW(hKey, ex ? L"BuildLabEx" : L"BuildLab", NULL, NULL, - reinterpret_cast<LPBYTE>(buf), &size); - if (res != ERROR_SUCCESS || size > sizeof(buf)) - return ex ? L"BuildLabEx reg value not found?!" : L"BuildLab reg value not found?!"; - size /= sizeof(buf[0]); - if (size && !buf[size - 1]) - --size; - return std::wstring(buf, size); -} - -} // namespace winapi::ex::wide diff --git a/libs/usvfs/src/shared/winapi.h b/libs/usvfs/src/shared/winapi.h deleted file mode 100644 index f94eff6..0000000 --- a/libs/usvfs/src/shared/winapi.h +++ /dev/null @@ -1,610 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include "logging.h" -#include "stringcast.h" -#include "windows_sane.h" -#include <ShlObj.h> - -#define ALIAS(alias, original) \ - template <typename... Args> \ - auto alias(Args&&... args) -> decltype(original(std::forward<Args>(args)...)) \ - { \ - return original(std::forward<Args>(args)...); \ - } - -#define ALIAST(alias, original) \ - template <typename T, typename... Args> \ - auto alias<T>(Args && ... args) \ - -> decltype(original<T>(std::forward<Args>(args)...)) \ - { \ - return original<T>(std::forward<Args>(args)...); \ - } - -namespace winapi -{ - -struct parameter_error : public std::runtime_error -{ - parameter_error(const std::string& msg) : runtime_error(msg) {} -}; - -} // namespace winapi - -namespace winapi::process -{ - -/** - * @brief result of process creation - */ -struct Result -{ - Result() - { - ::ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION)); - ::ZeroMemory(&startupInfo, sizeof(STARTUPINFO)); - startupInfo.cb = sizeof(STARTUPINFO); - } - - Result(Result&& reference) - : valid(reference.valid), startupInfo(reference.startupInfo), - processInfo(reference.processInfo), errorCode(reference.errorCode) - { - reference.valid = false; - } - - ~Result() - { - if (valid) { - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - - if (stdoutPipe != INVALID_HANDLE_VALUE) { - CloseHandle(stdoutPipe); - } - } - - Result(const Result&) = delete; - - size_t readStdout(std::vector<uint8_t>& buffer, bool& eof) - { - if (stdoutPipe != INVALID_HANDLE_VALUE) { - DWORD read; - BOOL res = ReadFile(stdoutPipe, &buffer[0], static_cast<DWORD>(buffer.size()), - &read, nullptr); - eof = (res == TRUE) && (read == 0); - return static_cast<size_t>(read); - } else { - eof = true; - return 0; - } - } - - bool valid{false}; - STARTUPINFO startupInfo; - PROCESS_INFORMATION processInfo; - DWORD errorCode{0UL}; - - HANDLE stdoutPipe{INVALID_HANDLE_VALUE}; -}; - -/** - * @brief internal class to handle process creation with named parameters. - */ -template <typename CharT> -class _Create -{ -public: - _Create(const std::basic_string<CharT>& binaryName); - _Create(const _Create<CharT>& reference) = delete; - _Create<CharT>& operator=(const _Create<CharT>& reference) = delete; - - _Create(_Create<CharT>&& reference) - : m_CurrentDirectory(std::move(reference.m_CurrentDirectory)), - m_ProcessAttributes(reference.m_ProcessAttributes), - m_ThreadAttributes(reference.m_ThreadAttributes), - m_InheritHandles(reference.m_InheritHandles), - m_CreationFlags(std::move(reference.m_CreationFlags)), - m_Executed(reference.m_Executed) - { - // stringstream should be moveable but it seems it isn't on mingw - m_CommandLine << reference.m_CommandLine.rdbuf(); - } - - /// named parameter "argument". May be called repeatedly. This is - /// directly appended to the command line with a separating space. No - /// quoting happens - template <typename ArgT> - _Create& argument(const ArgT& argin) - { - m_CommandLine << " " << argin; - return *this; - } - - template <typename ArgT> - _Create& arg(const ArgT& argin) - { - return this->argument(argin); - } - - template <typename IterT> - _Create& arguments(IterT begin, IterT end) - { - for (; begin != end; ++begin) { - m_CommandLine << " " << *begin; - } - - return *this; - } - - /// @brief set the working directory for the process - _Create& workingDirectory(const std::basic_string<CharT>& path); - - /// @brief set process attributes - _Create& processAttributes(SECURITY_ATTRIBUTES* attributes); - - /// @brief set thread attributes - _Create& threadAttributes(SECURITY_ATTRIBUTES* attributes); - - /// @brief activate inheriting handles - _Create& inheritHandles(); - - /// @brief have the process start suspended - _Create& suspended(); - - /// @brief set the process up to output stout to a pipe which can be - /// retrieved through the result object - _Create& stdoutPipe(); - - /// @brief end the named parameter cascade and create the process - Result operator()() - { - m_CommandLine.seekp(0, std::ios::end); - unsigned int length = static_cast<unsigned int>(m_CommandLine.tellp()); - std::unique_ptr<CharT[]> clBuffer(new CharT[length + 1]); - memset(clBuffer.get(), 0, (length + 1) * sizeof(CharT)); - memcpy(clBuffer.get(), m_CommandLine.str().c_str(), length * sizeof(CharT)); - Result result; - - if (m_StdoutPipe) { - result.stdoutPipe = setupPipe(result.startupInfo.hStdOutput); - result.startupInfo.dwFlags |= STARTF_USESTDHANDLES; - } - - result.valid = - createProcessInt(nullptr, clBuffer.get(), m_ProcessAttributes, - m_ThreadAttributes, m_InheritHandles, m_CreationFlags, nullptr, - m_CurrentDirectory.length() > 0 ? m_CurrentDirectory.c_str() - : nullptr, - &result.startupInfo, &result.processInfo) == TRUE; - - if (m_Stdout != INVALID_HANDLE_VALUE) { - // got to close the write end of pipes - CloseHandle(result.startupInfo.hStdOutput); - } - - if (result.valid) { - result.errorCode = NOERROR; - } else { - result.errorCode = GetLastError(); - } - return result; - } - -private: - static BOOL createProcessInt(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, - SECURITY_ATTRIBUTES* lpProcessAttributes, - SECURITY_ATTRIBUTES* lpThreadAttributes, - BOOL bInheritHandles, DWORD dwCreationFlags, - LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, - LPSTARTUPINFOW lpStartupInfo, - LPPROCESS_INFORMATION lpProcessInformation) - { - return ::CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, - lpThreadAttributes, bInheritHandles, dwCreationFlags, - lpEnvironment, lpCurrentDirectory, lpStartupInfo, - lpProcessInformation); - } - - static BOOL createProcessInt(LPCSTR lpApplicationName, LPSTR lpCommandLine, - SECURITY_ATTRIBUTES* lpProcessAttributes, - SECURITY_ATTRIBUTES* lpThreadAttributes, - BOOL bInheritHandles, DWORD dwCreationFlags, - LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, - LPSTARTUPINFOW lpStartupInfo, - LPPROCESS_INFORMATION lpProcessInformation) - { - std::wstring executable; - if (lpApplicationName != nullptr) { - executable = usvfs::shared::string_cast<std::wstring>(lpApplicationName); - } - - std::wstring cmdline; - if (lpCommandLine != nullptr) { - cmdline = usvfs::shared::string_cast<std::wstring>(lpCommandLine); - } - - std::wstring cwd; - if (lpCurrentDirectory != nullptr) { - cwd = usvfs::shared::string_cast<std::wstring>(lpCurrentDirectory); - } - - return ::CreateProcessW(lpApplicationName != nullptr ? executable.c_str() : nullptr, - lpCommandLine != nullptr ? &cmdline[0] : nullptr, - lpProcessAttributes, lpThreadAttributes, bInheritHandles, - dwCreationFlags, lpEnvironment, - lpCurrentDirectory != nullptr ? cwd.c_str() : nullptr, - lpStartupInfo, lpProcessInformation); - } - - HANDLE setupPipe(HANDLE& childHandle) - { - SECURITY_ATTRIBUTES attr; - attr.nLength = sizeof(SECURITY_ATTRIBUTES); - attr.bInheritHandle = TRUE; - attr.lpSecurityDescriptor = nullptr; - - HANDLE pipe[2]; - - CreatePipe(&pipe[0], &pipe[1], &attr, 0); - SetHandleInformation(pipe[0], HANDLE_FLAG_INHERIT, 0); - - childHandle = pipe[1]; - - return pipe[0]; - } - -private: - std::basic_stringstream<CharT> m_CommandLine; - std::basic_string<CharT> m_CurrentDirectory{}; - SECURITY_ATTRIBUTES* m_ProcessAttributes{nullptr}; - SECURITY_ATTRIBUTES* m_ThreadAttributes{nullptr}; - BOOL m_InheritHandles{false}; - DWORD m_CreationFlags{0UL}; - bool m_Executed{false}; - bool m_StdoutPipe{false}; - - HANDLE m_Stdout{INVALID_HANDLE_VALUE}; -}; - -} // namespace winapi::process - -namespace winapi::file -{ -/** - * @brief internal class to handle file creation (opening) with named - * parameters. - */ -template <typename CharT, DWORD DefaultDisposition> -class _Create -{ -public: - _Create(const std::basic_string<CharT>& fileName) : m_FileName(fileName) {} - - _Create& access(DWORD desiredAccess) - { - m_DesiredAccess = desiredAccess; - return *this; - } - - _Create& share(DWORD shareMode) - { - m_ShareMode = shareMode; - return *this; - } - - _Create& createAlways() - { - m_CreationDisposition = CREATE_ALWAYS; - return *this; - } - - _Create& openAlways() - { - m_CreationDisposition = OPEN_ALWAYS; - return *this; - } - - _Create& security(SECURITY_ATTRIBUTES* attributes) - { - m_SecurityAttributes = attributes; - return *this; - } - - _Create& templateFile(HANDLE templateFile) - { - m_Template = templateFile; - return *this; - } - - /// @brief end the named parameter cascade and open the file - HANDLE operator()() - { - return callDelegate( - std::integral_constant<bool, sizeof(CharT) == sizeof(wchar_t)>()); - } - -private: - HANDLE callDelegate(std::true_type) - { - return ::CreateFileW(m_FileName.c_str(), m_DesiredAccess, m_ShareMode, - m_SecurityAttributes, m_CreationDisposition, m_Flags, - m_Template); - } - - HANDLE callDelegate(std::false_type) - { - return ::CreateFileA(m_FileName.c_str(), m_DesiredAccess, m_ShareMode, - m_SecurityAttributes, m_CreationDisposition, m_Flags, - m_Template); - } - -private: - std::basic_string<CharT> m_FileName; - DWORD m_DesiredAccess{GENERIC_ALL}; - DWORD m_ShareMode{0UL}; - DWORD m_CreationDisposition{DefaultDisposition}; - DWORD m_Flags{FILE_ATTRIBUTE_NORMAL}; - HANDLE m_Template{nullptr}; - SECURITY_ATTRIBUTES* m_SecurityAttributes{nullptr}; -}; - -} // namespace winapi::file - -namespace winapi::ansi -{ - -std::string getModuleFileName(HMODULE module, HANDLE process = INVALID_HANDLE_VALUE); -std::pair<std::string, std::string> getFullPathName(LPCSTR fileName); -std::string getCurrentDirectory(); -typedef process::_Create<char> createProcess; -typedef file::_Create<char, CREATE_NEW> createFile; -typedef file::_Create<char, OPEN_EXISTING> openFile; - -} // namespace winapi::ansi - -namespace winapi::wide -{ - -std::wstring getModuleFileName(HMODULE module, HANDLE process = INVALID_HANDLE_VALUE); -std::pair<std::wstring, std::wstring> getFullPathName(LPCWSTR fileName); -std::wstring getCurrentDirectory(); -std::wstring getKnownFolderPath(REFKNOWNFOLDERID folderID); - -typedef process::_Create<wchar_t> createProcess; -typedef file::_Create<wchar_t, CREATE_NEW> createFile; -typedef file::_Create<wchar_t, OPEN_EXISTING> openFile; - -} // namespace winapi::wide - -/** - * useful convenience functions close to the api - */ -namespace winapi::ex -{ - -/** - * @brief retrieve the address range covering the code section of a module - * @param moduleHandle handle to the module - * @return start and end address of the code section - * @note the code section can only be identified if it has the standardized section name - * ".text" Otherwise the whole address range of all sections in the module is returned. - * This happens for compressed exectuables for example - */ -std::pair<uintptr_t, uintptr_t> getSectionRange(HANDLE moduleHandle); - -struct OSVersion -{ - DWORD major; - DWORD minor; - DWORD build; - DWORD platformid; - DWORD servicpack; -}; - -OSVersion getOSVersion(); - -} // namespace winapi::ex - -namespace winapi::ex::ansi -{ - -/** - * @brief retrieve an error string for a windows error message - * @param errorCode the error code to look up. If this is left at the default, - * ::GetLastError is used - * @return string representation of the error. Currently this is localized - */ -std::string errorString(DWORD errorCode = std::numeric_limits<DWORD>::max()); - -/** - * @brief convert filetime to string - * @param time time to convert - * @return a string representation (currently only supports utc and iso format with - * second precision) - */ -std::string toString(const FILETIME& time); - -/** - * @brief find file name in a windows file path - * @param path the path to search in - * @return the file name of the path or an empty string if the path ends on - * a slash - * @note this function doesn't access the file system so it doesn't depend - * on whether the file actually exists. This also means it can't - * determine if a path that doesn't end on a slash refers to a file or - * directory - * @note the return value is a pointer into the same buffer, no copy is - * created - */ -LPCSTR GetBaseName(LPCSTR string); - -} // namespace winapi::ex::ansi - -namespace winapi::ex::wide -{ -/** - * retrieve the name of the binary section containing the specified address - * @param address the address to test - * @param process the process for which to retrieve the section. If this is - * nullptr, the current process is analized. - * @return name of the section or "unknown" if no matching section was found - */ -std::wstring getSectionName(PVOID address, HANDLE process = nullptr); - -/** - * @brief test if a file exists - * @param path path to check - * @param isDirectory (optional) if this isn't null, it will be set to true if the path - * specifies a directory, false otherwise - * @return true if the file (or directory) exists. - */ -bool fileExists(LPCWSTR fileName, bool* isDirectory = nullptr); - -/** - * @brief retrieve an error string for a windows error message - * @param errorCode the error code to look up. If this is left at the default, - * ::GetLastError is used - * @return string representation of the error. Currently this is localized - */ -std::wstring errorString(DWORD errorCode = std::numeric_limits<DWORD>::max()); - -/** - * @brief convert filetime to string - * @param time time to convert - * @return a string representation (currently only supports utc and iso format with - * second precision) - */ -std::wstring toString(const FILETIME& time); - -/** - * @brief find file name in a windows file path - * @param path the path to search in - * @return the file name of the path or an empty string if the path ends on - * a slash - * @note this function doesn't access the file system so it doesn't depend - * on whether the file actually exists. This also means it can't - * determine if a path that doesn't end on a slash refers to a file or - * directory - * @note the return value is a pointer into the same buffer, no copy is - * created - */ -LPCWSTR GetBaseName(LPCWSTR path); - -/** - * @see const-variant of this function - */ -LPWSTR GetBaseName(LPWSTR path); - -struct FileResult -{ - std::wstring fileName; - ULONG attributes; -}; - -/** - * @brief a quick function to find all files in a directory or files following a - * pattern. This uses NtQueryDirectoryFile api internally so it should be faster than - * the usual FindFirstFile/FindNextFile pattern - * @param directoryName name of the directory to search in - * @param pattern name pattern that needs to match - * @return the list of files found - */ -std::vector<FileResult> quickFindFiles(LPCWSTR directoryName, LPCWSTR pattern); - -/** - * @brief create the specified directory including all intermediate - * directories - * @param path the path to create - * @param securityAttributes the security attributes to use for all created - * directories. if this is null (default), the standard attributes - * are used - * @return true if the directory (and possibly parent directories) were actually created - * and false if the directory already existed. Throws exceptions on failure. - */ -bool createPath(boost::filesystem::path path, - LPSECURITY_ATTRIBUTES securityAttributes = nullptr); -inline bool createPath(LPCWSTR path, LPSECURITY_ATTRIBUTES securityAttributes = nullptr) -{ - return createPath(boost::filesystem::path(path), securityAttributes); -} - -std::wstring getWindowsBuildLab(bool ex = false); - -} // namespace winapi::ex::wide - -namespace winapi::process -{ - -template <typename CharT> -_Create<CharT>::_Create(const std::basic_string<CharT>& binaryName) -{ - if (binaryName.length() > MAX_PATH) { - throw parameter_error("executable filename can't be longer than 260 characters"); - } - m_CommandLine << "\"" << binaryName << "\""; -} - -template <typename CharT> -_Create<CharT>& _Create<CharT>::workingDirectory(const std::basic_string<CharT>& path) -{ - m_CurrentDirectory = path; - return *this; -} - -template <typename CharT> -_Create<CharT>& _Create<CharT>::processAttributes(SECURITY_ATTRIBUTES* attributes) -{ - m_ProcessAttributes = attributes; - return *this; -} - -template <typename CharT> -_Create<CharT>& _Create<CharT>::threadAttributes(SECURITY_ATTRIBUTES* attributes) -{ - m_ThreadAttributes = attributes; - return *this; -} - -template <typename CharT> -_Create<CharT>& _Create<CharT>::inheritHandles() -{ - m_InheritHandles = true; - return *this; -} - -template <typename CharT> -_Create<CharT>& _Create<CharT>::suspended() -{ - m_CreationFlags |= CREATE_SUSPENDED; - return *this; -} - -template <typename CharT> -_Create<CharT>& _Create<CharT>::stdoutPipe() -{ - m_StdoutPipe = true; - return *this; -} - -} // namespace winapi::process diff --git a/libs/usvfs/src/shared/windows_sane.h b/libs/usvfs/src/shared/windows_sane.h deleted file mode 100644 index 7bb3726..0000000 --- a/libs/usvfs/src/shared/windows_sane.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#define WIN32_LEAN_AND_MEAN -#include <Windows.h> |
