1use std::{
7 fs::{remove_dir, remove_file, rename},
8 path::Path,
9};
10
11fn already_exists<A>(dst: &A) -> std::io::Result<()>
12where
13 A: AsRef<Path>,
14{
15 if !dst.as_ref().exists() {
16 Ok(())
17 } else {
18 Err(std::io::Error::new(
19 std::io::ErrorKind::AlreadyExists,
20 format!("file already exists: {}", dst.as_ref().display()),
21 ))
22 }
23}
24
25pub(crate) fn move_to_trash<A>(src: A) -> std::io::Result<()>
26where
27 A: AsRef<Path>,
28{
29 let src_type = src.as_ref().metadata()?.file_type();
30
31 if src_type.is_file() {
32 if let Err(err) = trash::delete(src.as_ref()) {
33 return Err(std::io::Error::new(
34 std::io::ErrorKind::Other,
35 format!("can not trash file: {}, {err}", src.as_ref().display()),
36 ));
37 };
38 } else if src_type.is_dir() {
39 if let Err(err) = trash::delete_all(src.as_ref()) {
40 return Err(std::io::Error::new(
41 std::io::ErrorKind::Other,
42 format!("can not trash directory: {}, {err}", src.as_ref().display()),
43 ));
44 };
45 } else if src_type.is_symlink() {
46 if let Err(err) = trash::delete(src.as_ref()) {
47 return Err(std::io::Error::new(
48 std::io::ErrorKind::Other,
49 format!("can not trash symlink: {}, {err}", src.as_ref().display()),
50 ));
51 };
52 } else {
53 return Err(std::io::Error::new(
54 std::io::ErrorKind::Other,
55 format!("can not trash: {}", src.as_ref().display()),
56 ));
57 }
58 Ok(())
59}
60
61pub(crate) fn remove_irrecoverably<A>(src: A) -> std::io::Result<()>
62where
63 A: AsRef<Path>,
64{
65 let src_type = src.as_ref().metadata()?.file_type();
66
67 if src_type.is_file() {
68 remove_file(src)?;
69 } else if src_type.is_dir() {
70 remove_dir(src)?;
73 } else if src_type.is_symlink() {
74 if let Err(err) = trash::delete(src.as_ref()) {
75 return Err(std::io::Error::new(
76 std::io::ErrorKind::Other,
77 format!("can not remove symlink: {}, {err}", src.as_ref().display()),
78 ));
79 };
80 } else {
81 return Err(std::io::Error::new(
82 std::io::ErrorKind::Other,
83 format!("can not remove: {}", src.as_ref().display()),
84 ));
85 }
86 Ok(())
87}
88
89pub(crate) fn move_to<A, D>(src: A, dst: D) -> std::io::Result<()>
91where
92 A: AsRef<Path>,
93 D: AsRef<Path>,
94{
95 rename_to(src, dst)
96}
97
98pub(crate) fn rename_to<A, D>(src: A, dst: D) -> std::io::Result<()>
99where
100 A: AsRef<Path>,
101 D: AsRef<Path>,
102{
103 already_exists(&dst)?;
105
106 let src_type = src.as_ref().metadata()?.file_type();
107
108 if src_type.is_file() {
109 rename(src, dst)?;
110 } else {
111 return Err(std::io::Error::new(
112 std::io::ErrorKind::Other,
113 format!("can not move/rename: {}", src.as_ref().display()),
114 ));
115 }
116 Ok(())
117}
118
119pub(crate) fn symlink_to<A, D>(src: A, dst: D) -> std::io::Result<()>
120where
121 A: AsRef<Path>,
122 D: AsRef<Path>,
123{
124 already_exists(&dst)?;
126
127 let src_type = src.as_ref().metadata()?.file_type();
128
129 if src_type.is_file() {
130 symlink_file(src, dst)?;
131 } else if src_type.is_dir() {
132 symlink_dir(src, dst)?;
133 } else {
134 return Err(std::io::Error::new(
135 std::io::ErrorKind::Other,
136 format!("can not symlink: {}", src.as_ref().display()),
137 ));
138 }
139 Ok(())
140}
141
142pub(crate) fn copy_to<A, D>(src: A, dst: D) -> std::io::Result<()>
143where
144 A: AsRef<Path>,
145 D: AsRef<Path>,
146{
147 already_exists(&dst)?;
149
150 let src_type = src.as_ref().metadata()?.file_type();
151
152 if src_type.is_file() {
153 std::fs::copy(src, dst)?;
154 } else if src_type.is_dir() {
155 copy_dir_to(src, dst)?;
156 } else {
157 return Err(std::io::Error::new(
158 std::io::ErrorKind::Other,
159 format!("can not deal with file_type: {}", src.as_ref().display()),
160 ));
161 }
162 Ok(())
163}
164
165pub(crate) fn copy_dir_to<A, D>(src: A, dst: D) -> std::io::Result<()>
167where
168 A: AsRef<Path>,
169 D: AsRef<Path>,
170{
171 already_exists(&dst)?;
173
174 if !dst.as_ref().is_dir() {
175 std::fs::create_dir(dst.as_ref())?;
176 }
177
178 for entry_result in src.as_ref().read_dir()? {
179 let entry = entry_result?;
180 copy_to(&entry.path(), &dst.as_ref().join(entry.file_name()))?;
181 }
182
183 Ok(())
184}
185
186pub fn symlink_dir<A, D>(src: A, dst: D) -> std::io::Result<()>
190where
191 A: AsRef<Path>,
192 D: AsRef<Path>,
193{
194 already_exists(&dst)?;
196
197 #[cfg(windows)]
198 fn imp(src: &Path, dst: &Path) -> std::io::Result<()> {
199 use std::os::windows::fs::symlink_dir;
200 symlink_dir(src, dst)
201 }
202
203 #[cfg(unix)]
204 fn imp(src: &Path, dst: &Path) -> std::io::Result<()> {
205 use std::os::unix::fs::symlink;
206 symlink(src, dst)
207 }
208
209 imp(src.as_ref(), dst.as_ref()).map_err(|e| {
210 std::io::Error::new(
211 std::io::ErrorKind::Other,
212 format!(
213 "failed to symlink directory {} with target {}: {}",
214 src.as_ref().display(),
215 dst.as_ref().display(),
216 e
217 ),
218 )
219 })
220}
221
222pub fn symlink_file<A, D>(src: A, dst: D) -> std::io::Result<()>
226where
227 A: AsRef<Path>,
228 D: AsRef<Path>,
229{
230 already_exists(&dst)?;
232
233 #[cfg(windows)]
234 fn imp(src: &Path, dst: &Path) -> std::io::Result<()> {
235 use std::os::windows::fs::symlink_file;
236 symlink_file(src, dst)
237 }
238
239 #[cfg(unix)]
240 fn imp(src: &Path, dst: &Path) -> std::io::Result<()> {
241 use std::os::unix::fs::symlink;
242 symlink(src, dst)
243 }
244
245 imp(src.as_ref(), dst.as_ref()).map_err(|e| {
246 std::io::Error::new(
247 std::io::ErrorKind::Other,
248 format!(
249 "failed to symlink file {} with target {}: {}",
250 src.as_ref().display(),
251 dst.as_ref().display(),
252 e
253 ),
254 )
255 })
256}