[Libreoffice-commits] online.git: loolwsd/ChildSession.cpp loolwsd/common loolwsd/LOOLForKit.cpp loolwsd/LOOLWSD.cpp loolwsd/Makefile.am loolwsd/Storage.cpp loolwsd/test loolwsd/TileCache.cpp loolwsd/Util.cpp loolwsd/Util.hpp
Ashod Nakashian
ashod.nakashian at collabora.co.uk
Mon Nov 14 05:23:20 UTC 2016
loolwsd/ChildSession.cpp | 3
loolwsd/LOOLForKit.cpp | 3
loolwsd/LOOLWSD.cpp | 15 +-
loolwsd/Makefile.am | 2
loolwsd/Storage.cpp | 3
loolwsd/TileCache.cpp | 11 +
loolwsd/Util.cpp | 167 -------------------------
loolwsd/Util.hpp | 59 ---------
loolwsd/common/FileUtil.cpp | 202 +++++++++++++++++++++++++++++++
loolwsd/common/FileUtil.hpp | 93 ++++++++++++++
loolwsd/test/Makefile.am | 1
loolwsd/test/helpers.hpp | 3
loolwsd/test/integration-http-server.cpp | 5
13 files changed, 328 insertions(+), 239 deletions(-)
New commits:
commit ad70138fc9c2df3b82b881f1f99b52b015cfb7f0
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date: Sat Nov 12 16:38:13 2016 -0500
loolwsd: move file utilities into FileUtil files
Change-Id: Ib0c0bc66adabe6885f7ac16414a3d5af13d72893
Reviewed-on: https://gerrit.libreoffice.org/30820
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
diff --git a/loolwsd/ChildSession.cpp b/loolwsd/ChildSession.cpp
index d27c91e..4a177ac 100644
--- a/loolwsd/ChildSession.cpp
+++ b/loolwsd/ChildSession.cpp
@@ -18,6 +18,7 @@
#include <Poco/StringTokenizer.h>
#include <Poco/URI.h>
+#include "common/FileUtil.hpp"
#include "LOKitHelper.hpp"
#include "Log.hpp"
#include "Png.hpp"
@@ -574,7 +575,7 @@ bool ChildSession::downloadAs(const char* /*buffer*/, int /*length*/, StringToke
}
// The file is removed upon downloading.
- const auto tmpDir = Util::createRandomDir(JAILED_DOCUMENT_ROOT);
+ const auto tmpDir = FileUtil::createRandomDir(JAILED_DOCUMENT_ROOT);
// Prevent user inputting anything funny here.
// A "name" should always be a name, not a path
const Poco::Path filenameParam(name);
diff --git a/loolwsd/LOOLForKit.cpp b/loolwsd/LOOLForKit.cpp
index 0bd55e8..9529139 100644
--- a/loolwsd/LOOLForKit.cpp
+++ b/loolwsd/LOOLForKit.cpp
@@ -32,6 +32,7 @@
#include <Poco/Util/Application.h>
#include "Common.hpp"
+#include "common/FileUtil.hpp"
#include "IoUtil.hpp"
#include "LOOLKit.hpp"
#include "Log.hpp"
@@ -185,7 +186,7 @@ static void cleanupChildren()
if (childJails.find(exitedChildPid) != childJails.end())
{
Log::info("Child " + std::to_string(exitedChildPid) + " has exited, removing its jail '" + childJails[exitedChildPid] + "'");
- Util::removeFile(childJails[exitedChildPid], true);
+ FileUtil::removeFile(childJails[exitedChildPid], true);
childJails.erase(exitedChildPid);
}
else
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index 799a79c..1563d6b 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -99,6 +99,7 @@
#include "Common.hpp"
#include "Exceptions.hpp"
#include "FileServer.hpp"
+#include "common/FileUtil.hpp"
#include "IoUtil.hpp"
#include "LOOLProtocol.hpp"
#include "LOOLSession.hpp"
@@ -257,7 +258,7 @@ static void forkChildren(const int number)
if (number > 0)
{
- Util::checkDiskSpaceOnRegisteredFileSystems();
+ FileUtil::checkDiskSpaceOnRegisteredFileSystems();
const std::string aMessage = "spawn " + std::to_string(number) + "\n";
LOG_DBG("MasterToForKit: " << aMessage.substr(0, aMessage.length() - 1));
@@ -585,7 +586,7 @@ private:
// Clean up the temporary directory the HTMLForm ctor created.
Path tempDirectory(fromPath);
tempDirectory.setFileName("");
- Util::removeFile(tempDirectory, /*recursive=*/true);
+ FileUtil::removeFile(tempDirectory, /*recursive=*/true);
}
if (!sent)
@@ -690,7 +691,7 @@ private:
(exc.nested() ? " (" + exc.nested()->displayText() + ")" : ""));
}
- Util::removeFile(File(filePath.parent()).path(), true);
+ FileUtil::removeFile(File(filePath.parent()).path(), true);
}
else
{
@@ -870,7 +871,7 @@ private:
LOG_TRC("Sending to Client [" << status << "].");
ws->sendFrame(status.data(), status.size());
- Util::checkDiskSpaceOnRegisteredFileSystems();
+ FileUtil::checkDiskSpaceOnRegisteredFileSystems();
// Request the child to connect to us and add this session.
auto sessionsCount = docBroker->addSession(session);
@@ -1899,8 +1900,8 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
else if (ChildRoot[ChildRoot.size() - 1] != '/')
ChildRoot += '/';
- Util::registerFileSystemForDiskSpaceChecks(ChildRoot);
- Util::registerFileSystemForDiskSpaceChecks(Cache + "/.");
+ FileUtil::registerFileSystemForDiskSpaceChecks(ChildRoot);
+ FileUtil::registerFileSystemForDiskSpaceChecks(Cache + "/.");
if (FileServerRoot.empty())
FileServerRoot = Poco::Path(Application::instance().commandPath()).parent().parent().toString();
@@ -2092,7 +2093,7 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
{
const auto path = ChildRoot + jail;
LOG_INF("Removing jail [" << path << "].");
- Util::removeFile(path, true);
+ FileUtil::removeFile(path, true);
}
if (LOOLWSD::isSSLEnabled())
diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am
index fd0efdc..e7e69ff 100644
--- a/loolwsd/Makefile.am
+++ b/loolwsd/Makefile.am
@@ -31,6 +31,7 @@ AM_ETAGSFLAGS = --c++-kinds=+p --fields=+iaS --extra=+q -R --totals=yes *
AM_CTAGSFLAGS = $(AM_ETAGSFLAGS)
shared_sources = ChildSession.cpp \
+ common/FileUtil.cpp \
IoUtil.cpp \
Log.cpp \
LOOLProtocol.cpp \
@@ -93,6 +94,7 @@ noinst_HEADERS = Admin.hpp \
DocumentBroker.hpp \
Exceptions.hpp \
FileServer.hpp \
+ common/FileUtil.hpp \
IoUtil.hpp \
LibreOfficeKit.hpp \
Log.hpp \
diff --git a/loolwsd/Storage.cpp b/loolwsd/Storage.cpp
index d504db0..bc65efe 100644
--- a/loolwsd/Storage.cpp
+++ b/loolwsd/Storage.cpp
@@ -30,6 +30,7 @@
#include "Auth.hpp"
#include "Common.hpp"
#include "Exceptions.hpp"
+#include "common/FileUtil.hpp"
#include "LOOLWSD.hpp"
#include "Log.hpp"
#include "Unit.hpp"
@@ -217,7 +218,7 @@ std::string LocalStorage::loadStorageFileToLocal()
// Despite the talk about URIs it seems that _uri is actually just a pathname here
const auto publicFilePath = _uri.getPath();
- if (!Util::checkDiskSpace(publicFilePath))
+ if (!FileUtil::checkDiskSpace(publicFilePath))
{
throw StorageSpaceLowException("Low disk space for " + publicFilePath);
}
diff --git a/loolwsd/TileCache.cpp b/loolwsd/TileCache.cpp
index d26db3b..41d9bd0 100644
--- a/loolwsd/TileCache.cpp
+++ b/loolwsd/TileCache.cpp
@@ -32,6 +32,7 @@
#include "ClientSession.hpp"
#include "Common.hpp"
+#include "common/FileUtil.hpp"
#include "LOOLProtocol.hpp"
#include "Unit.hpp"
#include "Util.hpp"
@@ -60,7 +61,7 @@ TileCache::TileCache(const std::string& docURL,
getTextFile("unsaved.txt") != ""))
{
// Document changed externally or modifications were not saved after all. Cache not useful.
- Util::removeFile(_cacheDir, true);
+ FileUtil::removeFile(_cacheDir, true);
Log::info("Completely cleared tile cache: " + _cacheDir);
}
@@ -157,8 +158,10 @@ void TileCache::saveTileAndNotify(const TileDesc& tile, const char *data, const
// Ignore if we can't save the tile, things will work anyway, but slower. An error indication
// has been supposed to be sent to all users in that case.
const auto fileName = _cacheDir + "/" + cachedName;
- if (Util::saveDataToFileSafely(fileName, data, size))
+ if (FileUtil::saveDataToFileSafely(fileName, data, size))
+ {
Log::trace() << "Saved cache tile: " << fileName << Log::end;
+ }
// Notify subscribers, if any.
if (tileBeingRendered)
@@ -294,7 +297,7 @@ void TileCache::saveRendering(const std::string& name, const std::string& dir, c
const std::string fileName = dirName + "/" + name;
- Util::saveDataToFileSafely(fileName, data, size);
+ FileUtil::saveDataToFileSafely(fileName, data, size);
}
std::unique_ptr<std::fstream> TileCache::lookupCachedFile(const std::string& name, const std::string& dir)
@@ -332,7 +335,7 @@ void TileCache::invalidateTiles(int part, int x, int y, int width, int height)
if (intersectsTile(fileName, part, x, y, width, height))
{
Log::debug("Removing tile: " + tileIterator.path().toString());
- Util::removeFile(tileIterator.path());
+ FileUtil::removeFile(tileIterator.path());
}
}
}
diff --git a/loolwsd/Util.cpp b/loolwsd/Util.cpp
index afa23f3..7949c09 100644
--- a/loolwsd/Util.cpp
+++ b/loolwsd/Util.cpp
@@ -98,8 +98,6 @@ namespace rng
return ss.str().substr(0, length);
}
- /// Generates a random string suitable for
- /// file/directory names.
std::string getFilename(const size_t length)
{
std::string s = getB64String(length);
@@ -109,15 +107,6 @@ namespace rng
}
}
-namespace
-{
- void alertAllUsersAndLog(const std::string& message, const std::string& cmd, const std::string& kind)
- {
- Log::error(message);
- Util::alertAllUsers(cmd, kind);
- }
-}
-
namespace Util
{
std::string encodeId(const unsigned number, const int padding)
@@ -136,171 +125,15 @@ namespace Util
return id;
}
- /// Create a secure, random directory path.
- std::string createRandomDir(const std::string& path)
- {
- const auto name = rng::getFilename(64);
- Poco::File(Poco::Path(path, name)).createDirectories();
- return name;
- }
-
- std::string getTempFilePath(const std::string& srcDir, const std::string& srcFilename)
- {
- const std::string srcPath = srcDir + '/' + srcFilename;
- const std::string dstPath = Poco::Path::temp() + encodeId(rng::getNext()) + '_' + srcFilename;
- Poco::File(srcPath).copyTo(dstPath);
- Poco::TemporaryFile::registerForDeletion(dstPath);
- return dstPath;
- }
-
bool windowingAvailable()
{
return std::getenv("DISPLAY") != nullptr;
}
- bool saveDataToFileSafely(const std::string& fileName, const char *data, size_t size)
- {
- const auto tempFileName = fileName + ".temp";
- std::fstream outStream(tempFileName, std::ios::out);
-
- // If we can't create the file properly, just remove it
- if (!outStream.good())
- {
- alertAllUsersAndLog("Creating " + tempFileName + " failed, disk full?", "internal", "diskfull");
- // Try removing both just in case
- std::remove(tempFileName.c_str());
- std::remove(fileName.c_str());
- return false;
- }
- else
- {
- outStream.write(data, size);
- if (!outStream.good())
- {
- alertAllUsersAndLog("Writing to " + tempFileName + " failed, disk full?", "internal", "diskfull");
- outStream.close();
- std::remove(tempFileName.c_str());
- std::remove(fileName.c_str());
- return false;
- }
- else
- {
- outStream.close();
- if (!outStream.good())
- {
- alertAllUsersAndLog("Closing " + tempFileName + " failed, disk full?", "internal", "diskfull");
- std::remove(tempFileName.c_str());
- std::remove(fileName.c_str());
- return false;
- }
- else
- {
- // Everything OK, rename the file to its proper name
- if (std::rename(tempFileName.c_str(), fileName.c_str()) == 0)
- {
- Log::debug() << "Renaming " << tempFileName << " to " << fileName << " OK." << Log::end;
- return true;
- }
- else
- {
- alertAllUsersAndLog("Renaming " + tempFileName + " to " + fileName + " failed, disk full?", "internal", "diskfull");
- std::remove(tempFileName.c_str());
- std::remove(fileName.c_str());
- return false;
- }
- }
- }
- }
- }
-
} // namespace Util
-namespace
-{
-
- struct fs
- {
- fs(const std::string& p, dev_t d)
- : path(p), dev(d)
- {
- }
-
- fs(dev_t d)
- : fs("", d)
- {
- }
-
- std::string path;
- dev_t dev;
- };
-
- struct fsComparator
- {
- bool operator() (const fs& lhs, const fs& rhs) const
- {
- return (lhs.dev < rhs.dev);
- }
- };
-
- static std::mutex fsmutex;
- static std::set<fs, fsComparator> filesystems;
-} // unnamed namespace
-
namespace Util
{
- void registerFileSystemForDiskSpaceChecks(const std::string& path)
- {
- std::lock_guard<std::mutex> lock(fsmutex);
-
- if (path != "")
- {
- std::string dirPath = path;
- std::string::size_type lastSlash = dirPath.rfind('/');
- assert(lastSlash != std::string::npos);
- dirPath = dirPath.substr(0, lastSlash + 1) + ".";
-
- struct stat s;
- if (stat(dirPath.c_str(), &s) == -1)
- return;
- filesystems.insert(fs(dirPath, s.st_dev));
- }
- }
-
- void checkDiskSpaceOnRegisteredFileSystems()
- {
- std::lock_guard<std::mutex> lock(fsmutex);
-
- static std::chrono::steady_clock::time_point lastCheck;
- std::chrono::steady_clock::time_point now(std::chrono::steady_clock::now());
-
- // Don't check more often that once a minute
- if (std::chrono::duration_cast<std::chrono::seconds>(now - lastCheck).count() < 60)
- return;
-
- lastCheck = now;
-
- for (auto& i: filesystems)
- {
- if (!checkDiskSpace(i.path))
- {
- alertAllUsersAndLog("File system of " + i.path + " dangerously low on disk space", "internal", "diskfull");
- break;
- }
- }
- }
-
- bool checkDiskSpace(const std::string& path)
- {
- assert(path != "");
- struct statfs sfs;
- if (statfs(path.c_str(), &sfs) == -1)
- return true;
-
- if (static_cast<double>(sfs.f_bavail) / sfs.f_blocks <= 0.05)
- return false;
- return true;
- }
-
const char *signalName(const int signo)
{
switch (signo)
diff --git a/loolwsd/Util.hpp b/loolwsd/Util.hpp
index ae4c3cd..7e4170f 100644
--- a/loolwsd/Util.hpp
+++ b/loolwsd/Util.hpp
@@ -40,6 +40,10 @@ namespace Util
{
void reseed();
unsigned getNext();
+
+ /// Generates a random string suitable for
+ /// file/directory names.
+ std::string getFilename(const size_t length);
}
/// Encode an integral ID into a string, with padding support.
@@ -47,21 +51,8 @@ namespace Util
/// Decode an integral ID from a string.
unsigned decodeId(const std::string& str);
- /// Creates a randomly name directory within path and returns the name.
- std::string createRandomDir(const std::string& path);
-
bool windowingAvailable();
- // Save data to a file (overwriting an existing file if necessary) with checks for errors. Write
- // to a temporary file in the same directory that is then atomically renamed to the desired name
- // if everything goes well. In case of any error, both the destination file (if it already
- // exists) and the temporary file (if was created, or existed already) are removed. Return true
- // if everything succeeded.
- bool saveDataToFileSafely(const std::string& fileName, const char* data, size_t size);
-
- // We work around some of the mess of using the same sources both on the server side and in unit
- // tests with conditional compilation based on BUILDING_TESTS.
-
#ifndef BUILDING_TESTS
// Send a 'error:' message with the specified cmd and kind parameters to all connected
// clients. This function can be called either in loolwsd or loolkit processes, even if only
@@ -76,21 +67,6 @@ namespace Util
}
#endif
- // Add the file system that 'path' is located on to a list of file systems that are periodically
- // checked for available space. The list is initially empty.
- void registerFileSystemForDiskSpaceChecks(const std::string& path);
-
- // Perform the check. If the free space on any of the registered file systems is below 5%, call
- // 'alertAllUsers("internal", "diskfull")'. The check will be made no more often than once a
- // minute.
- void checkDiskSpaceOnRegisteredFileSystems();
-
- // Check disk space on a specific file system, the one where 'path' is located. This does not
- // add that file system to the list used by 'registerFileSystemForDiskSpaceChecks'. If the free
- // space on the file system is below 5%, return false, otherwise true. Note that this function
- // does not call 'alertAllUsers'.
- bool checkDiskSpace(const std::string& path);
-
/// Assert that a lock is already taken.
template <typename T>
void assertIsLocked(const T& lock)
@@ -103,33 +79,6 @@ namespace Util
assert(!mtx.try_lock());
}
- /// Safely remove a file or directory.
- /// Supresses exception when the file is already removed.
- /// This can happen when there is a race (unavoidable) or when
- /// we don't care to check before we remove (when no race exists).
- inline void removeFile(const std::string& path, const bool recursive = false)
- {
- try
- {
- Poco::File(path).remove(recursive);
- }
- catch (const std::exception&)
- {
- // Already removed or we don't care about failures.
- }
- }
-
- inline void removeFile(const Poco::Path& path, const bool recursive = false)
- {
- removeFile(path.toString(), recursive);
- }
-
- /// Make a temp copy of a file.
- /// Primarily used by tests to avoid tainting the originals.
- /// srcDir shouldn't end with '/' and srcFilename shouldn't contain '/'.
- /// Returns the created file path.
- std::string getTempFilePath(const std::string& srcDir, const std::string& srcFilename);
-
/// Returns the name of the signal.
const char* signalName(int signo);
diff --git a/loolwsd/common/FileUtil.cpp b/loolwsd/common/FileUtil.cpp
new file mode 100644
index 0000000..461513e
--- /dev/null
+++ b/loolwsd/common/FileUtil.cpp
@@ -0,0 +1,202 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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 "FileUtil.hpp"
+#include "config.h"
+
+#include <sys/stat.h>
+#include <sys/vfs.h>
+
+#include <chrono>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fstream>
+#include <mutex>
+#include <string>
+
+#include <Poco/TemporaryFile.h>
+
+#include "Log.hpp"
+#include "Util.hpp"
+
+namespace
+{
+ void alertAllUsersAndLog(const std::string& message, const std::string& cmd, const std::string& kind)
+ {
+ Log::error(message);
+ Util::alertAllUsers(cmd, kind);
+ }
+}
+
+namespace FileUtil
+{
+ std::string createRandomDir(const std::string& path)
+ {
+ const auto name = Util::rng::getFilename(64);
+ Poco::File(Poco::Path(path, name)).createDirectories();
+ return name;
+ }
+
+ std::string getTempFilePath(const std::string& srcDir, const std::string& srcFilename)
+ {
+ const std::string srcPath = srcDir + '/' + srcFilename;
+ const std::string dstPath = Poco::Path::temp() + Util::encodeId(Util::rng::getNext()) + '_' + srcFilename;
+ Poco::File(srcPath).copyTo(dstPath);
+ Poco::TemporaryFile::registerForDeletion(dstPath);
+ return dstPath;
+ }
+
+ bool saveDataToFileSafely(const std::string& fileName, const char *data, size_t size)
+ {
+ const auto tempFileName = fileName + ".temp";
+ std::fstream outStream(tempFileName, std::ios::out);
+
+ // If we can't create the file properly, just remove it
+ if (!outStream.good())
+ {
+ alertAllUsersAndLog("Creating " + tempFileName + " failed, disk full?", "internal", "diskfull");
+ // Try removing both just in case
+ std::remove(tempFileName.c_str());
+ std::remove(fileName.c_str());
+ return false;
+ }
+ else
+ {
+ outStream.write(data, size);
+ if (!outStream.good())
+ {
+ alertAllUsersAndLog("Writing to " + tempFileName + " failed, disk full?", "internal", "diskfull");
+ outStream.close();
+ std::remove(tempFileName.c_str());
+ std::remove(fileName.c_str());
+ return false;
+ }
+ else
+ {
+ outStream.close();
+ if (!outStream.good())
+ {
+ alertAllUsersAndLog("Closing " + tempFileName + " failed, disk full?", "internal", "diskfull");
+ std::remove(tempFileName.c_str());
+ std::remove(fileName.c_str());
+ return false;
+ }
+ else
+ {
+ // Everything OK, rename the file to its proper name
+ if (std::rename(tempFileName.c_str(), fileName.c_str()) == 0)
+ {
+ Log::debug() << "Renaming " << tempFileName << " to " << fileName << " OK." << Log::end;
+ return true;
+ }
+ else
+ {
+ alertAllUsersAndLog("Renaming " + tempFileName + " to " + fileName + " failed, disk full?", "internal", "diskfull");
+ std::remove(tempFileName.c_str());
+ std::remove(fileName.c_str());
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+} // namespace FileUtil
+
+namespace
+{
+
+ struct fs
+ {
+ fs(const std::string& p, dev_t d)
+ : path(p), dev(d)
+ {
+ }
+
+ fs(dev_t d)
+ : fs("", d)
+ {
+ }
+
+ std::string path;
+ dev_t dev;
+ };
+
+ struct fsComparator
+ {
+ bool operator() (const fs& lhs, const fs& rhs) const
+ {
+ return (lhs.dev < rhs.dev);
+ }
+ };
+
+ static std::mutex fsmutex;
+ static std::set<fs, fsComparator> filesystems;
+
+} // anonymous namespace
+
+namespace FileUtil
+{
+ void registerFileSystemForDiskSpaceChecks(const std::string& path)
+ {
+ std::lock_guard<std::mutex> lock(fsmutex);
+
+ if (path != "")
+ {
+ std::string dirPath = path;
+ std::string::size_type lastSlash = dirPath.rfind('/');
+ assert(lastSlash != std::string::npos);
+ dirPath = dirPath.substr(0, lastSlash + 1) + ".";
+
+ struct stat s;
+ if (stat(dirPath.c_str(), &s) == -1)
+ return;
+ filesystems.insert(fs(dirPath, s.st_dev));
+ }
+ }
+
+ void checkDiskSpaceOnRegisteredFileSystems()
+ {
+ std::lock_guard<std::mutex> lock(fsmutex);
+
+ static std::chrono::steady_clock::time_point lastCheck;
+ std::chrono::steady_clock::time_point now(std::chrono::steady_clock::now());
+
+ // Don't check more often that once a minute
+ if (std::chrono::duration_cast<std::chrono::seconds>(now - lastCheck).count() < 60)
+ return;
+
+ lastCheck = now;
+
+ for (auto& i: filesystems)
+ {
+ if (!checkDiskSpace(i.path))
+ {
+ alertAllUsersAndLog("File system of " + i.path + " dangerously low on disk space", "internal", "diskfull");
+ break;
+ }
+ }
+ }
+
+ bool checkDiskSpace(const std::string& path)
+ {
+ assert(path != "");
+ struct statfs sfs;
+ if (statfs(path.c_str(), &sfs) == -1)
+ return true;
+
+ if (static_cast<double>(sfs.f_bavail) / sfs.f_blocks <= 0.05)
+ return false;
+ return true;
+ }
+
+} // namespace FileUtil
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/common/FileUtil.hpp b/loolwsd/common/FileUtil.hpp
new file mode 100644
index 0000000..aa6bba6
--- /dev/null
+++ b/loolwsd/common/FileUtil.hpp
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ */
+
+#ifndef INCLUDED_FILEUTIL_HPP
+#define INCLUDED_FILEUTIL_HPP
+
+#include <string>
+
+#include <Poco/File.h>
+#include <Poco/Path.h>
+
+namespace FileUtil
+{
+ /// Create a secure, random directory path.
+ std::string createRandomDir(const std::string& path);
+
+ // Save data to a file (overwriting an existing file if necessary) with checks for errors. Write
+ // to a temporary file in the same directory that is then atomically renamed to the desired name
+ // if everything goes well. In case of any error, both the destination file (if it already
+ // exists) and the temporary file (if was created, or existed already) are removed. Return true
+ // if everything succeeded.
+ bool saveDataToFileSafely(const std::string& fileName, const char* data, size_t size);
+
+ // We work around some of the mess of using the same sources both on the server side and in unit
+ // tests with conditional compilation based on BUILDING_TESTS.
+
+#ifndef BUILDING_TESTS
+ // Send a 'error:' message with the specified cmd and kind parameters to all connected
+ // clients. This function can be called either in loolwsd or loolkit processes, even if only
+ // loolwsd obviously has contact with the actual clients; in loolkit it will be forwarded to
+ // loolwsd for redistribution. (This function must be implemented separately in each program
+ // that uses it, it is not in Util.cpp.)
+ void alertAllUsers(const std::string& cmd, const std::string& kind);
+#else
+ // No-op implementation in the test programs
+ inline void alertAllUsers(const std::string&, const std::string&)
+ {
+ }
+#endif
+
+ // Add the file system that 'path' is located on to a list of file systems that are periodically
+ // checked for available space. The list is initially empty.
+ void registerFileSystemForDiskSpaceChecks(const std::string& path);
+
+ // Perform the check. If the free space on any of the registered file systems is below 5%, call
+ // 'alertAllUsers("internal", "diskfull")'. The check will be made no more often than once a
+ // minute.
+ void checkDiskSpaceOnRegisteredFileSystems();
+
+ // Check disk space on a specific file system, the one where 'path' is located. This does not
+ // add that file system to the list used by 'registerFileSystemForDiskSpaceChecks'. If the free
+ // space on the file system is below 5%, return false, otherwise true. Note that this function
+ // does not call 'alertAllUsers'.
+ bool checkDiskSpace(const std::string& path);
+
+ /// Safely remove a file or directory.
+ /// Supresses exception when the file is already removed.
+ /// This can happen when there is a race (unavoidable) or when
+ /// we don't care to check before we remove (when no race exists).
+ inline void removeFile(const std::string& path, const bool recursive = false)
+ {
+ try
+ {
+ Poco::File(path).remove(recursive);
+ }
+ catch (const std::exception&)
+ {
+ // Already removed or we don't care about failures.
+ }
+ }
+
+ inline void removeFile(const Poco::Path& path, const bool recursive = false)
+ {
+ removeFile(path.toString(), recursive);
+ }
+
+ /// Make a temp copy of a file.
+ /// Primarily used by tests to avoid tainting the originals.
+ /// srcDir shouldn't end with '/' and srcFilename shouldn't contain '/'.
+ /// Returns the created file path.
+ std::string getTempFilePath(const std::string& srcDir, const std::string& srcFilename);
+
+} // end namespace FileUtil
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/test/Makefile.am b/loolwsd/test/Makefile.am
index 12f30aa..9de6443 100644
--- a/loolwsd/test/Makefile.am
+++ b/loolwsd/test/Makefile.am
@@ -27,6 +27,7 @@ AM_LDFLAGS = -pthread -module $(MAGIC_TO_FORCE_SHLIB_CREATION)
AM_CPPFLAGS = -pthread -I$(top_srcdir) -DBUILDING_TESTS
wsd_sources = \
+ ../common/FileUtil.cpp \
../IoUtil.cpp \
../Log.cpp \
../LOOLKit.cpp \
diff --git a/loolwsd/test/helpers.hpp b/loolwsd/test/helpers.hpp
index 6b291d8..737601c 100644
--- a/loolwsd/test/helpers.hpp
+++ b/loolwsd/test/helpers.hpp
@@ -40,6 +40,7 @@
#include <cppunit/extensions/HelperMacros.h>
#include <Common.hpp>
+#include "common/FileUtil.hpp"
#include <LOOLProtocol.hpp>
#include <LOOLWebSocket.hpp>
#include <UserMessages.hpp>
@@ -113,7 +114,7 @@ std::vector<char> readDataFromFile(std::unique_ptr<std::fstream>& file)
inline
void getDocumentPathAndURL(const std::string& docFilename, std::string& documentPath, std::string& documentURL)
{
- documentPath = Util::getTempFilePath(TDOC, docFilename);
+ documentPath = FileUtil::getTempFilePath(TDOC, docFilename);
std::string encodedUri;
Poco::URI::encode("file://" + Poco::Path(documentPath).makeAbsolute().toString(), ":/?", encodedUri);
documentURL = "lool/" + encodedUri + "/ws";
diff --git a/loolwsd/test/integration-http-server.cpp b/loolwsd/test/integration-http-server.cpp
index 25aea88..9ca4ec1 100644
--- a/loolwsd/test/integration-http-server.cpp
+++ b/loolwsd/test/integration-http-server.cpp
@@ -26,6 +26,7 @@
#include <cppunit/extensions/HelperMacros.h>
#include <Common.hpp>
+#include "common/FileUtil.hpp"
#include <Util.hpp>
#include "countloolkits.hpp"
@@ -241,7 +242,7 @@ void HTTPServerTest::testScriptsAndLinksPost()
void HTTPServerTest::testConvertTo()
{
- const auto srcPath = Util::getTempFilePath(TDOC, "hello.odt");
+ const auto srcPath = FileUtil::getTempFilePath(TDOC, "hello.odt");
std::unique_ptr<Poco::Net::HTTPClientSession> session(helpers::createSession(_uri));
session->setTimeout(Poco::Timespan(2, 0)); // 2 seconds.
@@ -265,7 +266,7 @@ void HTTPServerTest::testConvertTo()
expectedStream << fileStream.rdbuf();
// Remove the temp files.
- Util::removeFile(srcPath);
+ FileUtil::removeFile(srcPath);
// In some cases the result is prefixed with (the UTF-8 encoding of) the Unicode BOM
// (U+FEFF). Skip that.
More information about the Libreoffice-commits
mailing list