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.nakash...@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 <ashnak...@gmail.com> Tested-by: Ashod Nakashian <ashnak...@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. _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits