1use super::Fuse;
5use super::Mapper;
6use super::protocol::*;
7use super::reply::ReplySender;
8use super::request::FuseOperation;
9use super::request::Request;
10use super::request::RequestReader;
11use parking_lot::RwLock;
12use std::io;
13use std::sync::atomic;
14use thiserror::Error;
15use zerocopy::FromZeros;
16use zerocopy::Immutable;
17use zerocopy::KnownLayout;
18
19const DEFAULT_FLAGS: u32 = FUSE_ASYNC_READ
21 | FUSE_PARALLEL_DIROPS
22 | FUSE_AUTO_INVAL_DATA
23 | FUSE_HANDLE_KILLPRIV
24 | FUSE_ASYNC_DIO
25 | FUSE_ATOMIC_O_TRUNC
26 | FUSE_BIG_WRITES;
27
28const DEFAULT_MAX_PAGES: u32 = 256;
29
30const PAGE_SIZE: u32 = 4096;
34
35pub struct Session {
39 fs: Box<dyn Fuse + Send + Sync>,
40 initialized: atomic::AtomicBool,
43 info: RwLock<SessionInfo>,
44}
45
46impl Session {
47 pub fn new<T>(fs: T) -> Self
49 where
50 T: 'static + Fuse + Send + Sync,
51 {
52 Self {
53 fs: Box::new(fs),
54 initialized: atomic::AtomicBool::new(false),
55 info: RwLock::new(SessionInfo::default()),
56 }
57 }
58
59 pub fn is_initialized(&self) -> bool {
63 self.initialized.load(atomic::Ordering::Acquire)
64 }
65
66 pub fn dispatch(
68 &self,
69 request: Request,
70 sender: &mut impl ReplySender,
71 mapper: Option<&dyn Mapper>,
72 ) {
73 let unique = request.unique();
74 let result = if self.is_initialized() {
75 self.dispatch_helper(request, sender, mapper)
76 } else {
77 self.dispatch_init(request, sender)
78 };
79
80 match result {
81 Err(OperationError::FsError(e)) => {
82 if let Err(e) = sender.send_error(unique, e.value()) {
83 tracing::error!(
84 unique,
85 error = &e as &dyn std::error::Error,
86 "Failed to send reply",
87 );
88 }
89 }
90 Err(OperationError::SendError(e)) => {
91 if e.kind() == io::ErrorKind::NotFound {
92 tracing::trace!(unique, "Request was interrupted.");
93 } else {
94 tracing::error!(
95 unique,
96 error = &e as &dyn std::error::Error,
97 "Failed to send reply",
98 );
99 }
100 }
101 Ok(_) => (),
102 }
103 }
104
105 pub fn destroy(&self) {
112 if self.initialized.swap(false, atomic::Ordering::AcqRel) {
113 self.fs.destroy();
114 }
115 }
116
117 fn dispatch_helper(
120 &self,
121 request: Request,
122 sender: &mut impl ReplySender,
123 mapper: Option<&dyn Mapper>,
124 ) -> Result<(), OperationError> {
125 request.log();
126
127 match request.operation() {
128 FuseOperation::Invalid => {
129 return Err(lx::Error::EIO.into());
132 }
133 FuseOperation::Error(e) => {
134 return Err((*e).into());
137 }
138 FuseOperation::Lookup { name } => {
139 let out = self.fs.lookup(&request, name)?;
140 sender.send_arg(request.unique(), out)?;
141 }
142 FuseOperation::Forget { arg } => {
143 self.fs.forget(request.node_id(), arg.nlookup);
144 }
145 FuseOperation::GetAttr { arg } => {
146 let out = self.fs.get_attr(&request, arg.getattr_flags, arg.fh)?;
147 sender.send_arg(request.unique(), out)?;
148 }
149 FuseOperation::SetAttr { arg } => {
150 let out = self.fs.set_attr(&request, arg)?;
151 sender.send_arg(request.unique(), out)?;
152 }
153 FuseOperation::ReadLink {} => {
154 let out = self.fs.read_link(&request)?;
155 sender.send_string(request.unique(), out)?;
156 }
157 FuseOperation::Symlink { name, target } => {
158 let out = self.fs.symlink(&request, name, target)?;
159 sender.send_arg(request.unique(), out)?;
160 }
161 FuseOperation::MkNod { arg, name } => {
162 let out = self.fs.mknod(&request, name, arg)?;
163 sender.send_arg(request.unique(), out)?;
164 }
165 FuseOperation::MkDir { arg, name } => {
166 let out = self.fs.mkdir(&request, name, arg)?;
167 sender.send_arg(request.unique(), out)?;
168 }
169 FuseOperation::Unlink { name } => {
170 self.fs.unlink(&request, name)?;
171 sender.send_empty(request.unique())?;
172 }
173 FuseOperation::RmDir { name } => {
174 self.fs.rmdir(&request, name)?;
175 sender.send_empty(request.unique())?;
176 }
177 FuseOperation::Rename {
178 arg,
179 name,
180 new_name,
181 } => {
182 self.fs.rename(&request, name, arg.newdir, new_name, 0)?;
183
184 sender.send_empty(request.unique())?;
185 }
186 FuseOperation::Link { arg, name } => {
187 let out = self.fs.link(&request, name, arg.oldnodeid)?;
188 sender.send_arg(request.unique(), out)?;
189 }
190 FuseOperation::Open { arg } => {
191 let out = self.fs.open(&request, arg.flags)?;
192 self.send_release_if_interrupted(&request, sender, out.fh, arg.flags, out, false)?;
193 }
194 FuseOperation::Read { arg } => {
195 let out = self.fs.read(&request, arg)?;
196 Self::send_max_size(sender, request.unique(), &out, arg.size)?;
197 }
198 FuseOperation::Write { arg, data } => {
199 let out = self.fs.write(&request, arg, data)?;
200 sender.send_arg(
201 request.unique(),
202 fuse_write_out {
203 size: out.try_into().unwrap(),
204 padding: 0,
205 },
206 )?;
207 }
208 FuseOperation::StatFs {} => {
209 let out = self.fs.statfs(&request)?;
210 sender.send_arg(request.unique(), fuse_statfs_out { st: out })?;
211 }
212 FuseOperation::Release { arg } => {
213 self.fs.release(&request, arg)?;
214 sender.send_empty(request.unique())?;
215 }
216 FuseOperation::FSync { arg } => {
217 self.fs.fsync(&request, arg.fh, arg.fsync_flags)?;
218 sender.send_empty(request.unique())?;
219 }
220 FuseOperation::SetXAttr { arg, name, value } => {
221 self.fs.set_xattr(&request, name, value, arg.flags)?;
222 sender.send_empty(request.unique())?;
223 }
224 FuseOperation::GetXAttr { arg, name } => {
225 if arg.size == 0 {
226 let out = self.fs.get_xattr_size(&request, name)?;
227 sender.send_arg(
228 request.unique(),
229 fuse_getxattr_out {
230 size: out,
231 padding: 0,
232 },
233 )?;
234 } else {
235 let out = self.fs.get_xattr(&request, name, arg.size)?;
236 Self::send_max_size(sender, request.unique(), &out, arg.size)?;
237 }
238 }
239 FuseOperation::ListXAttr { arg } => {
240 if arg.size == 0 {
241 let out = self.fs.list_xattr_size(&request)?;
242 sender.send_arg(
243 request.unique(),
244 fuse_getxattr_out {
245 size: out,
246 padding: 0,
247 },
248 )?;
249 } else {
250 let out = self.fs.list_xattr(&request, arg.size)?;
251 Self::send_max_size(sender, request.unique(), &out, arg.size)?;
252 }
253 }
254 FuseOperation::RemoveXAttr { name } => {
255 self.fs.remove_xattr(&request, name)?;
256 sender.send_empty(request.unique())?;
257 }
258 FuseOperation::Flush { arg } => {
259 self.fs.flush(&request, arg)?;
260 sender.send_empty(request.unique())?;
261 }
262 FuseOperation::Init { arg: _ } => {
263 tracing::warn!("Duplicate init message.");
264 return Err(lx::Error::EIO.into());
265 }
266 FuseOperation::OpenDir { arg } => {
267 let out = self.fs.open_dir(&request, arg.flags)?;
268 self.send_release_if_interrupted(&request, sender, out.fh, arg.flags, out, true)?;
269 }
270 FuseOperation::ReadDir { arg } => {
271 let out = self.fs.read_dir(&request, arg)?;
272 Self::send_max_size(sender, request.unique(), &out, arg.size)?;
273 }
274 FuseOperation::ReleaseDir { arg } => {
275 self.fs.release_dir(&request, arg)?;
276 sender.send_empty(request.unique())?;
277 }
278 FuseOperation::FSyncDir { arg } => {
279 self.fs.fsync_dir(&request, arg.fh, arg.fsync_flags)?;
280 sender.send_empty(request.unique())?;
281 }
282 FuseOperation::GetLock { arg } => {
283 let out = self.fs.get_lock(&request, arg)?;
284 sender.send_arg(request.unique(), out)?;
285 }
286 FuseOperation::SetLock { arg } => {
287 self.fs.set_lock(&request, arg, false)?;
288 sender.send_empty(request.unique())?;
289 }
290 FuseOperation::SetLockSleep { arg } => {
291 self.fs.set_lock(&request, arg, true)?;
292 sender.send_empty(request.unique())?;
293 }
294 FuseOperation::Access { arg } => {
295 self.fs.access(&request, arg.mask)?;
296 sender.send_empty(request.unique())?;
297 }
298 FuseOperation::Create { arg, name } => {
299 let out = self.fs.create(&request, name, arg)?;
300 self.send_release_if_interrupted(
301 &request,
302 sender,
303 out.open.fh,
304 arg.flags,
305 out,
306 false,
307 )?;
308 }
309 FuseOperation::Interrupt { arg: _ } => {
310 tracing::warn!("FUSE_INTERRUPT not supported.");
313 return Err(lx::Error::ENOSYS.into());
314 }
315 FuseOperation::BMap { arg } => {
316 let out = self.fs.block_map(&request, arg.block, arg.blocksize)?;
317 sender.send_arg(request.unique(), fuse_bmap_out { block: out })?;
318 }
319 FuseOperation::Destroy {} => {
320 if let Some(mapper) = mapper {
321 mapper.clear();
322 }
323 self.destroy();
324 }
325 FuseOperation::Ioctl { arg, data } => {
326 let out = self.fs.ioctl(&request, arg, data)?;
327 if out.1.len() > arg.out_size as usize {
328 return Err(lx::Error::EINVAL.into());
329 }
330
331 sender.send_arg_data(
333 request.unique(),
334 fuse_ioctl_out {
335 result: out.0,
336 flags: 0,
337 in_iovs: 0,
338 out_iovs: 0,
339 },
340 data,
341 )?;
342 }
343 FuseOperation::Poll { arg: _ } => {
344 tracing::warn!("FUSE_POLL not supported.");
348 return Err(lx::Error::ENOSYS.into());
349 }
350 FuseOperation::NotifyReply { arg: _, data: _ } => {
351 tracing::warn!("FUSE_NOTIFY_REPLY not supported.");
353 return Err(lx::Error::ENOSYS.into());
354 }
355 FuseOperation::BatchForget { arg, nodes } => {
356 self.batch_forget(arg.count, nodes);
357 }
358 FuseOperation::FAllocate { arg } => {
359 self.fs.fallocate(&request, arg)?;
360 sender.send_empty(request.unique())?;
361 }
362 FuseOperation::ReadDirPlus { arg } => {
363 let out = self.fs.read_dir_plus(&request, arg)?;
364 Self::send_max_size(sender, request.unique(), &out, arg.size)?;
365 }
366 FuseOperation::Rename2 {
367 arg,
368 name,
369 new_name,
370 } => {
371 self.fs
372 .rename(&request, name, arg.newdir, new_name, arg.flags)?;
373
374 sender.send_empty(request.unique())?;
375 }
376 FuseOperation::LSeek { arg } => {
377 let out = self.fs.lseek(&request, arg.fh, arg.offset, arg.whence)?;
378 sender.send_arg(request.unique(), fuse_lseek_out { offset: out })?;
379 }
380 FuseOperation::CopyFileRange { arg } => {
381 let out = self.fs.copy_file_range(&request, arg)?;
382 sender.send_arg(
383 request.unique(),
384 fuse_write_out {
385 size: out.try_into().unwrap(),
386 padding: 0,
387 },
388 )?;
389 }
390 FuseOperation::SetupMapping { arg } => {
391 if let Some(mapper) = mapper {
392 self.fs.setup_mapping(&request, mapper, arg)?;
393 sender.send_empty(request.unique())?;
394 } else {
395 return Err(lx::Error::ENOSYS.into());
396 }
397 }
398 FuseOperation::RemoveMapping { arg, mappings } => {
399 if let Some(mapper) = mapper {
400 self.remove_mapping(&request, mapper, arg.count, mappings)?;
401 sender.send_empty(request.unique())?;
402 } else {
403 return Err(lx::Error::ENOSYS.into());
404 }
405 }
406 FuseOperation::SyncFs { _arg } => {
407 sender.send_empty(request.unique())?;
409 }
410 FuseOperation::StatX { arg } => {
411 let out = self.fs.get_statx(
412 &request,
413 arg.fh,
414 arg.getattr_flags,
415 arg.flags,
416 arg.mask.into(),
417 )?;
418 sender.send_arg(request.unique(), out)?;
419 }
420 FuseOperation::CanonicalPath {} => {
421 tracing::trace!("Unsupported opcode FUSE_CANONICAL_PATH");
425 sender.send_error(request.unique(), lx::Error::ENOSYS.value())?;
426 }
427 }
428
429 Ok(())
430 }
431
432 fn dispatch_init(
434 &self,
435 request: Request,
436 sender: &mut impl ReplySender,
437 ) -> Result<(), OperationError> {
438 request.log();
439 let init: &fuse_init_in = if let FuseOperation::Init { arg } = request.operation() {
440 arg
441 } else {
442 tracing::error!(opcode = request.opcode(), "Expected FUSE_INIT");
443 return Err(lx::Error::EIO.into());
444 };
445
446 let mut info = self.info.write();
447 if self.is_initialized() {
448 tracing::error!("Racy FUSE_INIT requests.");
449 return Err(lx::Error::EIO.into());
450 }
451
452 let mut out = fuse_init_out::new_zeroed();
453 out.major = FUSE_KERNEL_VERSION;
454 out.minor = FUSE_KERNEL_MINOR_VERSION;
455
456 if init.major > FUSE_KERNEL_VERSION {
459 sender.send_arg(request.unique(), out)?;
460 return Ok(());
461 }
462
463 if init.major < FUSE_KERNEL_VERSION || init.minor < 27 {
466 tracing::error!(
467 major = init.major,
468 minor = init.minor,
469 "Got unsupported kernel version",
470 );
471 return Err(lx::Error::EIO.into());
472 }
473
474 info.major = init.major;
476 info.minor = init.minor;
477 info.max_readahead = init.max_readahead;
478 info.capable = init.flags;
479 info.want = DEFAULT_FLAGS & init.flags;
480 info.time_gran = 1;
481 info.max_write = DEFAULT_MAX_PAGES * PAGE_SIZE;
482 self.fs.init(&mut info);
483
484 assert!(info.want & !info.capable == 0);
485
486 out.max_readahead = info.max_readahead;
489 out.flags = info.want;
490 out.max_background = info.max_background;
491 out.congestion_threshold = info.congestion_threshold;
492 out.max_write = info.max_write;
493 out.time_gran = info.time_gran;
494 out.max_pages = ((info.max_write - 1) / PAGE_SIZE - 1).try_into().unwrap();
495
496 sender.send_arg(request.unique(), out)?;
497
498 self.initialized.store(true, atomic::Ordering::Release);
500 Ok(())
501 }
502
503 fn send_release_if_interrupted<
505 TArg: zerocopy::IntoBytes + std::fmt::Debug + Immutable + KnownLayout,
506 >(
507 &self,
508 request: &Request,
509 sender: &mut impl ReplySender,
510 fh: u64,
511 flags: u32,
512 arg: TArg,
513 dir: bool,
514 ) -> lx::Result<()> {
515 if let Err(e) = sender.send_arg(request.unique(), arg) {
516 if e.kind() == io::ErrorKind::NotFound {
519 let arg = fuse_release_in {
520 fh,
521 flags,
522 release_flags: 0,
523 lock_owner: 0,
524 };
525
526 if dir {
527 self.fs.release_dir(request, &arg)?;
528 } else {
529 self.fs.release(request, &arg)?;
530 }
531 } else {
532 return Err(e.into());
533 }
534 }
535
536 Ok(())
537 }
538
539 fn send_max_size(
543 sender: &mut impl ReplySender,
544 unique: u64,
545 data: &[u8],
546 max_size: u32,
547 ) -> Result<(), OperationError> {
548 assert!(data.len() <= max_size as usize);
549 sender.send_data(unique, data)?;
550 Ok(())
551 }
552
553 fn batch_forget(&self, count: u32, mut nodes: &[u8]) {
555 for _ in 0..count {
556 let forget: fuse_forget_one = match nodes.read_type() {
557 Ok(f) => f,
558 Err(_) => break,
559 };
560
561 self.fs.forget(forget.nodeid, forget.nlookup);
562 }
563 }
564
565 fn remove_mapping(
567 &self,
568 request: &Request,
569 mapper: &dyn Mapper,
570 count: u32,
571 mut mappings: &[u8],
572 ) -> lx::Result<()> {
573 for _ in 0..count {
574 let mapping: fuse_removemapping_one = mappings.read_type()?;
575 self.fs
576 .remove_mapping(request, mapper, mapping.moffset, mapping.len)?;
577 }
578
579 Ok(())
580 }
581}
582
583#[derive(Default)]
585pub struct SessionInfo {
586 major: u32,
587 minor: u32,
588 pub max_readahead: u32,
589 capable: u32,
590 pub want: u32,
591 pub max_background: u16,
592 pub congestion_threshold: u16,
593 pub max_write: u32,
594 pub time_gran: u32,
595}
596
597impl SessionInfo {
598 pub fn major(&self) -> u32 {
599 self.major
600 }
601
602 pub fn minor(&self) -> u32 {
603 self.minor
604 }
605
606 pub fn capable(&self) -> u32 {
607 self.capable
608 }
609}
610
611#[derive(Debug, Error)]
612enum OperationError {
613 #[error("File system error")]
614 FsError(#[from] lx::Error),
615 #[error("Send error")]
616 SendError(#[from] io::Error),
617}
618
619#[cfg(test)]
620mod tests {
621 use super::*;
622 use crate::request::tests::*;
623 use parking_lot::Mutex;
624 use std::sync::Arc;
625
626 #[test]
627 fn dispatch_error_name_too_long() {
628 let fs = TestFs::default();
629 let session = Session::new(fs);
630
631 let mut init_sender = MockSender::default();
633 session.dispatch(
634 Request::new(FUSE_INIT_REQUEST).unwrap(),
635 &mut init_sender,
636 None,
637 );
638 assert!(session.is_initialized());
639
640 let mut error_sender = ErrorCheckingSender::default();
642 let lookup_data = make_lookup_name_too_long();
643 let request = Request::new(lookup_data.as_slice()).unwrap();
644
645 assert!(
647 matches!(request.operation(), FuseOperation::Error(e) if *e == lx::Error::ENAMETOOLONG)
648 );
649
650 session.dispatch(request, &mut error_sender, None);
651
652 assert_eq!(
654 error_sender.last_error,
655 Some(lx::Error::ENAMETOOLONG.value())
656 );
657 }
658
659 #[test]
660 fn dispatch() {
661 let mut sender = MockSender::default();
662 let fs = TestFs::default();
663 let state = fs.state.clone();
664 let session = Session::new(fs);
665 assert!(!session.is_initialized());
666 let request = Request::new(FUSE_INIT_REQUEST).unwrap();
667 session.dispatch(request, &mut sender, None);
668 assert_eq!(state.lock().called, INIT_CALLED);
669 assert!(session.is_initialized());
670 session.dispatch(
671 Request::new(FUSE_GETATTR_REQUEST).unwrap(),
672 &mut sender,
673 None,
674 );
675 assert_eq!(state.lock().called, INIT_CALLED | GETATTR_CALLED);
676
677 session.dispatch(
678 Request::new(FUSE_LOOKUP_REQUEST).unwrap(),
679 &mut sender,
680 None,
681 );
682 assert_eq!(
683 state.lock().called,
684 INIT_CALLED | GETATTR_CALLED | LOOKUP_CALLED
685 );
686 }
687
688 #[derive(Default)]
689 struct State {
690 called: u32,
691 }
692
693 #[derive(Default)]
694 struct TestFs {
695 state: Arc<Mutex<State>>,
696 }
697
698 impl Fuse for TestFs {
699 fn init(&self, info: &mut SessionInfo) {
700 assert_eq!(self.state.lock().called & INIT_CALLED, 0);
701 assert_eq!(info.major(), 7);
702 assert_eq!(info.minor(), 27);
703 assert_eq!(info.capable(), 0x3FFFFB);
704 assert_eq!(info.want, 0xC9029);
705 assert_eq!(info.max_readahead, 131072);
706 assert_eq!(info.max_background, 0);
707 assert_eq!(info.max_write, 1048576);
708 assert_eq!(info.congestion_threshold, 0);
709 assert_eq!(info.time_gran, 1);
710 self.state.lock().called |= INIT_CALLED;
711 }
712
713 fn get_attr(&self, request: &Request, flags: u32, fh: u64) -> lx::Result<fuse_attr_out> {
714 assert_eq!(self.state.lock().called & GETATTR_CALLED, 0);
715 assert_eq!(request.node_id(), 1);
716 assert_eq!(flags, 0);
717 assert_eq!(fh, 0);
718 let mut attr = fuse_attr_out::new_zeroed();
719 attr.attr.ino = 1;
720 attr.attr.mode = lx::S_IFDIR | 0o755;
721 attr.attr.nlink = 2;
722 attr.attr_valid = 1;
723 self.state.lock().called |= GETATTR_CALLED;
724 Ok(attr)
725 }
726
727 fn lookup(&self, request: &Request, name: &lx::LxStr) -> lx::Result<fuse_entry_out> {
728 assert_eq!(self.state.lock().called & LOOKUP_CALLED, 0);
729 assert_eq!(request.node_id(), 1);
730 assert_eq!(name, "hello");
731 self.state.lock().called |= LOOKUP_CALLED;
732 let mut attr = fuse_attr::new_zeroed();
733 attr.ino = 2;
734 attr.mode = lx::S_IFREG | 0o644;
735 attr.nlink = 1;
736 attr.size = 13;
737 Ok(fuse_entry_out {
738 nodeid: 2,
739 generation: 0,
740 entry_valid: 1,
741 entry_valid_nsec: 0,
742 attr_valid: 1,
743 attr_valid_nsec: 0,
744 attr,
745 })
746 }
747 }
748
749 #[derive(Default)]
750 struct MockSender {
751 state: u32,
752 }
753
754 impl ReplySender for MockSender {
755 fn send(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<()> {
756 let flat: Vec<u8> = bufs.iter().flat_map(|s| s.iter()).copied().collect();
757 match self.state {
758 0 => assert_eq!(flat, INIT_REPLY),
759 1 => assert_eq!(flat, GETATTR_REPLY),
760 2 => assert_eq!(flat, LOOKUP_REPLY),
761 _ => panic!("Unexpected send."),
762 }
763
764 self.state += 1;
765 Ok(())
766 }
767 }
768
769 const INIT_CALLED: u32 = 0x1;
770 const GETATTR_CALLED: u32 = 0x2;
771 const LOOKUP_CALLED: u32 = 0x4;
772
773 const INIT_REPLY: &[u8] = &[
774 80, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 31, 0, 0, 0, 0, 0, 2, 0, 41,
775 144, 12, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 0, 0, 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
776 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
777 ];
778
779 const GETATTR_REPLY: &[u8] = &[
780 120, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
781 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
782 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
783 0, 0, 237, 65, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
784 0,
785 ];
786
787 const LOOKUP_REPLY: &[u8] = &[
788 144, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
789 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
790 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
791 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 129, 0,
792 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
793 ];
794
795 #[derive(Default)]
797 struct ErrorCheckingSender {
798 last_error: Option<i32>,
799 }
800
801 impl ReplySender for ErrorCheckingSender {
802 fn send(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<()> {
803 let flat: Vec<u8> = bufs.iter().flat_map(|s| s.iter()).copied().collect();
805 if flat.len() >= 16 {
806 let error = i32::from_ne_bytes([flat[4], flat[5], flat[6], flat[7]]);
808 if error != 0 {
809 self.last_error = Some(-error); }
811 }
812 Ok(())
813 }
814 }
815
816 fn make_lookup_name_too_long() -> Vec<u8> {
818 let mut data = vec![0u8; 297]; data[0] = 0x29;
823 data[1] = 0x01;
824 data[2] = 0x00;
825 data[3] = 0x00;
826
827 data[4] = 0x01;
829 data[5] = 0x00;
830 data[6] = 0x00;
831 data[7] = 0x00;
832
833 data[8] = 99;
835 data[9] = 0x00;
836 data[10] = 0x00;
837 data[11] = 0x00;
838 data[12] = 0x00;
839 data[13] = 0x00;
840 data[14] = 0x00;
841 data[15] = 0x00;
842
843 data[16] = 0x01;
845 data[17] = 0x00;
846 data[18] = 0x00;
847 data[19] = 0x00;
848 data[20] = 0x00;
849 data[21] = 0x00;
850 data[22] = 0x00;
851 data[23] = 0x00;
852
853 data[32] = 0xCB;
857 data[33] = 0x03;
858 data[34] = 0x00;
859 data[35] = 0x00;
860
861 for item in data.iter_mut().take(296).skip(40) {
865 *item = 0x61; }
867 data[296] = 0x00;
869
870 data
871 }
872}