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) {
485494bool 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