From 45060f03b67c87e548466f6f5a81473cd004e6e7 Mon Sep 17 00:00:00 2001 From: asypost Date: Fri, 31 Jul 2026 17:20:58 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8E=89=E5=85=B6=E4=B8=AD?= =?UTF-8?q?=E6=9C=89=E9=97=AE=E9=A2=98=E7=9A=84=E5=9C=B0=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/seafile/fs/seafile_store.hpp | 4 +- src/main.cpp | 2 +- src/seafile/fs/seafile_file_system.cpp | 2 +- src/seafile/fs/seafile_store.cpp | 106 +++++++++++++++---------- src/seafile/fs/winfsp_adapter.cpp | 88 ++++++++++---------- src/util/string_util.cpp | 48 ++++++----- 6 files changed, 146 insertions(+), 104 deletions(-) diff --git a/include/seafile/fs/seafile_store.hpp b/include/seafile/fs/seafile_store.hpp index 694afbf..ae20b86 100644 --- a/include/seafile/fs/seafile_store.hpp +++ b/include/seafile/fs/seafile_store.hpp @@ -48,7 +48,7 @@ namespace seafile::fs /// 返回路径下面的子项目信息 /// @param path 路径 /// @return 子项目信息 - [[nodiscard]] tl::expected, std::vector >, + [[nodiscard]] tl::expected, std::vector>, api::SeafileException> listDir(const std::string& path); /// 读取文件内容 @@ -90,7 +90,7 @@ namespace seafile::fs std::vector queryDirectoryChildren( const std::string& repo_id, const std::string& parent_path); - struct Database; + class Database; std::unique_ptr database; std::string api_server; std::string username; diff --git a/src/main.cpp b/src/main.cpp index e3a5ff7..6927a36 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,7 +10,7 @@ auto wmain(int argc, wchar_t** argv) -> int if (!NT_SUCCESS(FspLoad(nullptr))) return ERROR_DELAY_LOAD_FAILED; - spdlog::set_level(spdlog::level::err); + spdlog::set_level(spdlog::level::info); FspDebugLogSetHandle(GetStdHandle(STD_ERROR_HANDLE)); diff --git a/src/seafile/fs/seafile_file_system.cpp b/src/seafile/fs/seafile_file_system.cpp index 5d7b2c9..e4ecf51 100644 --- a/src/seafile/fs/seafile_file_system.cpp +++ b/src/seafile/fs/seafile_file_system.cpp @@ -232,7 +232,7 @@ namespace seafile::fs return STATUS_UNSUCCESSFUL; } - auto add_entry = [&](const std::wstring& name, uint64_t size, uint32_t attrs, int64_t mtime) + auto add_entry = [&](const std::wstring& name, const uint64_t size, const uint32_t attrs, const int64_t mtime) { const auto entry_size = sizeof(FSP_FSCTL_DIR_INFO) + ((name.size() + 1) * sizeof(WCHAR)); const auto dir_info = static_cast(std::malloc(entry_size)); diff --git a/src/seafile/fs/seafile_store.cpp b/src/seafile/fs/seafile_store.cpp index 9fc3fbd..1409ca4 100644 --- a/src/seafile/fs/seafile_store.cpp +++ b/src/seafile/fs/seafile_store.cpp @@ -130,18 +130,51 @@ namespace seafile::fs } } - struct SeafileStore::Database + class SeafileStore::Database { using Storage = decltype(make_storage("")); + Storage storage; std::recursive_mutex mutex; + class LockProxy final + { + Storage& storage; + std::lock_guard lock; + + public: + LockProxy(Storage& storage, std::recursive_mutex& mutex) : storage(storage), lock(mutex) + { + } + + LockProxy(const LockProxy&) = delete; + LockProxy& operator=(const LockProxy&) = delete; + + LockProxy(LockProxy&&) = delete; + LockProxy& operator=(LockProxy&&) = delete; + + Storage* operator->() const + { + return &this->storage; + } + }; + + public: explicit Database(const std::string& path) : storage(make_storage(path)) { storage.pragma.journal_mode(sqlite_orm::journal_mode::WAL); storage.pragma.synchronous(1); } + + Database(const Database&) = delete; + Database& operator=(const Database&) = delete; + + [[nodiscard]] + LockProxy operator->() + { + return LockProxy{storage, mutex}; + } }; tl::expected SeafileStore::auth() @@ -166,9 +199,8 @@ namespace seafile::fs tl::expected SeafileStore::findRepoEntry( const std::string& repo_id, const std::string& path) { - std::lock_guard lock(database->mutex); - auto& storage = this->database->storage; - const auto entries = storage.get_all( + auto& storage = *(this->database); + const auto entries = storage->get_all( sqlite_orm::where( sqlite_orm::and_( sqlite_orm::c(&RepoEntry::repo_id) == repo_id, @@ -185,9 +217,8 @@ namespace seafile::fs tl::expected SeafileStore::checkIsUpdated(const std::string& repo_id) { - std::lock_guard lock(database->mutex); - auto& storage = this->database->storage; - const auto repos = storage.get_all( + auto& storage = *(this->database); + const auto repos = storage->get_all( sqlite_orm::where( sqlite_orm::c(&RepoInfo::id) == repo_id )); @@ -218,9 +249,8 @@ namespace seafile::fs try { { - std::lock_guard lock(database->mutex); - auto& storage = this->database->storage; - storage.remove_all(sqlite_orm::where( + auto& storage = *this->database; + storage->remove_all(sqlite_orm::where( sqlite_orm::c(&RepoEntry::repo_id) == repo_id ) ); @@ -231,8 +261,7 @@ namespace seafile::fs return tl::make_unexpected(repo_entries.error()); } { - std::lock_guard lock(database->mutex); - auto& storage = this->database->storage; + auto& storage = *this->database; std::vector entries; entries.reserve(repo_entries->size()); std::transform(repo_entries->begin(), repo_entries->end(), std::back_inserter(entries), @@ -240,9 +269,9 @@ namespace seafile::fs { return RepoEntry::from_api_model(repo_id, "/", entry); }); - storage.transaction([&entries,&storage] + storage->transaction([&entries,&storage] { - storage.replace_range(entries.begin(), entries.end()); + storage->replace_range(entries.begin(), entries.end()); return true; }); } @@ -259,8 +288,7 @@ namespace seafile::fs { try { - std::lock_guard lock(database->mutex); - this->database->storage.sync_schema(); + (*this->database)->sync_schema(); } catch (std::exception& e) { @@ -280,8 +308,7 @@ namespace seafile::fs { return tl::make_unexpected(user_info.error()); } - std::lock_guard lock(database->mutex); - this->database->storage.replace(*user_info); + (*this->database)->replace(*user_info); return {}; } @@ -292,8 +319,7 @@ namespace seafile::fs { return tl::make_unexpected(repos.error()); } - std::lock_guard lock(database->mutex); - auto& storage = this->database->storage; + auto& storage = *this->database; std::vector result; result.reserve(repos->size()); for (const auto& repo : *repos) @@ -302,7 +328,7 @@ namespace seafile::fs result.push_back(storage_repo); try { - const auto existings = storage.get_all( + const auto existings = storage->get_all( sqlite_orm::where(sqlite_orm::c(&RepoInfo::id) == storage_repo.id)); std::optional existing = std::nullopt; if (!existings.empty()) @@ -311,10 +337,10 @@ namespace seafile::fs } if (existing && existing->head_commit_id != storage_repo.head_commit_id) { - storage.remove_all(sqlite_orm::where( + storage->remove_all(sqlite_orm::where( sqlite_orm::c(&RepoEntry::repo_id) == storage_repo.id)); } - storage.replace(storage_repo); + storage->replace(storage_repo); } catch (std::exception& e) { @@ -330,9 +356,8 @@ namespace seafile::fs { std::vector repos; { - std::lock_guard lock(database->mutex); - auto& storage = this->database->storage; - repos = storage.get_all( + auto& storage = *this->database; + repos = storage->get_all( sqlite_orm::where(sqlite_orm::c(&RepoInfo::name) == name)); } if (!repos.empty()) @@ -379,17 +404,17 @@ namespace seafile::fs { return RepoEntry::from_api_model(repo_id, parent_path, entry); }); - std::lock_guard lock(database->mutex); - auto& storage = this->database->storage; + auto& storage = *this->database; constexpr std::size_t batch_size = 500; - storage.transaction([&] + storage->transaction([&] { for (auto it = repo_entries.begin(); it != repo_entries.end();) { auto end = it; - std::advance(end, std::min(batch_size,static_cast(std::distance(it, repo_entries.end())))); + std::advance( + end, std::min(batch_size, static_cast(std::distance(it, repo_entries.end())))); - storage.replace_range(it, end); + storage->replace_range(it, end); it = end; } @@ -406,16 +431,15 @@ namespace seafile::fs std::vector SeafileStore::queryDirectoryChildren( const std::string& repo_id, const std::string& parent_path) { - std::lock_guard lock(database->mutex); - auto& storage = this->database->storage; + auto& storage = *this->database; const std::string prefix = (parent_path == "/") ? "" : parent_path; - const auto all = storage.get_all( + const auto all = storage->get_all( sqlite_orm::where( sqlite_orm::and_( sqlite_orm::c(&RepoEntry::repo_id) == repo_id, sqlite_orm::like(&RepoEntry::path, prefix + "/%") ) - ),sqlite_orm::order_by(&RepoEntry::name)); + ), sqlite_orm::order_by(&RepoEntry::name)); std::vector children; for (auto& entry : all) { @@ -478,14 +502,13 @@ namespace seafile::fs if (parts.empty()) { - std::lock_guard lock(database->mutex); - auto& storage = this->database->storage; - auto repos = storage.get_all(sqlite_orm::order_by(&RepoInfo::id)); + auto& storage = *this->database; + auto repos = storage->get_all(sqlite_orm::order_by(&RepoInfo::id)); if (repos.empty()) { if (const auto synced = this->syncRepos(); synced) { - repos = storage.get_all(); + repos = storage->get_all(); } else { @@ -527,9 +550,8 @@ namespace seafile::fs tl::expected SeafileStore::accountInfo() const { - std::lock_guard lock(database->mutex); - auto& storage = this->database->storage; - if (const auto infos = storage.get_all(); !infos.empty()) + auto& storage = *this->database; + if (const auto infos = storage->get_all(); !infos.empty()) { return infos.front(); } diff --git a/src/seafile/fs/winfsp_adapter.cpp b/src/seafile/fs/winfsp_adapter.cpp index 1c8d40a..a5d91bb 100644 --- a/src/seafile/fs/winfsp_adapter.cpp +++ b/src/seafile/fs/winfsp_adapter.cpp @@ -5,7 +5,6 @@ // Created by Shell on 2026/6/20. // #include -#include #include #include @@ -17,9 +16,9 @@ namespace seafile::fs { using namespace seafile::literals; + namespace { - FSP_FILE_SYSTEM_INTERFACE FsInterface = { .GetVolumeInfo = WinFSPAdapter::GetVolumeInfo, .SetVolumeLabel = WinFSPAdapter::SetVolumeLabel_, @@ -36,8 +35,6 @@ namespace seafile::fs .ReadDirectory = WinFSPAdapter::ReadDirectory, .GetDirInfoByName = WinFSPAdapter::GetDirInfoByName }; - std::unordered_map fstab; - std::shared_mutex fstab_mutex; } NTSTATUS WinFSPAdapter::SvcStart(FSP_SERVICE* Service, ULONG argc, PWSTR* argv) @@ -61,7 +58,7 @@ namespace seafile::fs VolumeParams.MaxComponentLength = 255; VolumeParams.VolumeCreationTime = reinterpret_cast(&CreationTime)->QuadPart; VolumeParams.VolumeSerialNumber = 0; - VolumeParams.FileInfoTimeout = 1000; + VolumeParams.FileInfoTimeout = 30000; VolumeParams.CaseSensitiveSearch = 0; VolumeParams.CasePreservedNames = 1; VolumeParams.UnicodeOnDisk = 1; @@ -99,62 +96,51 @@ namespace seafile::fs shell::util::StringUtil::utf8_to_utf16le( setting.value().mount_label)); FileSystem->UserContext = seafile_file_system; - { - std::lock_guard lock(fstab_mutex); - fstab.insert({FileSystem, seafile_file_system}); - } Result = FspFileSystemSetMountPoint(FileSystem, mount_point.data()); if (!NT_SUCCESS(Result)) { - { - std::lock_guard lock(fstab_mutex); - fstab.erase(FileSystem); - } FspFileSystemDelete(FileSystem); delete seafile_file_system; return Result; } - - Result = FspFileSystemStartDispatcher(FileSystem, 0); - - if (!NT_SUCCESS(Result)) - { - { - std::lock_guard lock(fstab_mutex); - fstab.erase(FileSystem); - } - FspFileSystemDelete(FileSystem); - delete seafile_file_system; - - return Result; - } FspFileSystemSetDebugLog( FileSystem, TRUE); + Result = FspFileSystemStartDispatcher(FileSystem, 0); + + if (!NT_SUCCESS(Result)) + { + FspFileSystemDelete(FileSystem); + delete seafile_file_system; + + return Result; + } + Service->UserContext = FileSystem; return Result; } NTSTATUS WinFSPAdapter::SvcStop(FSP_SERVICE* Service) { - decltype(fstab) snapshot; - { - std::lock_guard lock(fstab_mutex); - snapshot = std::move(fstab); - } - for (auto& [fileSystem, seafileFs] : snapshot) - { - FspFileSystemStopDispatcher(fileSystem); - FspFileSystemDelete(fileSystem); - delete seafileFs; - } + if (!Service) + return STATUS_INVALID_PARAMETER; + auto* FileSystem = static_cast(Service->UserContext); + if (!FileSystem) + return STATUS_SUCCESS; + const auto* SeafileFS = static_cast(FileSystem->UserContext); + FspFileSystemStopDispatcher(FileSystem); + delete SeafileFS; + FspFileSystemDelete(FileSystem); + return STATUS_SUCCESS; } NTSTATUS WinFSPAdapter::GetVolumeInfo(FSP_FILE_SYSTEM* FileSystem, FSP_FSCTL_VOLUME_INFO* VolumeInfo) { + if (!FileSystem) + return STATUS_INVALID_PARAMETER; const auto fs = static_cast(FileSystem->UserContext); if (!fs) return STATUS_INVALID_PARAMETER; return fs->GetVolumeInfo(VolumeInfo); @@ -164,6 +150,8 @@ namespace seafile::fs BOOLEAN ReplaceFileAttributes, UINT64 AllocationSize, FSP_FSCTL_FILE_INFO* FileInfo) { + if (!FileSystem) + return STATUS_INVALID_PARAMETER; const auto fs = static_cast(FileSystem->UserContext); if (!fs) return STATUS_INVALID_PARAMETER; return fs->Overwrite(FileContext, FileAttributes, ReplaceFileAttributes, AllocationSize, FileInfo); @@ -171,6 +159,7 @@ namespace seafile::fs void WinFSPAdapter::Close(FSP_FILE_SYSTEM* FileSystem, PVOID FileContext) { + if (!FileSystem) return; const auto fs = static_cast(FileSystem->UserContext); if (!fs) return; fs->Close(FileContext); @@ -180,6 +169,9 @@ namespace seafile::fs UINT32 GrantedAccess, UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize, PVOID* PFileContext, FSP_FSCTL_FILE_INFO* FileInfo) { + if (!FileSystem) + return STATUS_INVALID_PARAMETER; + const auto fs = static_cast(FileSystem->UserContext); if (!fs) return STATUS_INVALID_PARAMETER; return fs->Create(FileName, CreateOptions, @@ -189,6 +181,7 @@ namespace seafile::fs VOID WinFSPAdapter::Cleanup(FSP_FILE_SYSTEM* FileSystem, PVOID FileContext, PWSTR FileName, ULONG Flags) { + if (!FileSystem) return; const auto fs = static_cast(FileSystem->UserContext); if (!fs) return; fs->Cleanup(FileContext, FileName, Flags); @@ -197,6 +190,9 @@ namespace seafile::fs NTSTATUS WinFSPAdapter::ReadDirectory(FSP_FILE_SYSTEM* FileSystem, PVOID FileContext0, PWSTR Pattern, PWSTR Marker, PVOID Buffer, ULONG BufferLength, PULONG PBytesTransferred) { + if (!FileSystem) + return STATUS_INVALID_PARAMETER; + const auto fs = static_cast(FileSystem->UserContext); if (!fs) return STATUS_INVALID_PARAMETER; return fs->ReadDirectory(FileContext0, Pattern, Marker, Buffer, BufferLength, PBytesTransferred); @@ -206,6 +202,8 @@ namespace seafile::fs PVOID FileContext, PWSTR FileName, FSP_FSCTL_DIR_INFO* DirInfo) { + if (!FileSystem) + return STATUS_INVALID_PARAMETER; const auto fs = static_cast(FileSystem->UserContext); if (!fs) return STATUS_INVALID_PARAMETER; return fs->GetDirInfoByName(FileContext, FileName, DirInfo); @@ -216,6 +214,8 @@ namespace seafile::fs PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T* PSecurityDescriptorSize) { + if (!FileSystem) + return STATUS_INVALID_PARAMETER; const auto fs = static_cast(FileSystem->UserContext); if (!fs) return STATUS_INVALID_PARAMETER; return fs->GetSecurityByName(FileName, PFileAttributes, SecurityDescriptor, PSecurityDescriptorSize); @@ -224,6 +224,8 @@ namespace seafile::fs NTSTATUS WinFSPAdapter::SetVolumeLabel_(FSP_FILE_SYSTEM* FileSystem, PWSTR VolumeLabel, FSP_FSCTL_VOLUME_INFO* VolumeInfo) { + if (!FileSystem) + return STATUS_INVALID_PARAMETER; const auto fs = static_cast(FileSystem->UserContext); if (!fs) return STATUS_INVALID_PARAMETER; return fs->SetVolumeLabel_(VolumeLabel, VolumeInfo); @@ -232,6 +234,8 @@ namespace seafile::fs NTSTATUS WinFSPAdapter::Open(FSP_FILE_SYSTEM* FileSystem, PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess, PVOID* PFileContext, FSP_FSCTL_FILE_INFO* FileInfo) { + if (!FileSystem) + return STATUS_INVALID_PARAMETER; const auto fs = static_cast(FileSystem->UserContext); if (!fs) return STATUS_INVALID_PARAMETER; return fs->Open(FileName, CreateOptions, GrantedAccess, PFileContext, FileInfo); @@ -240,6 +244,8 @@ namespace seafile::fs NTSTATUS WinFSPAdapter::Read(FSP_FILE_SYSTEM* FileSystem, PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length, PULONG PBytesTransferred) { + if (!FileSystem) + return STATUS_INVALID_PARAMETER; const auto fs = static_cast(FileSystem->UserContext); if (!fs) return STATUS_INVALID_PARAMETER; return fs->Read(FileContext, Buffer, Offset, Length, PBytesTransferred); @@ -248,6 +254,8 @@ namespace seafile::fs NTSTATUS WinFSPAdapter::GetFileInfo(FSP_FILE_SYSTEM* FileSystem, HANDLE Handle, FSP_FSCTL_FILE_INFO* FileInfo) { + if (!FileSystem) + return STATUS_INVALID_PARAMETER; const auto fs = static_cast(FileSystem->UserContext); if (!fs) return STATUS_INVALID_PARAMETER; return fs->GetFileInfo(Handle, FileInfo); @@ -257,12 +265,12 @@ namespace seafile::fs SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor) { - return STATUS_ACCESS_DENIED; + return STATUS_SUCCESS; } NTSTATUS WinFSPAdapter::GetSecurity(FSP_FILE_SYSTEM* FileSystem, PVOID FileContext, PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T* PSecurityDescriptorSize) { - return STATUS_NOT_IMPLEMENTED; + return STATUS_SUCCESS; } } diff --git a/src/util/string_util.cpp b/src/util/string_util.cpp index b10001b..ece5690 100644 --- a/src/util/string_util.cpp +++ b/src/util/string_util.cpp @@ -13,15 +13,19 @@ #include "util/icu_raii.hpp" -namespace shell::util { - std::vector StringUtil::split(const std::string &s, const std::string &delim) { - if (delim.empty()) { +namespace shell::util +{ + std::vector StringUtil::split(const std::string& s, const std::string& delim) + { + if (delim.empty()) + { return {s}; } std::vector result; size_t start = 0, pos; - while ((pos = s.find(delim, start)) != std::string::npos) { + while ((pos = s.find(delim, start)) != std::string::npos) + { result.emplace_back(s.substr(start, pos - start)); start = pos + delim.length(); } @@ -30,36 +34,42 @@ namespace shell::util { return result; } - std::string StringUtil::convert_encoding(const std::string &input, const std::string &to) { + std::string StringUtil::convert_encoding(const std::string& input, const std::string& to) + { return convert_encoding(input, detect_encoding(input), to); } - std::string StringUtil::detect_encoding(const std::string &data) { + std::string StringUtil::detect_encoding(const std::string& data) + { UErrorCode status = U_ZERO_ERROR; const auto detector = UCharsetDetectorPtr(ucsdet_open(&status)); - if (U_FAILURE(status)) { + if (U_FAILURE(status)) + { throw std::runtime_error(std::format("ucsdet_open failed:{}", u_errorName(status))); } // 设置待检测数据 ucsdet_setText(detector.get(), data.data(), data.size(), &status); - if (U_FAILURE(status)) { + if (U_FAILURE(status)) + { throw std::runtime_error(std::format("ucsdet_open failed,can't set text:{}", u_errorName(status))); } // 检测 - const UCharsetMatch *match = ucsdet_detect(detector.get(), &status); + const UCharsetMatch* match = ucsdet_detect(detector.get(), &status); std::string encoding; - if (match && U_SUCCESS(status)) { + if (match && U_SUCCESS(status)) + { encoding = ucsdet_getName(match, &status); } return encoding; } - std::string StringUtil::convert_encoding(const std::string &input, const std::string &from, const std::string &to) { + std::string StringUtil::convert_encoding(const std::string& input, const std::string& from, const std::string& to) + { UErrorCode status = U_ZERO_ERROR; // 先获取输出长度 @@ -81,7 +91,8 @@ namespace shell::util { &status ); - if (U_FAILURE(status)) { + if (U_FAILURE(status)) + { throw std::runtime_error(std::format("convert from {} to {} failed:{}", from, to, u_errorName(status))); } @@ -89,23 +100,24 @@ namespace shell::util { } -#ifdef _WIN32 - std::wstring StringUtil::utf8_to_utf16le(const std::string &input) { + std::wstring StringUtil::utf8_to_utf16le(const std::string& input) + { const icu::UnicodeString unicode = icu::UnicodeString::fromUTF8(input); return std::wstring{ - reinterpret_cast(unicode.getBuffer()), + reinterpret_cast(unicode.getBuffer()), static_cast(unicode.length()) }; } - std::string StringUtil::utf16le_to_utf8(const std::wstring &input) { + std::string StringUtil::utf16le_to_utf8(const std::wstring& input) + { return utf16le_to_utf8(input.data()); } - std::string StringUtil::utf16le_to_utf8(const wchar_t *input) { + std::string StringUtil::utf16le_to_utf8(const wchar_t* input) + { const auto unicode = icu::UnicodeString(input); std::string utf8; return unicode.toUTF8String(utf8); } -#endif }