cat_dev/fsemul/pcfs/sata/proto/
write_file.rs

1//! Definitions for the `WriteFile` packet type, and it's response types.
2//!
3//! This is what actively handles writing bytes to a file. With either
4//! FFIO, and Combined Send/Recv options being turned on/off.
5
6use crate::{errors::NetworkParseError, fsemul::pcfs::sata::proto::MoveToFileLocation};
7use bytes::{Buf, BufMut, Bytes, BytesMut};
8use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
9
10/// A packet to write to an already open file.
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct SataWriteFilePacketBody {
13	block_count: u32,
14	block_size: u32,
15	handle: i32,
16	move_to_pointer: MoveToFileLocation,
17	should_move: bool,
18}
19
20impl SataWriteFilePacketBody {
21	/// Create a new write file packet.
22	#[must_use]
23	pub const fn new(
24		block_count: u32,
25		block_size: u32,
26		file_descriptor: i32,
27		move_to: Option<MoveToFileLocation>,
28	) -> Self {
29		Self {
30			block_count,
31			block_size,
32			handle: file_descriptor,
33			move_to_pointer: if let Some(mt) = move_to {
34				mt
35			} else {
36				MoveToFileLocation::Begin
37			},
38			should_move: move_to.is_some(),
39		}
40	}
41
42	#[must_use]
43	pub const fn block_count(&self) -> u32 {
44		self.block_count
45	}
46
47	pub const fn set_block_count(&mut self, new_count: u32) {
48		self.block_count = new_count;
49	}
50
51	#[must_use]
52	pub const fn block_size(&self) -> u32 {
53		self.block_size
54	}
55
56	pub const fn set_block_size(&mut self, new_size: u32) {
57		self.block_size = new_size;
58	}
59
60	#[must_use]
61	pub const fn file_descriptor(&self) -> i32 {
62		self.handle
63	}
64
65	pub const fn set_file_descriptor(&mut self, new_fd: i32) {
66		self.handle = new_fd;
67	}
68
69	#[must_use]
70	pub const fn move_to_pointer(&self) -> MoveToFileLocation {
71		self.move_to_pointer
72	}
73
74	pub const fn set_move_to(&mut self, new_move: Option<MoveToFileLocation>) {
75		if let Some(nm) = new_move {
76			self.move_to_pointer = nm;
77			self.should_move = true;
78		} else {
79			self.move_to_pointer = MoveToFileLocation::Begin;
80			self.should_move = false;
81		}
82	}
83
84	#[must_use]
85	pub const fn should_move(&self) -> bool {
86		self.should_move
87	}
88}
89
90impl From<&SataWriteFilePacketBody> for Bytes {
91	fn from(value: &SataWriteFilePacketBody) -> Self {
92		let mut buff = BytesMut::with_capacity(20);
93
94		buff.put_u32(value.block_count);
95		buff.put_u32(value.block_size);
96		buff.put_i32(value.handle);
97		buff.put_u32(u32::from(value.move_to_pointer));
98		// True is 1, False is 0
99		buff.put_u32(u32::from(value.should_move));
100
101		buff.freeze()
102	}
103}
104
105impl From<SataWriteFilePacketBody> for Bytes {
106	fn from(value: SataWriteFilePacketBody) -> Self {
107		Self::from(&value)
108	}
109}
110
111impl TryFrom<Bytes> for SataWriteFilePacketBody {
112	type Error = NetworkParseError;
113
114	fn try_from(mut value: Bytes) -> Result<Self, Self::Error> {
115		if value.len() < 20 {
116			return Err(NetworkParseError::FieldNotLongEnough(
117				"SataWriteFile",
118				"Body",
119				20,
120				value.len(),
121				value,
122			));
123		}
124		if value.len() > 20 {
125			return Err(NetworkParseError::UnexpectedTrailer(
126				"SataWriteFile",
127				value.slice(20..),
128			));
129		}
130
131		let block_count = value.get_u32();
132		let block_length = value.get_u32();
133		let handle = value.get_i32();
134		let move_to_ptr = value.get_u32();
135		let should_move = value.get_u32();
136
137		Ok(Self {
138			block_count,
139			block_size: block_length,
140			handle,
141			move_to_pointer: MoveToFileLocation::try_from(move_to_ptr)?,
142			should_move: (should_move & 1) != 0,
143		})
144	}
145}
146
147const SATA_WRITE_FILE_PACKET_BODY_FIELDS: &[NamedField<'static>] = &[
148	NamedField::new("block_count"),
149	NamedField::new("block_size"),
150	NamedField::new("handle"),
151	NamedField::new("move_to_pointer"),
152	NamedField::new("should_move"),
153];
154
155impl Structable for SataWriteFilePacketBody {
156	fn definition(&self) -> StructDef<'_> {
157		StructDef::new_static(
158			"SataWriteFilePacketBody",
159			Fields::Named(SATA_WRITE_FILE_PACKET_BODY_FIELDS),
160		)
161	}
162}
163
164impl Valuable for SataWriteFilePacketBody {
165	fn as_value(&self) -> Value<'_> {
166		Value::Structable(self)
167	}
168
169	fn visit(&self, visitor: &mut dyn Visit) {
170		visitor.visit_named_fields(&NamedValues::new(
171			SATA_WRITE_FILE_PACKET_BODY_FIELDS,
172			&[
173				Valuable::as_value(&self.block_count),
174				Valuable::as_value(&self.block_size),
175				Valuable::as_value(&self.handle),
176				Valuable::as_value(&self.move_to_pointer),
177				Valuable::as_value(&self.should_move),
178			],
179		));
180	}
181}