sftp_protocol/packet/
open.rs1use 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