1 /*! 2 Crate `walkdir` provides an efficient and cross platform implementation 3 of recursive directory traversal. Several options are exposed to control 4 iteration, such as whether to follow symbolic links (default off), limit the 5 maximum number of simultaneous open file descriptors and the ability to 6 efficiently skip descending into directories. 7 8 To use this crate, add `walkdir` as a dependency to your project's 9 `Cargo.toml`: 10 11 ```text 12 [dependencies] 13 walkdir = "2" 14 ``` 15 16 # From the top 17 18 The [`WalkDir`] type builds iterators. The [`DirEntry`] type describes values 19 yielded by the iterator. Finally, the [`Error`] type is a small wrapper around 20 [`std::io::Error`] with additional information, such as if a loop was detected 21 while following symbolic links (not enabled by default). 22 23 [`WalkDir`]: struct.WalkDir.html 24 [`DirEntry`]: struct.DirEntry.html 25 [`Error`]: struct.Error.html 26 [`std::io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html 27 28 # Example 29 30 The following code recursively iterates over the directory given and prints 31 the path for each entry: 32 33 ```no_run 34 use walkdir::WalkDir; 35 # use walkdir::Error; 36 37 # fn try_main() -> Result<(), Error> { 38 for entry in WalkDir::new("foo") { 39 println!("{}", entry?.path().display()); 40 } 41 # Ok(()) 42 # } 43 ``` 44 45 Or, if you'd like to iterate over all entries and ignore any errors that 46 may arise, use [`filter_map`]. (e.g., This code below will silently skip 47 directories that the owner of the running process does not have permission to 48 access.) 49 50 ```no_run 51 use walkdir::WalkDir; 52 53 for entry in WalkDir::new("foo").into_iter().filter_map(|e| e.ok()) { 54 println!("{}", entry.path().display()); 55 } 56 ``` 57 58 [`filter_map`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.filter_map 59 60 # Example: follow symbolic links 61 62 The same code as above, except [`follow_links`] is enabled: 63 64 ```no_run 65 use walkdir::WalkDir; 66 # use walkdir::Error; 67 68 # fn try_main() -> Result<(), Error> { 69 for entry in WalkDir::new("foo").follow_links(true) { 70 println!("{}", entry?.path().display()); 71 } 72 # Ok(()) 73 # } 74 ``` 75 76 [`follow_links`]: struct.WalkDir.html#method.follow_links 77 78 # Example: skip hidden files and directories on unix 79 80 This uses the [`filter_entry`] iterator adapter to avoid yielding hidden files 81 and directories efficiently (i.e. without recursing into hidden directories): 82 83 ```no_run 84 use walkdir::{DirEntry, WalkDir}; 85 # use walkdir::Error; 86 87 fn is_hidden(entry: &DirEntry) -> bool { 88 entry.file_name() 89 .to_str() 90 .map(|s| s.starts_with(".")) 91 .unwrap_or(false) 92 } 93 94 # fn try_main() -> Result<(), Error> { 95 let walker = WalkDir::new("foo").into_iter(); 96 for entry in walker.filter_entry(|e| !is_hidden(e)) { 97 println!("{}", entry?.path().display()); 98 } 99 # Ok(()) 100 # } 101 ``` 102 103 [`filter_entry`]: struct.IntoIter.html#method.filter_entry 104 */ 105 106 #![doc(html_root_url = "https://docs.rs/walkdir/2.0.0")] 107 #![deny(missing_docs)] 108 109 #[cfg(test)] 110 extern crate quickcheck; 111 #[cfg(test)] 112 extern crate rand; 113 extern crate same_file; 114 #[cfg(windows)] 115 extern crate winapi; 116 117 use std::cmp::{Ordering, min}; 118 use std::error; 119 use std::fmt; 120 use std::fs::{self, FileType, ReadDir}; 121 use std::io; 122 use std::ffi::OsStr; 123 use std::path::{Path, PathBuf}; 124 use std::result; 125 use std::vec; 126 127 use same_file::Handle; 128 129 #[cfg(unix)] 130 pub use unix::DirEntryExt; 131 132 #[cfg(test)] 133 mod tests; 134 #[cfg(unix)] 135 mod unix; 136 137 /// Like try, but for iterators that return [`Option<Result<_, _>>`]. 138 /// 139 /// [`Option<Result<_, _>>`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html 140 macro_rules! itry { 141 ($e:expr) => { 142 match $e { 143 Ok(v) => v, 144 Err(err) => return Some(Err(From::from(err))), 145 } 146 } 147 } 148 149 /// A result type for walkdir operations. 150 /// 151 /// Note that this result type embeds the error type in this crate. This 152 /// is only useful if you care about the additional information provided by 153 /// the error (such as the path associated with the error or whether a loop 154 /// was dectected). If you want things to Just Work, then you can use 155 /// [`io::Result`] instead since the error type in this package will 156 /// automatically convert to an [`io::Result`] when using the [`try!`] macro. 157 /// 158 /// [`io::Result`]: https://doc.rust-lang.org/stable/std/io/type.Result.html 159 /// [`try!`]: https://doc.rust-lang.org/stable/std/macro.try.html 160 pub type Result<T> = ::std::result::Result<T, Error>; 161 162 /// A builder to create an iterator for recursively walking a directory. 163 /// 164 /// Results are returned in depth first fashion, with directories yielded 165 /// before their contents. If [`contents_first`] is true, contents are yielded 166 /// before their directories. The order is unspecified but if [`sort_by`] is 167 /// given, directory entries are sorted according to this function. Directory 168 /// entries `.` and `..` are always omitted. 169 /// 170 /// If an error occurs at any point during iteration, then it is returned in 171 /// place of its corresponding directory entry and iteration continues as 172 /// normal. If an error occurs while opening a directory for reading, then it 173 /// is not descended into (but the error is still yielded by the iterator). 174 /// Iteration may be stopped at any time. When the iterator is destroyed, all 175 /// resources associated with it are freed. 176 /// 177 /// [`contents_first`]: struct.WalkDir.html#method.contents_first 178 /// [`sort_by`]: struct.WalkDir.html#method.sort_by 179 /// 180 /// # Usage 181 /// 182 /// This type implements [`IntoIterator`] so that it may be used as the subject 183 /// of a `for` loop. You may need to call [`into_iter`] explicitly if you want 184 /// to use iterator adapters such as [`filter_entry`]. 185 /// 186 /// Idiomatic use of this type should use method chaining to set desired 187 /// options. For example, this only shows entries with a depth of `1`, `2` or 188 /// `3` (relative to `foo`): 189 /// 190 /// ```no_run 191 /// use walkdir::WalkDir; 192 /// # use walkdir::Error; 193 /// 194 /// # fn try_main() -> Result<(), Error> { 195 /// for entry in WalkDir::new("foo").min_depth(1).max_depth(3) { 196 /// println!("{}", entry?.path().display()); 197 /// } 198 /// # Ok(()) 199 /// # } 200 /// ``` 201 /// 202 /// [`IntoIterator`]: https://doc.rust-lang.org/stable/std/iter/trait.IntoIterator.html 203 /// [`into_iter`]: https://doc.rust-lang.org/nightly/core/iter/trait.IntoIterator.html#tymethod.into_iter 204 /// [`filter_entry`]: struct.IntoIter.html#method.filter_entry 205 /// 206 /// Note that the iterator by default includes the top-most directory. Since 207 /// this is the only directory yielded with depth `0`, it is easy to ignore it 208 /// with the [`min_depth`] setting: 209 /// 210 /// ```no_run 211 /// use walkdir::WalkDir; 212 /// # use walkdir::Error; 213 /// 214 /// # fn try_main() -> Result<(), Error> { 215 /// for entry in WalkDir::new("foo").min_depth(1) { 216 /// println!("{}", entry?.path().display()); 217 /// } 218 /// # Ok(()) 219 /// # } 220 /// ``` 221 /// 222 /// [`min_depth`]: struct.WalkDir.html#method.min_depth 223 /// 224 /// This will only return descendents of the `foo` directory and not `foo` 225 /// itself. 226 /// 227 /// # Loops 228 /// 229 /// This iterator (like most/all recursive directory iterators) assumes that 230 /// no loops can be made with *hard* links on your file system. In particular, 231 /// this would require creating a hard link to a directory such that it creates 232 /// a loop. On most platforms, this operation is illegal. 233 /// 234 /// Note that when following symbolic/soft links, loops are detected and an 235 /// error is reported. 236 #[derive(Debug)] 237 pub struct WalkDir { 238 opts: WalkDirOptions, 239 root: PathBuf, 240 } 241 242 struct WalkDirOptions { 243 follow_links: bool, 244 max_open: usize, 245 min_depth: usize, 246 max_depth: usize, 247 sorter: Option<Box< 248 FnMut(&DirEntry,&DirEntry) -> Ordering + Send + Sync + 'static 249 >>, 250 contents_first: bool, 251 } 252 253 impl fmt::Debug for WalkDirOptions { fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error>254 fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { 255 let sorter_str = if self.sorter.is_some() { 256 // FnMut isn't `Debug` 257 "Some(...)" 258 } else { 259 "None" 260 }; 261 f.debug_struct("WalkDirOptions") 262 .field("follow_links", &self.follow_links) 263 .field("max_open", &self.max_open) 264 .field("min_depth", &self.min_depth) 265 .field("max_depth", &self.max_depth) 266 .field("sorter", &sorter_str) 267 .field("contents_first", &self.contents_first) 268 .finish() 269 } 270 } 271 272 impl WalkDir { 273 /// Create a builder for a recursive directory iterator starting at the 274 /// file path `root`. If `root` is a directory, then it is the first item 275 /// yielded by the iterator. If `root` is a file, then it is the first 276 /// and only item yielded by the iterator. If `root` is a symlink, then it 277 /// is always followed. new<P: AsRef<Path>>(root: P) -> Self278 pub fn new<P: AsRef<Path>>(root: P) -> Self { 279 WalkDir { 280 opts: WalkDirOptions { 281 follow_links: false, 282 max_open: 10, 283 min_depth: 0, 284 max_depth: ::std::usize::MAX, 285 sorter: None, 286 contents_first: false, 287 }, 288 root: root.as_ref().to_path_buf(), 289 } 290 } 291 292 /// Set the minimum depth of entries yielded by the iterator. 293 /// 294 /// The smallest depth is `0` and always corresponds to the path given 295 /// to the `new` function on this type. Its direct descendents have depth 296 /// `1`, and their descendents have depth `2`, and so on. min_depth(mut self, depth: usize) -> Self297 pub fn min_depth(mut self, depth: usize) -> Self { 298 self.opts.min_depth = depth; 299 if self.opts.min_depth > self.opts.max_depth { 300 self.opts.min_depth = self.opts.max_depth; 301 } 302 self 303 } 304 305 /// Set the maximum depth of entries yield by the iterator. 306 /// 307 /// The smallest depth is `0` and always corresponds to the path given 308 /// to the `new` function on this type. Its direct descendents have depth 309 /// `1`, and their descendents have depth `2`, and so on. 310 /// 311 /// Note that this will not simply filter the entries of the iterator, but 312 /// it will actually avoid descending into directories when the depth is 313 /// exceeded. max_depth(mut self, depth: usize) -> Self314 pub fn max_depth(mut self, depth: usize) -> Self { 315 self.opts.max_depth = depth; 316 if self.opts.max_depth < self.opts.min_depth { 317 self.opts.max_depth = self.opts.min_depth; 318 } 319 self 320 } 321 322 /// Follow symbolic links. By default, this is disabled. 323 /// 324 /// When `yes` is `true`, symbolic links are followed as if they were 325 /// normal directories and files. If a symbolic link is broken or is 326 /// involved in a loop, an error is yielded. 327 /// 328 /// When enabled, the yielded [`DirEntry`] values represent the target of 329 /// the link while the path corresponds to the link. See the [`DirEntry`] 330 /// type for more details. 331 /// 332 /// [`DirEntry`]: struct.DirEntry.html follow_links(mut self, yes: bool) -> Self333 pub fn follow_links(mut self, yes: bool) -> Self { 334 self.opts.follow_links = yes; 335 self 336 } 337 338 /// Set the maximum number of simultaneously open file descriptors used 339 /// by the iterator. 340 /// 341 /// `n` must be greater than or equal to `1`. If `n` is `0`, then it is set 342 /// to `1` automatically. If this is not set, then it defaults to some 343 /// reasonably low number. 344 /// 345 /// This setting has no impact on the results yielded by the iterator 346 /// (even when `n` is `1`). Instead, this setting represents a trade off 347 /// between scarce resources (file descriptors) and memory. Namely, when 348 /// the maximum number of file descriptors is reached and a new directory 349 /// needs to be opened to continue iteration, then a previous directory 350 /// handle is closed and has its unyielded entries stored in memory. In 351 /// practice, this is a satisfying trade off because it scales with respect 352 /// to the *depth* of your file tree. Therefore, low values (even `1`) are 353 /// acceptable. 354 /// 355 /// Note that this value does not impact the number of system calls made by 356 /// an exhausted iterator. 357 /// 358 /// # Platform behavior 359 /// 360 /// On Windows, if `follow_links` is enabled, then this limit is not 361 /// respected. In particular, the maximum number of file descriptors opened 362 /// is proportional to the depth of the directory tree traversed. max_open(mut self, mut n: usize) -> Self363 pub fn max_open(mut self, mut n: usize) -> Self { 364 if n == 0 { 365 n = 1; 366 } 367 self.opts.max_open = n; 368 self 369 } 370 371 /// Set a function for sorting directory entries. 372 /// 373 /// If a compare function is set, the resulting iterator will return all 374 /// paths in sorted order. The compare function will be called to compare 375 /// entries from the same directory. 376 /// 377 /// ```rust,no-run 378 /// use std::cmp; 379 /// use std::ffi::OsString; 380 /// use walkdir::WalkDir; 381 /// 382 /// WalkDir::new("foo").sort_by(|a,b| a.file_name().cmp(b.file_name())); 383 /// ``` sort_by<F>(mut self, cmp: F) -> Self where F: FnMut(&DirEntry, &DirEntry) -> Ordering + Send + Sync + 'static384 pub fn sort_by<F>(mut self, cmp: F) -> Self 385 where F: FnMut(&DirEntry, &DirEntry) -> Ordering + Send + Sync + 'static 386 { 387 self.opts.sorter = Some(Box::new(cmp)); 388 self 389 } 390 391 /// Yield a directory's contents before the directory itself. By default, 392 /// this is disabled. 393 /// 394 /// When `yes` is `false` (as is the default), the directory is yielded 395 /// before its contents are read. This is useful when, e.g. you want to 396 /// skip processing of some directories. 397 /// 398 /// When `yes` is `true`, the iterator yields the contents of a directory 399 /// before yielding the directory itself. This is useful when, e.g. you 400 /// want to recursively delete a directory. 401 /// 402 /// # Example 403 /// 404 /// Assume the following directory tree: 405 /// 406 /// ```text 407 /// foo/ 408 /// abc/ 409 /// qrs 410 /// tuv 411 /// def/ 412 /// ``` 413 /// 414 /// With contents_first disabled (the default), the following code visits 415 /// the directory tree in depth-first order: 416 /// 417 /// ```no_run 418 /// use walkdir::WalkDir; 419 /// 420 /// for entry in WalkDir::new("foo") { 421 /// let entry = entry.unwrap(); 422 /// println!("{}", entry.path().display()); 423 /// } 424 /// 425 /// // foo 426 /// // foo/abc 427 /// // foo/abc/qrs 428 /// // foo/abc/tuv 429 /// // foo/def 430 /// ``` 431 /// 432 /// With contents_first enabled: 433 /// 434 /// ```no_run 435 /// use walkdir::WalkDir; 436 /// 437 /// for entry in WalkDir::new("foo").contents_first(true) { 438 /// let entry = entry.unwrap(); 439 /// println!("{}", entry.path().display()); 440 /// } 441 /// 442 /// // foo/abc/qrs 443 /// // foo/abc/tuv 444 /// // foo/abc 445 /// // foo/def 446 /// // foo 447 /// ``` contents_first(mut self, yes: bool) -> Self448 pub fn contents_first(mut self, yes: bool) -> Self { 449 self.opts.contents_first = yes; 450 self 451 } 452 } 453 454 impl IntoIterator for WalkDir { 455 type Item = Result<DirEntry>; 456 type IntoIter = IntoIter; 457 into_iter(self) -> IntoIter458 fn into_iter(self) -> IntoIter { 459 IntoIter { 460 opts: self.opts, 461 start: Some(self.root), 462 stack_list: vec![], 463 stack_path: vec![], 464 oldest_opened: 0, 465 depth: 0, 466 deferred_dirs: vec![], 467 } 468 } 469 } 470 471 /// An iterator for recursively descending into a directory. 472 /// 473 /// A value with this type must be constructed with the [`WalkDir`] type, which 474 /// uses a builder pattern to set options such as min/max depth, max open file 475 /// descriptors and whether the iterator should follow symbolic links. After 476 /// constructing a `WalkDir`, call [`.into_iter()`] at the end of the chain. 477 /// 478 /// The order of elements yielded by this iterator is unspecified. 479 /// 480 /// [`WalkDir`]: struct.WalkDir.html 481 /// [`.into_iter()`]: struct.WalkDir.html#into_iter.v 482 #[derive(Debug)] 483 pub struct IntoIter { 484 /// Options specified in the builder. Depths, max fds, etc. 485 opts: WalkDirOptions, 486 /// The start path. 487 /// 488 /// This is only `Some(...)` at the beginning. After the first iteration, 489 /// this is always `None`. 490 start: Option<PathBuf>, 491 /// A stack of open (up to max fd) or closed handles to directories. 492 /// An open handle is a plain [`fs::ReadDir`] while a closed handle is 493 /// a `Vec<fs::DirEntry>` corresponding to the as-of-yet consumed entries. 494 /// 495 /// [`fs::ReadDir`]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html 496 stack_list: Vec<DirList>, 497 /// A stack of file paths. 498 /// 499 /// This is *only* used when [`follow_links`] is enabled. In all other 500 /// cases this stack is empty. 501 /// 502 /// [`follow_links`]: struct.WalkDir.html#method.follow_links 503 stack_path: Vec<Ancestor>, 504 /// An index into `stack_list` that points to the oldest open directory 505 /// handle. If the maximum fd limit is reached and a new directory needs to 506 /// be read, the handle at this index is closed before the new directory is 507 /// opened. 508 oldest_opened: usize, 509 /// The current depth of iteration (the length of the stack at the 510 /// beginning of each iteration). 511 depth: usize, 512 /// A list of DirEntries corresponding to directories, that are 513 /// yielded after their contents has been fully yielded. This is only 514 /// used when `contents_first` is enabled. 515 deferred_dirs: Vec<DirEntry>, 516 } 517 518 /// An ancestor is an item in the directory tree traversed by walkdir, and is 519 /// used to check for loops in the tree when traversing symlinks. 520 #[derive(Debug)] 521 struct Ancestor { 522 /// The path of this ancestor. 523 path: PathBuf, 524 /// An open file to this ancesor. This is only used on Windows where 525 /// opening a file handle appears to be quite expensive, so we choose to 526 /// cache it. This comes at the cost of not respecting the file descriptor 527 /// limit set by the user. 528 #[cfg(windows)] 529 handle: Handle, 530 } 531 532 impl Ancestor { 533 /// Create a new ancestor from the given directory path. 534 #[cfg(windows)] new(dent: &DirEntry) -> io::Result<Ancestor>535 fn new(dent: &DirEntry) -> io::Result<Ancestor> { 536 let handle = Handle::from_path(dent.path())?; 537 Ok(Ancestor { 538 path: dent.path().to_path_buf(), 539 handle: handle, 540 }) 541 } 542 543 /// Create a new ancestor from the given directory path. 544 #[cfg(not(windows))] new(dent: &DirEntry) -> io::Result<Ancestor>545 fn new(dent: &DirEntry) -> io::Result<Ancestor> { 546 Ok(Ancestor { path: dent.path().to_path_buf() }) 547 } 548 549 /// Returns true if and only if the given open file handle corresponds to 550 /// the same directory as this ancestor. 551 #[cfg(windows)] is_same(&self, child: &Handle) -> io::Result<bool>552 fn is_same(&self, child: &Handle) -> io::Result<bool> { 553 Ok(child == &self.handle) 554 } 555 556 /// Returns true if and only if the given open file handle corresponds to 557 /// the same directory as this ancestor. 558 #[cfg(not(windows))] is_same(&self, child: &Handle) -> io::Result<bool>559 fn is_same(&self, child: &Handle) -> io::Result<bool> { 560 Ok(child == &Handle::from_path(&self.path)?) 561 } 562 } 563 564 /// A sequence of unconsumed directory entries. 565 /// 566 /// This represents the opened or closed state of a directory handle. When 567 /// open, future entries are read by iterating over the raw `fs::ReadDir`. 568 /// When closed, all future entries are read into memory. Iteration then 569 /// proceeds over a [`Vec<fs::DirEntry>`]. 570 /// 571 /// [`fs::ReadDir`]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html 572 /// [`Vec<fs::DirEntry>`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html 573 #[derive(Debug)] 574 enum DirList { 575 /// An opened handle. 576 /// 577 /// This includes the depth of the handle itself. 578 /// 579 /// If there was an error with the initial [`fs::read_dir`] call, then it 580 /// is stored here. (We use an [`Option<...>`] to make yielding the error 581 /// exactly once simpler.) 582 /// 583 /// [`fs::read_dir`]: https://doc.rust-lang.org/stable/std/fs/fn.read_dir.html 584 /// [`Option<...>`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html 585 Opened { depth: usize, it: result::Result<ReadDir, Option<Error>> }, 586 /// A closed handle. 587 /// 588 /// All remaining directory entries are read into memory. 589 Closed(vec::IntoIter<Result<DirEntry>>), 590 } 591 592 /// A directory entry. 593 /// 594 /// This is the type of value that is yielded from the iterators defined in 595 /// this crate. 596 /// 597 /// On Unix systems, this type implements the [`DirEntryExt`] trait, which 598 /// provides efficient access to the inode number of the directory entry. 599 /// 600 /// # Differences with `std::fs::DirEntry` 601 /// 602 /// This type mostly mirrors the type by the same name in [`std::fs`]. There 603 /// are some differences however: 604 /// 605 /// * All recursive directory iterators must inspect the entry's type. 606 /// Therefore, the value is stored and its access is guaranteed to be cheap and 607 /// successful. 608 /// * [`path`] and [`file_name`] return borrowed variants. 609 /// * If [`follow_links`] was enabled on the originating iterator, then all 610 /// operations except for [`path`] operate on the link target. Otherwise, all 611 /// operations operate on the symbolic link. 612 /// 613 /// [`std::fs`]: https://doc.rust-lang.org/stable/std/fs/index.html 614 /// [`path`]: #method.path 615 /// [`file_name`]: #method.file_name 616 /// [`follow_links`]: struct.WalkDir.html#method.follow_links 617 /// [`DirEntryExt`]: trait.DirEntryExt.html 618 pub struct DirEntry { 619 /// The path as reported by the [`fs::ReadDir`] iterator (even if it's a 620 /// symbolic link). 621 /// 622 /// [`fs::ReadDir`]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html 623 path: PathBuf, 624 /// The file type. Necessary for recursive iteration, so store it. 625 ty: FileType, 626 /// Is set when this entry was created from a symbolic link and the user 627 /// excepts the iterator to follow symbolic links. 628 follow_link: bool, 629 /// The depth at which this entry was generated relative to the root. 630 depth: usize, 631 /// The underlying inode number (Unix only). 632 #[cfg(unix)] 633 ino: u64, 634 /// The underlying metadata (Windows only). We store this on Windows 635 /// because this comes for free while reading a directory. 636 /// 637 /// We use this to determine whether an entry is a directory or not, which 638 /// works around a bug in Rust's standard library: 639 /// https://github.com/rust-lang/rust/issues/46484 640 #[cfg(windows)] 641 metadata: fs::Metadata, 642 } 643 644 impl Iterator for IntoIter { 645 type Item = Result<DirEntry>; 646 /// Advances the iterator and returns the next value. 647 /// 648 /// # Errors 649 /// 650 /// If the iterator fails to retrieve the next value, this method returns 651 /// an error value. The error will be wrapped in an Option::Some. next(&mut self) -> Option<Result<DirEntry>>652 fn next(&mut self) -> Option<Result<DirEntry>> { 653 if let Some(start) = self.start.take() { 654 let dent = itry!(DirEntry::from_link(0, start)); 655 if let Some(result) = self.handle_entry(dent) { 656 return Some(result); 657 } 658 } 659 while !self.stack_list.is_empty() { 660 self.depth = self.stack_list.len(); 661 if let Some(dentry) = self.get_deferred_dir() { 662 return Some(Ok(dentry)); 663 } 664 if self.depth > self.opts.max_depth { 665 // If we've exceeded the max depth, pop the current dir 666 // so that we don't descend. 667 self.pop(); 668 continue; 669 } 670 // Unwrap is safe here because we've verified above that 671 // `self.stack_list` is not empty 672 match self.stack_list.last_mut().expect("bug in walkdir").next() { 673 None => self.pop(), 674 Some(Err(err)) => return Some(Err(err)), 675 Some(Ok(dent)) => { 676 if let Some(result) = self.handle_entry(dent) { 677 return Some(result); 678 } 679 } 680 } 681 } 682 if self.opts.contents_first { 683 self.depth = self.stack_list.len(); 684 if let Some(dentry) = self.get_deferred_dir() { 685 return Some(Ok(dentry)); 686 } 687 } 688 None 689 } 690 } 691 692 impl IntoIter { 693 /// Skips the current directory. 694 /// 695 /// This causes the iterator to stop traversing the contents of the least 696 /// recently yielded directory. This means any remaining entries in that 697 /// directory will be skipped (including sub-directories). 698 /// 699 /// Note that the ergonomics of this method are questionable since it 700 /// borrows the iterator mutably. Namely, you must write out the looping 701 /// condition manually. For example, to skip hidden entries efficiently on 702 /// unix systems: 703 /// 704 /// ```no_run 705 /// use walkdir::{DirEntry, WalkDir}; 706 /// 707 /// fn is_hidden(entry: &DirEntry) -> bool { 708 /// entry.file_name() 709 /// .to_str() 710 /// .map(|s| s.starts_with(".")) 711 /// .unwrap_or(false) 712 /// } 713 /// 714 /// let mut it = WalkDir::new("foo").into_iter(); 715 /// loop { 716 /// let entry = match it.next() { 717 /// None => break, 718 /// Some(Err(err)) => panic!("ERROR: {}", err), 719 /// Some(Ok(entry)) => entry, 720 /// }; 721 /// if is_hidden(&entry) { 722 /// if entry.file_type().is_dir() { 723 /// it.skip_current_dir(); 724 /// } 725 /// continue; 726 /// } 727 /// println!("{}", entry.path().display()); 728 /// } 729 /// ``` 730 /// 731 /// You may find it more convenient to use the [`filter_entry`] iterator 732 /// adapter. (See its documentation for the same example functionality as 733 /// above.) 734 /// 735 /// [`filter_entry`]: #method.filter_entry skip_current_dir(&mut self)736 pub fn skip_current_dir(&mut self) { 737 if !self.stack_list.is_empty() { 738 self.stack_list.pop(); 739 } 740 if !self.stack_path.is_empty() { 741 self.stack_path.pop(); 742 } 743 } 744 745 /// Yields only entries which satisfy the given predicate and skips 746 /// descending into directories that do not satisfy the given predicate. 747 /// 748 /// The predicate is applied to all entries. If the predicate is 749 /// true, iteration carries on as normal. If the predicate is false, the 750 /// entry is ignored and if it is a directory, it is not descended into. 751 /// 752 /// This is often more convenient to use than [`skip_current_dir`]. For 753 /// example, to skip hidden files and directories efficiently on unix 754 /// systems: 755 /// 756 /// ```no_run 757 /// use walkdir::{DirEntry, WalkDir}; 758 /// # use walkdir::Error; 759 /// 760 /// fn is_hidden(entry: &DirEntry) -> bool { 761 /// entry.file_name() 762 /// .to_str() 763 /// .map(|s| s.starts_with(".")) 764 /// .unwrap_or(false) 765 /// } 766 /// 767 /// # fn try_main() -> Result<(), Error> { 768 /// for entry in WalkDir::new("foo") 769 /// .into_iter() 770 /// .filter_entry(|e| !is_hidden(e)) { 771 /// println!("{}", entry?.path().display()); 772 /// } 773 /// # Ok(()) 774 /// # } 775 /// ``` 776 /// 777 /// Note that the iterator will still yield errors for reading entries that 778 /// may not satisfy the predicate. 779 /// 780 /// Note that entries skipped with [`min_depth`] and [`max_depth`] are not 781 /// passed to this predicate. 782 /// 783 /// Note that if the iterator has `contents_first` enabled, then this 784 /// method is no different than calling the standard `Iterator::filter` 785 /// method (because directory entries are yielded after they've been 786 /// descended into). 787 /// 788 /// [`skip_current_dir`]: #method.skip_current_dir 789 /// [`min_depth`]: struct.WalkDir.html#method.min_depth 790 /// [`max_depth`]: struct.WalkDir.html#method.max_depth filter_entry<P>(self, predicate: P) -> FilterEntry<Self, P> where P: FnMut(&DirEntry) -> bool791 pub fn filter_entry<P>(self, predicate: P) -> FilterEntry<Self, P> 792 where P: FnMut(&DirEntry) -> bool 793 { 794 FilterEntry { it: self, predicate: predicate } 795 } 796 handle_entry( &mut self, mut dent: DirEntry, ) -> Option<Result<DirEntry>>797 fn handle_entry( 798 &mut self, 799 mut dent: DirEntry, 800 ) -> Option<Result<DirEntry>> { 801 if self.opts.follow_links && dent.file_type().is_symlink() { 802 dent = itry!(self.follow(dent)); 803 } 804 let is_normal_dir = !dent.file_type().is_symlink() && dent.is_dir(); 805 if is_normal_dir { 806 itry!(self.push(&dent)); 807 } 808 if is_normal_dir && self.opts.contents_first { 809 self.deferred_dirs.push(dent); 810 None 811 } else if self.skippable() { 812 None 813 } else { 814 Some(Ok(dent)) 815 } 816 } 817 get_deferred_dir(&mut self) -> Option<DirEntry>818 fn get_deferred_dir(&mut self) -> Option<DirEntry> { 819 if self.opts.contents_first { 820 if self.depth < self.deferred_dirs.len() { 821 // Unwrap is safe here because we've guaranteed that 822 // `self.deferred_dirs.len()` can never be less than 1 823 let deferred: DirEntry = self.deferred_dirs.pop() 824 .expect("bug in walkdir"); 825 if !self.skippable() { 826 return Some(deferred); 827 } 828 } 829 } 830 None 831 } 832 push(&mut self, dent: &DirEntry) -> Result<()>833 fn push(&mut self, dent: &DirEntry) -> Result<()> { 834 // Make room for another open file descriptor if we've hit the max. 835 let free = self.stack_list 836 .len() 837 .checked_sub(self.oldest_opened).unwrap(); 838 if free == self.opts.max_open { 839 self.stack_list[self.oldest_opened].close(); 840 // Unwrap is safe here because self.oldest_opened is guaranteed to 841 // never be greater than `self.stack_list.len()`, which implies 842 // that the subtraction won't underflow and that adding 1 will 843 // never overflow. 844 self.oldest_opened = self.oldest_opened.checked_add(1).unwrap(); 845 } 846 // Open a handle to reading the directory's entries. 847 let rd = fs::read_dir(dent.path()).map_err(|err| { 848 Some(Error::from_path(self.depth, dent.path().to_path_buf(), err)) 849 }); 850 let mut list = DirList::Opened { depth: self.depth, it: rd }; 851 if let Some(ref mut cmp) = self.opts.sorter { 852 let mut entries: Vec<_> = list.collect(); 853 entries.sort_by(|a, b| { 854 match (a, b) { 855 (&Ok(ref a), &Ok(ref b)) => { 856 cmp(a, b) 857 } 858 (&Err(_), &Err(_)) => Ordering::Equal, 859 (&Ok(_), &Err(_)) => Ordering::Greater, 860 (&Err(_), &Ok(_)) => Ordering::Less, 861 } 862 }); 863 list = DirList::Closed(entries.into_iter()); 864 } 865 if self.opts.follow_links { 866 let ancestor = Ancestor::new(&dent).map_err(|err| { 867 Error::from_io(self.depth, err) 868 })?; 869 self.stack_path.push(ancestor); 870 } 871 // We push this after stack_path since creating the Ancestor can fail. 872 // If it fails, then we return the error and won't descend. 873 self.stack_list.push(list); 874 Ok(()) 875 } 876 pop(&mut self)877 fn pop(&mut self) { 878 self.stack_list.pop().expect("cannot pop from empty stack"); 879 if self.opts.follow_links { 880 self.stack_path.pop().expect("BUG: list/path stacks out of sync"); 881 } 882 // If everything in the stack is already closed, then there is 883 // room for at least one more open descriptor and it will 884 // always be at the top of the stack. 885 self.oldest_opened = min(self.oldest_opened, self.stack_list.len()); 886 } 887 follow(&self, mut dent: DirEntry) -> Result<DirEntry>888 fn follow(&self, mut dent: DirEntry) -> Result<DirEntry> { 889 dent = DirEntry::from_link(self.depth, dent.path().to_path_buf())?; 890 // The only way a symlink can cause a loop is if it points 891 // to a directory. Otherwise, it always points to a leaf 892 // and we can omit any loop checks. 893 if dent.is_dir() { 894 self.check_loop(dent.path())?; 895 } 896 Ok(dent) 897 } 898 check_loop<P: AsRef<Path>>(&self, child: P) -> Result<()>899 fn check_loop<P: AsRef<Path>>(&self, child: P) -> Result<()> { 900 let hchild = Handle::from_path(&child).map_err(|err| { 901 Error::from_io(self.depth, err) 902 })?; 903 for ancestor in self.stack_path.iter().rev() { 904 let is_same = ancestor.is_same(&hchild).map_err(|err| { 905 Error::from_io(self.depth, err) 906 })?; 907 if is_same { 908 return Err(Error { 909 depth: self.depth, 910 inner: ErrorInner::Loop { 911 ancestor: ancestor.path.to_path_buf(), 912 child: child.as_ref().to_path_buf(), 913 }, 914 }); 915 } 916 } 917 Ok(()) 918 } 919 skippable(&self) -> bool920 fn skippable(&self) -> bool { 921 self.depth < self.opts.min_depth || self.depth > self.opts.max_depth 922 } 923 } 924 925 impl DirList { close(&mut self)926 fn close(&mut self) { 927 if let DirList::Opened { .. } = *self { 928 *self = DirList::Closed(self.collect::<Vec<_>>().into_iter()); 929 } 930 } 931 } 932 933 impl Iterator for DirList { 934 type Item = Result<DirEntry>; 935 936 #[inline(always)] next(&mut self) -> Option<Result<DirEntry>>937 fn next(&mut self) -> Option<Result<DirEntry>> { 938 match *self { 939 DirList::Closed(ref mut it) => it.next(), 940 DirList::Opened { depth, ref mut it } => match *it { 941 Err(ref mut err) => err.take().map(Err), 942 Ok(ref mut rd) => rd.next().map(|r| match r { 943 Ok(r) => DirEntry::from_entry(depth + 1, &r), 944 Err(err) => Err(Error::from_io(depth + 1, err)) 945 }), 946 } 947 } 948 } 949 } 950 951 impl DirEntry { 952 /// The full path that this entry represents. 953 /// 954 /// The full path is created by joining the parents of this entry up to the 955 /// root initially given to [`WalkDir::new`] with the file name of this 956 /// entry. 957 /// 958 /// Note that this *always* returns the path reported by the underlying 959 /// directory entry, even when symbolic links are followed. To get the 960 /// target path, use [`path_is_symlink`] to (cheaply) check if this entry 961 /// corresponds to a symbolic link, and [`std::fs::read_link`] to resolve 962 /// the target. 963 /// 964 /// [`WalkDir::new`]: struct.WalkDir.html#method.new 965 /// [`path_is_symlink`]: struct.DirEntry.html#method.path_is_symlink 966 /// [`std::fs::read_link`]: https://doc.rust-lang.org/stable/std/fs/fn.read_link.html path(&self) -> &Path967 pub fn path(&self) -> &Path { 968 &self.path 969 } 970 971 /// Returns `true` if and only if this entry was created from a symbolic 972 /// link. This is unaffected by the [`follow_links`] setting. 973 /// 974 /// When `true`, the value returned by the [`path`] method is a 975 /// symbolic link name. To get the full target path, you must call 976 /// [`std::fs::read_link(entry.path())`]. 977 /// 978 /// [`path`]: struct.DirEntry.html#method.path 979 /// [`follow_links`]: struct.WalkDir.html#method.follow_links 980 /// [`std::fs::read_link(entry.path())`]: https://doc.rust-lang.org/stable/std/fs/fn.read_link.html path_is_symlink(&self) -> bool981 pub fn path_is_symlink(&self) -> bool { 982 self.ty.is_symlink() || self.follow_link 983 } 984 985 /// Return the metadata for the file that this entry points to. 986 /// 987 /// This will follow symbolic links if and only if the [`WalkDir`] value 988 /// has [`follow_links`] enabled. 989 /// 990 /// # Platform behavior 991 /// 992 /// This always calls [`std::fs::symlink_metadata`]. 993 /// 994 /// If this entry is a symbolic link and [`follow_links`] is enabled, then 995 /// [`std::fs::metadata`] is called instead. 996 /// 997 /// # Errors 998 /// 999 /// Similar to [`std::fs::metadata`], returns errors for path values that 1000 /// the program does not have permissions to access or if the path does not 1001 /// exist. 1002 /// 1003 /// [`WalkDir`]: struct.WalkDir.html 1004 /// [`follow_links`]: struct.WalkDir.html#method.follow_links 1005 /// [`std::fs::metadata`]: https://doc.rust-lang.org/std/fs/fn.metadata.html 1006 /// [`std::fs::symlink_metadata`]: https://doc.rust-lang.org/stable/std/fs/fn.symlink_metadata.html metadata(&self) -> Result<fs::Metadata>1007 pub fn metadata(&self) -> Result<fs::Metadata> { 1008 self.metadata_internal() 1009 } 1010 1011 #[cfg(windows)] metadata_internal(&self) -> Result<fs::Metadata>1012 fn metadata_internal(&self) -> Result<fs::Metadata> { 1013 if self.follow_link { 1014 fs::metadata(&self.path) 1015 } else { 1016 Ok(self.metadata.clone()) 1017 }.map_err(|err| Error::from_entry(self, err)) 1018 } 1019 1020 #[cfg(not(windows))] metadata_internal(&self) -> Result<fs::Metadata>1021 fn metadata_internal(&self) -> Result<fs::Metadata> { 1022 if self.follow_link { 1023 fs::metadata(&self.path) 1024 } else { 1025 fs::symlink_metadata(&self.path) 1026 }.map_err(|err| Error::from_entry(self, err)) 1027 } 1028 1029 /// Return the file type for the file that this entry points to. 1030 /// 1031 /// If this is a symbolic link and [`follow_links`] is `true`, then this 1032 /// returns the type of the target. 1033 /// 1034 /// This never makes any system calls. 1035 /// 1036 /// [`follow_links`]: struct.WalkDir.html#method.follow_links file_type(&self) -> fs::FileType1037 pub fn file_type(&self) -> fs::FileType { 1038 self.ty 1039 } 1040 1041 /// Return the file name of this entry. 1042 /// 1043 /// If this entry has no file name (e.g., `/`), then the full path is 1044 /// returned. file_name(&self) -> &OsStr1045 pub fn file_name(&self) -> &OsStr { 1046 self.path.file_name().unwrap_or_else(|| self.path.as_os_str()) 1047 } 1048 1049 /// Returns the depth at which this entry was created relative to the root. 1050 /// 1051 /// The smallest depth is `0` and always corresponds to the path given 1052 /// to the `new` function on `WalkDir`. Its direct descendents have depth 1053 /// `1`, and their descendents have depth `2`, and so on. depth(&self) -> usize1054 pub fn depth(&self) -> usize { 1055 self.depth 1056 } 1057 1058 /// Returns true if and only if this entry points to a directory. 1059 /// 1060 /// This works around a bug in Rust's standard library: 1061 /// https://github.com/rust-lang/rust/issues/46484 1062 #[cfg(windows)] is_dir(&self) -> bool1063 fn is_dir(&self) -> bool { 1064 use std::os::windows::fs::MetadataExt; 1065 use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY; 1066 self.metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 1067 } 1068 1069 /// Returns true if and only if this entry points to a directory. 1070 #[cfg(not(windows))] is_dir(&self) -> bool1071 fn is_dir(&self) -> bool { 1072 self.ty.is_dir() 1073 } 1074 1075 #[cfg(windows)] from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry>1076 fn from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry> { 1077 let path = ent.path(); 1078 let ty = ent.file_type().map_err(|err| { 1079 Error::from_path(depth, path.clone(), err) 1080 })?; 1081 let md = ent.metadata().map_err(|err| { 1082 Error::from_path(depth, path.clone(), err) 1083 })?; 1084 Ok(DirEntry { 1085 path: path, 1086 ty: ty, 1087 follow_link: false, 1088 depth: depth, 1089 metadata: md, 1090 }) 1091 } 1092 1093 #[cfg(unix)] from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry>1094 fn from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry> { 1095 use std::os::unix::fs::DirEntryExt; 1096 1097 let ty = ent.file_type().map_err(|err| { 1098 Error::from_path(depth, ent.path(), err) 1099 })?; 1100 Ok(DirEntry { 1101 path: ent.path(), 1102 ty: ty, 1103 follow_link: false, 1104 depth: depth, 1105 ino: ent.ino(), 1106 }) 1107 } 1108 1109 #[cfg(not(any(unix, windows)))] from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry>1110 fn from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry> { 1111 use std::os::unix::fs::DirEntryExt; 1112 1113 let ty = ent.file_type().map_err(|err| { 1114 Error::from_path(depth, ent.path(), err) 1115 })?; 1116 Ok(DirEntry { 1117 path: ent.path(), 1118 ty: ty, 1119 follow_link: false, 1120 depth: depth, 1121 }) 1122 } 1123 1124 #[cfg(windows)] from_link(depth: usize, pb: PathBuf) -> Result<DirEntry>1125 fn from_link(depth: usize, pb: PathBuf) -> Result<DirEntry> { 1126 let md = fs::metadata(&pb).map_err(|err| { 1127 Error::from_path(depth, pb.clone(), err) 1128 })?; 1129 Ok(DirEntry { 1130 path: pb, 1131 ty: md.file_type(), 1132 follow_link: true, 1133 depth: depth, 1134 metadata: md, 1135 }) 1136 } 1137 1138 #[cfg(unix)] from_link(depth: usize, pb: PathBuf) -> Result<DirEntry>1139 fn from_link(depth: usize, pb: PathBuf) -> Result<DirEntry> { 1140 use std::os::unix::fs::MetadataExt; 1141 1142 let md = fs::metadata(&pb).map_err(|err| { 1143 Error::from_path(depth, pb.clone(), err) 1144 })?; 1145 Ok(DirEntry { 1146 path: pb, 1147 ty: md.file_type(), 1148 follow_link: true, 1149 depth: depth, 1150 ino: md.ino(), 1151 }) 1152 } 1153 1154 #[cfg(not(any(unix, windows)))] from_link(depth: usize, pb: PathBuf) -> Result<DirEntry>1155 fn from_link(depth: usize, pb: PathBuf) -> Result<DirEntry> { 1156 use std::os::unix::fs::MetadataExt; 1157 1158 let md = fs::metadata(&pb).map_err(|err| { 1159 Error::from_path(depth, pb.clone(), err) 1160 })?; 1161 Ok(DirEntry { 1162 path: pb, 1163 ty: md.file_type(), 1164 follow_link: true, 1165 depth: depth, 1166 }) 1167 } 1168 } 1169 1170 impl Clone for DirEntry { 1171 #[cfg(windows)] clone(&self) -> DirEntry1172 fn clone(&self) -> DirEntry { 1173 DirEntry { 1174 path: self.path.clone(), 1175 ty: self.ty, 1176 follow_link: self.follow_link, 1177 depth: self.depth, 1178 metadata: self.metadata.clone(), 1179 } 1180 } 1181 1182 #[cfg(unix)] clone(&self) -> DirEntry1183 fn clone(&self) -> DirEntry { 1184 DirEntry { 1185 path: self.path.clone(), 1186 ty: self.ty, 1187 follow_link: self.follow_link, 1188 depth: self.depth, 1189 ino: self.ino, 1190 } 1191 } 1192 1193 #[cfg(not(any(unix, windows)))] clone(&self) -> DirEntry1194 fn clone(&self) -> DirEntry { 1195 DirEntry { 1196 path: self.path.clone(), 1197 ty: self.ty, 1198 follow_link: self.follow_link, 1199 depth: self.depth, 1200 ino: self.ino, 1201 } 1202 } 1203 } 1204 1205 impl fmt::Debug for DirEntry { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1206 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1207 write!(f, "DirEntry({:?})", self.path) 1208 } 1209 } 1210 1211 /// A recursive directory iterator that skips entries. 1212 /// 1213 /// Values of this type are created by calling [`.filter_entry()`] on an 1214 /// `IntoIter`, which is formed by calling [`.into_iter()`] on a `WalkDir`. 1215 /// 1216 /// Directories that fail the predicate `P` are skipped. Namely, they are 1217 /// never yielded and never descended into. 1218 /// 1219 /// Entries that are skipped with the [`min_depth`] and [`max_depth`] options 1220 /// are not passed through this filter. 1221 /// 1222 /// If opening a handle to a directory resulted in an error, then it is yielded 1223 /// and no corresponding call to the predicate is made. 1224 /// 1225 /// Type parameter `I` refers to the underlying iterator and `P` refers to the 1226 /// predicate, which is usually `FnMut(&DirEntry) -> bool`. 1227 /// 1228 /// [`.filter_entry()`]: struct.IntoIter.html#method.filter_entry 1229 /// [`.into_iter()`]: struct.WalkDir.html#into_iter.v 1230 /// [`min_depth`]: struct.WalkDir.html#method.min_depth 1231 /// [`max_depth`]: struct.WalkDir.html#method.max_depth 1232 #[derive(Debug)] 1233 pub struct FilterEntry<I, P> { 1234 it: I, 1235 predicate: P, 1236 } 1237 1238 impl<P> Iterator for FilterEntry<IntoIter, P> 1239 where P: FnMut(&DirEntry) -> bool 1240 { 1241 type Item = Result<DirEntry>; 1242 1243 /// Advances the iterator and returns the next value. 1244 /// 1245 /// # Errors 1246 /// 1247 /// If the iterator fails to retrieve the next value, this method returns 1248 /// an error value. The error will be wrapped in an `Option::Some`. next(&mut self) -> Option<Result<DirEntry>>1249 fn next(&mut self) -> Option<Result<DirEntry>> { 1250 loop { 1251 let dent = match self.it.next() { 1252 None => return None, 1253 Some(result) => itry!(result), 1254 }; 1255 if !(self.predicate)(&dent) { 1256 if dent.is_dir() { 1257 self.it.skip_current_dir(); 1258 } 1259 continue; 1260 } 1261 return Some(Ok(dent)); 1262 } 1263 } 1264 } 1265 1266 impl<P> FilterEntry<IntoIter, P> where P: FnMut(&DirEntry) -> bool { 1267 /// Yields only entries which satisfy the given predicate and skips 1268 /// descending into directories that do not satisfy the given predicate. 1269 /// 1270 /// The predicate is applied to all entries. If the predicate is 1271 /// true, iteration carries on as normal. If the predicate is false, the 1272 /// entry is ignored and if it is a directory, it is not descended into. 1273 /// 1274 /// This is often more convenient to use than [`skip_current_dir`]. For 1275 /// example, to skip hidden files and directories efficiently on unix 1276 /// systems: 1277 /// 1278 /// ```no_run 1279 /// use walkdir::{DirEntry, WalkDir}; 1280 /// # use walkdir::Error; 1281 /// 1282 /// fn is_hidden(entry: &DirEntry) -> bool { 1283 /// entry.file_name() 1284 /// .to_str() 1285 /// .map(|s| s.starts_with(".")) 1286 /// .unwrap_or(false) 1287 /// } 1288 /// 1289 /// # fn try_main() -> Result<(), Error> { 1290 /// for entry in WalkDir::new("foo") 1291 /// .into_iter() 1292 /// .filter_entry(|e| !is_hidden(e)) { 1293 /// println!("{}", entry?.path().display()); 1294 /// } 1295 /// # Ok(()) 1296 /// # } 1297 /// ``` 1298 /// 1299 /// Note that the iterator will still yield errors for reading entries that 1300 /// may not satisfy the predicate. 1301 /// 1302 /// Note that entries skipped with [`min_depth`] and [`max_depth`] are not 1303 /// passed to this predicate. 1304 /// 1305 /// Note that if the iterator has `contents_first` enabled, then this 1306 /// method is no different than calling the standard `Iterator::filter` 1307 /// method (because directory entries are yielded after they've been 1308 /// descended into). 1309 /// 1310 /// [`skip_current_dir`]: #method.skip_current_dir 1311 /// [`min_depth`]: struct.WalkDir.html#method.min_depth 1312 /// [`max_depth`]: struct.WalkDir.html#method.max_depth filter_entry(self, predicate: P) -> FilterEntry<Self, P>1313 pub fn filter_entry(self, predicate: P) -> FilterEntry<Self, P> { 1314 FilterEntry { it: self, predicate: predicate } 1315 } 1316 1317 /// Skips the current directory. 1318 /// 1319 /// This causes the iterator to stop traversing the contents of the least 1320 /// recently yielded directory. This means any remaining entries in that 1321 /// directory will be skipped (including sub-directories). 1322 /// 1323 /// Note that the ergonomics of this method are questionable since it 1324 /// borrows the iterator mutably. Namely, you must write out the looping 1325 /// condition manually. For example, to skip hidden entries efficiently on 1326 /// unix systems: 1327 /// 1328 /// ```no_run 1329 /// use walkdir::{DirEntry, WalkDir}; 1330 /// 1331 /// fn is_hidden(entry: &DirEntry) -> bool { 1332 /// entry.file_name() 1333 /// .to_str() 1334 /// .map(|s| s.starts_with(".")) 1335 /// .unwrap_or(false) 1336 /// } 1337 /// 1338 /// let mut it = WalkDir::new("foo").into_iter(); 1339 /// loop { 1340 /// let entry = match it.next() { 1341 /// None => break, 1342 /// Some(Err(err)) => panic!("ERROR: {}", err), 1343 /// Some(Ok(entry)) => entry, 1344 /// }; 1345 /// if is_hidden(&entry) { 1346 /// if entry.file_type().is_dir() { 1347 /// it.skip_current_dir(); 1348 /// } 1349 /// continue; 1350 /// } 1351 /// println!("{}", entry.path().display()); 1352 /// } 1353 /// ``` 1354 /// 1355 /// You may find it more convenient to use the [`filter_entry`] iterator 1356 /// adapter. (See its documentation for the same example functionality as 1357 /// above.) 1358 /// 1359 /// [`filter_entry`]: #method.filter_entry skip_current_dir(&mut self)1360 pub fn skip_current_dir(&mut self) { 1361 self.it.skip_current_dir(); 1362 } 1363 } 1364 1365 /// An error produced by recursively walking a directory. 1366 /// 1367 /// This error type is a light wrapper around [`std::io::Error`]. In 1368 /// particular, it adds the following information: 1369 /// 1370 /// * The depth at which the error occurred in the file tree, relative to the 1371 /// root. 1372 /// * The path, if any, associated with the IO error. 1373 /// * An indication that a loop occurred when following symbolic links. In this 1374 /// case, there is no underlying IO error. 1375 /// 1376 /// To maintain good ergonomics, this type has a 1377 /// [`impl From<Error> for std::io::Error`][impl] defined which preserves the original context. 1378 /// This allows you to use an [`io::Result`] with methods in this crate if you don't care about 1379 /// accessing the underlying error data in a structured form. 1380 /// 1381 /// [`std::io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html 1382 /// [`io::Result`]: https://doc.rust-lang.org/stable/std/io/type.Result.html 1383 /// [impl]: struct.Error.html#impl-From%3CError%3E 1384 #[derive(Debug)] 1385 pub struct Error { 1386 depth: usize, 1387 inner: ErrorInner, 1388 } 1389 1390 #[derive(Debug)] 1391 enum ErrorInner { 1392 Io { path: Option<PathBuf>, err: io::Error }, 1393 Loop { ancestor: PathBuf, child: PathBuf }, 1394 } 1395 1396 impl Error { 1397 /// Returns the path associated with this error if one exists. 1398 /// 1399 /// For example, if an error occurred while opening a directory handle, 1400 /// the error will include the path passed to [`std::fs::read_dir`]. 1401 /// 1402 /// [`std::fs::read_dir`]: https://doc.rust-lang.org/stable/std/fs/fn.read_dir.html path(&self) -> Option<&Path>1403 pub fn path(&self) -> Option<&Path> { 1404 match self.inner { 1405 ErrorInner::Io { path: None, .. } => None, 1406 ErrorInner::Io { path: Some(ref path), .. } => Some(path), 1407 ErrorInner::Loop { ref child, .. } => Some(child), 1408 } 1409 } 1410 1411 /// Returns the path at which a cycle was detected. 1412 /// 1413 /// If no cycle was detected, [`None`] is returned. 1414 /// 1415 /// A cycle is detected when a directory entry is equivalent to one of 1416 /// its ancestors. 1417 /// 1418 /// To get the path to the child directory entry in the cycle, use the 1419 /// [`path`] method. 1420 /// 1421 /// [`None`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#variant.None 1422 /// [`path`]: struct.Error.html#path loop_ancestor(&self) -> Option<&Path>1423 pub fn loop_ancestor(&self) -> Option<&Path> { 1424 match self.inner { 1425 ErrorInner::Loop { ref ancestor, .. } => Some(ancestor), 1426 _ => None, 1427 } 1428 } 1429 1430 /// Returns the depth at which this error occurred relative to the root. 1431 /// 1432 /// The smallest depth is `0` and always corresponds to the path given to 1433 /// the [`new`] function on [`WalkDir`]. Its direct descendents have depth 1434 /// `1`, and their descendents have depth `2`, and so on. 1435 /// 1436 /// [`new`]: struct.WalkDir.html#method.new 1437 /// [`WalkDir`]: struct.WalkDir.html depth(&self) -> usize1438 pub fn depth(&self) -> usize { 1439 self.depth 1440 } 1441 1442 /// Inspect the original [`io::Error`] if there is one. 1443 /// 1444 /// [`None`] is returned if the [`Error`] doesn't correspond to an 1445 /// [`io::Error`]. This might happen, for example, when the error was 1446 /// produced because a cycle was found in the directory tree while 1447 /// following symbolic links. 1448 /// 1449 /// This method returns a borrowed value that is bound to the lifetime of the [`Error`]. To 1450 /// obtain an owned value, the [`into_io_error`] can be used instead. 1451 /// 1452 /// > This is the original [`io::Error`] and is _not_ the same as 1453 /// > [`impl From<Error> for std::io::Error`][impl] which contains additional context about the 1454 /// error. 1455 /// 1456 /// # Example 1457 /// 1458 /// ```rust,no-run 1459 /// use std::io; 1460 /// use std::path::Path; 1461 /// 1462 /// use walkdir::WalkDir; 1463 /// 1464 /// for entry in WalkDir::new("foo") { 1465 /// match entry { 1466 /// Ok(entry) => println!("{}", entry.path().display()), 1467 /// Err(err) => { 1468 /// let path = err.path().unwrap_or(Path::new("")).display(); 1469 /// println!("failed to access entry {}", path); 1470 /// if let Some(inner) = err.io_error() { 1471 /// match inner.kind() { 1472 /// io::ErrorKind::InvalidData => { 1473 /// println!( 1474 /// "entry contains invalid data: {}", 1475 /// inner) 1476 /// } 1477 /// io::ErrorKind::PermissionDenied => { 1478 /// println!( 1479 /// "Missing permission to read entry: {}", 1480 /// inner) 1481 /// } 1482 /// _ => { 1483 /// println!( 1484 /// "Unexpected error occurred: {}", 1485 /// inner) 1486 /// } 1487 /// } 1488 /// } 1489 /// } 1490 /// } 1491 /// } 1492 /// ``` 1493 /// 1494 /// [`None`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#variant.None 1495 /// [`io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html 1496 /// [`From`]: https://doc.rust-lang.org/stable/std/convert/trait.From.html 1497 /// [`Error`]: struct.Error.html 1498 /// [`into_io_error`]: struct.Error.html#method.into_io_error 1499 /// [impl]: struct.Error.html#impl-From%3CError%3E io_error(&self) -> Option<&io::Error>1500 pub fn io_error(&self) -> Option<&io::Error> { 1501 match self.inner { 1502 ErrorInner::Io { ref err, .. } => Some(err), 1503 ErrorInner::Loop { .. } => None, 1504 } 1505 } 1506 1507 /// Similar to [`io_error`] except consumes self to convert to the original 1508 /// [`io::Error`] if one exists. 1509 /// 1510 /// [`io_error`]: struct.Error.html#method.io_error 1511 /// [`io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html into_io_error(self) -> Option<io::Error>1512 pub fn into_io_error(self) -> Option<io::Error> { 1513 match self.inner { 1514 ErrorInner::Io { err, .. } => Some(err), 1515 ErrorInner::Loop { .. } => None, 1516 } 1517 } 1518 from_path(depth: usize, pb: PathBuf, err: io::Error) -> Self1519 fn from_path(depth: usize, pb: PathBuf, err: io::Error) -> Self { 1520 Error { 1521 depth: depth, 1522 inner: ErrorInner::Io { path: Some(pb), err: err }, 1523 } 1524 } 1525 from_entry(dent: &DirEntry, err: io::Error) -> Self1526 fn from_entry(dent: &DirEntry, err: io::Error) -> Self { 1527 Error { 1528 depth: dent.depth, 1529 inner: ErrorInner::Io { 1530 path: Some(dent.path().to_path_buf()), 1531 err: err, 1532 }, 1533 } 1534 } 1535 from_io(depth: usize, err: io::Error) -> Self1536 fn from_io(depth: usize, err: io::Error) -> Self { 1537 Error { 1538 depth: depth, 1539 inner: ErrorInner::Io { path: None, err: err }, 1540 } 1541 } 1542 } 1543 1544 impl error::Error for Error { description(&self) -> &str1545 fn description(&self) -> &str { 1546 match self.inner { 1547 ErrorInner::Io { ref err, .. } => err.description(), 1548 ErrorInner::Loop { .. } => "file system loop found", 1549 } 1550 } 1551 cause(&self) -> Option<&error::Error>1552 fn cause(&self) -> Option<&error::Error> { 1553 match self.inner { 1554 ErrorInner::Io { ref err, .. } => Some(err), 1555 ErrorInner::Loop { .. } => None, 1556 } 1557 } 1558 } 1559 1560 impl fmt::Display for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1561 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1562 match self.inner { 1563 ErrorInner::Io { path: None, ref err } => { 1564 err.fmt(f) 1565 } 1566 ErrorInner::Io { path: Some(ref path), ref err } => { 1567 write!(f, "IO error for operation on {}: {}", 1568 path.display(), err) 1569 } 1570 ErrorInner::Loop { ref ancestor, ref child } => { 1571 write!(f, "File system loop found: \ 1572 {} points to an ancestor {}", 1573 child.display(), ancestor.display()) 1574 } 1575 } 1576 } 1577 } 1578 1579 impl From<Error> for io::Error { 1580 /// Convert the [`Error`] to an [`io::Error`], preserving the original [`Error`] as the ["inner 1581 /// error"]. Note that this also makes the display of the error include the context. 1582 /// 1583 /// This is different from [`into_io_error`] which returns the original [`io::Error`]. 1584 /// 1585 /// [`Error`]: struct.Error.html 1586 /// [`io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html 1587 /// ["inner error"]: https://doc.rust-lang.org/std/io/struct.Error.html#method.into_inner 1588 /// [`into_io_error`]: struct.WalkDir.html#method.into_io_error from(walk_err: Error) -> io::Error1589 fn from(walk_err: Error) -> io::Error { 1590 let kind = match walk_err { 1591 Error { inner: ErrorInner::Io { ref err, .. }, .. } => { 1592 err.kind() 1593 } 1594 Error { inner: ErrorInner::Loop { .. }, .. } => { 1595 io::ErrorKind::Other 1596 } 1597 }; 1598 io::Error::new(kind, walk_err) 1599 } 1600 } 1601