sftp_protocol/
packet.rs

1use camino::Utf8Path;
2use nom_derive::Parse;
3use serde::Serialize;
4
5use crate::common::FileAttributes;
6#[cfg(test)]
7use proptest::strategy::Strategy;
8
9pub mod kind;
10use kind::PacketType;
11
12pub mod init;
13use init::Init;
14pub mod version;
15use version::Version;
16pub mod open;
17use open::Open;
18pub mod close;
19use close::Close;
20pub mod read;
21use read::Read;
22pub mod write;
23use write::Write;
24pub mod lstat;
25use lstat::Lstat;
26pub mod fstat;
27use fstat::Fstat;
28pub mod setstat;
29use setstat::SetStat;
30pub mod fsetstat;
31use fsetstat::FSetStat;
32pub mod opendir;
33use opendir::OpenDir;
34pub mod readdir;
35use readdir::ReadDir;
36pub mod remove;
37use remove::Remove;
38pub mod mkdir;
39use mkdir::MkDir;
40pub mod rmdir;
41use rmdir::RmDir;
42pub mod realpath;
43use realpath::RealPath;
44pub mod stat;
45use stat::Stat;
46pub mod rename;
47use rename::Rename;
48pub mod readlink;
49use readlink::ReadLink;
50pub mod symlink;
51use symlink::Symlink;
52pub mod status;
53use status::Status;
54use status::StatusType;
55pub mod handle;
56use handle::Handle;
57pub mod data;
58use data::Data;
59pub mod name;
60use name::Name;
61pub mod attrs;
62use attrs::Attrs;
63pub mod extended;
64use extended::Request as ExtendedRequest;
65use extended::Response as ExtendedResponse;
66
67#[derive(Debug, Nom, Serialize)]
68#[nom(BigEndian)]
69pub struct PacketRaw<'a> {
70	pub length: u32,
71	pub kind: PacketType,
72	#[nom(Take="i.len()")]
73	pub raw_payload: &'a [u8]
74}
75
76#[derive(Clone, Debug, Eq, PartialEq, Nom, Serialize)]
77#[nom(BigEndian)]
78pub struct PacketHeader {
79	pub length: u32,
80	pub kind: PacketType
81}
82
83#[derive(Debug, Eq, PartialEq, Nom, Serialize)]
84#[nom(BigEndian)]
85pub struct Packet {
86	pub header: PacketHeader,
87	#[nom(Parse="{ |i| Payload::parse(i, header.kind) }")]
88	pub payload: Payload
89}
90
91#[cfg(test)]
92impl proptest::arbitrary::Arbitrary for Packet {
93	type Parameters = ();
94	type Strategy = proptest::strategy::BoxedStrategy<Self>;
95	fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
96		Payload::arbitrary_with(()).prop_map(|payload| payload.into_packet()).boxed()
97	}
98}
99
100pub trait PayloadTrait : Serialize + Into<Payload> {
101	const Type: PacketType;
102	fn binsize(&self) -> u32;
103
104	fn header(&self) -> PacketHeader {
105		PacketHeader{
106			length: 1 + self.binsize(),
107			kind: Self::Type
108		}
109	}
110
111	fn into_packet(self) -> Packet {
112		Packet{
113			header: self.header(),
114			payload: self.into()
115		}
116	}
117}
118
119#[derive(Debug, Eq, PartialEq, Nom, Serialize)]
120#[nom(Selector = "PacketType")]
121#[serde(untagged)]
122#[cfg_attr(test, derive(test_strategy::Arbitrary))]
123pub enum Payload {
124	#[nom(Selector = "PacketType::Init")]
125	Init(Init),
126	#[nom(Selector = "PacketType::Version")]
127	Version(Version),
128	#[nom(Selector = "PacketType::Open")]
129	Open(Open),
130	#[nom(Selector = "PacketType::Close")]
131	Close(Close),
132	#[nom(Selector = "PacketType::Read")]
133	Read(Read),
134	#[nom(Selector = "PacketType::Write")]
135	Write(Write),
136	#[nom(Selector = "PacketType::Lstat")]
137	Lstat(Lstat),
138	#[nom(Selector = "PacketType::Fstat")]
139	Fstat(Fstat),
140	#[nom(Selector = "PacketType::SetStat")]
141	SetStat(SetStat),
142	#[nom(Selector = "PacketType::FSetStat")]
143	FSetStat(FSetStat),
144	#[nom(Selector = "PacketType::OpenDir")]
145	OpenDir(OpenDir),
146	#[nom(Selector = "PacketType::ReadDir")]
147	ReadDir(ReadDir),
148	#[nom(Selector = "PacketType::Remove")]
149	Remove(Remove),
150	#[nom(Selector = "PacketType::MkDir")]
151	MkDir(MkDir),
152	#[nom(Selector = "PacketType::RmDir")]
153	RmDir(RmDir),
154	#[nom(Selector = "PacketType::RealPath")]
155	RealPath(RealPath),
156	#[nom(Selector = "PacketType::Stat")]
157	Stat(Stat),
158	#[nom(Selector = "PacketType::Rename")]
159	Rename(Rename),
160	#[nom(Selector = "PacketType::ReadLink")]
161	ReadLink(ReadLink),
162	#[nom(Selector = "PacketType::Symlink")]
163	Symlink(Symlink),
164	#[nom(Selector = "PacketType::Status")]
165	Status(Status),
166	#[nom(Selector = "PacketType::Handle")]
167	Handle(Handle),
168	#[nom(Selector = "PacketType::Data")]
169	Data(Data),
170	#[nom(Selector = "PacketType::Name")]
171	Name(Name),
172	#[nom(Selector = "PacketType::Attrs")]
173	Attrs(Attrs),
174	#[nom(Selector = "PacketType::Extended")]
175	Extended(ExtendedRequest),
176	#[nom(Selector = "PacketType::ExtendedReply")]
177	ExtendedReply(ExtendedResponse)
178}
179
180impl Payload {
181	pub fn init(version: u32, extension_data: Vec<u8>) -> Self {
182		Self::Init(Init{
183			version,
184			extension_data
185		})
186	}
187
188	pub fn version(version: u32, extension_data: Vec<u8>) -> Self {
189		Self::Version(Version{
190			version,
191			extension_data
192		})
193	}
194
195	pub fn real_path(id: u32, path: impl AsRef<Utf8Path>) -> Self {
196		Self::RealPath(RealPath{
197			id,
198			path: path.as_ref().to_path_buf()
199		})
200	}
201
202	pub fn status(id: u32, status: StatusType, message: impl AsRef<str>) -> Self {
203		Self::Status(Status{
204			id,
205			status,
206			message: message.as_ref().to_string(),
207			language: "en-US".to_string()
208		})
209	}
210
211	pub fn handle(id: u32) -> Handle {
212		Handle{
213			id,
214			handle: uuid::Uuid::new_v4()
215		}
216	}
217
218	pub fn name(id: u32) -> Name {
219		Name{
220			id,
221			files: Vec::with_capacity(1)
222		}
223	}
224
225	pub fn attrs(id: u32) -> Attrs {
226		Attrs{
227			id,
228			attrs: FileAttributes::new()
229		}
230	}
231
232	// TODO:  Configurable limit for size
233	pub fn data_with_size(id: u32, size: u32) -> Data {
234		Data{
235			id,
236			data: vec![0; size as usize]
237		}
238	}
239
240	pub fn into_packet(self) -> Packet {
241		match self {
242			Self::Init(p) => p.into_packet(),
243			Self::Version(p) => p.into_packet(),
244			Self::Open(p) => p.into_packet(),
245			Self::Close(p) => p.into_packet(),
246			Self::Read(p) => p.into_packet(),
247			Self::Write(p) => p.into_packet(),
248			Self::Lstat(p) => p.into_packet(),
249			Self::Fstat(p) => p.into_packet(),
250			Self::SetStat(p) => p.into_packet(),
251			Self::FSetStat(p) => p.into_packet(),
252			Self::OpenDir(p) => p.into_packet(),
253			Self::ReadDir(p) => p.into_packet(),
254			Self::Remove(p) => p.into_packet(),
255			Self::MkDir(p) => p.into_packet(),
256			Self::RmDir(p) => p.into_packet(),
257			Self::RealPath(p) => p.into_packet(),
258			Self::Stat(p) => p.into_packet(),
259			Self::Rename(p) => p.into_packet(),
260			Self::ReadLink(p) => p.into_packet(),
261			Self::Symlink(p) => p.into_packet(),
262			Self::Status(p) => p.into_packet(),
263			Self::Handle(p) => p.into_packet(),
264			Self::Data(p) => p.into_packet(),
265			Self::Name(p) => p.into_packet(),
266			Self::Attrs(p) => p.into_packet(),
267			Self::Extended(p) => p.into_packet(),
268			Self::ExtendedReply(p) => p.into_packet()
269		}
270	}
271}
272
273