Skip to content

Commit

Permalink
Refactor dir iteration methods
Browse files Browse the repository at this point in the history
Instead of having multiple implementations that iterate over all the
files in a directory for different purposes, create a single unified
version that is generic enough to satisfy all of them.
  • Loading branch information
dtrugman committed May 25, 2021
1 parent c599166 commit dc1b1c9
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 38 deletions.
10 changes: 9 additions & 1 deletion include/pfs/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
#ifndef PFS_UTILS_HPP
#define PFS_UTILS_HPP

#include <stddef.h>
#include <fcntl.h>
#include <stddef.h>

#include <functional>
#include <limits>
#include <set>
#include <string>
Expand Down Expand Up @@ -83,6 +84,13 @@ stot(const std::string& str, T& out, base b = base::decimal)
out = static_cast<T>(temp);
}

// Iterate over all the files in a given directory.
// Calls 'handle' for every file found.
// Note: 'handle' can be nullptr. Use this to count the number of files in a
// directory. Returns the number of files found.
size_t iterate_files(const std::string& dir, bool include_dots,
std::function<void(const char*)> handle);

// Count all the files under the specified directory.
// File can be any unix file type, i.e. regular file, directory, link, etc.
size_t count_files(const std::string& dir, bool include_dots = false);
Expand Down
61 changes: 24 additions & 37 deletions src/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* limitations under the License.
*/

#include <stddef.h>
#include <dirent.h>
#include <linux/limits.h>
#include <stddef.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
Expand All @@ -32,10 +32,13 @@ namespace pfs {
namespace impl {
namespace utils {

size_t count_files(const std::string& dir, bool include_dots)
size_t iterate_files(const std::string& dir, bool include_dots,
std::function<void(const char*)> handle)
{
static const char DOTFILE_PREFIX = '.';

size_t count = 0;

DIR* dp = opendir(dir.c_str());
if (!dp)
{
Expand All @@ -44,8 +47,6 @@ size_t count_files(const std::string& dir, bool include_dots)
}
defer close_dp([dp] { closedir(dp); });

size_t count = 0;

struct dirent* entry;
while ((entry = readdir(dp)))
{
Expand All @@ -56,61 +57,47 @@ size_t count_files(const std::string& dir, bool include_dots)
continue;
}

count++;
++count;

if (handle)
{
handle(entry->d_name);
}
}

return count;
}

std::set<std::string> enumerate_files(const std::string& dir, bool include_dots)
size_t count_files(const std::string& dir, bool include_dots)
{
static const char DOTFILE_PREFIX = '.';

DIR* dp = opendir(dir.c_str());
if (!dp)
{
throw std::system_error(errno, std::system_category(),
"Couldn't open dir");
}
defer close_dp([dp] { closedir(dp); });
return iterate_files(dir, include_dots, nullptr);
}

std::set<std::string> enumerate_files(const std::string& dir, bool include_dots)
{
std::set<std::string> files;
auto handle = [&files](const char* name) { files.emplace(name); };

struct dirent* entry;
while ((entry = readdir(dp)))
{
// It's safe to access index 0.
// It's either a valid char or a null-terminator.
if (entry->d_name[0] == DOTFILE_PREFIX && !include_dots)
{
continue;
}

files.emplace(entry->d_name);
}

(void)iterate_files(dir, include_dots, handle);
return files;
}

std::set<int> enumerate_numeric_files(const std::string& dir)
{
std::set<int> num_files;

auto files = enumerate_files(dir);
for (const auto& file : files)
{
std::set<int> files;
auto handle = [&files](const char* name) {
try
{
int num = std::stoi(file);
num_files.insert(num);
files.insert(std::stoi(name));
}
catch (const std::logic_error&)
{
// Do nothing, not a numeric file name
}
}
};

return num_files;
(void)iterate_files(dir, false /* include_dots */, handle);
return files;
}

std::string readlink(const std::string& link, int dirfd)
Expand Down

0 comments on commit dc1b1c9

Please sign in to comment.