]> git.proxmox.com Git - cargo.git/blob - vendor/walkdir-1.0.7/src/lib.rs
New upstream version 0.22.0
[cargo.git] / vendor / walkdir-1.0.7 / src / lib.rs
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.
203 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.
221 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.
238 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.
255 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.
279 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 /// ```
301 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
312 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.)
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.
403 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
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 {
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 {
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
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
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
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
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
627 fn skippable(&self) -> bool {
628 self.depth < self.opts.min_depth || self.depth > self.opts.max_depth
629 }
630 }
631
632 impl DirList {
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)]
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.
669 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())`.
679 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.
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.
708 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.
716 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.
725 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)]
732 pub fn ino(&self) -> u64 {
733 self.ino
734 }
735
736 #[cfg(not(unix))]
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)]
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))]
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)]
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))]
797 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)]
807 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 {
819 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
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 {
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`.
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.
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.
933 pub fn depth(&self) -> usize {
934 self.depth
935 }
936
937 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
944 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
954 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 {
963 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
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 {
979 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 {
998 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 }