cat_dev/fsemul/pcfs/sata/proto/
read_folder.rs1use crate::{
7 errors::NetworkParseError,
8 fsemul::pcfs::{errors::PcfsApiError, sata::proto::get_info_by_query::SataFDInfo},
9};
10use bytes::{Buf, BufMut, Bytes, BytesMut};
11use std::ffi::CStr;
12use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
13
14pub const NO_MORE_ITEMS: u32 = 0xFFF0_FFFC;
16
17#[derive(Clone, Debug, PartialEq, Eq)]
19pub struct SataReadFolderPacketBody {
20 file_descriptor: i32,
21}
22
23impl SataReadFolderPacketBody {
24 #[must_use]
26 pub const fn new(file_descriptor: i32) -> Self {
27 Self { file_descriptor }
28 }
29
30 #[must_use]
31 pub const fn file_descriptor(&self) -> i32 {
32 self.file_descriptor
33 }
34
35 pub const fn set_file_descriptor(&mut self) -> i32 {
36 self.file_descriptor
37 }
38}
39
40impl From<&SataReadFolderPacketBody> for Bytes {
41 fn from(value: &SataReadFolderPacketBody) -> Self {
42 let mut buff = BytesMut::with_capacity(4);
43 buff.put_i32(value.file_descriptor);
44 buff.freeze()
45 }
46}
47
48impl From<SataReadFolderPacketBody> for Bytes {
49 fn from(value: SataReadFolderPacketBody) -> Self {
50 Self::from(&value)
51 }
52}
53
54impl TryFrom<Bytes> for SataReadFolderPacketBody {
55 type Error = NetworkParseError;
56
57 fn try_from(mut value: Bytes) -> Result<Self, Self::Error> {
58 if value.len() < 0x4 {
59 return Err(NetworkParseError::FieldNotLongEnough(
60 "SataReadDir",
61 "Body",
62 0x4,
63 value.len(),
64 value,
65 ));
66 }
67 if value.len() > 0x4 {
68 return Err(NetworkParseError::UnexpectedTrailer(
69 "SataReadDir",
70 value.slice(0x4..),
71 ));
72 }
73
74 let fd = value.get_i32();
75
76 Ok(Self {
77 file_descriptor: fd,
78 })
79 }
80}
81
82const SATA_READ_FOLDER_PACKET_BODY_FIELDS: &[NamedField<'static>] = &[NamedField::new("fd")];
83
84impl Structable for SataReadFolderPacketBody {
85 fn definition(&self) -> StructDef<'_> {
86 StructDef::new_static(
87 "SataReadDirPacketBody",
88 Fields::Named(SATA_READ_FOLDER_PACKET_BODY_FIELDS),
89 )
90 }
91}
92
93impl Valuable for SataReadFolderPacketBody {
94 fn as_value(&self) -> Value<'_> {
95 Value::Structable(self)
96 }
97
98 fn visit(&self, visitor: &mut dyn Visit) {
99 visitor.visit_named_fields(&NamedValues::new(
100 SATA_READ_FOLDER_PACKET_BODY_FIELDS,
101 &[Valuable::as_value(&self.file_descriptor)],
102 ));
103 }
104}
105
106#[derive(Clone, Debug, PartialEq, Eq, Valuable)]
107pub struct DirectoryItemResponse {
108 return_code: u32,
110 next_file_info: Option<(SataFDInfo, String)>,
113}
114
115impl DirectoryItemResponse {
116 pub fn new_next(info: SataFDInfo, path: String) -> Result<Self, PcfsApiError> {
125 if path.len() > 255 {
126 return Err(PcfsApiError::PathTooLong(path));
127 }
128
129 Ok(Self {
130 return_code: 0,
131 next_file_info: Some((info, path)),
132 })
133 }
134
135 #[must_use]
137 pub const fn new_nothing_left() -> Self {
138 Self {
139 return_code: NO_MORE_ITEMS,
140 next_file_info: None,
141 }
142 }
143
144 #[must_use]
146 pub const fn new_error_code(rc: u32) -> Self {
147 Self {
148 return_code: rc,
149 next_file_info: None,
150 }
151 }
152
153 #[must_use]
155 pub const fn return_code(&self) -> u32 {
156 self.return_code
157 }
158
159 #[must_use]
165 pub fn is_successful(&self) -> bool {
166 [NO_MORE_ITEMS, 0].contains(&self.return_code)
167 }
168
169 #[must_use]
171 pub const fn file_info(&self) -> Option<&(SataFDInfo, String)> {
172 self.next_file_info.as_ref()
173 }
174
175 #[must_use]
178 pub fn take_file_info(self) -> Option<(SataFDInfo, String)> {
179 self.next_file_info
180 }
181}
182
183impl From<&DirectoryItemResponse> for Bytes {
184 fn from(value: &DirectoryItemResponse) -> Self {
185 if let Some(nfi) = value.file_info() {
186 let mut buff = BytesMut::with_capacity(0x158);
187 buff.put_u32(value.return_code());
188 buff.extend(Bytes::from(&nfi.0));
189 let path_bytes = nfi.1.as_bytes();
190 buff.extend(Bytes::from(Vec::from(path_bytes)));
191 buff.extend(BytesMut::zeroed(256 - path_bytes.len()));
192 buff.freeze()
193 } else {
194 let mut bytes = BytesMut::with_capacity(0x158);
195 bytes.put_u32(value.return_code());
196 bytes.extend([0; 0x154]);
197 bytes.freeze()
198 }
199 }
200}
201
202impl From<DirectoryItemResponse> for Bytes {
203 fn from(value: DirectoryItemResponse) -> Self {
204 Self::from(&value)
205 }
206}
207
208impl TryFrom<Bytes> for DirectoryItemResponse {
209 type Error = NetworkParseError;
210
211 fn try_from(mut value: Bytes) -> Result<Self, Self::Error> {
212 if value.len() < 4 {
213 return Err(NetworkParseError::NotEnoughData(
214 "DirectoryItemResponse",
215 4,
216 value.len(),
217 value,
218 ));
219 }
220
221 let rc = value.get_u32();
223 if rc != 0 && rc != NO_MORE_ITEMS {
224 return Err(NetworkParseError::ErrorCode(rc));
225 }
226 if rc == NO_MORE_ITEMS {
227 return Ok(DirectoryItemResponse::new_nothing_left());
228 }
229
230 if value.len() < 0x154 {
232 return Err(NetworkParseError::NotEnoughData(
233 "DirectoryItemResponse",
234 0x154,
235 value.len(),
236 value,
237 ));
238 }
239 if value.len() > 0x154 {
240 return Err(NetworkParseError::UnexpectedTrailer(
241 "DirectoryItemResponse",
242 value.slice(0x154..),
243 ));
244 }
245
246 let fd_info = SataFDInfo::try_from(value.slice(..84))?;
247 let path_bytes = value.slice(84..);
248 let path =
249 CStr::from_bytes_until_nul(&path_bytes).map_err(NetworkParseError::BadCString)?;
250
251 Ok(Self {
252 return_code: rc,
253 next_file_info: Some((fd_info, path.to_str()?.to_owned())),
254 })
255 }
256}