diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-02-11 02:37:39 -0600 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-02-11 02:37:39 -0600 |
| commit | 7ee008e150bc5bcf76082d726f719ee0fdfda982 (patch) | |
| tree | 27fb39be241fdb5ac2734c574de678977d1856d0 /libs/usvfs/include | |
Fluorine Manager: full Linux port of Mod Organizer 2
Complete native Linux port with FUSE-based virtual filesystem,
Proton/umu-run integration, and Flatpak packaging.
Key features:
- FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak)
- Proton/GE-Proton/umu-run launcher with env var forwarding
- Flatpak support (sandbox-aware VFS, NXM handler, umu-run)
- Wine prefix management UI
- Case-insensitive path resolution for Linux filesystems
- QSettings-safe INI handling (avoids Bethesda INI corruption)
- Portable instance support with auto-generated launcher scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'libs/usvfs/include')
| -rw-r--r-- | libs/usvfs/include/usvfs/dllimport.h | 31 | ||||
| -rw-r--r-- | libs/usvfs/include/usvfs/logging.h | 29 | ||||
| -rw-r--r-- | libs/usvfs/include/usvfs/sharedparameters.h | 112 | ||||
| -rw-r--r-- | libs/usvfs/include/usvfs/usvfs.h | 232 | ||||
| -rw-r--r-- | libs/usvfs/include/usvfs/usvfs_version.h | 30 | ||||
| -rw-r--r-- | libs/usvfs/include/usvfs/usvfsparameters.h | 68 | ||||
| -rw-r--r-- | libs/usvfs/include/usvfs/usvfsparametersprivate.h | 32 |
7 files changed, 534 insertions, 0 deletions
diff --git a/libs/usvfs/include/usvfs/dllimport.h b/libs/usvfs/include/usvfs/dllimport.h new file mode 100644 index 0000000..c17f648 --- /dev/null +++ b/libs/usvfs/include/usvfs/dllimport.h @@ -0,0 +1,31 @@ +/* +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 DLLEXPORT + +#ifdef BUILDING_USVFS_DLL +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT __declspec(dllimport) +#endif + +#endif DLLEXPORT diff --git a/libs/usvfs/include/usvfs/logging.h b/libs/usvfs/include/usvfs/logging.h new file mode 100644 index 0000000..4647df5 --- /dev/null +++ b/libs/usvfs/include/usvfs/logging.h @@ -0,0 +1,29 @@ +/* +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 + +enum class LogLevel : uint8_t +{ + Debug, + Info, + Warning, + Error +}; diff --git a/libs/usvfs/include/usvfs/sharedparameters.h b/libs/usvfs/include/usvfs/sharedparameters.h new file mode 100644 index 0000000..f428dc0 --- /dev/null +++ b/libs/usvfs/include/usvfs/sharedparameters.h @@ -0,0 +1,112 @@ +#pragma once + +#include "dllimport.h" +#include "usvfsparameters.h" +#include <shared_memory.h> + +namespace usvfs +{ + +class ForcedLibrary +{ +public: + ForcedLibrary(const std::string& processName, const std::string& libraryPath, + const shared::VoidAllocatorT& allocator); + + std::string processName() const; + std::string libraryPath() const; + +private: + shared::StringT m_processName; + shared::StringT m_libraryPath; +}; + +class DLLEXPORT SharedParameters +{ +public: + SharedParameters() = delete; + SharedParameters(const SharedParameters& reference) = delete; + SharedParameters& operator=(const SharedParameters& reference) = delete; + + SharedParameters(const usvfsParameters& reference, + const shared::VoidAllocatorT& allocator); + + usvfsParameters makeLocal() const; + + std::string instanceName() const; + std::string currentSHMName() const; + std::string currentInverseSHMName() const; + void setSHMNames(const std::string& current, const std::string& inverse); + + void setDebugParameters(LogLevel level, CrashDumpsType dumpType, + const std::string& dumpPath, + std::chrono::milliseconds delayProcess); + + std::size_t userConnected(); + std::size_t userDisconnected(); + std::size_t userCount(); + + std::size_t registeredProcessCount() const; + std::vector<DWORD> registeredProcesses() const; + void registerProcess(DWORD pid); + void unregisterProcess(DWORD pid); + + void blacklistExecutable(const std::string& name); + void clearExecutableBlacklist(); + bool executableBlacklisted(const std::string& app, const std::string& cmd) const; + + void addSkipFileSuffix(const std::string& fileSuffix); + void clearSkipFileSuffixes(); + std::vector<std::string> skipFileSuffixes() const; + + void addSkipDirectory(const std::string& directory); + void clearSkipDirectories(); + std::vector<std::string> skipDirectories() const; + + void addForcedLibrary(const std::string& process, const std::string& path); + std::vector<std::string> forcedLibraries(const std::string& processName); + void clearForcedLibraries(); + +private: + using StringAllocatorT = shared::VoidAllocatorT::rebind<shared::StringT>::other; + + using DWORDAllocatorT = shared::VoidAllocatorT::rebind<DWORD>::other; + + using ForcedLibraryAllocatorT = shared::VoidAllocatorT::rebind<ForcedLibrary>::other; + + using ProcessBlacklist = + boost::container::flat_set<shared::StringT, std::less<shared::StringT>, + StringAllocatorT>; + + using ProcessList = + boost::container::flat_set<DWORD, std::less<DWORD>, DWORDAllocatorT>; + + using FileSuffixSkipList = + boost::container::flat_set<shared::StringT, std::less<shared::StringT>, + StringAllocatorT>; + + using DirectorySkipList = + boost::container::flat_set<shared::StringT, std::less<shared::StringT>, + StringAllocatorT>; + + using ForcedLibraries = + boost::container::slist<ForcedLibrary, ForcedLibraryAllocatorT>; + + mutable bi::interprocess_mutex m_mutex; + shared::StringT m_instanceName; + shared::StringT m_currentSHMName; + shared::StringT m_currentInverseSHMName; + bool m_debugMode; + LogLevel m_logLevel; + CrashDumpsType m_crashDumpsType; + shared::StringT m_crashDumpsPath; + std::chrono::milliseconds m_delayProcess; + uint32_t m_userCount; + ProcessBlacklist m_processBlacklist; + ProcessList m_processList; + FileSuffixSkipList m_fileSuffixSkipList; + DirectorySkipList m_directorySkipList; + ForcedLibraries m_forcedLibraries; +}; + +} // namespace usvfs diff --git a/libs/usvfs/include/usvfs/usvfs.h b/libs/usvfs/include/usvfs/usvfs.h new file mode 100644 index 0000000..6754922 --- /dev/null +++ b/libs/usvfs/include/usvfs/usvfs.h @@ -0,0 +1,232 @@ +/* +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 "usvfsparameters.h" + +/* + * Virtual operations: + * - link file + * - link directory (empty) + * - link directory (static) + * - link directory (dynamic) + * - delete file + * - delete directory + * Maybe: + * - rename/move (= copy + delete) + * - copy-on-write semantics (changes to files are done in a separate copy of the + * file, the original is kept on disc but hidden) + */ + +static const unsigned int LINKFLAG_FAILIFEXISTS = + 0x00000001; // if set, linking fails in case of an error +static const unsigned int LINKFLAG_MONITORCHANGES = + 0x00000002; // if set, changes to the source directory after the link operation + // will be updated in the virtual fs. only relevant in static + // link directory operations +static const unsigned int LINKFLAG_CREATETARGET = + 0x00000004; // if set, file creation (including move or copy) operations to + // destination will be redirected to the source. Only one createtarget + // can be set for a destination folder so this flag will replace + // the previous create target. + // If there different create-target have been set for an element and + // one of its ancestors, the inner-most create-target is used +static const unsigned int LINKFLAG_RECURSIVE = + 0x00000008; // if set, directories are linked recursively +static const unsigned int LINKFLAG_FAILIFSKIPPED = + 0x00000010; // if set, linking fails if the file or directory is skipped + // files or directories are skipped depending on whats been added to + // the skip file suffixes or skip directories list in + // the sharedparameters class, those lists are checked during virtual + // linking + +extern "C" +{ + + /** + * removes all virtual mappings + */ + DLLEXPORT void WINAPI usvfsClearVirtualMappings(); + + /** + * link a file virtually + * @note: the directory the destination file resides in has to exist - at least + * virtually. + */ + DLLEXPORT BOOL WINAPI usvfsVirtualLinkFile(LPCWSTR source, LPCWSTR destination, + unsigned int flags); + + /** + * link a directory virtually. This static variant recursively links all files + * individually, change notifications are used to update the information. + * @param failIfExists if true, this call fails if the destination directory exists + * (virtually or physically) + */ + DLLEXPORT BOOL WINAPI usvfsVirtualLinkDirectoryStatic(LPCWSTR source, + LPCWSTR destination, + unsigned int flags); + + /** + * connect to a virtual filesystem as a controller, without hooking the calling + * process. Please note that you can only be connected to one vfs, so this will + * silently disconnect from a previous vfs. + */ + DLLEXPORT BOOL WINAPI usvfsConnectVFS(const usvfsParameters* p); + + /** + * @brief create a new VFS. This is similar to ConnectVFS except it guarantees + * the vfs is reset before use. + */ + DLLEXPORT BOOL WINAPI usvfsCreateVFS(const usvfsParameters* p); + + /** + * disconnect from a virtual filesystem. This removes hooks if necessary + */ + DLLEXPORT void WINAPI usvfsDisconnectVFS(); + + DLLEXPORT void WINAPI usvfsGetCurrentVFSName(char* buffer, size_t size); + + /** + * retrieve a list of all processes connected to the vfs + */ + DLLEXPORT BOOL WINAPI usvfsGetVFSProcessList(size_t* count, LPDWORD processIDs); + + // retrieve a list of all processes connected to the vfs, stores an array + // of `count` elements in `*buffer` + // + // if this returns TRUE and `count` is not 0, the caller must release the buffer + // with `free(*buffer)` + // + // return values: + // - ERROR_INVALID_PARAMETERS: either `count` or `buffer` is NULL + // - ERROR_TOO_MANY_OPEN_FILES: there seems to be way too many usvfs processes + // running, probably some internal error + // - ERROR_NOT_ENOUGH_MEMORY: malloc() failed + // + DLLEXPORT BOOL WINAPI usvfsGetVFSProcessList2(size_t* count, DWORD** buffer); + + /** + * spawn a new process that can see the virtual file system. The signature is + * identical to CreateProcess + */ + DLLEXPORT BOOL WINAPI usvfsCreateProcessHooked( + LPCWSTR lpApplicationName, LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, + DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation); + + /** + * retrieve a single log message. + * FIXME There is currently no way to unblock from the caller side + * FIXME retrieves log messages from all instances, the logging queue is not separated + */ + DLLEXPORT bool WINAPI usvfsGetLogMessages(LPSTR buffer, size_t size, + bool blocking = false); + + /** + * retrieves a readable representation of the vfs tree + * @param buffer the buffer to write to. this may be null if you only want to + * determine the required buffer size + * @param size pointer to a variable that contains the buffer. After the call + * this value will have been updated to contain the required size, + * even if this is bigger than the buffer size + */ + DLLEXPORT BOOL WINAPI usvfsCreateVFSDump(LPSTR buffer, size_t* size); + + /** + * adds an executable to the blacklist so it doesn't get exposed to the virtual + * file system + * @param executableName name of the executable + */ + DLLEXPORT VOID WINAPI usvfsBlacklistExecutable(LPCWSTR executableName); + + /** + * clears the executable blacklist + */ + DLLEXPORT VOID WINAPI usvfsClearExecutableBlacklist(); + + /** + * adds a file suffix to a list to skip during file linking + * .txt and some_file.txt are both valid file suffixes, + * not to be confused with file extensions + * @param fileSuffix a valid file suffix + */ + DLLEXPORT VOID WINAPI usvfsAddSkipFileSuffix(LPCWSTR fileSuffix); + + /** + * clears the file suffix skip-list + */ + DLLEXPORT VOID WINAPI usvfsClearSkipFileSuffixes(); + + /** + * adds a directory name that will be skipped during directory linking. + * Not a path. Any directory matching the name will be skipped, + * regardless of it's path, for example if .git is added, + * any sub-path or root-path containing a .git directory + * will have the .git directory skipped during directory linking + * @param directory name of the directory + */ + DLLEXPORT VOID WINAPI usvfsAddSkipDirectory(LPCWSTR directory); + + /** + * clears the directory skip-list + */ + DLLEXPORT VOID WINAPI usvfsClearSkipDirectories(); + + /** + * adds a library to be force loaded when the given process is injected + * @param + */ + DLLEXPORT VOID WINAPI usvfsForceLoadLibrary(LPCWSTR processName, LPCWSTR libraryPath); + + /** + * clears all previous calls to ForceLoadLibrary + */ + DLLEXPORT VOID WINAPI usvfsClearLibraryForceLoads(); + + /** + * print debugging info about the vfs. The format is currently not fixed and may + * change between usvfs versions + */ + DLLEXPORT VOID WINAPI usvfsPrintDebugInfo(); + + // #if defined(UNITTEST) || defined(_WINDLL) + DLLEXPORT void WINAPI usvfsInitLogging(bool toLocal = false); + // #endif + + /** + * used internally to initialize a process at startup-time as a "slave". Don't call + * directly + */ + DLLEXPORT void __cdecl InitHooks(LPVOID userData, size_t userDataSize); + + // the instance and shm names are not updated + // + DLLEXPORT void WINAPI usvfsUpdateParameters(usvfsParameters* p); + + DLLEXPORT int WINAPI usvfsCreateMiniDump(PEXCEPTION_POINTERS exceptionPtrs, + CrashDumpsType type, + const wchar_t* dumpPath); + + DLLEXPORT const char* WINAPI usvfsVersionString(); +} diff --git a/libs/usvfs/include/usvfs/usvfs_version.h b/libs/usvfs/include/usvfs/usvfs_version.h new file mode 100644 index 0000000..03e0cf0 --- /dev/null +++ b/libs/usvfs/include/usvfs/usvfs_version.h @@ -0,0 +1,30 @@ +#pragma once + +#define USVFS_VERSION_MAJOR 0 +#define USVFS_VERSION_MINOR 5 +#define USVFS_VERSION_BUILD 7 +#define USVFS_VERSION_REVISION 2 + +#define USVFS_BUILD_STRING "" +#define USVFS_BUILD_WSTRING L"" + +#ifndef USVFS_STRINGIFY +#define USVFS_STRINGIFY(x) USVFS_STRINGIFY_HELPER(x) +#define USVFS_STRINGIFY_HELPER(x) #x +#endif + +#ifndef USVFS_STRINGIFYW +#define USVFS_STRINGIFYW(x) USVFS_STRINGIFYW_HELPER(x) +#define USVFS_STRINGIFYW_HELPER(x) L## #x +#endif + +#define USVFS_VERSION_STRING \ + USVFS_STRINGIFY(USVFS_VERSION_MAJOR) \ + "." USVFS_STRINGIFY(USVFS_VERSION_MINOR) "." USVFS_STRINGIFY( \ + USVFS_VERSION_BUILD) "." USVFS_STRINGIFY(USVFS_VERSION_REVISION) \ + USVFS_BUILD_STRING +#define USVFS_VERSION_WSTRING \ + USVFS_STRINGIFYW(USVFS_VERSION_MAJOR) \ + L"." USVFS_STRINGIFYW(USVFS_VERSION_MINOR) L"." USVFS_STRINGIFYW( \ + USVFS_VERSION_BUILD) L"." USVFS_STRINGIFYW(USVFS_VERSION_REVISION) \ + USVFS_BUILD_WSTRING diff --git a/libs/usvfs/include/usvfs/usvfsparameters.h b/libs/usvfs/include/usvfs/usvfsparameters.h new file mode 100644 index 0000000..1351d69 --- /dev/null +++ b/libs/usvfs/include/usvfs/usvfsparameters.h @@ -0,0 +1,68 @@ +/* +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 "logging.h" +#include <chrono> + +enum class CrashDumpsType : uint8_t +{ + None, + Mini, + Data, + Full +}; + +extern "C" +{ + + // deprecated, use usvfsParameters and usvfsCreateParameters() + // + struct USVFSParameters + { + char instanceName[65]; + char currentSHMName[65]; + char currentInverseSHMName[65]; + bool debugMode{false}; + LogLevel logLevel{LogLevel::Debug}; + CrashDumpsType crashDumpsType{CrashDumpsType::None}; + char crashDumpsPath[260]; + }; + + struct usvfsParameters; + + DLLEXPORT usvfsParameters* usvfsCreateParameters(); + DLLEXPORT usvfsParameters* usvfsDupeParameters(usvfsParameters* p); + DLLEXPORT void usvfsCopyParameters(const usvfsParameters* source, + usvfsParameters* dest); + DLLEXPORT void usvfsFreeParameters(usvfsParameters* p); + + DLLEXPORT void usvfsSetInstanceName(usvfsParameters* p, const char* name); + DLLEXPORT void usvfsSetDebugMode(usvfsParameters* p, BOOL debugMode); + DLLEXPORT void usvfsSetLogLevel(usvfsParameters* p, LogLevel level); + DLLEXPORT void usvfsSetCrashDumpType(usvfsParameters* p, CrashDumpsType type); + DLLEXPORT void usvfsSetCrashDumpPath(usvfsParameters* p, const char* path); + DLLEXPORT void usvfsSetProcessDelay(usvfsParameters* p, int milliseconds); + + DLLEXPORT const char* usvfsLogLevelToString(LogLevel lv); + DLLEXPORT const char* usvfsCrashDumpTypeToString(CrashDumpsType t); +} diff --git a/libs/usvfs/include/usvfs/usvfsparametersprivate.h b/libs/usvfs/include/usvfs/usvfsparametersprivate.h new file mode 100644 index 0000000..6c2d5f2 --- /dev/null +++ b/libs/usvfs/include/usvfs/usvfsparametersprivate.h @@ -0,0 +1,32 @@ +#pragma once +#include "usvfsparameters.h" + +struct usvfsParameters +{ + char instanceName[65]; + char currentSHMName[65]; + char currentInverseSHMName[65]; + bool debugMode; + LogLevel logLevel{LogLevel::Debug}; + CrashDumpsType crashDumpsType{CrashDumpsType::None}; + char crashDumpsPath[260]; + int delayProcessMs; + + usvfsParameters(); + usvfsParameters(const usvfsParameters&) = default; + usvfsParameters& operator=(const usvfsParameters&) = default; + + usvfsParameters(const char* instanceName, const char* currentSHMName, + const char* currentInverseSHMName, bool debugMode, LogLevel logLevel, + CrashDumpsType crashDumpsType, const char* crashDumpsPath, + int delayProcessMs); + + usvfsParameters(const USVFSParameters& oldParams); + + void setInstanceName(const char* name); + void setDebugMode(bool debugMode); + void setLogLevel(LogLevel level); + void setCrashDumpType(CrashDumpsType type); + void setCrashDumpPath(const char* path); + void setProcessDelay(int milliseconds); +}; |
