Mountain/Environment/FileSystemProvider/
WriteOperations.rs1use std::path::PathBuf;
29
30use CommonLibrary::{Error::CommonError::CommonError, FileSystem::DTO::FileTypeDTO::FileTypeDTO};
31use tokio::fs;
32
33use super::super::{MountainEnvironment::MountainEnvironment, Utility};
34
35pub(super) async fn write_file_impl(
37 env:&MountainEnvironment,
38
39 path:&PathBuf,
40
41 content:Vec<u8>,
42
43 create:bool,
44
45 overwrite:bool,
46) -> Result<(), CommonError> {
47 Utility::PathSecurity::IsPathAllowedForAccess(&env.ApplicationState, path)?;
48
49 if content.len() > 1024 * 1024 * 1024 {
51 return Err(CommonError::InvalidArgument {
53 ArgumentName:"Content".to_string(),
54 Reason:"Content exceeds maximum size limit of 1GB".to_string(),
55 });
56 }
57
58 let path_exists = fs::try_exists(path).await.unwrap_or(false);
59
60 if path_exists && !overwrite {
61 return Err(CommonError::FileSystemFileExists(path.clone()));
62 }
63
64 if !path_exists && !create {
65 return Err(CommonError::FileSystemNotFound(path.clone()));
66 }
67
68 if let Some(parent_directory) = path.parent() {
70 if !fs::try_exists(parent_directory).await.unwrap_or(false) {
71 fs::create_dir_all(parent_directory).await.map_err(|error| {
72 CommonError::FromStandardIOError(error, parent_directory.to_path_buf(), "WriteFile.CreateParent")
73 })?;
74 }
75 }
76
77 fs::write(path, &content)
78 .await
79 .map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "WriteFile"))?;
80
81 Ok(())
92}
93
94pub(super) async fn create_directory_impl(
96 env:&MountainEnvironment,
97
98 path:&PathBuf,
99
100 recursive:bool,
101) -> Result<(), CommonError> {
102 Utility::PathSecurity::IsPathAllowedForAccess(&env.ApplicationState, path)?;
103
104 if let Some(parent_path) = path.parent().filter(|p| !p.as_os_str().is_empty()) {
106 if fs::try_exists(parent_path).await.unwrap_or(false) {
107 let parent_metadata = fs::metadata(parent_path).await.map_err(|error| {
108 CommonError::FromStandardIOError(error, parent_path.to_path_buf(), "CreateDirectory.ParentStat")
109 })?;
110
111 if parent_metadata.is_file() {
112 return Err(CommonError::InvalidArgument {
113 ArgumentName:"Path".to_string(),
114 Reason:format!("Cannot create directory: parent path is a file: {}", parent_path.display()),
115 });
116 }
117 }
118 }
119
120 let operation = if recursive {
121 fs::create_dir_all(path).await
122 } else {
123 fs::create_dir(path).await
124 };
125
126 operation.map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "CreateDirectory"))
127}
128
129pub(super) async fn delete_impl(
131 env:&MountainEnvironment,
132
133 path:&PathBuf,
134
135 recursive:bool,
136
137 _use_trash:bool,
138) -> Result<(), CommonError> {
139 Utility::PathSecurity::IsPathAllowedForAccess(&env.ApplicationState, path)?;
140
141 match fs::metadata(path).await {
143 Ok(metadata) => {
144 let operation = if metadata.is_dir() {
145 if recursive {
146 fs::remove_dir_all(path).await
147 } else {
148 fs::remove_dir(path).await
149 }
150 } else {
151 fs::remove_file(path).await
152 };
153
154 operation.map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "Delete"))
155 },
156
157 Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
159
160 Err(error) => Err(CommonError::FromStandardIOError(error, path.clone(), "Delete.Stat")),
161 }
162}
163
164pub(super) async fn rename_impl(
166 env:&MountainEnvironment,
167
168 source:&PathBuf,
169
170 target:&PathBuf,
171
172 overwrite:bool,
173) -> Result<(), CommonError> {
174 Utility::PathSecurity::IsPathAllowedForAccess(&env.ApplicationState, source)?;
175
176 Utility::PathSecurity::IsPathAllowedForAccess(&env.ApplicationState, target)?;
177
178 if !overwrite && fs::try_exists(target).await.unwrap_or(false) {
179 return Err(CommonError::FileSystemFileExists(target.clone()));
180 }
181
182 fs::rename(source, target)
183 .await
184 .map_err(|error| CommonError::FromStandardIOError(error, source.clone(), "Rename"))
185}
186
187pub(super) async fn copy_impl(
189 env:&MountainEnvironment,
190
191 source:&PathBuf,
192
193 target:&PathBuf,
194
195 overwrite:bool,
196) -> Result<(), CommonError> {
197 Utility::PathSecurity::IsPathAllowedForAccess(&env.ApplicationState, source)?;
198
199 Utility::PathSecurity::IsPathAllowedForAccess(&env.ApplicationState, target)?;
200
201 if !fs::try_exists(source).await.unwrap_or(false) {
203 return Err(CommonError::FileSystemNotFound(source.clone()));
204 }
205
206 let source_metadata = super::ReadOperations::stat_file_impl(env, source).await?;
208
209 let SourceIsDir = (source_metadata.FileType & FileTypeDTO::Directory as u8) != 0;
210
211 if fs::canonicalize(source).await.ok().as_ref() == fs::canonicalize(target).await.ok().as_ref() {
214 return Err(CommonError::InvalidArgument {
215 ArgumentName:"Target".to_string(),
216 Reason:"Cannot copy file to itself".to_string(),
217 });
218 }
219
220 if !overwrite && fs::try_exists(target).await.unwrap_or(false) {
221 return Err(CommonError::FileSystemFileExists(target.clone()));
222 }
223
224 if let Some(target_parent) = target.parent() {
228 if !fs::try_exists(target_parent).await.unwrap_or(false) {
229 fs::create_dir_all(target_parent).await.map_err(|error| {
230 CommonError::FromStandardIOError(error, target_parent.to_path_buf(), "Copy.CreateTargetParent")
231 })?;
232 }
233 }
234
235 if SourceIsDir {
236 return copy_directory_recursive(source, target, overwrite).await;
244 }
245
246 fs::copy(source, target)
247 .await
248 .map(|_| ())
249 .map_err(|error| CommonError::FromStandardIOError(error, source.clone(), "Copy"))
250}
251
252async fn copy_directory_recursive(source:&PathBuf, target:&PathBuf, overwrite:bool) -> Result<(), CommonError> {
258 if !fs::try_exists(target).await.unwrap_or(false) {
260 fs::create_dir(target)
261 .await
262 .map_err(|error| CommonError::FromStandardIOError(error, target.clone(), "Copy.CreateTargetRoot"))?;
263 }
264
265 let mut Stack:Vec<(PathBuf, PathBuf)> = vec![(source.clone(), target.clone())];
266
267 while let Some((SrcDir, DstDir)) = Stack.pop() {
268 let mut Entries = fs::read_dir(&SrcDir)
269 .await
270 .map_err(|error| CommonError::FromStandardIOError(error, SrcDir.clone(), "Copy.ReadDir"))?;
271
272 while let Some(Entry) = Entries
273 .next_entry()
274 .await
275 .map_err(|error| CommonError::FromStandardIOError(error, SrcDir.clone(), "Copy.NextEntry"))?
276 {
277 let Name = Entry.file_name();
278
279 let SrcPath = SrcDir.join(&Name);
280
281 let DstPath = DstDir.join(&Name);
282
283 let FileType = Entry
284 .file_type()
285 .await
286 .map_err(|error| CommonError::FromStandardIOError(error, SrcPath.clone(), "Copy.FileType"))?;
287
288 if FileType.is_dir() {
289 if !fs::try_exists(&DstPath).await.unwrap_or(false) {
290 fs::create_dir(&DstPath).await.map_err(|error| {
291 CommonError::FromStandardIOError(error, DstPath.clone(), "Copy.CreateSubDir")
292 })?;
293 }
294
295 Stack.push((SrcPath, DstPath));
296 } else {
297 if !overwrite && fs::try_exists(&DstPath).await.unwrap_or(false) {
298 return Err(CommonError::FileSystemFileExists(DstPath));
299 }
300
301 fs::copy(&SrcPath, &DstPath)
302 .await
303 .map_err(|error| CommonError::FromStandardIOError(error, SrcPath.clone(), "Copy.CopyFile"))?;
304 }
305 }
306 }
307
308 Ok(())
309}
310
311pub(super) async fn create_file_impl(env:&MountainEnvironment, path:&PathBuf) -> Result<(), CommonError> {
313 write_file_impl(env, path, vec![], true, false).await
316}