/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "QuarantineUtil.hpp" #include #include #include "ClientSession.hpp" #include "LOOLWSD.hpp" #include "DocumentBroker.hpp" #include #include #include namespace Quarantine { void createQuarantineMap() { std::vector files; Poco::File(LOOLWSD::QuarantinePath).list(files); LOOLWSD::QuarantineMap.clear(); std::vector tokens; std::string decoded; std::sort(files.begin(), files.end()); for (auto file : files) { Util::tokenize(file.c_str(), file.size(), '_', tokens); Poco::URI::decode(file.substr(tokens[2]._index), decoded); LOOLWSD::QuarantineMap[decoded].emplace_back(LOOLWSD::QuarantinePath + file); tokens.clear(); decoded.clear(); } } void removeQuarantine() { FileUtil::removeFile(LOOLWSD::QuarantinePath, true); } // returns quarentine directory size in bytes // files with hardlink count of more than 1 is not counted // because they are originally stored in jails std::size_t quarantineSize() { std::vector files; Poco::File(LOOLWSD::QuarantinePath).list(files); std::size_t size = 0; for (auto file : files) { FileUtil::Stat f(LOOLWSD::QuarantinePath + file); if (f.hardLinkCount() == 1) size += f.size(); } return size; } void makeQuarantineSpace() { std::size_t sizeLimit = LOOLWSD::getConfigValue("quarantine_files.limit_dir_size_mb", 0)*1024*1024; if(sizeLimit == 0) return; std::vector files; Poco::File(LOOLWSD::QuarantinePath).list(files); std::sort(files.begin(), files.end()); std::size_t currentSize = quarantineSize(); std::size_t index = 0; while (currentSize >= sizeLimit && !files.empty()) { FileUtil::Stat file(LOOLWSD::QuarantinePath + files[index]); if(file.hardLinkCount() != 1) { index++; continue; } currentSize -= file.size(); FileUtil::removeFile(LOOLWSD::QuarantinePath + files[index], true); files.erase(files.begin()); } } void clearOldQuarantineVersions(std::string Wopiscr) { std::size_t maxVersionCount = LOOLWSD::getConfigValue("quarantine_files.max_versions_to_maintain", 2); std::string decoded; Poco::URI::decode(Wopiscr, decoded); while (LOOLWSD::QuarantineMap[decoded].size() > maxVersionCount) { FileUtil::removeFile(LOOLWSD::QuarantineMap[decoded][0]); LOOLWSD::QuarantineMap[decoded].erase(LOOLWSD::QuarantineMap[decoded].begin()); } } bool quarantineFile(DocumentBroker* docBroker, std::string docName) { //return if directory size limit is 0 std::size_t sizeLimit = LOOLWSD::getConfigValue("quarantine_files.limit_dir_size_mb", 0); if (sizeLimit == 0) return false; std::string docKey; Poco::URI::encode(docBroker->getDocKey(), "?#/", docKey); const auto timeNow = std::chrono::system_clock::now(); const std::string ts = std::to_string(std::chrono::duration_cast(timeNow.time_since_epoch()).count()); std::string sourcefilePath = LOOLWSD::ChildRoot + "tmp/lool-" + docBroker->getJailId() + "/user/docs/" + docBroker->getJailId() + "/" + docName; std::string linkedFileName = ts + "_" + std::to_string(docBroker->getPid()) + "_" + docKey; std::string linkedFilePath = LOOLWSD::QuarantinePath + linkedFileName; FileUtil::Stat fileStat(linkedFilePath); makeQuarantineSpace(); int result_link = link(sourcefilePath.c_str(),linkedFilePath.c_str()); if(result_link == 0) { LOOLWSD::QuarantineMap[docBroker->getDocKey()].emplace_back(linkedFilePath); clearOldQuarantineVersions(docKey); makeQuarantineSpace(); LOG_INF("Quarantined " + sourcefilePath + " to " + linkedFilePath); return true; } else { LOG_ERR("Quarantining of file " + sourcefilePath + " filed"); return false; } return false; } }