1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use std::fs::File;
use std::io::{self, BufRead, BufReader, Write};
use std::path::{Path, PathBuf};
use chrono::{DateTime, Local, TimeZone};
use regex::Regex;
use crate::errors::{Error, TrashInfoError};
lazy_static! {
static ref KEY_VALUE_PATTERN: Regex = Regex::new(r"([A-Za-z]+)\s*=\s*(.*)").unwrap();
}
const DATE_FORMAT: &str = "%Y-%m-%dT%H:%M:%S";
#[derive(Debug)]
pub struct TrashInfo {
pub path: PathBuf,
pub deletion_date: DateTime<Local>,
pub deleted_path: PathBuf,
pub info_path: PathBuf,
}
impl TrashInfo {
pub fn from_files(
info_path: impl AsRef<Path>,
deleted_path: impl AsRef<Path>,
) -> Result<Self, Error> {
let path = info_path.as_ref();
let info_path = path.to_path_buf();
let deleted_path = deleted_path.as_ref().to_path_buf();
let file = File::open(path)?;
let reader = BufReader::new(file);
let mut path = None;
let mut deletion_date = None;
for (i, line) in reader.lines().enumerate() {
let line = line?;
if i == 0 && line != "[Trash Info]" {
return Err(Error::BadTrashInfo(TrashInfoError::MissingHeader));
}
let captures = match KEY_VALUE_PATTERN.captures(&line) {
Some(captures) => captures,
None => continue,
};
let key = captures.get(1).unwrap().as_str();
let value = captures.get(2).unwrap().as_str();
match key {
"Path" => {
let value = PathBuf::from(value);
path = Some(value)
}
"DeletionDate" => {
let date = Local.datetime_from_str(value, DATE_FORMAT)?;
deletion_date = Some(date)
}
_ => continue,
}
}
let path = match path {
Some(path) => path,
None => return Err(Error::BadTrashInfo(TrashInfoError::MissingPath)),
};
let deletion_date = match deletion_date {
Some(deletion_date) => deletion_date,
None => return Err(Error::BadTrashInfo(TrashInfoError::MissingDate)),
};
Ok(TrashInfo {
path,
deletion_date,
deleted_path,
info_path,
})
}
pub fn write(&self, mut out: impl Write) -> Result<(), io::Error> {
writeln!(out, "[Trash Info]")?;
writeln!(out, "Path={}", self.path.to_str().unwrap())?;
writeln!(
out,
"DeletionDate={}",
self.deletion_date.format(DATE_FORMAT)
)?;
Ok(())
}
}