1use super::protocol::*;
5use std::io;
6use std::io::Write;
7use zerocopy::FromZeros;
8use zerocopy::Immutable;
9use zerocopy::IntoBytes;
10use zerocopy::KnownLayout;
11
12pub trait ReplySender {
14 fn send(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<()>;
16
17 fn send_empty(&mut self, unique: u64) -> io::Result<()> {
19 tracing::trace!(unique, "Reply");
20 self.send_error(unique, 0)
21 }
22
23 fn send_arg<T: std::fmt::Debug + IntoBytes + Immutable + KnownLayout>(
25 &mut self,
26 unique: u64,
27 arg: T,
28 ) -> io::Result<()> {
29 tracing::trace!(unique, ?arg, "reply");
30 let header = make_header(unique, size_of_val(&arg), 0);
31 let header = header.as_bytes();
32 let arg = arg.as_bytes();
33 self.send(&[io::IoSlice::new(header), io::IoSlice::new(arg)])
34 }
35
36 fn send_error(&mut self, unique: u64, error: i32) -> io::Result<()> {
38 if error != 0 {
39 tracing::debug!(unique, error, "reply");
40 }
41
42 let header = make_header(unique, 0, -error);
43 let header = header.as_bytes();
44 self.send(&[io::IoSlice::new(header)])
45 }
46
47 fn send_data(&mut self, unique: u64, data: &[u8]) -> io::Result<()> {
49 tracing::trace!(unique, len = data.len(), "reply");
50 let header = make_header(unique, data.len(), 0);
51 let header = header.as_bytes();
52 self.send(&[io::IoSlice::new(header), io::IoSlice::new(data)])
53 }
54
55 fn send_arg_data<T: std::fmt::Debug + IntoBytes + Immutable + KnownLayout>(
57 &mut self,
58 unique: u64,
59 arg: T,
60 data: &[u8],
61 ) -> io::Result<()> {
62 tracing::trace!(unique, ?arg, len = data.len(), "reply");
63
64 let header = make_header(unique, size_of_val(&arg), 0);
65 let header = header.as_bytes();
66 let arg = arg.as_bytes();
67 self.send(&[
68 io::IoSlice::new(header),
69 io::IoSlice::new(arg),
70 io::IoSlice::new(data),
71 ])
72 }
73
74 fn send_string(&mut self, unique: u64, value: lx::LxString) -> io::Result<()> {
76 tracing::trace!(unique, len = value.len(), "reply");
77 let header = make_header(unique, value.len() + 1, 0);
78 let header = header.as_bytes();
79 self.send(&[
80 io::IoSlice::new(header),
81 io::IoSlice::new(value.as_bytes()),
82 io::IoSlice::new(&[0]),
83 ])
84 }
85}
86
87fn make_header(unique: u64, extra_len: usize, error: i32) -> fuse_out_header {
88 fuse_out_header {
89 len: (size_of::<fuse_out_header>() + extra_len)
90 .try_into()
91 .unwrap(),
92 error,
93 unique,
94 }
95}
96
97pub trait DirEntryWriter {
105 fn dir_entry(
109 &mut self,
110 name: impl AsRef<lx::LxStr>,
111 inode_nr: u64,
112 offset: u64,
113 file_type: u32,
114 ) -> bool;
115
116 fn dir_entry_plus(
120 &mut self,
121 name: impl AsRef<lx::LxStr>,
122 offset: u64,
123 entry: fuse_entry_out,
124 ) -> bool;
125
126 fn check_dir_entry_plus(&self, name: impl AsRef<lx::LxStr>) -> bool;
130}
131
132impl DirEntryWriter for Vec<u8> {
133 fn dir_entry(
134 &mut self,
135 name: impl AsRef<lx::LxStr>,
136 inode_nr: u64,
137 offset: u64,
138 file_type: u32,
139 ) -> bool {
140 let name = name.as_ref();
142 let size = size_of::<fuse_dirent>() + name.len();
143 let aligned_size = fuse_dirent_align(size);
144 if self.capacity() - self.len() < aligned_size {
145 return false;
146 }
147
148 let dentry = fuse_dirent {
150 ino: inode_nr,
151 off: offset,
152 namelen: name.len().try_into().unwrap(),
153 file_type,
154 };
155
156 self.write_all(dentry.as_bytes()).unwrap();
157 self.write_all(name.as_bytes()).unwrap();
158
159 write_padding(self, aligned_size - size);
161 true
162 }
163
164 fn dir_entry_plus(
165 &mut self,
166 name: impl AsRef<lx::LxStr>,
167 offset: u64,
168 entry: fuse_entry_out,
169 ) -> bool {
170 let name = name.as_ref();
172 let size = size_of::<fuse_direntplus>() + name.len();
173 let aligned_size = fuse_dirent_align(size);
174 if self.capacity() - self.len() < aligned_size {
175 return false;
176 }
177
178 let mut dentry = fuse_direntplus::new_zeroed();
180 dentry.dirent.ino = entry.attr.ino;
181 dentry.dirent.off = offset;
182 dentry.dirent.namelen = name.len().try_into().unwrap();
183 dentry.dirent.file_type = (entry.attr.mode & lx::S_IFMT) >> 12;
184 dentry.entry_out = entry;
185 self.write_all(dentry.as_bytes()).unwrap();
186 self.write_all(name.as_bytes()).unwrap();
187
188 write_padding(self, aligned_size - size);
190 true
191 }
192
193 fn check_dir_entry_plus(&self, name: impl AsRef<lx::LxStr>) -> bool {
194 let size = size_of::<fuse_direntplus>() + name.as_ref().len();
195 let aligned_size = fuse_dirent_align(size);
196 self.capacity() - self.len() >= aligned_size
197 }
198}
199
200fn write_padding(writer: &mut impl Write, count: usize) {
202 const PADDING: [u8; 8] = [0; 8];
203 writer.write_all(&PADDING[..count]).unwrap();
204}