Skip to content

Commit c8aeb26

Browse files
author
Andrei Popescu
authored
Fix olp::utils::Dir::Size() recursive behaviour. (#1362)
This commit fixes the recursive behaviour of the olp::utils::Dir::Size() method to go all the way deep and find all not filtered out files to consider for calculating the dir size. This is done by using a queue to push every found dir inside the currently scanned dir onto it for further dept scanning. Relates-To: OLPEDGE-2700 Signed-off-by: Andrei Popescu <andrei.popescu@here.com> Signed-off-by: Andrei Popescu <andrei.popescu@here.com>
1 parent 16e1212 commit c8aeb26

File tree

2 files changed

+45
-33
lines changed

2 files changed

+45
-33
lines changed

olp-cpp-sdk-core/include/olp/core/utils/Dir.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace olp {
2828
namespace utils {
2929

3030
/** @brief Manages directories.
31-
*/
31+
*/
3232
class CORE_API Dir {
3333
public:
3434
/// An alias for the filter function.
@@ -115,8 +115,11 @@ class CORE_API Dir {
115115
/**
116116
* @brief Calculates the size of a directory.
117117
*
118-
* Use a filter to exclude
119-
* unnecessary files or directories from the calculation.
118+
* Use a filter to exclude unnecessary files or directories from the
119+
* calculation.
120+
*
121+
* @note This method will go all the way recursive for as long as needed
122+
* to gather all files which pass the given filter.
120123
*
121124
* @param path The path of the directory.
122125
* @param filter_fn The filter function.

olp-cpp-sdk-core/src/utils/Dir.cpp

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
#include <sys/stat.h>
3737
#include <sys/types.h>
3838
#include <unistd.h>
39+
#include <queue>
40+
#include <string>
3941
#endif
4042

4143
#if defined(_WIN32) && !defined(__MINGW32__)
@@ -436,36 +438,38 @@ uint64_t Dir::Size(const std::string& path, FilterFunction filter_fn) {
436438

437439
#else
438440

439-
DIR* dir = nullptr;
440-
struct dirent* ent = nullptr;
441+
std::queue<std::string> recursive_queue;
442+
recursive_queue.push(path);
443+
444+
auto iterate_directory = [&](const std::string& path) {
445+
auto* dir = ::opendir(path.c_str());
446+
if (dir == nullptr) {
447+
return;
448+
}
449+
450+
struct ::dirent* entry = nullptr;
451+
while ((entry = ::readdir(dir)) != nullptr) {
452+
const char* entry_name = entry->d_name;
453+
454+
if (strcmp(entry_name, ".") == 0 || strcmp(entry_name, "..") == 0) {
455+
continue;
456+
}
457+
458+
std::string full_path = path + "/" + entry_name;
441459

442-
if ((dir = opendir(path.c_str())) != nullptr) {
443-
while ((ent = readdir(dir)) != nullptr) {
444-
std::string ent_path = path + "/" + ent->d_name;
445460
#ifdef __APPLE__
446-
struct stat sb;
447-
if (lstat(ent_path.c_str(), &sb) == 0) {
461+
struct ::stat path_stat;
462+
if (::lstat(full_path.c_str(), &path_stat) == 0) {
448463
#else
449-
struct stat64 sb;
450-
if (lstat64(ent_path.c_str(), &sb) == 0) {
464+
struct ::stat64 path_stat;
465+
if (::lstat64(full_path.c_str(), &path_stat) == 0) {
451466
#endif
452-
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
453-
continue;
454-
}
455-
456-
if (filter_fn && !filter_fn(ent->d_name)) {
457-
continue;
458-
}
459-
460-
switch (sb.st_mode & S_IFMT) {
461-
case S_IFDIR:
462-
result += Size(ent_path, filter_fn);
463-
break;
464-
case S_IFREG:
465-
result += sb.st_size;
466-
break;
467-
default:
468-
break;
467+
if (S_ISREG(path_stat.st_mode)) {
468+
if (filter_fn && filter_fn(entry_name)) {
469+
result += path_stat.st_size;
470+
}
471+
} else if (S_ISDIR(path_stat.st_mode)) {
472+
recursive_queue.push(std::move(full_path));
469473
}
470474
} else if (errno != ENOENT) {
471475
// Ignore ENOENT errors as its a common case, e.g. cache compaction.
@@ -474,7 +478,12 @@ uint64_t Dir::Size(const std::string& path, FilterFunction filter_fn) {
474478
}
475479
}
476480

477-
closedir(dir);
481+
::closedir(dir);
482+
};
483+
484+
while (!recursive_queue.empty()) {
485+
iterate_directory(recursive_queue.front());
486+
recursive_queue.pop();
478487
}
479488

480489
#endif
@@ -485,10 +494,10 @@ uint64_t Dir::Size(const std::string& path, FilterFunction filter_fn) {
485494
bool Dir::IsReadOnly(const std::string& path) {
486495
#if defined(_WIN32) && !defined(__MINGW32__)
487496
#ifdef _UNICODE
488-
std::wstring wstrPath = ConvertStringToWideString(path);
489-
const TCHAR* syspath = wstrPath.c_str();
497+
std::wstring wstrPath = ConvertStringToWideString(path);
498+
const TCHAR* syspath = wstrPath.c_str();
490499
#else
491-
const TCHAR* syspath = path.c_str();
500+
const TCHAR* syspath = path.c_str();
492501
#endif // _UNICODE
493502

494503
// Read only flag is for files inside directory

0 commit comments

Comments
 (0)