4 use std
::path
::{Path, PathBuf}
;
8 /// An error produced by recursively walking a directory.
10 /// This error type is a light wrapper around [`std::io::Error`]. In
11 /// particular, it adds the following information:
13 /// * The depth at which the error occurred in the file tree, relative to the
15 /// * The path, if any, associated with the IO error.
16 /// * An indication that a loop occurred when following symbolic links. In this
17 /// case, there is no underlying IO error.
19 /// To maintain good ergonomics, this type has a
20 /// [`impl From<Error> for std::io::Error`][impl] defined which preserves the original context.
21 /// This allows you to use an [`io::Result`] with methods in this crate if you don't care about
22 /// accessing the underlying error data in a structured form.
24 /// [`std::io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html
25 /// [`io::Result`]: https://doc.rust-lang.org/stable/std/io/type.Result.html
26 /// [impl]: struct.Error.html#impl-From%3CError%3E
35 Io { path: Option<PathBuf>, err: io::Error }
,
36 Loop { ancestor: PathBuf, child: PathBuf }
,
40 /// Returns the path associated with this error if one exists.
42 /// For example, if an error occurred while opening a directory handle,
43 /// the error will include the path passed to [`std::fs::read_dir`].
45 /// [`std::fs::read_dir`]: https://doc.rust-lang.org/stable/std/fs/fn.read_dir.html
46 pub fn path(&self) -> Option
<&Path
> {
48 ErrorInner
::Io { path: None, .. }
=> None
,
49 ErrorInner
::Io { path: Some(ref path), .. }
=> Some(path
),
50 ErrorInner
::Loop { ref child, .. }
=> Some(child
),
54 /// Returns the path at which a cycle was detected.
56 /// If no cycle was detected, [`None`] is returned.
58 /// A cycle is detected when a directory entry is equivalent to one of
61 /// To get the path to the child directory entry in the cycle, use the
64 /// [`None`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#variant.None
65 /// [`path`]: struct.Error.html#path
66 pub fn loop_ancestor(&self) -> Option
<&Path
> {
68 ErrorInner
::Loop { ref ancestor, .. }
=> Some(ancestor
),
73 /// Returns the depth at which this error occurred relative to the root.
75 /// The smallest depth is `0` and always corresponds to the path given to
76 /// the [`new`] function on [`WalkDir`]. Its direct descendents have depth
77 /// `1`, and their descendents have depth `2`, and so on.
79 /// [`new`]: struct.WalkDir.html#method.new
80 /// [`WalkDir`]: struct.WalkDir.html
81 pub fn depth(&self) -> usize {
85 /// Inspect the original [`io::Error`] if there is one.
87 /// [`None`] is returned if the [`Error`] doesn't correspond to an
88 /// [`io::Error`]. This might happen, for example, when the error was
89 /// produced because a cycle was found in the directory tree while
90 /// following symbolic links.
92 /// This method returns a borrowed value that is bound to the lifetime of the [`Error`]. To
93 /// obtain an owned value, the [`into_io_error`] can be used instead.
95 /// > This is the original [`io::Error`] and is _not_ the same as
96 /// > [`impl From<Error> for std::io::Error`][impl] which contains additional context about the
103 /// use std::path::Path;
105 /// use walkdir::WalkDir;
107 /// for entry in WalkDir::new("foo") {
109 /// Ok(entry) => println!("{}", entry.path().display()),
111 /// let path = err.path().unwrap_or(Path::new("")).display();
112 /// println!("failed to access entry {}", path);
113 /// if let Some(inner) = err.io_error() {
114 /// match inner.kind() {
115 /// io::ErrorKind::InvalidData => {
117 /// "entry contains invalid data: {}",
120 /// io::ErrorKind::PermissionDenied => {
122 /// "Missing permission to read entry: {}",
127 /// "Unexpected error occurred: {}",
137 /// [`None`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#variant.None
138 /// [`io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html
139 /// [`From`]: https://doc.rust-lang.org/stable/std/convert/trait.From.html
140 /// [`Error`]: struct.Error.html
141 /// [`into_io_error`]: struct.Error.html#method.into_io_error
142 /// [impl]: struct.Error.html#impl-From%3CError%3E
143 pub fn io_error(&self) -> Option
<&io
::Error
> {
145 ErrorInner
::Io { ref err, .. }
=> Some(err
),
146 ErrorInner
::Loop { .. }
=> None
,
150 /// Similar to [`io_error`] except consumes self to convert to the original
151 /// [`io::Error`] if one exists.
153 /// [`io_error`]: struct.Error.html#method.io_error
154 /// [`io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html
155 pub fn into_io_error(self) -> Option
<io
::Error
> {
157 ErrorInner
::Io { err, .. }
=> Some(err
),
158 ErrorInner
::Loop { .. }
=> None
,
162 pub(crate) fn from_path(
169 inner
: ErrorInner
::Io { path: Some(pb), err: err }
,
173 pub(crate) fn from_entry(dent
: &DirEntry
, err
: io
::Error
) -> Self {
176 inner
: ErrorInner
::Io
{
177 path
: Some(dent
.path().to_path_buf()),
183 pub(crate) fn from_io(depth
: usize, err
: io
::Error
) -> Self {
184 Error { depth: depth, inner: ErrorInner::Io { path: None, err: err }
}
187 pub(crate) fn from_loop(
194 inner
: ErrorInner
::Loop
{
195 ancestor
: ancestor
.to_path_buf(),
196 child
: child
.to_path_buf(),
202 impl error
::Error
for Error
{
204 fn description(&self) -> &str {
206 ErrorInner
::Io { ref err, .. }
=> err
.description(),
207 ErrorInner
::Loop { .. }
=> "file system loop found",
211 fn cause(&self) -> Option
<&dyn error
::Error
> {
215 fn source(&self) -> Option
<&(dyn error
::Error
+ '
static)> {
217 ErrorInner
::Io { ref err, .. }
=> Some(err
),
218 ErrorInner
::Loop { .. }
=> None
,
223 impl fmt
::Display
for Error
{
224 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
226 ErrorInner
::Io { path: None, ref err }
=> err
.fmt(f
),
227 ErrorInner
::Io { path: Some(ref path), ref err }
=> write
!(
229 "IO error for operation on {}: {}",
233 ErrorInner
::Loop { ref ancestor, ref child }
=> write
!(
235 "File system loop found: \
236 {} points to an ancestor {}",
244 impl From
<Error
> for io
::Error
{
245 /// Convert the [`Error`] to an [`io::Error`], preserving the original
246 /// [`Error`] as the ["inner error"]. Note that this also makes the display
247 /// of the error include the context.
249 /// This is different from [`into_io_error`] which returns the original
252 /// [`Error`]: struct.Error.html
253 /// [`io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html
254 /// ["inner error"]: https://doc.rust-lang.org/std/io/struct.Error.html#method.into_inner
255 /// [`into_io_error`]: struct.WalkDir.html#method.into_io_error
256 fn from(walk_err
: Error
) -> io
::Error
{
257 let kind
= match walk_err
{
258 Error { inner: ErrorInner::Io { ref err, .. }
, .. } => err
.kind(),
259 Error { inner: ErrorInner::Loop { .. }
, .. } => {
263 io
::Error
::new(kind
, walk_err
)