diff --git a/src/fileshelter/main/main.cpp b/src/fileshelter/main/main.cpp index 5e13f4e..6bc83bc 100644 --- a/src/fileshelter/main/main.cpp +++ b/src/fileshelter/main/main.cpp @@ -187,6 +187,7 @@ int main(int argc, char *argv[]) const std::string deployPath {Service::get()->getString("deploy-path", "/")}; Service shareManager {Share::createShareManager(Service::get()->getPath("working-dir") / "fileshelter.db", true /* enableCleaner */)}; + shareManager->removeOrphanFiles(uploadedFilesPath); ShareResource shareResource; server.addResource(&shareResource, std::string {shareResource.getDeployPath()}); diff --git a/src/libs/share/impl/File.cpp b/src/libs/share/impl/File.cpp index 6b9ca3f..db7c8df 100644 --- a/src/libs/share/impl/File.cpp +++ b/src/libs/share/impl/File.cpp @@ -36,7 +36,13 @@ namespace Share session.flush(); return res; + } + File::pointer + File::getByPath(Wt::Dbo::Session& session, const std::filesystem::path& filePath) + { + return session.find().where("path = ?").bind(filePath); } + } diff --git a/src/libs/share/impl/File.hpp b/src/libs/share/impl/File.hpp index cbf887f..1e5c379 100644 --- a/src/libs/share/impl/File.hpp +++ b/src/libs/share/impl/File.hpp @@ -39,6 +39,7 @@ namespace Share // Helpers static pointer create(Wt::Dbo::Session& session, const FileCreateParameters& parameters, Wt::Dbo::ptr share); + static pointer getByPath(Wt::Dbo::Session& session, const std::filesystem::path& path); // Getters const FileUUID& getUUID() const { return _uuid; } diff --git a/src/libs/share/impl/Share.cpp b/src/libs/share/impl/Share.cpp index 0ca9d79..be4e00d 100644 --- a/src/libs/share/impl/Share.cpp +++ b/src/libs/share/impl/Share.cpp @@ -111,7 +111,13 @@ namespace Share std::error_code ec; std::filesystem::remove(file->getPath(), ec); if (ec) + { FS_LOG(SHARE, ERROR) << "Cannot remove file '" << file->getPath().string() << "' from share '" << share->getUUID().toString() << "': " << ec.message(); + } + else + { + FS_LOG(SHARE, DEBUG) << "Removed file '" << file->getPath().string() << "' from share '" << share->getUUID().toString() << "'"; + } } }); diff --git a/src/libs/share/impl/ShareCleaner.cpp b/src/libs/share/impl/ShareCleaner.cpp index 89de018..3af0b14 100644 --- a/src/libs/share/impl/ShareCleaner.cpp +++ b/src/libs/share/impl/ShareCleaner.cpp @@ -24,6 +24,7 @@ #include "utils/Logger.hpp" #include "utils/Service.hpp" #include "Db.hpp" +#include "File.hpp" #include "Share.hpp" namespace Share @@ -47,6 +48,44 @@ namespace Share FS_LOG(SHARE, DEBUG) << "Stopped cleaner"; } + void + ShareCleaner::removeOrphanFiles(const std::filesystem::path& directory) + { + FS_LOG(SHARE, DEBUG) << "Removing orphan files in directory '" << directory.string() << "'"; + + for (const std::filesystem::path& directoryEntry: std::filesystem::directory_iterator {directory}) + { + if (!std::filesystem::is_regular_file(directoryEntry)) + { + FS_LOG(SHARE, DEBUG) << "Skipping '" << directoryEntry.string() << "': not regular"; + continue; + } + + if (isOrphanFile(directoryEntry)) + { + std::error_code ec; + std::filesystem::remove(directoryEntry, ec); + if (ec) + { + FS_LOG(SHARE, ERROR) << "Cannot remove file '" << directoryEntry.string() << "'"; + } + else + { + FS_LOG(SHARE, INFO) << "Removed orphan file '" << directoryEntry.string() << "'"; + } + } + } + } + + bool + ShareCleaner::isOrphanFile(const std::filesystem::path& filePath) + { + Wt::Dbo::Session& session {_db.getTLSSession()}; + Wt::Dbo::Transaction transaction {session}; + + return !File::getByPath(session, filePath); + } + void ShareCleaner::scheduleNextCheck() { @@ -58,6 +97,7 @@ namespace Share return; checkExpiredShares(); + scheduleNextCheck(); }); } @@ -80,6 +120,10 @@ namespace Share FS_LOG(SHARE, INFO) << "Removing expired share '" << share->getUUID().toString() << "'"; Share::destroy(share); } + else + { + FS_LOG(SHARE, DEBUG) << "Share '" << share->getUUID().toString() << "' not due to removal"; + } }); } } // namespace Share diff --git a/src/libs/share/impl/ShareCleaner.hpp b/src/libs/share/impl/ShareCleaner.hpp index 7d9a1a8..7862181 100644 --- a/src/libs/share/impl/ShareCleaner.hpp +++ b/src/libs/share/impl/ShareCleaner.hpp @@ -20,12 +20,14 @@ #pragma once #include +#include #include #include namespace Share { class Db; + class Share; class ShareCleaner { public: @@ -37,7 +39,10 @@ namespace Share ShareCleaner& operator=(const ShareCleaner&) = delete; ShareCleaner& operator=(ShareCleaner&&) = delete; + void removeOrphanFiles(const std::filesystem::path& directory); + private: + bool isOrphanFile(const std::filesystem::path& file); void scheduleNextCheck(); void checkExpiredShares(); diff --git a/src/libs/share/impl/ShareManager.cpp b/src/libs/share/impl/ShareManager.cpp index 08ee78f..6500487 100644 --- a/src/libs/share/impl/ShareManager.cpp +++ b/src/libs/share/impl/ShareManager.cpp @@ -273,6 +273,13 @@ namespace Share share.modify()->incReadCount(); } + void + ShareManager::removeOrphanFiles(const std::filesystem::path& directory) + { + if (_shareCleaner) + _shareCleaner->removeOrphanFiles(directory); + } + void ShareManager::validateShareSizes(const std::vector& files, const std::vector& fileSizes) { diff --git a/src/libs/share/impl/ShareManager.hpp b/src/libs/share/impl/ShareManager.hpp index 8ee8e3b..47601f4 100644 --- a/src/libs/share/impl/ShareManager.hpp +++ b/src/libs/share/impl/ShareManager.hpp @@ -53,6 +53,7 @@ namespace Share ShareDesc getShareDesc(const ShareEditUUID& shareUUID) override; void visitShares(std::function) override; void incrementReadCount(const ShareUUID& shareUUID) override; + void removeOrphanFiles(const std::filesystem::path& directory) override; void validateShareSizes(const std::vector& files, const std::vector& fileSizes); diff --git a/src/libs/share/include/share/IShareManager.hpp b/src/libs/share/include/share/IShareManager.hpp index 17c5ce4..8cc2752 100644 --- a/src/libs/share/include/share/IShareManager.hpp +++ b/src/libs/share/include/share/IShareManager.hpp @@ -56,6 +56,7 @@ namespace Share virtual void visitShares(std::function) = 0; virtual void incrementReadCount(const ShareUUID& shareUUID) = 0; + virtual void removeOrphanFiles(const std::filesystem::path& directory) = 0; }; std::unique_ptr createShareManager(const std::filesystem::path& dbFile, bool enableCleaner);