sftp_protocol/packet/
open.rs

1use camino::Utf8PathBuf;
2use nom::IResult;
3use nom::number::streaming::be_u32;
4use nom::number::streaming::le_u32;
5
6use crate::common::FileAttributes;
7
8use super::kind::PacketType;
9use super::PayloadTrait;
10
11#[derive(Debug, Eq, PartialEq, Nom, Serialize)]
12#[nom(BigEndian)]
13#[cfg_attr(test, derive(test_strategy::Arbitrary))]
14pub struct Open {
15	pub id: u32,
16	#[nom(Parse(crate::util::parse_path))]
17	#[serde(serialize_with = "crate::util::path_with_u32_length")]
18	pub path: Utf8PathBuf,
19	pub pflags: OpenFlags,
20	pub attrs: FileAttributes
21}
22
23impl PayloadTrait for Open {
24	const Type: PacketType = PacketType::Open;
25	fn binsize(&self) -> u32 {
26		4 + (4 + self.path.as_str().len() as u32) + 4 + self.attrs.binsize()
27	}
28}
29
30impl From<Open> for super::Payload {
31	fn from(p: Open) -> Self {
32		Self::Open(p)
33	}
34}
35
36bitflags::bitflags! {
37	#[derive(Default, Serialize)]
38	pub struct OpenFlags: u32 {
39		const Read = 0x01;
40		const Write = 0x02;
41		const Append = 0x04;
42		const Create = 0x08;
43		const Truncate = 0x10;
44		const Exclude = 0x20;
45	}
46}
47
48#[cfg(test)]
49impl proptest::bits::BitSetLike for OpenFlags {
50	fn new_bitset(_max: usize) -> Self {
51		Self::empty()
52	}
53
54	fn len(&self) -> usize {
55		7
56	}
57
58	fn test(&self, i: usize) -> bool {
59		(self.bits() & 2 << i) != 0
60	}
61
62	fn set(&mut self, i: usize) {
63		self.insert(Self::from_bits_truncate(2 << i))
64	}
65
66	fn clear(&mut self, i: usize) {
67		self.remove(Self::from_bits_truncate(2 << i))
68	}
69}
70
71#[cfg(test)]
72impl proptest::prelude::Arbitrary for OpenFlags {
73	type Parameters = ();
74	type Strategy = proptest::bits::BitSetStrategy<Self>;
75	fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
76		proptest::bits::BitSetStrategy::masked(Self::from_bits_truncate(0x3f))
77	}
78}
79
80impl<I: nom_derive::InputSlice> nom_derive::Parse<I> for OpenFlags {
81	fn parse_be(i: I) -> IResult<I, Self> {
82		let (i, flags) = be_u32(i)?;
83		let this = Self::from_bits_truncate(flags);
84		Ok((i, this))
85	}
86
87	fn parse_le(i: I) -> IResult<I, Self> {
88		let (i, flags) = le_u32(i)?;
89		let this = Self::from_bits_truncate(flags);
90		Ok((i, this))
91	}
92
93	fn parse(i: I) -> IResult<I, Self> {
94		Self::parse_be(i)
95	}
96}
97
98#[cfg(test)]
99mod tests {
100	use test_strategy::proptest;
101	use crate::parser::encode;
102	use crate::parser::Parser;
103	use super::*;
104
105	#[proptest]
106	fn roundtrip_whole(input: Open) {
107		let mut stream = Parser::default();
108		let packet = input.into_packet();
109		stream.write(&encode(&packet)).unwrap();
110		assert_eq!(stream.get_packet(), Ok(Some(packet)));
111		assert_eq!(stream.get_packet(), Ok(None));
112	}
113}
114