fdir/sync/
recover.rs

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}