summaryrefslogtreecommitdiffstats
path: root/wsd
diff options
context:
space:
mode:
authorPranam Lashkari <lpranam@collabora.com>2021-10-22 00:59:15 +0530
committerTor Lillqvist <tml@iki.fi>2021-11-01 17:21:51 +0200
commitf84df1161c8b3aedff9575716043ca2ecc78b992 (patch)
tree6cf310fd4049bacffbd4c7bceafe91398871be32 /wsd
parentwsd: use the WOPI protocol for local files instead of the current "local stor... (diff)
downloadonline-f84df1161c8b3aedff9575716043ca2ecc78b992.tar.gz
online-f84df1161c8b3aedff9575716043ca2ecc78b992.zip
quarantine: create hard links for quarantining when file is saved
number of versions to maintain per file can be specified in loolwsd.xml on exceeding specified quarantine size oldest file(s) is deleted Signed-off-by: Pranam Lashkari <lpranam@collabora.com> Change-Id: I3ca55b9ab29a82988f19fe0acd43e0fae2c2a423
Diffstat (limited to 'wsd')
-rw-r--r--wsd/DocumentBroker.cpp4
-rw-r--r--wsd/LOOLWSD.cpp14
-rw-r--r--wsd/LOOLWSD.hpp5
-rw-r--r--wsd/QuarantineUtil.cpp150
-rw-r--r--wsd/QuarantineUtil.hpp27
5 files changed, 198 insertions, 2 deletions
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 42d9f08c5c..ac2489cb80 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -34,6 +34,7 @@
#include "TileCache.hpp"
#include "ProxyProtocol.hpp"
#include "Util.hpp"
+#include "QuarantineUtil.hpp"
#include <common/Log.hpp>
#include <common/Message.hpp>
#include <common/Clipboard.hpp>
@@ -1136,6 +1137,9 @@ void DocumentBroker::handleSaveResponse(const std::string& sessionId, bool succe
// DocBroker will have to decide to upload or skip.
const std::string oldName = _storage->getRootFilePathToUpload();
const std::string newName = _storage->getRootFilePathUploading();
+
+ Quarantine::quarantineFile(this, _storage->getFileInfo().getFilename() + TO_UPLOAD_SUFFIX);
+
if (rename(oldName.c_str(), newName.c_str()) < 0)
{
// It's not an error if there was no file to rename, when the document isn't modified.
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 597b857714..632ad3f6ad 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -887,6 +887,8 @@ static std::string UnitTestLibrary;
unsigned int LOOLWSD::NumPreSpawnedChildren = 0;
std::unique_ptr<TraceFileWriter> LOOLWSD::TraceDumper;
+std::unordered_map<std::string, std::vector<std::string>> LOOLWSD::QuarantineMap;
+std::string LOOLWSD::QuarantinePath;
#if !MOBILEAPP
std::unique_ptr<ClipboardCache> LOOLWSD::SavedClipboards;
#endif
@@ -1125,7 +1127,9 @@ void LOOLWSD::innerInitialize(Application& self)
#ifdef ENABLE_FEATURE_RESTRICTION
{ "restricted_commands", "" },
#endif
- { "user_interface.mode", USER_INTERFACE_MODE }
+ { "user_interface.mode", USER_INTERFACE_MODE },
+ {"quarantine_files.limit_dir_size_mb", "250"},
+ {"quarantine_files.max_versions_to_maintain", "2"}
};
// Set default values, in case they are missing from the config file.
@@ -1453,6 +1457,14 @@ void LOOLWSD::innerInitialize(Application& self)
FileServerRoot = getPathFromConfig("file_server_root_path");
LOG_DBG("FileServerRoot after config: " << FileServerRoot);
+ //creating quarantine directory
+ QuarantinePath = FileServerRoot + "quarantine/";
+ Poco::File p(QuarantinePath);
+ p.createDirectories();
+ LOG_INF("Created quarantine directory " + p.path());
+
+ Quarantine::createQuarantineMap();
+
WelcomeFilesRoot = getPathFromConfig("welcome.path");
if (!getConfigValue<bool>(conf, "welcome.enable", true))
WelcomeFilesRoot = "";
diff --git a/wsd/LOOLWSD.hpp b/wsd/LOOLWSD.hpp
index 50c82e5f05..5a14e39bd8 100644
--- a/wsd/LOOLWSD.hpp
+++ b/wsd/LOOLWSD.hpp
@@ -13,6 +13,7 @@
#include <cstdio>
#include <map>
#include <set>
+#include <unordered_map>
#include <unordered_set>
#include <string>
#include <utility>
@@ -28,7 +29,7 @@
#include "FileUtil.hpp"
#include "RequestDetails.hpp"
#include "WebSocketHandler.hpp"
-
+#include "QuarantineUtil.hpp"
class ChildProcess;
class TraceFileWriter;
class DocumentBroker;
@@ -263,6 +264,8 @@ public:
static bool IsProxyPrefixEnabled;
static std::atomic<unsigned> NumConnections;
static std::unique_ptr<TraceFileWriter> TraceDumper;
+ static std::unordered_map<std::string, std::vector<std::string>> QuarantineMap;
+ static std::string QuarantinePath;
#if !MOBILEAPP
static std::unique_ptr<ClipboardCache> SavedClipboards;
#endif
diff --git a/wsd/QuarantineUtil.cpp b/wsd/QuarantineUtil.cpp
new file mode 100644
index 0000000000..6a286a5a67
--- /dev/null
+++ b/wsd/QuarantineUtil.cpp
@@ -0,0 +1,150 @@
+/* -*- 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 <Poco/Path.h>
+#include <Poco/URI.h>
+#include "ClientSession.hpp"
+#include "LOOLWSD.hpp"
+#include "DocumentBroker.hpp"
+
+#include <common/Common.hpp>
+#include <common/StringVector.hpp>
+#include <common/Log.hpp>
+
+namespace Quarantine
+{
+ void createQuarantineMap()
+ {
+ std::vector<std::string> files;
+ Poco::File(LOOLWSD::QuarantinePath).list(files);
+ LOOLWSD::QuarantineMap.clear();
+
+ std::vector<StringToken> 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<std::string> 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<std::size_t>("quarantine_files.limit_dir_size_mb", 0)*1024*1024;
+
+ if(sizeLimit == 0)
+ return;
+
+ std::vector<std::string> 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<std::size_t>("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<std::size_t>("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<std::chrono::seconds>(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;
+ }
+} \ No newline at end of file
diff --git a/wsd/QuarantineUtil.hpp b/wsd/QuarantineUtil.hpp
new file mode 100644
index 0000000000..1fb629c549
--- /dev/null
+++ b/wsd/QuarantineUtil.hpp
@@ -0,0 +1,27 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <config.h>
+#include <string>
+
+class DocumentBroker;
+namespace Quarantine
+{
+ void createQuarantineMap();
+
+ void removeQuarantine();
+
+ std::size_t quarantineSize();
+
+ void makeQuarantineSpace();
+
+ void clearOldQuarantineVersions(std::string Wopiscr);
+
+ bool quarantineFile(DocumentBroker* docBroker, std::string docName);
+}