CodeNebula
C++17stladvanced

std::filesystem::directory_options

C++17 · Practical Modern · Compiler flag: -std=c++17

Explanation

Controls the behavior of directory iterators, such as whether to follow symlinks or skip permission-denied entries instead of throwing exceptions.

Real-World Scenario

Scan a directory tree while gracefully skipping folders the current user cannot access.

Quick Snippet

snippet.cpp
#include <filesystem>
namespace fs = std::filesystem;

for (const auto& entry : fs::recursive_directory_iterator(
        "/var", fs::directory_options::skip_permission_denied)) {
    std::cout << entry.path() << "\n";
}

Full Example

directory_options.cpp
// CodeNebula - C++17 Example: std::filesystem::directory_options
// Compile: g++ -std=c++17 -Wall -Wextra -o example directory_options.cpp -lstdc++fs

// std::filesystem::directory_options controls directory iterator behavior:
// whether to follow symlinks and how to handle permission denied errors.

#include <iostream>
#include <filesystem>
#include <fstream>

namespace fs = std::filesystem;

int main() {
    try {
        fs::path base = fs::temp_directory_path() / "cn_dir_opts";
        fs::create_directories(base / "accessible" / "nested");
        { std::ofstream(base / "accessible" / "file.txt") << "data"; }
        { std::ofstream(base / "accessible" / "nested" / "deep.txt") << "deep"; }

        // --- Default options (none) ---
        std::cout << "=== directory_options::none ===" << std::endl;
        std::cout << "Iterating with default options:" << std::endl;
        for (const auto& entry : fs::recursive_directory_iterator(
                base, fs::directory_options::none)) {
            std::cout << "  " << entry.path().filename().string() << std::endl;
        }

        // --- follow_directory_symlink ---
        std::cout << "\n=== follow_directory_symlink ===" << std::endl;
        std::cout << "This option causes recursive_directory_iterator to" << std::endl;
        std::cout << "follow directory symlinks during recursion." << std::endl;
        // Demonstrate the option (symlink creation may fail in sandboxed envs)
        std::error_code ec;
        fs::create_directory_symlink(base / "accessible", base / "link", ec);
        if (!ec) {
            for (const auto& entry : fs::recursive_directory_iterator(
                    base, fs::directory_options::follow_directory_symlink)) {
                std::cout << "  " << entry.path().filename().string() << std::endl;
            }
        } else {
            std::cout << "  (symlink creation not supported here)" << std::endl;
        }

        // --- skip_permission_denied ---
        std::cout << "\n=== skip_permission_denied ===" << std::endl;
        std::cout << "This option silently skips directories that cause" << std::endl;
        std::cout << "permission denied errors instead of throwing." << std::endl;
        // Iterate safely with skip_permission_denied
        for (const auto& entry : fs::recursive_directory_iterator(
                base, fs::directory_options::skip_permission_denied)) {
            std::cout << "  " << entry.path().filename().string() << std::endl;
        }

        // --- Combining options with bitwise OR ---
        std::cout << "\n=== Combining options ===" << std::endl;
        auto combined = fs::directory_options::follow_directory_symlink
                      | fs::directory_options::skip_permission_denied;
        int count = 0;
        for (const auto& entry : fs::recursive_directory_iterator(base, combined)) {
            ++count;
        }
        std::cout << "Entries found with combined options: " << count << std::endl;

        // --- Error handling without skip_permission_denied ---
        std::cout << "\n=== Error code variant ===" << std::endl;
        auto it = fs::recursive_directory_iterator(base, fs::directory_options::none, ec);
        if (!ec) {
            std::cout << "Iterator created successfully" << std::endl;
        }

        // Cleanup
        fs::remove_all(base);
    } catch (const fs::filesystem_error& e) {
        std::cerr << "Filesystem error: " << e.what() << std::endl;
    }

    return 0;
}

/*
Expected output (order may vary):
=== directory_options::none ===
Iterating with default options:
  accessible
  file.txt
  nested
  deep.txt

=== follow_directory_symlink ===
This option causes recursive_directory_iterator to
follow directory symlinks during recursion.
  accessible
  file.txt
  nested
  deep.txt
  link
  file.txt
  nested
  deep.txt

=== skip_permission_denied ===
This option silently skips directories that cause
permission denied errors instead of throwing.
  accessible
  file.txt
  nested
  deep.txt

=== Combining options ===
Entries found with combined options: 4

=== Error code variant ===
Iterator created successfully
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example directory_options.cpp -lstdc++fs