use crate::{errors::NetworkParseError, fsemul::pcfs::errors::PcfsApiError};
use bytes::{BufMut, Bytes, BytesMut};
use std::ffi::CStr;
use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SataChangeOwnerPacketBody {
path: String,
uid: u32,
gid: u32,
}
impl SataChangeOwnerPacketBody {
pub fn new(path: String, uid: u32, gid: u32) -> Result<Self, PcfsApiError> {
if path.len() > 511 {
return Err(PcfsApiError::PathTooLong(path));
}
Ok(Self { path, uid, gid })
}
#[must_use]
pub fn path(&self) -> &str {
self.path.as_str()
}
pub fn set_path(&mut self, new_path: String) -> Result<(), PcfsApiError> {
if new_path.len() > 511 {
return Err(PcfsApiError::PathTooLong(new_path));
}
self.path = new_path;
Ok(())
}
#[must_use]
pub const fn uid(&self) -> u32 {
self.uid
}
pub const fn set_uid(&mut self, new_uid: u32) {
self.uid = new_uid;
}
#[must_use]
pub const fn gid(&self) -> u32 {
self.gid
}
pub const fn set_gid(&mut self, new_gid: u32) {
self.gid = new_gid;
}
}
impl TryFrom<Bytes> for SataChangeOwnerPacketBody {
type Error = NetworkParseError;
fn try_from(value: Bytes) -> Result<Self, Self::Error> {
if value.len() < 0x208 {
return Err(NetworkParseError::FieldNotLongEnough(
"SataChangeMode",
"Body",
0x208,
value.len(),
value,
));
}
if value.len() > 0x208 {
return Err(NetworkParseError::UnexpectedTrailer(
"SataChangeMode",
value.slice(0x208..),
));
}
let (path_bytes, num) = value.split_at(0x200);
let path_c_str =
CStr::from_bytes_until_nul(path_bytes).map_err(NetworkParseError::BadCString)?;
let uid = u32::from_be_bytes([num[0], num[1], num[2], num[3]]);
let gid = u32::from_be_bytes([num[4], num[5], num[6], num[7]]);
let final_path = path_c_str.to_str()?.to_owned();
Ok(Self {
path: final_path,
uid,
gid,
})
}
}
impl From<&SataChangeOwnerPacketBody> for Bytes {
fn from(value: &SataChangeOwnerPacketBody) -> Self {
let mut result = BytesMut::with_capacity(0x208);
result.extend_from_slice(value.path.as_bytes());
result.extend(BytesMut::zeroed(0x200 - result.len()));
result.put_u32(value.uid);
result.put_u32(value.gid);
result.freeze()
}
}
impl From<SataChangeOwnerPacketBody> for Bytes {
fn from(value: SataChangeOwnerPacketBody) -> Self {
Self::from(&value)
}
}
const SATA_CHANGE_OWNER_PACKET_BODY_FIELDS: &[NamedField<'static>] = &[
NamedField::new("path"),
NamedField::new("uid"),
NamedField::new("gid"),
];
impl Structable for SataChangeOwnerPacketBody {
fn definition(&self) -> StructDef<'_> {
StructDef::new_static(
"SataChangeOwnerPacketBody",
Fields::Named(SATA_CHANGE_OWNER_PACKET_BODY_FIELDS),
)
}
}
impl Valuable for SataChangeOwnerPacketBody {
fn as_value(&self) -> Value<'_> {
Value::Structable(self)
}
fn visit(&self, visitor: &mut dyn Visit) {
visitor.visit_named_fields(&NamedValues::new(
SATA_CHANGE_OWNER_PACKET_BODY_FIELDS,
&[
Valuable::as_value(&self.path),
Valuable::as_value(&self.uid),
Valuable::as_value(&self.gid),
],
));
}
}