cat_dev/fsemul/pcfs/sata/proto/
change_mode.rs1use crate::{errors::NetworkParseError, fsemul::pcfs::errors::PcfsApiError};
8use bytes::{BufMut, Bytes, BytesMut};
9use std::ffi::CStr;
10use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
11
12#[derive(Clone, Debug, PartialEq, Eq)]
14pub struct SataChangeModePacketBody {
15 path: String,
26 set_write_mode: bool,
28}
29
30impl SataChangeModePacketBody {
31 pub fn new(path: String, set_write_mode: bool) -> Result<Self, PcfsApiError> {
42 if path.len() > 511 {
43 return Err(PcfsApiError::PathTooLong(path));
44 }
45
46 Ok(Self {
47 path,
48 set_write_mode,
49 })
50 }
51
52 #[must_use]
53 pub fn path(&self) -> &str {
54 self.path.as_str()
55 }
56
57 pub fn set_path(&mut self, new_path: String) -> Result<(), PcfsApiError> {
68 if new_path.len() > 511 {
69 return Err(PcfsApiError::PathTooLong(new_path));
70 }
71
72 self.path = new_path;
73 Ok(())
74 }
75
76 #[must_use]
77 pub const fn will_set_write_mode(&self) -> bool {
78 self.set_write_mode
79 }
80
81 pub const fn set_write_mode(&mut self, will_set: bool) {
84 self.set_write_mode = will_set;
85 }
86}
87
88impl TryFrom<Bytes> for SataChangeModePacketBody {
89 type Error = NetworkParseError;
90
91 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
92 if value.len() < 0x204 {
93 return Err(NetworkParseError::FieldNotLongEnough(
94 "SataChangeMode",
95 "Body",
96 0x204,
97 value.len(),
98 value,
99 ));
100 }
101 if value.len() > 0x204 {
102 return Err(NetworkParseError::UnexpectedTrailer(
103 "SataChangeMode",
104 value.slice(0x204..),
105 ));
106 }
107
108 let (path_bytes, num) = value.split_at(0x200);
109 let path_c_str =
110 CStr::from_bytes_until_nul(path_bytes).map_err(NetworkParseError::BadCString)?;
111 let write_mode_flags = u32::from_be_bytes([num[0], num[1], num[2], num[3]]);
112 let final_path = path_c_str.to_str()?.to_owned();
113
114 Ok(Self {
115 path: final_path,
116 set_write_mode: write_mode_flags & 0x222 != 0,
117 })
118 }
119}
120
121impl From<&SataChangeModePacketBody> for Bytes {
122 fn from(value: &SataChangeModePacketBody) -> Self {
123 let mut result = BytesMut::with_capacity(0x204);
124 result.extend_from_slice(value.path.as_bytes());
125 result.extend(BytesMut::zeroed(0x200 - result.len()));
128 result.put_u32(if value.set_write_mode { 0x666 } else { 0x444 });
129 result.freeze()
130 }
131}
132
133impl From<SataChangeModePacketBody> for Bytes {
134 fn from(value: SataChangeModePacketBody) -> Self {
135 Self::from(&value)
136 }
137}
138
139const SATA_CHANGE_MODE_PACKET_BODY_FIELDS: &[NamedField<'static>] = &[NamedField::new("path")];
140
141impl Structable for SataChangeModePacketBody {
142 fn definition(&self) -> StructDef<'_> {
143 StructDef::new_static(
144 "SataChangeModePacketBody",
145 Fields::Named(SATA_CHANGE_MODE_PACKET_BODY_FIELDS),
146 )
147 }
148}
149
150impl Valuable for SataChangeModePacketBody {
151 fn as_value(&self) -> Value<'_> {
152 Value::Structable(self)
153 }
154
155 fn visit(&self, visitor: &mut dyn Visit) {
156 visitor.visit_named_fields(&NamedValues::new(
157 SATA_CHANGE_MODE_PACKET_BODY_FIELDS,
158 &[Valuable::as_value(&self.path)],
159 ));
160 }
161}