| Crates.io | walkdir_minimal |
| lib.rs | walkdir_minimal |
| version | 1.0.1 |
| created_at | 2025-11-09 14:26:42.317085+00 |
| updated_at | 2025-11-09 14:41:05.683795+00 |
| description | Minimal, dependency-free POSIX-focused directory walker in 100% Rust |
| homepage | https://github.com/LinuxDicasPro/walkdir_minimal |
| repository | https://github.com/LinuxDicasPro/walkdir_minimal |
| max_upload_size | |
| id | 1924171 |
| size | 427,266 |
walkdir_minimal is a lightweight, POSIX-only directory walker written in
100% safe Rust, designed for maximum portability, robust error handling,
and predictable iteration order across UNIX-like systems (Linux, BSDs, Solaris).
Unlike the popular walkdir crate, which
offers extensive configurability and Windows support, walkdir_minimal aims to
provide a clean, dependency-free and fully deterministic implementation
that follows the UNIX filesystem model precisely β no abstractions, no hidden
buffering, no non-POSIX extensions.
π§± POSIX-only: Works on Linux, FreeBSD, OpenBSD, NetBSD, and Solaris.
βοΈ No dependencies: Implemented using only std::fs, std::path, and
minimal data structures.
𦦠Lightweight and predictable: The walker uses a manual stack (no recursion), allowing predictable memory and performance behavior.
π¦ Configurable options via WalkOptions:
follow_links: whether to follow symbolic links to directories.max_depth: optional limit on traversal depth.π§ Cycle detection: Detects and prevents infinite loops caused by symbolic links that form cycles.
π« Graceful handling of I/O errors: Broken symlinks, permission-denied
directories, and other errors are returned as Err(WalkError::Io).
𦦠Filtering: Supports entry-level filtering with a user-provided closure.
π§« Deterministic: The order of traversal follows the order provided by the
filesystemβs readdir(3) implementation β consistent across runs on the same system.
π§ͺ Minimal yet robust: Designed for projects that require reliable, low-level control rather than high-level abstraction.
walkdir_minimal is built under the following principles:
lstat, stat, opendir, readdir, etc., via Rustβs std::fs).Vec for the manual stack
and HashSet for visited inode/device pairs (loop detection).walkdir_minimal embodies clarity over complexity. Its goal is not to compete
with feature-rich crates, but to provide a clean reference implementation
of a POSIX-only directory walker.
walkdir| Feature | walkdir |
walkdir_minimal |
|---|---|---|
| Cross-platform | β (Windows, macOS, Linux) | β POSIX only |
| Dependencies | Many (e.g., same-file, winapi) | β None |
| Error handling | Complex iterator states | Simple Result<Entry, WalkError> |
| Loop detection | Optional, platform-specific | Deterministic (dev, ino) hashing |
| Symbolic links | Optional follow | Optional follow |
| Custom sorting | Supported | Not supported (filesystem order only) |
| Performance | Optimized for general use | Optimized for predictability |
| Safety | 100% safe Rust | 100% safe Rust |
| Recursion | Implicit | Manual stack |
| Binary size | Larger | Tiny |
| Filter API | Supported (filter_entry) |
Supported |
| Error type | walkdir::Error |
WalkError |
| Metadata caching | Yes | No (on-demand) |
| Thread safety | Yes | No (intentionally minimal) |
use walkdir_minimal::{WalkDir, WalkError};
fn main() -> Result<(), WalkError> {
for entry in WalkDir::new(".")?.follow_links(false) {
match entry {
Ok(e) => println!("{}", e.path().display()),
Err(err) => eprintln!("Error: {}", err),
}
}
Ok(())
}
Output example:
.
./src
./src/lib.rs
./src/entry.rs
./src/error.rs
./src/walkdir.rs
#[derive(Clone, Debug)]
pub struct WalkOptions {
pub follow_links: bool,
pub max_depth: usize,
}
follow_links β When true, symbolic links to directories are followed.
max_depth β Optional limit to recursion depth. None means unlimited.
0.1, and so on.pub struct Entry {
path: PathBuf,
depth: usize,
}
impl Entry {
pub fn path(&self) -> &Path;
pub fn depth(&self) -> usize;
pub fn metadata(&self) -> io::Result<fs::Metadata>;
pub fn symlink_metadata(&self) -> io::Result<fs::Metadata>;
pub fn file_type(&self) -> io::Result<fs::FileType>;
}
metadata() calls fs::metadata, following symlinks.symlink_metadata() calls fs::symlink_metadata, not following symlinks.file_type() reports the symbolic link type correctly.pub enum WalkError {
Io(io::Error),
LoopDetected(PathBuf),
}
Io(io::Error) β Covers all I/O-related errors, including:
ENOENT)EACCES)LoopDetected(PathBuf) β Reported when a cyclic symbolic link is
detected (only if loop detection is enabled).
| Case | Behavior |
|---|---|
| Broken symlink | Yields Err(WalkError::Io) |
| Permission denied directory | Yields Err(WalkError::Io) and continues |
| Loop via symlink | Yields Err(WalkError::LoopDetected) if detection is on |
| Regular file as root | Returns file directly, no traversal |
| Unreadable entry | Returns Err(WalkError::Io) |
Exceeds max_depth |
Skips entry silently (depth-guarded) |
walkdir_minimal implements a depth-first directory traversal without relying on
any external dependencies, using only POSIX APIs available through Rustβs standard
library. The iterator is built around a manual stack-based traversal that mimics
recursion, avoiding stack overflows for deeply nested directories.
StackEntry structs,
each holding an active ReadDir handle and its depth.HashSet<(dev, ino)> to detect and skip cyclic
symlinks, preventing infinite recursion.filter_entry) allow
pruning of the traversal tree dynamically.Result, and errors
are surfaced as WalkError variants (Io, LoopDetected).walkdir_minimal follows a fail-soft philosophy:
Ok(Entry) unless metadata is explicitly requested.EACCES) return an Err(WalkError::Io),
allowing iteration to continue with the next entry.Err(WalkError::Io) gracefully.This mirrors walkdirβs behavior but keeps it predictable and minimal.
Entry deliberately does not cache metadata by default. This ensures:
metadata() or
symlink_metadata() selectively.let entry = Entry::new(path, depth);
if let Ok(meta) = entry.metadata() {
println!("File size: {} bytes", meta.len());
}
walkdir_minimal targets POSIX systems only β this includes:
It relies on MetadataExt for device/inode access, which is non-portable
to Windows. No attempt is made to support non-POSIX environments.
ReadDir handle open at a time per stack frame.HashSet, Vec, ReadDir, etc.).Example: skipping hidden files and following symlinks safely:
use walkdir_minimal::WalkDir;
let iter = WalkDir::new("/usr")
.unwrap()
.follow_links(true)
.filter_entry(|e| !e.path().file_name().map(|n| n.to_string_lossy().starts_with('.')).unwrap_or(false));
for entry in iter {
match entry {
Ok(e) => println!("{}", e.path().display()),
Err(err) => eprintln!("Error: {}", err),
}
}
walkdir_minimal?(dev, ino) pairs to identify unique directories.follow_links is disabled, symlink loops are naturally impossible.max_depth limits traversal, excluding deeper entries.Contributions are very welcome! Whether itβs fixing a bug, improving documentation, or adding new features that align with the minimalist and POSIX-only philosophy, your input is appreciated.
Please follow these guidelines when contributing:
unsafe code will be accepted.If you find a bug or have a suggestion for improvement:
Pull requests should target the main branch and include clear commit messages.
walkdir_minimal includes tests for common scenarios:
Run the test suite with:
cargo test
walkdir_minimal/
βββ src/
β βββ lib.rs # Main crate entry
β βββ entry.rs # Defines the Entry type
β βββ error.rs # WalkError and error utilities
β βββ options.rs # WalkOptions definition
β βββ tests.rs # Unit and integration tests
β βββ walkdir.rs # Core iterator implementation
βββ README.md # Project documentation
βββ LICENSE # License file (MIT)
βββ Cargo.toml # Package metadata
This project is licensed under the MIT License.
See the LICENSE file for full details.
By contributing to this repository, you agree that your contributions will be licensed under the same MIT terms.
All notable changes to this project will be documented
in the changelog file.
Created and maintained by LinuxDicasPro.
If you find this project useful, consider starring the repository or contributing feedback to improve it further.