Mountain/Environment/FileSystemProvider/
read_operations.rs1use std::path::PathBuf;
11
12use CommonLibrary::{
13 Error::CommonError::CommonError,
14 FileSystem::DTO::{FileSystemStatDTO::FileSystemStatDTO, FileTypeDTO::FileTypeDTO},
15};
16use tokio::fs;
17
18use super::super::{MountainEnvironment::MountainEnvironment, Utility};
19
20pub(super) async fn read_file_impl(env:&MountainEnvironment, path:&PathBuf) -> Result<Vec<u8>, CommonError> {
22 Utility::IsPathAllowedForAccess(&env.ApplicationState, path)?;
23
24 let metadata = fs::metadata(path)
26 .await
27 .map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "ReadFile.Stat"))?;
28
29 if metadata.is_dir() {
30 return Err(CommonError::InvalidArgument {
31 ArgumentName:"Path".to_string(),
32 Reason:format!("Cannot read directory as file: {}", path.display()),
33 });
34 }
35
36 fs::read(path)
37 .await
38 .map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "ReadFile"))
39}
40
41pub(super) async fn stat_file_impl(env:&MountainEnvironment, path:&PathBuf) -> Result<FileSystemStatDTO, CommonError> {
43 Utility::IsPathAllowedForAccess(&env.ApplicationState, path)?;
44
45 let metadata = fs::metadata(path)
46 .await
47 .map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "StatFile"))?;
48
49 let mut file_type = 0_u8;
50
51 if metadata.is_file() {
52 file_type |= FileTypeDTO::File as u8;
53 }
54
55 if metadata.is_dir() {
56 file_type |= FileTypeDTO::Directory as u8;
57 }
58
59 let file_type_raw = fs::symlink_metadata(path)
61 .await
62 .map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "StatFile.FileType"))?;
63
64 if file_type_raw.is_symlink() {
65 file_type |= FileTypeDTO::SymbolicLink as u8;
66 }
67
68 let get_milli_timestamp = |system_time_result:Result<std::time::SystemTime, _>| -> u64 {
70 system_time_result
71 .ok()
72 .and_then(|time| time.duration_since(std::time::SystemTime::UNIX_EPOCH).ok())
73 .map_or(0, |duration| duration.as_millis() as u64)
74 };
75
76 Ok(FileSystemStatDTO {
77 FileType:file_type,
78
79 CreationTime:get_milli_timestamp(metadata.created()),
80
81 ModificationTime:get_milli_timestamp(metadata.modified()),
82
83 Size:metadata.len(),
84
85 Permissions:None,
92 })
93}
94
95pub(super) async fn read_directory_impl(
97 env:&MountainEnvironment,
98 path:&PathBuf,
99) -> Result<Vec<(String, FileTypeDTO)>, CommonError> {
100 Utility::IsPathAllowedForAccess(&env.ApplicationState, path)?;
101
102 let metadata = fs::metadata(path)
104 .await
105 .map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "ReadDirectory.Stat"))?;
106
107 if !metadata.is_dir() {
108 return Err(CommonError::InvalidArgument {
109 ArgumentName:"Path".to_string(),
110 Reason:format!("Cannot read directory: path is not a directory: {}", path.display()),
111 });
112 }
113
114 let mut entries = Vec::new();
115
116 let mut read_dir = fs::read_dir(path)
117 .await
118 .map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "ReadDirectory"))?;
119
120 while let Some(entry_result) = read_dir
121 .next_entry()
122 .await
123 .map_err(|error| CommonError::FromStandardIOError(error, path.clone(), "ReadDirectory.NextEntry"))?
124 {
125 let file_name = entry_result.file_name().to_string_lossy().into_owned();
126
127 let file_type = match entry_result.file_type().await {
129 Ok(ft) => {
130 if ft.is_symlink() {
131 FileTypeDTO::SymbolicLink
132 } else if ft.is_dir() {
133 FileTypeDTO::Directory
134 } else if ft.is_file() {
135 FileTypeDTO::File
136 } else {
137 FileTypeDTO::Unknown
138 }
139 },
140
141 Err(_) => FileTypeDTO::Unknown,
142 };
143
144 entries.push((file_name, file_type));
145 }
146
147 Ok(entries)
148}