1#![allow(non_snake_case, non_camel_case_types)]
8
9use std::path::PathBuf;
10
11use Common::{
12 Error::CommonError::CommonError,
13 FileSystem::{
14 DTO::{FileSystemStatDTO::FileSystemStatDTO, FileTypeDTO::FileTypeDTO},
15 FileSystemReader::FileSystemReader,
16 FileSystemWriter::FileSystemWriter,
17 },
18};
19use async_trait::async_trait;
20use tokio::fs;
21
22use super::{MountainEnvironment::MountainEnvironment, Utility};
23
24#[async_trait]
25impl FileSystemReader for MountainEnvironment {
26 async fn ReadFile(&self, Path:&PathBuf) -> Result<Vec<u8>, CommonError> {
29 Utility::IsPathAllowedForAccess(&self.ApplicationState, Path)?;
30
31 fs::read(Path)
32 .await
33 .map_err(|Error| CommonError::FromStandardIOError(Error, Path.clone(), "ReadFile"))
34 }
35
36 async fn StatFile(&self, Path:&PathBuf) -> Result<FileSystemStatDTO, CommonError> {
39 Utility::IsPathAllowedForAccess(&self.ApplicationState, Path)?;
40
41 let Metadata = fs::metadata(Path)
42 .await
43 .map_err(|Error| CommonError::FromStandardIOError(Error, Path.clone(), "StatFile"))?;
44
45 let mut FileType = 0_u8;
46
47 if Metadata.is_file() {
48 FileType |= FileTypeDTO::File as u8;
49 }
50
51 if Metadata.is_dir() {
52 FileType |= FileTypeDTO::Directory as u8;
53 }
54
55 if Metadata.file_type().is_symlink() {
56 FileType |= FileTypeDTO::SymbolicLink as u8;
57 }
58
59 let GetMilliTimestamp = |SystemTimeResult:Result<std::time::SystemTime, _>| -> u64 {
60 SystemTimeResult
61 .ok()
62 .and_then(|time| time.duration_since(std::time::SystemTime::UNIX_EPOCH).ok())
63 .map_or(0, |duration| duration.as_millis() as u64)
64 };
65
66 Ok(FileSystemStatDTO {
67 FileType,
68
69 CreationTime:GetMilliTimestamp(Metadata.created()),
70
71 ModificationTime:GetMilliTimestamp(Metadata.modified()),
72
73 Size:Metadata.len(),
74
75 Permissions:None,
77 })
78 }
79
80 async fn ReadDirectory(&self, Path:&PathBuf) -> Result<Vec<(String, FileTypeDTO)>, CommonError> {
82 Utility::IsPathAllowedForAccess(&self.ApplicationState, Path)?;
83
84 let mut Entries = Vec::new();
85
86 let mut ReadDirectory = fs::read_dir(Path)
87 .await
88 .map_err(|Error| CommonError::FromStandardIOError(Error, Path.clone(), "ReadDirectory"))?;
89
90 while let Some(EntryResult) = ReadDirectory
91 .next_entry()
92 .await
93 .map_err(|Error| CommonError::FromStandardIOError(Error, Path.clone(), "ReadDirectory.NextEntry"))?
94 {
95 let FileName = EntryResult.file_name().to_string_lossy().into_owned();
96
97 let FileType = match EntryResult.file_type().await {
98 Ok(ft) => {
99 if ft.is_dir() {
100 FileTypeDTO::Directory
101 } else if ft.is_file() {
102 FileTypeDTO::File
103 } else {
104 FileTypeDTO::Unknown
105 }
106 },
107
108 Err(_) => FileTypeDTO::Unknown,
109 };
110
111 Entries.push((FileName, FileType));
112 }
113
114 Ok(Entries)
115 }
116}
117
118#[async_trait]
119impl FileSystemWriter for MountainEnvironment {
120 async fn WriteFile(&self, Path:&PathBuf, Content:Vec<u8>, Create:bool, Overwrite:bool) -> Result<(), CommonError> {
122 Utility::IsPathAllowedForAccess(&self.ApplicationState, Path)?;
123
124 let PathExists = fs::try_exists(Path).await.unwrap_or(false);
125
126 if PathExists && !Overwrite {
127 return Err(CommonError::FileSystemFileExists(Path.clone()));
128 }
129
130 if !PathExists && !Create {
131 return Err(CommonError::FileSystemNotFound(Path.clone()));
132 }
133
134 if let Some(ParentDirectory) = Path.parent() {
135 if !fs::try_exists(ParentDirectory).await.unwrap_or(false) {
136 fs::create_dir_all(ParentDirectory).await.map_err(|Error| {
137 CommonError::FromStandardIOError(Error, ParentDirectory.to_path_buf(), "WriteFile.CreateParent")
138 })?;
139 }
140 }
141
142 fs::write(Path, &Content)
143 .await
144 .map_err(|Error| CommonError::FromStandardIOError(Error, Path.clone(), "WriteFile"))
145 }
146
147 async fn CreateDirectory(&self, Path:&PathBuf, Recursive:bool) -> Result<(), CommonError> {
149 Utility::IsPathAllowedForAccess(&self.ApplicationState, Path)?;
150
151 let Operation = if Recursive {
152 fs::create_dir_all(Path).await
153 } else {
154 fs::create_dir(Path).await
155 };
156
157 Operation.map_err(|Error| CommonError::FromStandardIOError(Error, Path.clone(), "CreateDirectory"))
158 }
159
160 async fn Delete(&self, Path:&PathBuf, Recursive:bool, _UseTrash:bool) -> Result<(), CommonError> {
162 Utility::IsPathAllowedForAccess(&self.ApplicationState, Path)?;
163
164 match fs::metadata(Path).await {
166 Ok(Metadata) => {
167 let Operation = if Metadata.is_dir() {
168 if Recursive {
169 fs::remove_dir_all(Path).await
170 } else {
171 fs::remove_dir(Path).await
172 }
173 } else {
174 fs::remove_file(Path).await
175 };
176
177 Operation.map_err(|Error| CommonError::FromStandardIOError(Error, Path.clone(), "Delete"))
178 },
179
180 Err(Error) if Error.kind() == std::io::ErrorKind::NotFound => Ok(()),
182
183 Err(Error) => Err(CommonError::FromStandardIOError(Error, Path.clone(), "Delete.Stat")),
184 }
185 }
186
187 async fn Rename(&self, Source:&PathBuf, Target:&PathBuf, Overwrite:bool) -> Result<(), CommonError> {
189 Utility::IsPathAllowedForAccess(&self.ApplicationState, Source)?;
190
191 Utility::IsPathAllowedForAccess(&self.ApplicationState, Target)?;
192
193 if !Overwrite && fs::try_exists(Target).await.unwrap_or(false) {
194 return Err(CommonError::FileSystemFileExists(Target.clone()));
195 }
196
197 fs::rename(Source, Target)
198 .await
199 .map_err(|Error| CommonError::FromStandardIOError(Error, Source.clone(), "Rename"))
200 }
201
202 async fn Copy(&self, Source:&PathBuf, Target:&PathBuf, Overwrite:bool) -> Result<(), CommonError> {
204 Utility::IsPathAllowedForAccess(&self.ApplicationState, Source)?;
205
206 Utility::IsPathAllowedForAccess(&self.ApplicationState, Target)?;
207
208 let SourceMetadata = self.StatFile(Source).await?;
209
210 if (SourceMetadata.FileType & FileTypeDTO::Directory as u8) != 0 {
211 return Err(CommonError::NotImplemented { FeatureName:"Recursive directory copy".to_string() });
212 }
213
214 if !Overwrite && fs::try_exists(Target).await.unwrap_or(false) {
215 return Err(CommonError::FileSystemFileExists(Target.clone()));
216 }
217
218 fs::copy(Source, Target)
219 .await
220 .map(|_| ())
221 .map_err(|Error| CommonError::FromStandardIOError(Error, Source.clone(), "Copy"))
222 }
223
224 async fn CreateFile(&self, Path:&PathBuf) -> Result<(), CommonError> {
226 self.WriteFile(Path, vec![], true, false).await
228 }
229}