1use crate::error::{MyError, MyResult};
2use crate::fs::file::Signature;
3use crate::fs::flags::FileFlags;
4use crate::fs::metadata::Metadata;
5#[cfg(windows)]
6use crate::util::version;
7use std::cell::RefCell;
8use std::ffi::OsStr;
9use std::fs::File;
10use std::io::Read;
11use std::path::{Path, PathBuf};
12use std::time::SystemTime;
13#[cfg(unix)]
14use uzers::{gid_t, uid_t};
15use walkdir::DirEntry;
16
17pub type EntryResult<'a> = MyResult<&'a dyn Entry>;
18
19pub trait Entry {
20 fn file_path(&self) -> &Path;
21
22 fn file_name(&self) -> &OsStr;
23
24 fn file_depth(&self) -> usize;
25
26 fn zip_depth(&self) -> Option<usize>;
27
28 fn file_flags(&self) -> FileFlags;
29
30 fn read_sig(&self) -> Option<Signature>;
31
32 #[cfg(windows)]
33 fn read_version(&self) -> Option<String>;
34
35 fn read_link(&self) -> MyResult<Option<PathBuf>>;
36
37 fn copy_metadata(&self, other: &dyn Entry);
38
39 fn reset_metadata(&self);
40
41 fn file_mode(&self) -> u32;
42
43 #[cfg(unix)]
44 fn owner_uid(&self) -> uid_t;
45
46 #[cfg(unix)]
47 fn owner_gid(&self) -> gid_t;
48
49 fn file_size(&self) -> u64;
50
51 fn file_time(&self) -> SystemTime;
52}
53
54#[derive(Clone)]
55pub struct FileEntry {
56 file_path: PathBuf,
57 file_depth: usize,
58 zip_archive: bool,
59 file_flags: FileFlags,
60 file_metadata: RefCell<Option<Metadata>>,
61}
62
63impl FileEntry {
64 pub fn from_entry(dir_entry: DirEntry, zip_archive: bool) -> Box<dyn Entry> {
65 let file_flags = FileFlags::from_type(dir_entry.file_type(), zip_archive);
66 let file_depth = dir_entry.depth();
67 let file_path = dir_entry.into_path();
68 let file_metadata = RefCell::new(None);
69 let entry = Self {
70 file_path,
71 file_depth,
72 zip_archive,
73 file_flags,
74 file_metadata,
75 };
76 Box::new(entry)
77 }
78
79 pub fn from_path(path: &Path) -> MyResult<Box<dyn Entry>> {
80 let file_path = PathBuf::from(path);
81 let file_metadata = Metadata::from_path(path)?;
82 let file_flags = file_metadata.file_flags;
83 let file_metadata = RefCell::new(Some(file_metadata));
84 let entry = Self {
85 file_path,
86 file_depth: 0,
87 zip_archive: false,
88 file_flags,
89 file_metadata,
90 };
91 Ok(Box::new(entry))
92 }
93
94 #[cfg(test)]
95 pub fn from_fields(
96 file_path: PathBuf,
97 file_depth: usize,
98 file_type: char,
99 file_metadata: Metadata,
100 ) -> Self {
101 let file_flags = FileFlags::from_char(file_type);
102 let file_metadata = RefCell::new(Some(file_metadata));
103 Self {
104 file_path,
105 file_depth,
106 zip_archive: false,
107 file_flags,
108 file_metadata,
109 }
110 }
111
112 #[cfg(test)]
113 pub fn subtract_depth(&self, depth: usize) -> Option<Self> {
114 if self.file_depth >= depth {
115 let mut entry = self.clone();
116 entry.file_depth -= depth;
117 return Some(entry);
118 }
119 None
120 }
121
122 fn get_metadata(&self) -> Metadata {
123 Metadata::from_path(&self.file_path).unwrap_or_default()
124 }
125}
126
127impl Entry for FileEntry {
128 fn file_path(&self) -> &Path {
129 &self.file_path
130 }
131
132 fn file_name(&self) -> &OsStr {
133 self.file_path.file_name().unwrap_or_default()
134 }
135
136 fn file_depth(&self) -> usize {
137 self.file_depth
138 }
139
140 fn zip_depth(&self) -> Option<usize> {
141 self.zip_archive.then_some(0)
142 }
143
144 fn file_flags(&self) -> FileFlags {
145 self.file_flags
146 }
147
148 fn read_sig(&self) -> Option<Signature> {
149 let mut data = [0; 4];
150 match File::open(&self.file_path) {
151 Ok(mut file) => file.read(&mut data).map(|_| data).ok(),
152 Err(_) => None,
153 }
154 }
155
156 #[cfg(windows)]
157 fn read_version(&self) -> Option<String> {
158 if version::inner::test_extension(&self.file_path) {
159 version::inner::query_file(&self.file_path)
160 } else {
161 None
162 }
163 }
164
165 fn read_link(&self) -> MyResult<Option<PathBuf>> {
166 match self.file_path.read_link() {
167 Ok(link) => Ok(Some(link)),
168 Err(error) => Err(MyError::from((error, self.file_path.as_path()))),
169 }
170 }
171
172 #[cfg(unix)]
173 fn copy_metadata(&self, other: &dyn Entry) {
174 let mut metadata = self.file_metadata.borrow_mut();
175 let metadata = metadata.get_or_insert_with(|| self.get_metadata());
176 metadata.file_mode = other.file_mode();
177 metadata.owner_uid = other.owner_uid();
178 metadata.owner_gid = other.owner_gid();
179 metadata.file_size = other.file_size();
180 metadata.file_time = other.file_time();
181 }
182
183 #[cfg(not(unix))]
184 fn copy_metadata(&self, other: &dyn Entry) {
185 let mut metadata = self.file_metadata.borrow_mut();
186 let metadata = metadata.get_or_insert_with(|| self.get_metadata());
187 metadata.file_mode = other.file_mode();
188 metadata.file_size = other.file_size();
189 metadata.file_time = other.file_time();
190 }
191
192 fn reset_metadata(&self) {
193 let mut metadata = self.file_metadata.borrow_mut();
194 let metadata = metadata.get_or_insert_with(|| self.get_metadata());
195 metadata.file_size = 0;
196 metadata.file_time = SystemTime::UNIX_EPOCH;
197 }
198
199 fn file_mode(&self) -> u32 {
200 let mut metadata = self.file_metadata.borrow_mut();
201 let metadata = metadata.get_or_insert_with(|| self.get_metadata());
202 metadata.file_mode
203 }
204
205 #[cfg(unix)]
206 fn owner_uid(&self) -> uid_t {
207 let mut metadata = self.file_metadata.borrow_mut();
208 let metadata = metadata.get_or_insert_with(|| self.get_metadata());
209 metadata.owner_uid
210 }
211
212 #[cfg(unix)]
213 fn owner_gid(&self) -> gid_t {
214 let mut metadata = self.file_metadata.borrow_mut();
215 let metadata = metadata.get_or_insert_with(|| self.get_metadata());
216 metadata.owner_gid
217 }
218
219 fn file_size(&self) -> u64 {
220 let mut metadata = self.file_metadata.borrow_mut();
221 let metadata = metadata.get_or_insert_with(|| self.get_metadata());
222 metadata.file_size
223 }
224
225 fn file_time(&self) -> SystemTime {
226 let mut metadata = self.file_metadata.borrow_mut();
227 let metadata = metadata.get_or_insert_with(|| self.get_metadata());
228 metadata.file_time
229 }
230}