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 ```ignore
12 [dependencies]
13 walkdir = "1"
14 ```
15 
16 # From the top
17 
18 The `WalkDir` type builds iterators. The `WalkDirIterator` trait provides
19 methods for directory iterator adapters, such as efficiently pruning entries
20 during traversal. The `DirEntry` type describes values yielded by the iterator.
21 Finally, the `Error` type is a small wrapper around `std::io::Error` with
22 additional information, such as if a loop was detected while following symbolic
23 links (not enabled by default).
24 
25 # Example
26 
27 The following code recursively iterates over the directory given and prints
28 the path for each entry:
29 
30 ```rust,no_run
31 use walkdir::WalkDir;
32 
33 for entry in WalkDir::new("foo") {
34     let entry = entry.unwrap();
35     println!("{}", entry.path().display());
36 }
37 ```
38 
39 Or, if you'd like to iterate over all entries and ignore any errors that may
40 arise, use `filter_map`. (e.g., This code below will silently skip directories
41 that the owner of the running process does not have permission to access.)
42 
43 ```rust,no_run
44 use walkdir::WalkDir;
45 
46 for entry in WalkDir::new("foo").into_iter().filter_map(|e| e.ok()) {
47     println!("{}", entry.path().display());
48 }
49 ```
50 
51 # Example: follow symbolic links
52 
53 The same code as above, except `follow_links` is enabled:
54 
55 ```rust,no_run
56 use walkdir::WalkDir;
57 
58 for entry in WalkDir::new("foo").follow_links(true) {
59     let entry = entry.unwrap();
60     println!("{}", entry.path().display());
61 }
62 ```
63 
64 # Example: skip hidden files and directories efficiently on unix
65 
66 This uses the `filter_entry` iterator adapter to avoid yielding hidden files
67 and directories efficiently:
68 
69 ```rust,no_run
70 use walkdir::{DirEntry, WalkDir, WalkDirIterator};
71 
72 fn is_hidden(entry: &DirEntry) -> bool {
73     entry.file_name()
74          .to_str()
75          .map(|s| s.starts_with("."))
76          .unwrap_or(false)
77 }
78 
79 let walker = WalkDir::new("foo").into_iter();
80 for entry in walker.filter_entry(|e| !is_hidden(e)) {
81     let entry = entry.unwrap();
82     println!("{}", entry.path().display());
83 }
84 ```
85 
86 */
87 #[cfg(windows)] extern crate kernel32;
88 #[cfg(windows)] extern crate winapi;
89 #[cfg(test)] extern crate quickcheck;
90 #[cfg(test)] extern crate rand;
91 extern crate same_file;
92 
93 use std::cmp::{Ordering, min};
94 use std::error;
95 use std::fmt;
96 use std::fs::{self, FileType, ReadDir};
97 use std::io;
98 use std::ffi::OsStr;
99 use std::ffi::OsString;
100 use std::path::{Path, PathBuf};
101 use std::result;
102 use std::vec;
103 
104 pub use same_file::is_same_file;
105 
106 #[cfg(test)] mod tests;
107 
108 /// Like try, but for iterators that return `Option<Result<_, _>>`.
109 macro_rules! itry {
110     ($e:expr) => {
111         match $e {
112             Ok(v) => v,
113             Err(err) => return Some(Err(From::from(err))),
114         }
115     }
116 }
117 
118 /// A result type for walkdir operations.
119 ///
120 /// Note that this result type embeds the error type in this crate. This
121 /// is only useful if you care about the additional information provided by
122 /// the error (such as the path associated with the error or whether a loop
123 /// was dectected). If you want things to Just Work, then you can use
124 /// `io::Result` instead since the error type in this package will
125 /// automatically convert to an `io::Result` when using the `try!` macro.
126 pub type Result<T> = ::std::result::Result<T, Error>;
127 
128 /// A builder to create an iterator for recursively walking a directory.
129 ///
130 /// Results are returned in depth first fashion, with directories yielded
131 /// before their contents. The order is unspecified. Directory entries `.`
132 /// and `..` are always omitted.
133 ///
134 /// If an error occurs at any point during iteration, then it is returned in
135 /// place of its corresponding directory entry and iteration continues as
136 /// normal. If an error occurs while opening a directory for reading, it
137 /// is skipped. Iteration may be stopped at any time. When the iterator is
138 /// destroyed, all resources associated with it are freed.
139 ///
140 /// # Usage
141 ///
142 /// This type implements `IntoIterator` so that it may be used as the subject
143 /// of a `for` loop. You may need to call `into_iter` explicitly if you want
144 /// to use iterator adapters such as `filter_entry`.
145 ///
146 /// Idiomatic use of this type should use method chaining to set desired
147 /// options. For example, this only shows entries with a depth of `1`, `2`
148 /// or `3` (relative to `foo`):
149 ///
150 /// ```rust,no_run
151 /// use walkdir::WalkDir;
152 ///
153 /// for entry in WalkDir::new("foo").min_depth(1).max_depth(3) {
154 ///     let entry = entry.unwrap();
155 ///     println!("{}", entry.path().display());
156 /// }
157 /// ```
158 ///
159 /// Note that the iterator by default includes the top-most directory. Since
160 /// this is the only directory yielded with depth `0`, it is easy to ignore it
161 /// with the `min_depth` setting:
162 ///
163 /// ```rust,no_run
164 /// use walkdir::WalkDir;
165 ///
166 /// for entry in WalkDir::new("foo").min_depth(1) {
167 ///     let entry = entry.unwrap();
168 ///     println!("{}", entry.path().display());
169 /// }
170 /// ```
171 ///
172 /// This will only return descendents of the `foo` directory and not `foo`
173 /// itself.
174 ///
175 /// # Loops
176 ///
177 /// This iterator (like most/all recursive directory iterators) assumes that
178 /// no loops can be made with *hard* links on your file system. In particular,
179 /// this would require creating a hard link to a directory such that it creates
180 /// a loop. On most platforms, this operation is illegal.
181 ///
182 /// Note that when following symbolic/soft links, loops are detected and an
183 /// error is reported.
184 pub struct WalkDir {
185     opts: WalkDirOptions,
186     root: PathBuf,
187 }
188 
189 struct WalkDirOptions {
190     follow_links: bool,
191     max_open: usize,
192     min_depth: usize,
193     max_depth: usize,
194     sorter: Option<Box<FnMut(&OsString,&OsString) -> Ordering + 'static>>,
195 }
196 
197 impl WalkDir {
198     /// Create a builder for a recursive directory iterator starting at the
199     /// file path `root`. If `root` is a directory, then it is the first item
200     /// yielded by the iterator. If `root` is a file, then it is the first
201     /// and only item yielded by the iterator. If `root` is a symlink, then it
202     /// is always followed.
new<P: AsRef<Path>>(root: P) -> Self203     pub fn new<P: AsRef<Path>>(root: P) -> Self {
204         WalkDir {
205             opts: WalkDirOptions {
206                 follow_links: false,
207                 max_open: 10,
208                 min_depth: 0,
209                 max_depth: ::std::usize::MAX,
210                 sorter: None,
211             },
212             root: root.as_ref().to_path_buf(),
213         }
214     }
215 
216     /// Set the minimum depth of entries yielded by the iterator.
217     ///
218     /// The smallest depth is `0` and always corresponds to the path given
219     /// to the `new` function on this type. Its direct descendents have depth
220     /// `1`, and their descendents have depth `2`, and so on.
min_depth(mut self, depth: usize) -> Self221     pub fn min_depth(mut self, depth: usize) -> Self {
222         self.opts.min_depth = depth;
223         if self.opts.min_depth > self.opts.max_depth {
224             self.opts.min_depth = self.opts.max_depth;
225         }
226         self
227     }
228 
229     /// Set the maximum depth of entries yield by the iterator.
230     ///
231     /// The smallest depth is `0` and always corresponds to the path given
232     /// to the `new` function on this type. Its direct descendents have depth
233     /// `1`, and their descendents have depth `2`, and so on.
234     ///
235     /// Note that this will not simply filter the entries of the iterator, but
236     /// it will actually avoid descending into directories when the depth is
237     /// exceeded.
max_depth(mut self, depth: usize) -> Self238     pub fn max_depth(mut self, depth: usize) -> Self {
239         self.opts.max_depth = depth;
240         if self.opts.max_depth < self.opts.min_depth {
241             self.opts.max_depth = self.opts.min_depth;
242         }
243         self
244     }
245 
246     /// Follow symbolic links. By default, this is disabled.
247     ///
248     /// When `yes` is `true`, symbolic links are followed as if they were
249     /// normal directories and files. If a symbolic link is broken or is
250     /// involved in a loop, an error is yielded.
251     ///
252     /// When enabled, the yielded `DirEntry` values represent the target of
253     /// the link while the path corresponds to the link. See the `DirEntry`
254     /// type for more details.
follow_links(mut self, yes: bool) -> Self255     pub fn follow_links(mut self, yes: bool) -> Self {
256         self.opts.follow_links = yes;
257         self
258     }
259 
260     /// Set the maximum number of simultaneously open file descriptors used
261     /// by the iterator.
262     ///
263     /// `n` must be greater than or equal to `1`. If `n` is `0`, then it is set
264     /// to `1` automatically. If this is not set, then it defaults to some
265     /// reasonably low number.
266     ///
267     /// This setting has no impact on the results yielded by the iterator
268     /// (even when `n` is `1`). Instead, this setting represents a trade off
269     /// between scarce resources (file descriptors) and memory. Namely, when
270     /// the maximum number of file descriptors is reached and a new directory
271     /// needs to be opened to continue iteration, then a previous directory
272     /// handle is closed and has its unyielded entries stored in memory. In
273     /// practice, this is a satisfying trade off because it scales with respect
274     /// to the *depth* of your file tree. Therefore, low values (even `1`) are
275     /// acceptable.
276     ///
277     /// Note that this value does not impact the number of system calls made by
278     /// an exhausted iterator.
max_open(mut self, mut n: usize) -> Self279     pub fn max_open(mut self, mut n: usize) -> Self {
280         if n == 0 {
281             n = 1;
282         }
283         self.opts.max_open = n;
284         self
285     }
286 
287     /// Set a function for sorting directory entries.
288     ///
289     /// If a compare function is set, the resulting iterator will return all
290     /// paths in sorted order. The compare function will be called to compare
291     /// names from entries from the same directory using only the name of the
292     /// entry.
293     ///
294     /// ```rust,no-run
295     /// use std::cmp;
296     /// use std::ffi::OsString;
297     /// use walkdir::WalkDir;
298     ///
299     /// WalkDir::new("foo").sort_by(|a,b| a.cmp(b));
300     /// ```
sort_by<F>(mut self, cmp: F) -> Self where F: FnMut(&OsString, &OsString) -> Ordering + 'static301     pub fn sort_by<F>(mut self, cmp: F) -> Self
302             where F: FnMut(&OsString, &OsString) -> Ordering + 'static {
303         self.opts.sorter = Some(Box::new(cmp));
304         self
305     }
306 }
307 
308 impl IntoIterator for WalkDir {
309     type Item = Result<DirEntry>;
310     type IntoIter = Iter;
311 
into_iter(self) -> Iter312     fn into_iter(self) -> Iter {
313         Iter {
314             opts: self.opts,
315             start: Some(self.root),
316             stack_list: vec![],
317             stack_path: vec![],
318             oldest_opened: 0,
319             depth: 0,
320         }
321     }
322 }
323 
324 /// A trait for recursive directory iterators.
325 pub trait WalkDirIterator: Iterator {
326     /// Skips the current directory.
327     ///
328     /// This causes the iterator to stop traversing the contents of the least
329     /// recently yielded directory. This means any remaining entries in that
330     /// directory will be skipped (including sub-directories).
331     ///
332     /// Note that the ergnomics of this method are questionable since it
333     /// borrows the iterator mutably. Namely, you must write out the looping
334     /// condition manually. For example, to skip hidden entries efficiently on
335     /// unix systems:
336     ///
337     /// ```rust,no_run
338     /// use walkdir::{DirEntry, WalkDir, WalkDirIterator};
339     ///
340     /// fn is_hidden(entry: &DirEntry) -> bool {
341     ///     entry.file_name()
342     ///          .to_str()
343     ///          .map(|s| s.starts_with("."))
344     ///          .unwrap_or(false)
345     /// }
346     ///
347     /// let mut it = WalkDir::new("foo").into_iter();
348     /// loop {
349     ///     let entry = match it.next() {
350     ///         None => break,
351     ///         Some(Err(err)) => panic!("ERROR: {}", err),
352     ///         Some(Ok(entry)) => entry,
353     ///     };
354     ///     if is_hidden(&entry) {
355     ///         if entry.file_type().is_dir() {
356     ///             it.skip_current_dir();
357     ///         }
358     ///         continue;
359     ///     }
360     ///     println!("{}", entry.path().display());
361     /// }
362     /// ```
363     ///
364     /// You may find it more convenient to use the `filter_entry` iterator
365     /// adapter. (See its documentation for the same example functionality as
366     /// above.)
skip_current_dir(&mut self)367     fn skip_current_dir(&mut self);
368 
369     /// Yields only entries which satisfy the given predicate and skips
370     /// descending into directories that do not satisfy the given predicate.
371     ///
372     /// The predicate is applied to all entries. If the predicate is
373     /// true, iteration carries on as normal. If the predicate is false, the
374     /// entry is ignored and if it is a directory, it is not descended into.
375     ///
376     /// This is often more convenient to use than `skip_current_dir`. For
377     /// example, to skip hidden files and directories efficiently on unix
378     /// systems:
379     ///
380     /// ```rust,no_run
381     /// use walkdir::{DirEntry, WalkDir, WalkDirIterator};
382     ///
383     /// fn is_hidden(entry: &DirEntry) -> bool {
384     ///     entry.file_name()
385     ///          .to_str()
386     ///          .map(|s| s.starts_with("."))
387     ///          .unwrap_or(false)
388     /// }
389     ///
390     /// for entry in WalkDir::new("foo")
391     ///                      .into_iter()
392     ///                      .filter_entry(|e| !is_hidden(e)) {
393     ///     let entry = entry.unwrap();
394     ///     println!("{}", entry.path().display());
395     /// }
396     /// ```
397     ///
398     /// Note that the iterator will still yield errors for reading entries that
399     /// may not satisfy the predicate.
400     ///
401     /// Note that entries skipped with `min_depth` and `max_depth` are not
402     /// passed to this predicate.
filter_entry<P>(self, predicate: P) -> IterFilterEntry<Self, P> where Self: Sized, P: FnMut(&DirEntry) -> bool403     fn filter_entry<P>(self, predicate: P) -> IterFilterEntry<Self, P>
404             where Self: Sized, P: FnMut(&DirEntry) -> bool {
405         IterFilterEntry { it: self, predicate: predicate }
406     }
407 }
408 
409 /// An iterator for recursively descending into a directory.
410 ///
411 /// A value with this type must be constructed with the `WalkDir` type, which
412 /// uses a builder pattern to set options such as min/max depth, max open file
413 /// descriptors and whether the iterator should follow symbolic links.
414 ///
415 /// The order of elements yielded by this iterator is unspecified.
416 pub struct Iter {
417     /// Options specified in the builder. Depths, max fds, etc.
418     opts: WalkDirOptions,
419     /// The start path.
420     ///
421     /// This is only `Some(...)` at the beginning. After the first iteration,
422     /// this is always `None`.
423     start: Option<PathBuf>,
424     /// A stack of open (up to max fd) or closed handles to directories.
425     /// An open handle is a plain `fs::ReadDir` while a closed handle is
426     /// a `Vec<fs::DirEntry>` corresponding to the as-of-yet consumed entries.
427     stack_list: Vec<DirList>,
428     /// A stack of file paths.
429     ///
430     /// This is *only* used when `follow_links` is enabled. In all other cases
431     /// this stack is empty.
432     stack_path: Vec<PathBuf>,
433     /// An index into `stack_list` that points to the oldest open directory
434     /// handle. If the maximum fd limit is reached and a new directory needs
435     /// to be read, the handle at this index is closed before the new directory
436     /// is opened.
437     oldest_opened: usize,
438     /// The current depth of iteration (the length of the stack at the
439     /// beginning of each iteration).
440     depth: usize,
441 }
442 
443 /// A sequence of unconsumed directory entries.
444 ///
445 /// This represents the opened or closed state of a directory handle. When
446 /// open, future entries are read by iterating over the raw `fs::ReadDir`.
447 /// When closed, all future entries are read into memory. Iteration then
448 /// proceeds over a `Vec<fs::DirEntry>`.
449 enum DirList {
450     /// An opened handle.
451     ///
452     /// This includes the depth of the handle itself.
453     ///
454     /// If there was an error with the initial `fs::read_dir` call, then it is
455     /// stored here. (We use an `Option<...>` to make yielding the error
456     /// exactly once simpler.)
457     Opened { depth: usize, it: result::Result<ReadDir, Option<Error>> },
458     /// A closed handle.
459     ///
460     /// All remaining directory entries are read into memory.
461     Closed(vec::IntoIter<Result<fs::DirEntry>>),
462 }
463 
464 /// A directory entry.
465 ///
466 /// This is the type of value that is yielded from the iterators defined in
467 /// this crate.
468 ///
469 /// # Differences with `std::fs::DirEntry`
470 ///
471 /// This type mostly mirrors the type by the same name in `std::fs`. There are
472 /// some differences however:
473 ///
474 /// * All recursive directory iterators must inspect the entry's type.
475 /// Therefore, the value is stored and its access is guaranteed to be cheap and
476 /// successful.
477 /// * `path` and `file_name` return borrowed variants.
478 /// * If `follow_links` was enabled on the originating iterator, then all
479 /// operations except for `path` operate on the link target. Otherwise, all
480 /// operations operate on the symbolic link.
481 pub struct DirEntry {
482     /// The path as reported by the `fs::ReadDir` iterator (even if it's a
483     /// symbolic link).
484     path: PathBuf,
485     /// The file type. Necessary for recursive iteration, so store it.
486     ty: FileType,
487     /// Is set when this entry was created from a symbolic link and the user
488     /// excepts the iterator to follow symbolic links.
489     follow_link: bool,
490     /// The depth at which this entry was generated relative to the root.
491     depth: usize,
492     /// The underlying inode number (Unix only).
493     #[cfg(unix)]
494     ino: u64,
495 }
496 
497 impl Iterator for Iter {
498     type Item = Result<DirEntry>;
499 
next(&mut self) -> Option<Result<DirEntry>>500     fn next(&mut self) -> Option<Result<DirEntry>> {
501         if let Some(start) = self.start.take() {
502             let dent = itry!(DirEntry::from_link(0, start));
503             if let Some(result) = self.handle_entry(dent) {
504                 return Some(result);
505             }
506         }
507         while !self.stack_list.is_empty() {
508             self.depth = self.stack_list.len();
509             if self.depth > self.opts.max_depth {
510                 // If we've exceeded the max depth, pop the current dir
511                 // so that we don't descend.
512                 self.pop();
513                 continue;
514             }
515             match self.stack_list.last_mut().unwrap().next() {
516                 None => self.pop(),
517                 Some(Err(err)) => return Some(Err(err)),
518                 Some(Ok(dent)) => {
519                     let dent = itry!(DirEntry::from_entry(self.depth, &dent));
520                     if let Some(result) = self.handle_entry(dent) {
521                         return Some(result);
522                     }
523                 }
524             }
525         }
526         None
527     }
528 }
529 
530 impl WalkDirIterator for Iter {
skip_current_dir(&mut self)531     fn skip_current_dir(&mut self) {
532         if !self.stack_list.is_empty() {
533             self.stack_list.pop();
534         }
535         if !self.stack_path.is_empty() {
536             self.stack_path.pop();
537         }
538     }
539 }
540 
541 impl Iter {
handle_entry( &mut self, mut dent: DirEntry, ) -> Option<Result<DirEntry>>542     fn handle_entry(
543         &mut self,
544         mut dent: DirEntry,
545     ) -> Option<Result<DirEntry>> {
546         if self.opts.follow_links && dent.file_type().is_symlink() {
547             dent = itry!(self.follow(dent));
548         }
549         if dent.file_type().is_dir() {
550             self.push(&dent);
551         }
552         if self.skippable() { None } else { Some(Ok(dent)) }
553     }
554 
push(&mut self, dent: &DirEntry)555     fn push(&mut self, dent: &DirEntry) {
556         // Make room for another open file descriptor if we've hit the max.
557         if self.stack_list.len() - self.oldest_opened == self.opts.max_open {
558             self.stack_list[self.oldest_opened].close();
559             self.oldest_opened = self.oldest_opened.checked_add(1).unwrap();
560         }
561         // Open a handle to reading the directory's entries.
562         let rd = fs::read_dir(dent.path()).map_err(|err| {
563             Some(Error::from_path(self.depth, dent.path().to_path_buf(), err))
564         });
565         let mut list = DirList::Opened { depth: self.depth, it: rd };
566         if let Some(ref mut cmp) = self.opts.sorter {
567             let mut entries: Vec<_> = list.collect();
568             entries.sort_by(|a, b| {
569                 match (a, b) {
570                     (&Ok(ref a), &Ok(ref b)) => {
571                         cmp(&a.file_name(), &b.file_name())
572                     }
573                     (&Err(_), &Err(_)) => Ordering::Equal,
574                     (&Ok(_), &Err(_)) => Ordering::Greater,
575                     (&Err(_), &Ok(_)) => Ordering::Less,
576                 }
577             });
578             list = DirList::Closed(entries.into_iter());
579         }
580         self.stack_list.push(list);
581         if self.opts.follow_links {
582             self.stack_path.push(dent.path().to_path_buf());
583         }
584     }
585 
pop(&mut self)586     fn pop(&mut self) {
587         self.stack_list.pop().expect("cannot pop from empty stack");
588         if self.opts.follow_links {
589             self.stack_path.pop().expect("BUG: list/path stacks out of sync");
590         }
591         // If everything in the stack is already closed, then there is
592         // room for at least one more open descriptor and it will
593         // always be at the top of the stack.
594         self.oldest_opened = min(self.oldest_opened, self.stack_list.len());
595     }
596 
follow(&self, mut dent: DirEntry) -> Result<DirEntry>597     fn follow(&self, mut dent: DirEntry) -> Result<DirEntry> {
598         dent = try!(DirEntry::from_link(self.depth,
599                                         dent.path().to_path_buf()));
600         // The only way a symlink can cause a loop is if it points
601         // to a directory. Otherwise, it always points to a leaf
602         // and we can omit any loop checks.
603         if dent.file_type().is_dir() {
604             try!(self.check_loop(dent.path()));
605         }
606         Ok(dent)
607     }
608 
check_loop<P: AsRef<Path>>(&self, child: P) -> Result<()>609     fn check_loop<P: AsRef<Path>>(&self, child: P) -> Result<()> {
610         for ancestor in self.stack_path.iter().rev() {
611             let same = try!(is_same_file(ancestor, &child).map_err(|err| {
612                 Error::from_io(self.depth, err)
613             }));
614             if same {
615                 return Err(Error {
616                     depth: self.depth,
617                     inner: ErrorInner::Loop {
618                         ancestor: ancestor.to_path_buf(),
619                         child: child.as_ref().to_path_buf(),
620                     },
621                 });
622             }
623         }
624         Ok(())
625     }
626 
skippable(&self) -> bool627     fn skippable(&self) -> bool {
628         self.depth < self.opts.min_depth || self.depth > self.opts.max_depth
629     }
630 }
631 
632 impl DirList {
close(&mut self)633     fn close(&mut self) {
634         if let DirList::Opened { .. } = *self {
635             *self = DirList::Closed(self.collect::<Vec<_>>().into_iter());
636         }
637     }
638 }
639 
640 impl Iterator for DirList {
641     type Item = Result<fs::DirEntry>;
642 
643     #[inline(always)]
next(&mut self) -> Option<Result<fs::DirEntry>>644     fn next(&mut self) -> Option<Result<fs::DirEntry>> {
645         match *self {
646             DirList::Closed(ref mut it) => it.next(),
647             DirList::Opened { depth, ref mut it } => match *it {
648                 Err(ref mut err) => err.take().map(Err),
649                 Ok(ref mut rd) => rd.next().map(|r| r.map_err(|err| {
650                     Error::from_io(depth + 1, err)
651                 })),
652             }
653         }
654     }
655 }
656 
657 impl DirEntry {
658     /// The full path that this entry represents.
659     ///
660     /// The full path is created by joining the parents of this entry up to the
661     /// root initially given to `WalkDir::new` with the file name of this
662     /// entry.
663     ///
664     /// Note that this *always* returns the path reported by the underlying
665     /// directory entry, even when symbolic links are followed. To get the
666     /// target path, use `path_is_symbolic_link` to (cheaply) check if
667     /// this entry corresponds to a symbolic link, and `std::fs::read_link` to
668     /// resolve the target.
path(&self) -> &Path669     pub fn path(&self) -> &Path {
670         &self.path
671     }
672 
673     /// Returns `true` if and only if this entry was created from a symbolic
674     /// link. This is unaffected by the `follow_links` setting.
675     ///
676     /// When `true`, the value returned by the `path` method is a
677     /// symbolic link name. To get the full target path, you must call
678     /// `std::fs::read_link(entry.path())`.
path_is_symbolic_link(&self) -> bool679     pub fn path_is_symbolic_link(&self) -> bool {
680         self.ty.is_symlink() || self.follow_link
681     }
682 
683     /// Return the metadata for the file that this entry points to.
684     ///
685     /// This will follow symbolic links if and only if the `WalkDir` value
686     /// has `follow_links` enabled.
687     ///
688     /// # Platform behavior
689     ///
690     /// This always calls `std::fs::symlink_metadata`.
691     ///
692     /// If this entry is a symbolic link and `follow_links` is enabled, then
693     /// `std::fs::metadata` is called instead.
metadata(&self) -> Result<fs::Metadata>694     pub fn metadata(&self) -> Result<fs::Metadata> {
695         if self.follow_link {
696             fs::metadata(&self.path)
697         } else {
698             fs::symlink_metadata(&self.path)
699         }.map_err(|err| Error::from_entry(self, err))
700     }
701 
702     /// Return the file type for the file that this entry points to.
703     ///
704     /// If this is a symbolic link and `follow_links` is `true`, then this
705     /// returns the type of the target.
706     ///
707     /// This never makes any system calls.
file_type(&self) -> fs::FileType708     pub fn file_type(&self) -> fs::FileType {
709         self.ty
710     }
711 
712     /// Return the file name of this entry.
713     ///
714     /// If this entry has no file name (e.g., `/`), then the full path is
715     /// returned.
file_name(&self) -> &OsStr716     pub fn file_name(&self) -> &OsStr {
717         self.path.file_name().unwrap_or_else(|| self.path.as_os_str())
718     }
719 
720     /// Returns the depth at which this entry was created relative to the root.
721     ///
722     /// The smallest depth is `0` and always corresponds to the path given
723     /// to the `new` function on `WalkDir`. Its direct descendents have depth
724     /// `1`, and their descendents have depth `2`, and so on.
depth(&self) -> usize725     pub fn depth(&self) -> usize {
726         self.depth
727     }
728 
729     /// Returns the underlying `d_ino` field in the contained `dirent`
730     /// structure.
731     #[cfg(unix)]
ino(&self) -> u64732     pub fn ino(&self) -> u64 {
733         self.ino
734     }
735 
736     #[cfg(not(unix))]
from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry>737     fn from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry> {
738         let ty = try!(ent.file_type().map_err(|err| {
739             Error::from_path(depth, ent.path(), err)
740         }));
741         Ok(DirEntry {
742             path: ent.path(),
743             ty: ty,
744             follow_link: false,
745             depth: depth,
746         })
747     }
748 
749     #[cfg(unix)]
from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry>750     fn from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry> {
751         use std::os::unix::fs::DirEntryExt;
752 
753         let ty = try!(ent.file_type().map_err(|err| {
754             Error::from_path(depth, ent.path(), err)
755         }));
756         Ok(DirEntry {
757             path: ent.path(),
758             ty: ty,
759             follow_link: false,
760             depth: depth,
761             ino: ent.ino(),
762         })
763     }
764 
765     #[cfg(not(unix))]
from_link(depth: usize, pb: PathBuf) -> Result<DirEntry>766     fn from_link(depth: usize, pb: PathBuf) -> Result<DirEntry> {
767         let md = try!(fs::metadata(&pb).map_err(|err| {
768             Error::from_path(depth, pb.clone(), err)
769         }));
770         Ok(DirEntry {
771             path: pb,
772             ty: md.file_type(),
773             follow_link: true,
774             depth: depth,
775         })
776     }
777 
778     #[cfg(unix)]
from_link(depth: usize, pb: PathBuf) -> Result<DirEntry>779     fn from_link(depth: usize, pb: PathBuf) -> Result<DirEntry> {
780         use std::os::unix::fs::MetadataExt;
781 
782         let md = try!(fs::metadata(&pb).map_err(|err| {
783             Error::from_path(depth, pb.clone(), err)
784         }));
785         Ok(DirEntry {
786             path: pb,
787             ty: md.file_type(),
788             follow_link: true,
789             depth: depth,
790             ino: md.ino(),
791         })
792     }
793 }
794 
795 impl Clone for DirEntry {
796     #[cfg(not(unix))]
clone(&self) -> DirEntry797     fn clone(&self) -> DirEntry {
798         DirEntry {
799             path: self.path.clone(),
800             ty: self.ty,
801             follow_link: self.follow_link,
802             depth: self.depth,
803         }
804     }
805 
806     #[cfg(unix)]
clone(&self) -> DirEntry807     fn clone(&self) -> DirEntry {
808         DirEntry {
809             path: self.path.clone(),
810             ty: self.ty,
811             follow_link: self.follow_link,
812             depth: self.depth,
813             ino: self.ino,
814         }
815     }
816 }
817 
818 impl fmt::Debug for DirEntry {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result819     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
820         write!(f, "DirEntry({:?})", self.path)
821     }
822 }
823 
824 /// A recursive directory iterator that skips entries.
825 ///
826 /// Directories that fail the predicate `P` are skipped. Namely, they are
827 /// never yielded and never descended into.
828 ///
829 /// Entries that are skipped with the `min_depth` and `max_depth` options are
830 /// not passed through this filter.
831 ///
832 /// If opening a handle to a directory resulted in an error, then it is yielded
833 /// and no corresponding call to the predicate is made.
834 ///
835 /// Type parameter `I` refers to the underlying iterator and `P` refers to the
836 /// predicate, which is usually `FnMut(&DirEntry) -> bool`.
837 pub struct IterFilterEntry<I, P> {
838     it: I,
839     predicate: P,
840 }
841 
842 impl<I, P> Iterator for IterFilterEntry<I, P>
843         where I: WalkDirIterator<Item=Result<DirEntry>>,
844               P: FnMut(&DirEntry) -> bool {
845     type Item = Result<DirEntry>;
846 
next(&mut self) -> Option<Result<DirEntry>>847     fn next(&mut self) -> Option<Result<DirEntry>> {
848         loop {
849             let dent = match self.it.next() {
850                 None => return None,
851                 Some(result) => itry!(result),
852             };
853             if !(self.predicate)(&dent) {
854                 if dent.file_type().is_dir() {
855                     self.it.skip_current_dir();
856                 }
857                 continue;
858             }
859             return Some(Ok(dent));
860         }
861     }
862 }
863 
864 impl<I, P> WalkDirIterator for IterFilterEntry<I, P>
865         where I: WalkDirIterator<Item=Result<DirEntry>>,
866               P: FnMut(&DirEntry) -> bool {
skip_current_dir(&mut self)867     fn skip_current_dir(&mut self) {
868         self.it.skip_current_dir();
869     }
870 }
871 
872 /// An error produced by recursively walking a directory.
873 ///
874 /// This error type is a light wrapper around `std::io::Error`. In particular,
875 /// it adds the following information:
876 ///
877 /// * The depth at which the error occurred in the file tree, relative to the
878 /// root.
879 /// * The path, if any, associated with the IO error.
880 /// * An indication that a loop occurred when following symbolic links. In this
881 /// case, there is no underlying IO error.
882 ///
883 /// To maintain good ergnomics, this type has a
884 /// `impl From<Error> for std::io::Error` defined so that you may use an
885 /// `io::Result` with methods in this crate if you don't care about accessing
886 /// the underlying error data in a structured form.
887 #[derive(Debug)]
888 pub struct Error {
889     depth: usize,
890     inner: ErrorInner,
891 }
892 
893 #[derive(Debug)]
894 enum ErrorInner {
895     Io { path: Option<PathBuf>, err: io::Error },
896     Loop { ancestor: PathBuf, child: PathBuf },
897 }
898 
899 impl Error {
900     /// Returns the path associated with this error if one exists.
901     ///
902     /// For example, if an error occurred while opening a directory handle,
903     /// the error will include the path passed to `std::fs::read_dir`.
path(&self) -> Option<&Path>904     pub fn path(&self) -> Option<&Path> {
905         match self.inner {
906             ErrorInner::Io { path: None, .. } => None,
907             ErrorInner::Io { path: Some(ref path), .. } => Some(path),
908             ErrorInner::Loop { ref child, .. } => Some(child),
909         }
910     }
911 
912     /// Returns the path at which a cycle was detected.
913     ///
914     /// If no cycle was detected, `None` is returned.
915     ///
916     /// A cycle is detected when a directory entry is equivalent to one of
917     /// its ancestors.
918     ///
919     /// To get the path to the child directory entry in the cycle, use the
920     /// `path` method.
loop_ancestor(&self) -> Option<&Path>921     pub fn loop_ancestor(&self) -> Option<&Path> {
922         match self.inner {
923             ErrorInner::Loop { ref ancestor, .. } => Some(ancestor),
924             _ => None,
925         }
926     }
927 
928     /// Returns the depth at which this error occurred relative to the root.
929     ///
930     /// The smallest depth is `0` and always corresponds to the path given
931     /// to the `new` function on `WalkDir`. Its direct descendents have depth
932     /// `1`, and their descendents have depth `2`, and so on.
depth(&self) -> usize933     pub fn depth(&self) -> usize {
934         self.depth
935     }
936 
from_path(depth: usize, pb: PathBuf, err: io::Error) -> Self937     fn from_path(depth: usize, pb: PathBuf, err: io::Error) -> Self {
938         Error {
939             depth: depth,
940             inner: ErrorInner::Io { path: Some(pb), err: err },
941         }
942     }
943 
from_entry(dent: &DirEntry, err: io::Error) -> Self944     fn from_entry(dent: &DirEntry, err: io::Error) -> Self {
945         Error {
946             depth: dent.depth,
947             inner: ErrorInner::Io {
948                 path: Some(dent.path().to_path_buf()),
949                 err: err,
950             },
951         }
952     }
953 
from_io(depth: usize, err: io::Error) -> Self954     fn from_io(depth: usize, err: io::Error) -> Self {
955         Error {
956             depth: depth,
957             inner: ErrorInner::Io { path: None, err: err },
958         }
959     }
960 }
961 
962 impl error::Error for Error {
description(&self) -> &str963     fn description(&self) -> &str {
964         match self.inner {
965             ErrorInner::Io { ref err, .. } => err.description(),
966             ErrorInner::Loop { .. } => "file system loop found",
967         }
968     }
969 
cause(&self) -> Option<&error::Error>970     fn cause(&self) -> Option<&error::Error> {
971         match self.inner {
972             ErrorInner::Io { ref err, .. } => Some(err),
973             ErrorInner::Loop { .. } => None,
974         }
975     }
976 }
977 
978 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result979     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
980         match self.inner {
981             ErrorInner::Io { path: None, ref err } => {
982                 err.fmt(f)
983             }
984             ErrorInner::Io { path: Some(ref path), ref err } => {
985                 write!(f, "IO error for operation on {}: {}",
986                        path.display(), err)
987             }
988             ErrorInner::Loop { ref ancestor, ref child } => {
989                 write!(f, "File system loop found: \
990                            {} points to an ancestor {}",
991                        child.display(), ancestor.display())
992             }
993         }
994     }
995 }
996 
997 impl From<Error> for io::Error {
from(err: Error) -> io::Error998     fn from(err: Error) -> io::Error {
999         match err {
1000             Error { inner: ErrorInner::Io { err, .. }, .. } => err,
1001             err @ Error { inner: ErrorInner::Loop { .. }, .. } => {
1002                 io::Error::new(io::ErrorKind::Other, err)
1003             }
1004         }
1005     }
1006 }
1007