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