1use super::dir::_write_dir;
2use super::{dir::DirectoryInfo, file::FileInfo};
3use super::{remove_file_any, Action, Info};
4use std::fs::{copy, rename};
5use std::io::Result;
6use std::io::{Error, ErrorKind};
7use std::path::PathBuf;
8
9pub type TryRecoverResult<'a, T> = std::result::Result<T, TryRecover<'a>>;
10
11pub enum Status<'a> {
12 CopyFile(&'a FileInfo, PathBuf),
13 CopyDirectory(&'a DirectoryInfo, PathBuf),
14 MoveFile(&'a mut FileInfo, PathBuf),
15 MoveDirectory(&'a mut DirectoryInfo, PathBuf),
16}
17
18impl<'a> From<TryRecover<'a>> for Error {
19 fn from(value: TryRecover<'a>) -> Self {
20 value.error
21 }
22}
23
24impl<'a> From<Error> for TryRecover<'a> {
25 fn from(value: Error) -> Self {
26 TryRecover {
27 error: value,
28 status: None,
29 }
30 }
31}
32
33pub struct TryRecover<'a> {
34 pub error: Error,
35 pub status: Option<Status<'a>>,
36}
37use Status::*;
38impl<'a> TryRecover<'a> {
39 pub fn new(error: Error, status: Status<'a>) -> TryRecover<'a> {
40 Self {
41 error,
42 status: Some(status),
43 }
44 }
45 pub fn try_recover(self) -> Result<()> {
46 if self.error.kind() == ErrorKind::AlreadyExists {
47 let status = match self.status {
48 Some(status) => status,
49 _ => return Err(self.error),
50 };
51 match status {
52 CopyFile(f, to) => {
53 remove_file_any(&to)?;
54 copy(f.as_path(), to)?;
55 Ok(())
56 }
57 MoveFile(f, to) => {
58 remove_file_any(&to)?;
59 if rename(f.as_path(), &to).is_err() {
60 copy(f.as_path(), &to)?;
61 remove_file_any(f.as_path())?;
62 *f = unsafe { FileInfo::open_uncheck(to) };
63 }
64 Ok(())
65 }
66 CopyDirectory(dir, to) => {
67 _write_dir(dir.clone(), &to, true)
68 }
69 MoveDirectory(dir, to) => {
70 _write_dir(dir.clone(), &to, true)?;
71 *dir = unsafe {
72 DirectoryInfo::open_uncheck(to)
73 };
74 Ok(())
75 }
76 }
77 } else {
78 Err(self.error)
79 }
80 }
81}