1use crate::ll::{Errno, Response, fuse_abi as abi};
9use log::{debug, error, warn};
10use std::convert::TryFrom;
11#[cfg(feature = "abi-7-28")]
12use std::convert::TryInto;
13use std::path::Path;
14use std::sync::atomic::Ordering;
15
16use crate::Filesystem;
17use crate::PollHandle;
18use crate::channel::ChannelSender;
19use crate::ll::Request as _;
20#[cfg(feature = "abi-7-21")]
21use crate::reply::ReplyDirectoryPlus;
22use crate::reply::{Reply, ReplyDirectory, ReplySender};
23use crate::session::{Session, SessionACL};
24use crate::{KernelConfig, ll};
25
26#[derive(Debug)]
28pub struct Request<'a> {
29 ch: ChannelSender,
31 #[allow(unused)]
33 data: &'a [u8],
34 request: ll::AnyRequest<'a>,
36}
37
38impl<'a> Request<'a> {
39 pub(crate) fn new(ch: ChannelSender, data: &'a [u8]) -> Option<Request<'a>> {
41 let request = match ll::AnyRequest::try_from(data) {
42 Ok(request) => request,
43 Err(err) => {
44 error!("{err}");
45 return None;
46 }
47 };
48
49 Some(Self { ch, data, request })
50 }
51
52 pub(crate) fn dispatch<FS: Filesystem>(&self, se: &Session<FS>) {
56 debug!("{}", self.request);
57 let unique = self.request.unique();
58
59 let res = match self.dispatch_req(se) {
60 Ok(Some(resp)) => resp,
61 Ok(None) => return,
62 Err(errno) => self.request.reply_err(errno),
63 }
64 .with_iovec(unique, |iov| self.ch.send(iov));
65
66 if let Err(err) = res {
67 warn!("Request {unique:?}: Failed to send reply: {err}");
68 }
69 }
70
71 fn dispatch_req<FS: Filesystem>(
72 &self,
73 se: &Session<FS>,
74 ) -> Result<Option<Response<'_>>, Errno> {
75 let op = self.request.operation().map_err(|_| Errno::ENOSYS)?;
76 if (se.allowed == SessionACL::RootAndOwner
78 && self.request.uid() != se.session_owner
79 && self.request.uid() != 0)
80 || (se.allowed == SessionACL::Owner && self.request.uid() != se.session_owner)
81 {
82 #[cfg(feature = "abi-7-21")]
83 {
84 match op {
85 ll::Operation::Init(_)
87 | ll::Operation::Destroy(_)
88 | ll::Operation::Read(_)
89 | ll::Operation::ReadDir(_)
90 | ll::Operation::ReadDirPlus(_)
91 | ll::Operation::BatchForget(_)
92 | ll::Operation::Forget(_)
93 | ll::Operation::Write(_)
94 | ll::Operation::FSync(_)
95 | ll::Operation::FSyncDir(_)
96 | ll::Operation::Release(_)
97 | ll::Operation::ReleaseDir(_) => {}
98 _ => {
99 return Err(Errno::EACCES);
100 }
101 }
102 }
103 #[cfg(not(feature = "abi-7-21"))]
104 {
105 match op {
106 ll::Operation::Init(_)
108 | ll::Operation::Destroy(_)
109 | ll::Operation::Read(_)
110 | ll::Operation::ReadDir(_)
111 | ll::Operation::BatchForget(_)
112 | ll::Operation::Forget(_)
113 | ll::Operation::Write(_)
114 | ll::Operation::FSync(_)
115 | ll::Operation::FSyncDir(_)
116 | ll::Operation::Release(_)
117 | ll::Operation::ReleaseDir(_) => {}
118 _ => {
119 return Err(Errno::EACCES);
120 }
121 }
122 }
123 }
124 match op {
125 ll::Operation::Init(x) => {
127 let v = x.version();
129 if v < ll::Version(7, 6) {
130 error!("Unsupported FUSE ABI version {v}");
131 return Err(Errno::EPROTO);
132 }
133 se.proto_major.store(v.major(), Ordering::SeqCst);
135 se.proto_minor.store(v.minor(), Ordering::SeqCst);
136
137 let mut config = KernelConfig::new(x.capabilities(), x.max_readahead());
138 se.filesystem
140 .init(self, &mut config)
141 .map_err(Errno::from_i32)?;
142
143 debug!(
147 "INIT response: ABI {}.{}, flags {:#x}, max readahead {}, max write {}",
148 abi::FUSE_KERNEL_VERSION,
149 abi::FUSE_KERNEL_MINOR_VERSION,
150 x.capabilities() & config.requested,
151 config.max_readahead,
152 config.max_write
153 );
154 se.initialized.store(true, Ordering::SeqCst);
155 return Ok(Some(x.reply(&config)));
156 }
157 _ if !se.initialized.load(Ordering::SeqCst) => {
159 warn!("Ignoring FUSE operation before init: {}", self.request);
160 return Err(Errno::EIO);
161 }
162 ll::Operation::Destroy(x) => {
164 if !se.destroyed.swap(true, Ordering::SeqCst) {
165 se.filesystem.destroy();
166 }
167 return Ok(Some(x.reply()));
168 }
169 _ if se.destroyed.load(Ordering::SeqCst) => {
171 warn!("Ignoring FUSE operation after destroy: {}", self.request);
172 return Err(Errno::EIO);
173 }
174
175 ll::Operation::Interrupt(_) => {
176 return Err(Errno::ENOSYS);
178 }
179
180 ll::Operation::Lookup(x) => {
181 se.filesystem.lookup(
182 self,
183 self.request.nodeid().into(),
184 x.name().as_ref(),
185 self.reply(),
186 );
187 }
188 ll::Operation::Forget(x) => {
189 se.filesystem
190 .forget(self, self.request.nodeid().into(), x.nlookup()); }
192 ll::Operation::GetAttr(_attr) => {
193 se.filesystem.getattr(
194 self,
195 self.request.nodeid().into(),
196 _attr.file_handle().map(|fh| fh.into()),
197 self.reply(),
198 );
199 }
200 ll::Operation::SetAttr(x) => {
201 se.filesystem.setattr(
202 self,
203 self.request.nodeid().into(),
204 x.mode(),
205 x.uid(),
206 x.gid(),
207 x.size(),
208 x.atime(),
209 x.mtime(),
210 x.ctime(),
211 x.file_handle().map(|fh| fh.into()),
212 x.crtime(),
213 x.chgtime(),
214 x.bkuptime(),
215 x.flags(),
216 self.reply(),
217 );
218 }
219 ll::Operation::ReadLink(_) => {
220 se.filesystem
221 .readlink(self, self.request.nodeid().into(), self.reply());
222 }
223 ll::Operation::MkNod(x) => {
224 se.filesystem.mknod(
225 self,
226 self.request.nodeid().into(),
227 x.name().as_ref(),
228 x.mode(),
229 x.umask(),
230 x.rdev(),
231 self.reply(),
232 );
233 }
234 ll::Operation::MkDir(x) => {
235 se.filesystem.mkdir(
236 self,
237 self.request.nodeid().into(),
238 x.name().as_ref(),
239 x.mode(),
240 x.umask(),
241 self.reply(),
242 );
243 }
244 ll::Operation::Unlink(x) => {
245 se.filesystem.unlink(
246 self,
247 self.request.nodeid().into(),
248 x.name().as_ref(),
249 self.reply(),
250 );
251 }
252 ll::Operation::RmDir(x) => {
253 se.filesystem.rmdir(
254 self,
255 self.request.nodeid().into(),
256 x.name().as_ref(),
257 self.reply(),
258 );
259 }
260 ll::Operation::SymLink(x) => {
261 se.filesystem.symlink(
262 self,
263 self.request.nodeid().into(),
264 x.link_name().as_ref(),
265 Path::new(x.target()),
266 self.reply(),
267 );
268 }
269 ll::Operation::Rename(x) => {
270 se.filesystem.rename(
271 self,
272 self.request.nodeid().into(),
273 x.src().name.as_ref(),
274 x.dest().dir.into(),
275 x.dest().name.as_ref(),
276 0,
277 self.reply(),
278 );
279 }
280 ll::Operation::Link(x) => {
281 se.filesystem.link(
282 self,
283 x.inode_no().into(),
284 self.request.nodeid().into(),
285 x.dest().name.as_ref(),
286 self.reply(),
287 );
288 }
289 ll::Operation::Open(x) => {
290 se.filesystem
291 .open(self, self.request.nodeid().into(), x.flags(), self.reply());
292 }
293 ll::Operation::Read(x) => {
294 se.filesystem.read(
295 self,
296 self.request.nodeid().into(),
297 x.file_handle().into(),
298 x.offset(),
299 x.size(),
300 x.flags(),
301 x.lock_owner().map(|l| l.into()),
302 self.reply(),
303 );
304 }
305 ll::Operation::Write(x) => {
306 se.filesystem.write(
307 self,
308 self.request.nodeid().into(),
309 x.file_handle().into(),
310 x.offset(),
311 x.data(),
312 x.write_flags(),
313 x.flags(),
314 x.lock_owner().map(|l| l.into()),
315 self.reply(),
316 );
317 }
318 ll::Operation::Flush(x) => {
319 se.filesystem.flush(
320 self,
321 self.request.nodeid().into(),
322 x.file_handle().into(),
323 x.lock_owner().into(),
324 self.reply(),
325 );
326 }
327 ll::Operation::Release(x) => {
328 se.filesystem.release(
329 self,
330 self.request.nodeid().into(),
331 x.file_handle().into(),
332 x.flags(),
333 x.lock_owner().map(|x| x.into()),
334 x.flush(),
335 self.reply(),
336 );
337 }
338 ll::Operation::FSync(x) => {
339 se.filesystem.fsync(
340 self,
341 self.request.nodeid().into(),
342 x.file_handle().into(),
343 x.fdatasync(),
344 self.reply(),
345 );
346 }
347 ll::Operation::OpenDir(x) => {
348 se.filesystem
349 .opendir(self, self.request.nodeid().into(), x.flags(), self.reply());
350 }
351 ll::Operation::ReadDir(x) => {
352 se.filesystem.readdir(
353 self,
354 self.request.nodeid().into(),
355 x.file_handle().into(),
356 x.offset(),
357 ReplyDirectory::new(
358 self.request.unique().into(),
359 self.ch.clone(),
360 x.size() as usize,
361 ),
362 );
363 }
364 ll::Operation::ReleaseDir(x) => {
365 se.filesystem.releasedir(
366 self,
367 self.request.nodeid().into(),
368 x.file_handle().into(),
369 x.flags(),
370 self.reply(),
371 );
372 }
373 ll::Operation::FSyncDir(x) => {
374 se.filesystem.fsyncdir(
375 self,
376 self.request.nodeid().into(),
377 x.file_handle().into(),
378 x.fdatasync(),
379 self.reply(),
380 );
381 }
382 ll::Operation::StatFs(_) => {
383 se.filesystem
384 .statfs(self, self.request.nodeid().into(), self.reply());
385 }
386 ll::Operation::SetXAttr(x) => {
387 se.filesystem.setxattr(
388 self,
389 self.request.nodeid().into(),
390 x.name(),
391 x.value(),
392 x.flags(),
393 x.position(),
394 self.reply(),
395 );
396 }
397 ll::Operation::GetXAttr(x) => {
398 se.filesystem.getxattr(
399 self,
400 self.request.nodeid().into(),
401 x.name(),
402 x.size_u32(),
403 self.reply(),
404 );
405 }
406 ll::Operation::ListXAttr(x) => {
407 se.filesystem
408 .listxattr(self, self.request.nodeid().into(), x.size(), self.reply());
409 }
410 ll::Operation::RemoveXAttr(x) => {
411 se.filesystem.removexattr(
412 self,
413 self.request.nodeid().into(),
414 x.name(),
415 self.reply(),
416 );
417 }
418 ll::Operation::Access(x) => {
419 se.filesystem
420 .access(self, self.request.nodeid().into(), x.mask(), self.reply());
421 }
422 ll::Operation::Create(x) => {
423 se.filesystem.create(
424 self,
425 self.request.nodeid().into(),
426 x.name().as_ref(),
427 x.mode(),
428 x.umask(),
429 x.flags(),
430 self.reply(),
431 );
432 }
433 ll::Operation::GetLk(x) => {
434 se.filesystem.getlk(
435 self,
436 self.request.nodeid().into(),
437 x.file_handle().into(),
438 x.lock_owner().into(),
439 x.lock().range.0,
440 x.lock().range.1,
441 x.lock().typ,
442 x.lock().pid,
443 self.reply(),
444 );
445 }
446 ll::Operation::SetLk(x) => {
447 se.filesystem.setlk(
448 self,
449 self.request.nodeid().into(),
450 x.file_handle().into(),
451 x.lock_owner().into(),
452 x.lock().range.0,
453 x.lock().range.1,
454 x.lock().typ,
455 x.lock().pid,
456 false,
457 self.reply(),
458 );
459 }
460 ll::Operation::SetLkW(x) => {
461 se.filesystem.setlk(
462 self,
463 self.request.nodeid().into(),
464 x.file_handle().into(),
465 x.lock_owner().into(),
466 x.lock().range.0,
467 x.lock().range.1,
468 x.lock().typ,
469 x.lock().pid,
470 true,
471 self.reply(),
472 );
473 }
474 ll::Operation::BMap(x) => {
475 se.filesystem.bmap(
476 self,
477 self.request.nodeid().into(),
478 x.block_size(),
479 x.block(),
480 self.reply(),
481 );
482 }
483
484 ll::Operation::IoCtl(x) => {
485 if x.unrestricted() {
486 return Err(Errno::ENOSYS);
487 } else {
488 se.filesystem.ioctl(
489 self,
490 self.request.nodeid().into(),
491 x.file_handle().into(),
492 x.flags(),
493 x.command(),
494 x.in_data(),
495 x.out_size(),
496 self.reply(),
497 );
498 }
499 }
500 ll::Operation::Poll(x) => {
501 let ph = PollHandle::new(se.ch.sender(), x.kernel_handle());
502
503 se.filesystem.poll(
504 self,
505 self.request.nodeid().into(),
506 x.file_handle().into(),
507 ph,
508 x.events(),
509 x.flags(),
510 self.reply(),
511 );
512 }
513 ll::Operation::NotifyReply(_) => {
514 return Err(Errno::ENOSYS);
516 }
517 ll::Operation::BatchForget(x) => {
518 se.filesystem.batch_forget(self, x.nodes()); }
520 #[cfg(feature = "abi-7-19")]
521 ll::Operation::FAllocate(x) => {
522 se.filesystem.fallocate(
523 self,
524 self.request.nodeid().into(),
525 x.file_handle().into(),
526 x.offset(),
527 x.len(),
528 x.mode(),
529 self.reply(),
530 );
531 }
532 #[cfg(feature = "abi-7-21")]
533 ll::Operation::ReadDirPlus(x) => {
534 se.filesystem.readdirplus(
535 self,
536 self.request.nodeid().into(),
537 x.file_handle().into(),
538 x.offset(),
539 ReplyDirectoryPlus::new(
540 self.request.unique().into(),
541 self.ch.clone(),
542 x.size() as usize,
543 ),
544 );
545 }
546 #[cfg(feature = "abi-7-23")]
547 ll::Operation::Rename2(x) => {
548 se.filesystem.rename(
549 self,
550 x.from().dir.into(),
551 x.from().name.as_ref(),
552 x.to().dir.into(),
553 x.to().name.as_ref(),
554 x.flags(),
555 self.reply(),
556 );
557 }
558 #[cfg(feature = "abi-7-24")]
559 ll::Operation::Lseek(x) => {
560 se.filesystem.lseek(
561 self,
562 self.request.nodeid().into(),
563 x.file_handle().into(),
564 x.offset(),
565 x.whence(),
566 self.reply(),
567 );
568 }
569 #[cfg(feature = "abi-7-28")]
570 ll::Operation::CopyFileRange(x) => {
571 let (i, o) = (x.src(), x.dest());
572 se.filesystem.copy_file_range(
573 self,
574 i.inode.into(),
575 i.file_handle.into(),
576 i.offset,
577 o.inode.into(),
578 o.file_handle.into(),
579 o.offset,
580 x.len(),
581 x.flags().try_into().unwrap(),
582 self.reply(),
583 );
584 }
585 #[cfg(target_os = "macos")]
586 ll::Operation::SetVolName(x) => {
587 se.filesystem.setvolname(self, x.name(), self.reply());
588 }
589 #[cfg(target_os = "macos")]
590 ll::Operation::GetXTimes(x) => {
591 se.filesystem
592 .getxtimes(self, x.nodeid().into(), self.reply());
593 }
594 #[cfg(target_os = "macos")]
595 ll::Operation::Exchange(x) => {
596 se.filesystem.exchange(
597 self,
598 x.from().dir.into(),
599 x.from().name.as_ref(),
600 x.to().dir.into(),
601 x.to().name.as_ref(),
602 x.options(),
603 self.reply(),
604 );
605 }
606
607 ll::Operation::CuseInit(_) => {
608 return Err(Errno::ENOSYS);
610 }
611 }
612 Ok(None)
613 }
614
615 fn reply<T: Reply>(&self) -> T {
618 Reply::new(self.request.unique().into(), self.ch.clone())
619 }
620
621 #[inline]
623 pub fn unique(&self) -> u64 {
624 self.request.unique().into()
625 }
626
627 #[inline]
629 pub fn uid(&self) -> u32 {
630 self.request.uid()
631 }
632
633 #[inline]
635 pub fn gid(&self) -> u32 {
636 self.request.gid()
637 }
638
639 #[inline]
641 pub fn pid(&self) -> u32 {
642 self.request.pid()
643 }
644
645 pub fn is_forget(&self) -> bool {
647 matches!(
648 self.request.opcode(),
649 Ok(abi::fuse_opcode::FUSE_FORGET) | Ok(abi::fuse_opcode::FUSE_BATCH_FORGET)
650 )
651 }
652}