Mountain/Environment/FileSystemProvider/
write_operations.rs1use std::path::PathBuf;
11
12use CommonLibrary::{Error::CommonError::CommonError, FileSystem::DTO::FileTypeDTO::FileTypeDTO};
13use tokio::fs;
14
15use super::super::{MountainEnvironment::MountainEnvironment, Utility};
16
17pub(super) async fn write_file_impl(
19 env:&MountainEnvironment,
20 path:&PathBuf,
21 content:Vec<u8>,
22 create:bool,
23 overwrite:bool,
24) -> Result<(), CommonError> {
25 Utility::IsPathAllowedForAccess(&env.ApplicationState, path)?;
26
27 if content.len() > 1024 * 1024 * 1024 {
29 return Err(CommonError::InvalidArgument {
31 ArgumentName:"Content".to_string(),
32 Reason:"Content exceeds maximum size limit of 1GB".to_string(),
33 });
34 }
35
36 let path_exists = fs::try_exists(path).await.unwrap_or(false);
37
38 if path_exists && !overwrite {
39 return Err(CommonError::FileSystemFileExists(path.clone()));
40 }
41
42 if !path_exists && !create {
43 return Err(CommonError::FileSystemNotFound(path.clone()));
44 }
45
46 if let Some(parent_directory) = path.parent() {
48 if !fs::try_exists(parent_directory).await.unwrap_or(false) {
49 fs::create_dir_all(parent_directory).await.map_err(|error| {
50 CommonError::FromStandardIOError(error, parent_directory.to_path_buf(), "WriteFile.CreateParent")
51 })?;
52 }
53 }
54
55 fs::write(path, &content)
56 .await
57 .map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "WriteFile"))?;
58
59 Ok(())
70}
71
72pub(super) async fn create_directory_impl(
74 env:&MountainEnvironment,
75 path:&PathBuf,
76 recursive:bool,
77) -> Result<(), CommonError> {
78 Utility::IsPathAllowedForAccess(&env.ApplicationState, path)?;
79
80 if let Some(parent_path) = path.parent().filter(|p| !p.as_os_str().is_empty()) {
82 if fs::try_exists(parent_path).await.unwrap_or(false) {
83 let parent_metadata = fs::metadata(parent_path).await.map_err(|error| {
84 CommonError::FromStandardIOError(error, parent_path.to_path_buf(), "CreateDirectory.ParentStat")
85 })?;
86
87 if parent_metadata.is_file() {
88 return Err(CommonError::InvalidArgument {
89 ArgumentName:"Path".to_string(),
90 Reason:format!("Cannot create directory: parent path is a file: {}", parent_path.display()),
91 });
92 }
93 }
94 }
95
96 let operation = if recursive {
97 fs::create_dir_all(path).await
98 } else {
99 fs::create_dir(path).await
100 };
101
102 operation.map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "CreateDirectory"))
103}
104
105pub(super) async fn delete_impl(
107 env:&MountainEnvironment,
108 path:&PathBuf,
109 recursive:bool,
110 _use_trash:bool,
111) -> Result<(), CommonError> {
112 Utility::IsPathAllowedForAccess(&env.ApplicationState, path)?;
113
114 match fs::metadata(path).await {
116 Ok(metadata) => {
117 let operation = if metadata.is_dir() {
118 if recursive {
119 fs::remove_dir_all(path).await
120 } else {
121 fs::remove_dir(path).await
122 }
123 } else {
124 fs::remove_file(path).await
125 };
126
127 operation.map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "Delete"))
128 },
129
130 Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
132
133 Err(error) => Err(CommonError::FromStandardIOError(error, path.clone(), "Delete.Stat")),
134 }
135}
136
137pub(super) async fn rename_impl(
139 env:&MountainEnvironment,
140 source:&PathBuf,
141 target:&PathBuf,
142 overwrite:bool,
143) -> Result<(), CommonError> {
144 Utility::IsPathAllowedForAccess(&env.ApplicationState, source)?;
145
146 Utility::IsPathAllowedForAccess(&env.ApplicationState, target)?;
147
148 if !overwrite && fs::try_exists(target).await.unwrap_or(false) {
149 return Err(CommonError::FileSystemFileExists(target.clone()));
150 }
151
152 fs::rename(source, target)
153 .await
154 .map_err(|error| CommonError::FromStandardIOError(error, source.clone(), "Rename"))
155}
156
157pub(super) async fn copy_impl(
159 env:&MountainEnvironment,
160 source:&PathBuf,
161 target:&PathBuf,
162 overwrite:bool,
163) -> Result<(), CommonError> {
164 Utility::IsPathAllowedForAccess(&env.ApplicationState, source)?;
165
166 Utility::IsPathAllowedForAccess(&env.ApplicationState, target)?;
167
168 if !fs::try_exists(source).await.unwrap_or(false) {
170 return Err(CommonError::FileSystemNotFound(source.clone()));
171 }
172
173 let source_metadata = super::read_operations::stat_file_impl(env, source).await?;
175
176 if (source_metadata.FileType & FileTypeDTO::Directory as u8) != 0 {
177 return Err(CommonError::NotImplemented { FeatureName:"Recursive directory copy".to_string() });
178 }
179
180 if fs::canonicalize(source).await.ok().as_ref() == fs::canonicalize(target).await.ok().as_ref() {
182 return Err(CommonError::InvalidArgument {
183 ArgumentName:"Target".to_string(),
184 Reason:"Cannot copy file to itself".to_string(),
185 });
186 }
187
188 if !overwrite && fs::try_exists(target).await.unwrap_or(false) {
189 return Err(CommonError::FileSystemFileExists(target.clone()));
190 }
191
192 if let Some(target_parent) = target.parent() {
194 if !fs::try_exists(target_parent).await.unwrap_or(false) {
195 fs::create_dir_all(target_parent).await.map_err(|error| {
196 CommonError::FromStandardIOError(error, target_parent.to_path_buf(), "Copy.CreateTargetParent")
197 })?;
198 }
199 }
200
201 fs::copy(source, target)
202 .await
203 .map(|_| ())
204 .map_err(|error| CommonError::FromStandardIOError(error, source.clone(), "Copy"))
205}
206
207pub(super) async fn create_file_impl(env:&MountainEnvironment, path:&PathBuf) -> Result<(), CommonError> {
209 write_file_impl(env, path, vec![], true, false).await
212}