1use std::ffi::NulError;
4use thiserror::Error;
5
6#[derive(Debug, Error)]
8pub enum Error {
9 #[error("I/O error: {0}")]
11 Io(#[from] std::io::Error),
12
13 #[error("not found: {0}")]
15 NotFound(String),
16
17 #[error("already exists: {0}")]
19 AlreadyExists(String),
20
21 #[error("not a directory: {0}")]
23 NotADirectory(String),
24
25 #[error("is a directory: {0}")]
27 IsADirectory(String),
28
29 #[error("directory not empty: {0}")]
31 NotEmpty(String),
32
33 #[error("permission denied")]
35 PermissionDenied,
36
37 #[error("no space left on device")]
39 NoSpace,
40
41 #[error("read-only filesystem")]
43 ReadOnly,
44
45 #[error("invalid argument: {0}")]
47 InvalidArgument(String),
48
49 #[error("path contains null byte")]
51 NulError(#[from] NulError),
52
53 #[error("filesystem error: {0}")]
55 Filesystem(i32),
56
57 #[error("device not found")]
59 DeviceNotFound,
60
61 #[error("mount point not found")]
63 MountPointNotFound,
64
65 #[error("name too long")]
67 NameTooLong,
68
69 #[error("too many open files")]
71 TooManyOpenFiles,
72
73 #[error("invalid filesystem")]
75 InvalidFilesystem,
76}
77
78pub type Result<T> = std::result::Result<T, Error>;
80
81impl From<i32> for Error {
83 fn from(errno: i32) -> Self {
84 match errno {
85 0 => panic!("attempted to convert success (0) to error"),
86 libc::ENOENT => Error::NotFound(String::new()),
87 libc::EEXIST => Error::AlreadyExists(String::new()),
88 libc::ENOTDIR => Error::NotADirectory(String::new()),
89 libc::EISDIR => Error::IsADirectory(String::new()),
90 libc::ENOTEMPTY => Error::NotEmpty(String::new()),
91 libc::EACCES | libc::EPERM => Error::PermissionDenied,
92 libc::ENOSPC => Error::NoSpace,
93 libc::EROFS => Error::ReadOnly,
94 libc::EINVAL => Error::InvalidArgument(String::new()),
95 libc::ENXIO | libc::ENODEV => Error::DeviceNotFound,
96 libc::ENAMETOOLONG => Error::NameTooLong,
97 libc::EMFILE | libc::ENFILE => Error::TooManyOpenFiles,
98 _ => Error::Filesystem(errno),
99 }
100 }
101}
102
103pub(crate) fn check_errno(errno: i32) -> Result<()> {
105 if errno == 0 {
106 Ok(())
107 } else {
108 Err(Error::from(errno))
109 }
110}
111
112pub(crate) fn check_errno_with_path(errno: i32, path: &str) -> Result<()> {
114 if errno == 0 {
115 Ok(())
116 } else {
117 let err = match errno {
118 libc::ENOENT => Error::NotFound(path.to_string()),
119 libc::EEXIST => Error::AlreadyExists(path.to_string()),
120 libc::ENOTDIR => Error::NotADirectory(path.to_string()),
121 libc::EISDIR => Error::IsADirectory(path.to_string()),
122 libc::ENOTEMPTY => Error::NotEmpty(path.to_string()),
123 _ => Error::from(errno),
124 };
125 Err(err)
126 }
127}