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