diff --git a/src/libcommonserver/io/iohelper.cpp b/src/libcommonserver/io/iohelper.cpp index f6c669a8d..17f1092c1 100644 --- a/src/libcommonserver/io/iohelper.cpp +++ b/src/libcommonserver/io/iohelper.cpp @@ -323,7 +323,8 @@ bool IoHelper::getFileSize(const SyncPath &path, uint64_t &size, IoError &ioErro return true; } -bool IoHelper::getDirectorySize(const SyncPath &path, uint64_t &size, IoError &ioError) { +bool IoHelper::getDirectorySize(const SyncPath &path, uint64_t &size, unsigned int maxDepth, bool &skipedTooDeep, + IoError &ioError) { ItemType itemType; const bool success = getItemType(path, itemType); ioError = itemType.ioError; @@ -350,6 +351,19 @@ bool IoHelper::getDirectorySize(const SyncPath &path, uint64_t &size, IoError &i bool endOfDirectory = false; size = 0; while (dir.next(entry, endOfDirectory, ioError) && !endOfDirectory) { + if (entry.is_directory()) { + if (maxDepth == 0) { + LOG_WARN(Log::instance()->getLogger(), "Max depth reached in getDirectorySize, skipping deeper directories: " + << Utility::formatSyncPath(path).c_str()); + skipedTooDeep = true; + continue; + } + uint64_t entrySize; + if (!getDirectorySize(entry.path(), entrySize, maxDepth - 1, skipedTooDeep, ioError)) { + return false; + } + size += entrySize; + } uint64_t entrySize; std::error_code ec; entrySize = _fileSize(entry.path(), ec); diff --git a/src/libcommonserver/io/iohelper.h b/src/libcommonserver/io/iohelper.h index 086d93360..5e225ffd4 100644 --- a/src/libcommonserver/io/iohelper.h +++ b/src/libcommonserver/io/iohelper.h @@ -61,7 +61,7 @@ struct IoHelper { #ifdef _WIN32 static int _getAndSetRightsMethod; #endif - + static IoError stdError2ioError(int error) noexcept; static IoError stdError2ioError(const std::error_code &ec) noexcept; static IoError posixError2ioError(int error) noexcept; @@ -184,15 +184,18 @@ struct IoHelper { static bool getFileSize(const SyncPath &path, uint64_t &size, IoError &ioError); //! Get the size of the directory indicated by `path`, in bytes. - //! This funciton is recursive. + //! This funciton is recursiv. /*! \param path is the file system path of a directory. \param size holds the size in bytes of the directory indicated by path in case of success. \param ioError holds the error associated to a failure of the underlying OS API call, if any. + \param maxDepth is the maximum depth of the recursion. + \param skipedTooDeep is set to true if the recursion skipped some directories because the depth was too high. \return true if no unexpected error occurred, false otherwise. If path indicates a File, the function returns false and ioError is set with IoErrorIsADirectory. */ - static bool getDirectorySize(const SyncPath &path, uint64_t &size, IoError &ioError); + static bool getDirectorySize(const SyncPath &path, uint64_t &size, unsigned int maxDepth, bool &skipedTooDeep, + IoError &ioError); //! Check if the file indicated by `path` is accessible. //! This is especially useful on Windows where the OS will send a CREATE event while the file is still being copied. diff --git a/src/libcommonserver/log/log.cpp b/src/libcommonserver/log/log.cpp index 1651e21c1..84816ee38 100644 --- a/src/libcommonserver/log/log.cpp +++ b/src/libcommonserver/log/log.cpp @@ -118,9 +118,9 @@ Log::Log(const log4cplus::tstring &filePath) : _filePath(filePath) { bool Log::getLogEstimatedSize(uint64_t &size, IoError &ioError) { const SyncPath logPath = _filePath.parent_path(); ioError = IoErrorSuccess; - for (int i = 0; i < 2; i++) { // Retry once in case a log file is archived/created during the first iteration - bool result = IoHelper::getDirectorySize(logPath, size, ioError); + bool tooDeep = false; + bool result = IoHelper::getDirectorySize(logPath, size, 0, tooDeep, ioError); if (result && ioError == IoErrorSuccess) { return true; } diff --git a/test/libcommonserver/log/testlog.cpp b/test/libcommonserver/log/testlog.cpp index a8510c7ea..9db428ed6 100644 --- a/test/libcommonserver/log/testlog.cpp +++ b/test/libcommonserver/log/testlog.cpp @@ -87,7 +87,8 @@ void TestLog::testCopyLogsTo(void) { CPPUNIT_ASSERT_EQUAL(ExitCodeOk, exitCode); uint64_t tempDirSize = 0; - IoHelper::getDirectorySize(tempDir.path, tempDirSize, err); + bool tooDeep = false; + IoHelper::getDirectorySize(tempDir.path, tempDirSize, 0, tooDeep, err); CPPUNIT_ASSERT_EQUAL(IoErrorSuccess, err); CPPUNIT_ASSERT_EQUAL(logDirsize, tempDirSize); } @@ -157,7 +158,8 @@ void TestLog::testCopyParmsDbTo(void) { CPPUNIT_ASSERT_EQUAL(ExitCodeOk, exitCode); uint64_t tempDirSize = 0; - IoHelper::getDirectorySize(tempDir.path, tempDirSize, err); + bool tooDeep = false; + IoHelper::getDirectorySize(tempDir.path, tempDirSize, 0, tooDeep, err); CPPUNIT_ASSERT_EQUAL(IoErrorSuccess, err); CPPUNIT_ASSERT_EQUAL(parmsDbSize, tempDirSize); } @@ -183,7 +185,9 @@ void TestLog::testCompressLogs(void) { CPPUNIT_ASSERT_EQUAL(IoErrorSuccess, err); uint64_t logDirSize = 0; - CPPUNIT_ASSERT_EQUAL(true, IoHelper::getDirectorySize(logDir, logDirSize, err)); + bool tooDeep = false; + + CPPUNIT_ASSERT_EQUAL(true, IoHelper::getDirectorySize(logDir, logDirSize, 0, tooDeep, err)); CPPUNIT_ASSERT_EQUAL(IoErrorSuccess, err); CPPUNIT_ASSERT(logDirSize >= 0); @@ -194,7 +198,7 @@ void TestLog::testCompressLogs(void) { CPPUNIT_ASSERT_EQUAL(ExitCodeOk, exitCode); uint64_t tempDirSize = 0; - IoHelper::getDirectorySize(tempDir.path, tempDirSize, err); + IoHelper::getDirectorySize(tempDir.path, tempDirSize, 0, tooDeep, err); CPPUNIT_ASSERT_EQUAL(IoErrorSuccess, err); CPPUNIT_ASSERT(tempDirSize < logDirSize);