mirror of
https://github.com/NixOS/nix
synced 2025-06-25 10:41:16 +02:00
add DirectoryIterator to re-throw std::filesystem::filesystem_error
Co-authored-by: Sergei Zimmerman <145775305+xokdvium@users.noreply.github.com>
(cherry picked from commit 7ccc0d591f
)
This commit is contained in:
parent
8de4c272dc
commit
0f4b17e51f
3 changed files with 126 additions and 0 deletions
|
@ -275,4 +275,26 @@ TEST(makeParentCanonical, root)
|
|||
{
|
||||
ASSERT_EQ(makeParentCanonical("/"), "/");
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* DirectoryIterator
|
||||
* --------------------------------------------------------------------------*/
|
||||
|
||||
TEST(DirectoryIterator, works)
|
||||
{
|
||||
auto tmpDir = nix::createTempDir();
|
||||
nix::AutoDelete delTmpDir(tmpDir, true);
|
||||
|
||||
nix::writeFile(tmpDir + "/somefile", "");
|
||||
|
||||
for (auto path : DirectoryIterator(tmpDir)) {
|
||||
ASSERT_EQ(path.path().string(), tmpDir + "/somefile");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DirectoryIterator, nonexistent)
|
||||
{
|
||||
ASSERT_THROW(DirectoryIterator("/schnitzel/darmstadt/pommes"), SysError);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,34 @@ namespace fs {
|
|||
}
|
||||
}
|
||||
|
||||
DirectoryIterator::DirectoryIterator(const std::filesystem::path& p) {
|
||||
try {
|
||||
// **Attempt to create the underlying directory_iterator**
|
||||
it_ = std::filesystem::directory_iterator(p);
|
||||
} catch (const std::filesystem::filesystem_error& e) {
|
||||
// **Catch filesystem_error and throw SysError**
|
||||
// Adapt the error message as needed for SysError
|
||||
throw SysError("cannot read directory %s", p);
|
||||
}
|
||||
}
|
||||
|
||||
DirectoryIterator& DirectoryIterator::operator++() {
|
||||
// **Attempt to increment the underlying iterator**
|
||||
std::error_code ec;
|
||||
it_.increment(ec);
|
||||
if (ec) {
|
||||
// Try to get path info if possible, might fail if iterator is bad
|
||||
try {
|
||||
if (it_ != std::filesystem::directory_iterator{}) {
|
||||
throw SysError("cannot read directory past %s: %s", it_->path(), ec.message());
|
||||
}
|
||||
} catch (...) {
|
||||
throw SysError("cannot read directory");
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isAbsolute(PathView path)
|
||||
{
|
||||
return fs::path { path }.is_absolute();
|
||||
|
|
|
@ -360,4 +360,80 @@ typedef std::function<bool(const Path & path)> PathFilter;
|
|||
|
||||
extern PathFilter defaultPathFilter;
|
||||
|
||||
/**
|
||||
* Change permissions of a file only if necessary.
|
||||
*
|
||||
* @details
|
||||
* Skip chmod call if the directory already has the requested permissions.
|
||||
* This is to avoid failing when the executing user lacks permissions to change the
|
||||
* directory's permissions even if it would be no-op.
|
||||
*
|
||||
* @param path Path to the file to change the permissions for.
|
||||
* @param mode New file mode.
|
||||
* @param mask Used for checking if the file already has requested permissions.
|
||||
*
|
||||
* @return true if permissions changed, false otherwise.
|
||||
*/
|
||||
bool chmodIfNeeded(const std::filesystem::path & path, mode_t mode, mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
|
||||
/**
|
||||
* @brief A directory iterator that can be used to iterate over the
|
||||
* contents of a directory. It is similar to std::filesystem::directory_iterator
|
||||
* but throws NixError on failure instead of std::filesystem::filesystem_error.
|
||||
*/
|
||||
class DirectoryIterator {
|
||||
public:
|
||||
// --- Iterator Traits ---
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = std::filesystem::directory_entry;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = const std::filesystem::directory_entry*;
|
||||
using reference = const std::filesystem::directory_entry&;
|
||||
|
||||
// Default constructor (represents end iterator)
|
||||
DirectoryIterator() noexcept = default;
|
||||
|
||||
// Constructor taking a path
|
||||
explicit DirectoryIterator(const std::filesystem::path& p);
|
||||
|
||||
reference operator*() const {
|
||||
// Accessing the value itself doesn't typically throw filesystem_error
|
||||
// after successful construction/increment, but underlying operations might.
|
||||
// If directory_entry methods called via -> could throw, add try-catch there.
|
||||
return *it_;
|
||||
}
|
||||
|
||||
pointer operator->() const {
|
||||
return &(*it_);
|
||||
}
|
||||
|
||||
|
||||
DirectoryIterator& operator++();
|
||||
|
||||
// Postfix increment operator
|
||||
DirectoryIterator operator++(int) {
|
||||
DirectoryIterator temp = *this;
|
||||
++(*this); // Uses the prefix increment's try-catch logic
|
||||
return temp;
|
||||
}
|
||||
|
||||
// Equality comparison
|
||||
friend bool operator==(const DirectoryIterator& a, const DirectoryIterator& b) noexcept {
|
||||
return a.it_ == b.it_;
|
||||
}
|
||||
|
||||
// Inequality comparison
|
||||
friend bool operator!=(const DirectoryIterator& a, const DirectoryIterator& b) noexcept {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
// Allow direct use in range-based for loops if iterating over an instance
|
||||
DirectoryIterator begin() const { return *this; }
|
||||
DirectoryIterator end() const { return DirectoryIterator{}; }
|
||||
|
||||
|
||||
private:
|
||||
std::filesystem::directory_iterator it_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue