loolwsd/TileCache.cpp | 11 ++------- loolwsd/Util.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ loolwsd/Util.hpp | 7 ++++++ 3 files changed, 67 insertions(+), 8 deletions(-)
New commits: commit 8055dfc089cf860806b987f7aa2dd07dc72d6f26 Author: Tor Lillqvist <t...@collabora.com> Date: Tue Oct 11 19:35:16 2016 +0300 Handle disk full situations more gracefully Introduce new API in our Util namespace to save data to a file safely. The data is written to a temporary file in the same directory and after that has succeeded, it is renamed atomicaly to the intended name. If any step of the saving fails, neither the temporay file or the intended target (if one exists before) is left behind. Unlike in the master branch, here we don't show any message to the users when that happens. At least not yet. Back-porting that full functionality was harder than expected, and I wanted to get in at least this fix first, to avoid zero-size cached tiles. diff --git a/loolwsd/TileCache.cpp b/loolwsd/TileCache.cpp index 74bafc6..fb32f0c 100644 --- a/loolwsd/TileCache.cpp +++ b/loolwsd/TileCache.cpp @@ -122,11 +122,8 @@ void TileCache::saveTile(int part, int width, int height, int tilePosX, int tile { const std::string fileName = _cacheDir + "/" + cacheFileName(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight); - Log::trace() << "Saving cache tile: " << fileName << Log::end; - - std::fstream outStream(fileName, std::ios::out); - outStream.write(data, size); - outStream.close(); + if (Util::saveDataToFileSafely(fileName, data, size)) + Log::trace() << "Saved cache tile: " << fileName << Log::end; } std::string TileCache::getTextFile(const std::string& fileName) @@ -193,9 +190,7 @@ void TileCache::saveRendering(const std::string& name, const std::string& dir, c const std::string fileName = dirName + "/" + name; - std::fstream outStream(fileName, std::ios::out); - outStream.write(data, size); - outStream.close(); + Util::saveDataToFileSafely(fileName, data, size); } std::unique_ptr<std::fstream> TileCache::lookupRendering(const std::string& name, const std::string& dir) diff --git a/loolwsd/Util.cpp b/loolwsd/Util.cpp index 6bc06cc..8caf37f 100644 --- a/loolwsd/Util.cpp +++ b/loolwsd/Util.cpp @@ -18,8 +18,10 @@ #include <atomic> #include <cassert> +#include <cstdio> #include <cstdlib> #include <cstring> +#include <fstream> #include <iostream> #include <iomanip> #include <mutex> @@ -169,6 +171,61 @@ namespace Util return std::getenv("DISPLAY") != nullptr; } + bool saveDataToFileSafely(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()) + { + Log::error("Creating " + tempFileName + " failed, disk full?"); + // 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()) + { + Log::error("Writing to " + tempFileName + " failed, disk full?"); + outStream.close(); + std::remove(tempFileName.c_str()); + std::remove(fileName.c_str()); + return false; + } + else + { + outStream.close(); + if (!outStream.good()) + { + Log::error("Closing " + tempFileName + " failed, disk full?"); + 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 + { + Log::error("Renaming " + tempFileName + " to " + fileName + " failed, disk full?"); + std::remove(tempFileName.c_str()); + std::remove(fileName.c_str()); + return false; + } + } + } + } + } + bool encodeBufferToPNG(unsigned char *pixmap, int width, int height, std::vector<char>& output, LibreOfficeKitTileMode mode) { diff --git a/loolwsd/Util.hpp b/loolwsd/Util.hpp index 8907d9c..17142f1 100644 --- a/loolwsd/Util.hpp +++ b/loolwsd/Util.hpp @@ -49,6 +49,13 @@ namespace Util 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(std::string fileName, const char *data, size_t size); + // Sadly, older libpng headers don't use const for the pixmap pointer parameter to // png_write_row(), so can't use const here for pixmap. bool encodeBufferToPNG(unsigned char* pixmap, int width, int height, _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits