blown_fuse/ops/
xattr.rs

1use super::{
2    c_to_os,
3    traits::{ReplyGather, ReplyNotFound, ReplyOk, RequestData, RequestName, RequestSize},
4};
5
6use crate::{proto, sealed::Sealed, util::OutputChain, Done, Errno, Operation, Reply, Request};
7use std::ffi::{CStr, OsStr};
8
9pub enum Setxattr {}
10pub enum Getxattr {}
11pub enum Listxattr {}
12pub enum Removexattr {}
13
14pub struct XattrReadState {
15    size: u32,
16}
17
18pub trait ReplyXattrRead<'o>: Operation<'o> {
19    fn requires_size(reply: Reply<'o, Self>, size: u32) -> Done<'o>;
20
21    fn buffer_too_small(reply: Reply<'o, Self>) -> Done<'o> {
22        reply.fail(Errno::ERANGE)
23    }
24}
25
26impl Sealed for Setxattr {}
27impl Sealed for Getxattr {}
28impl Sealed for Listxattr {}
29impl Sealed for Removexattr {}
30
31impl<'o> Operation<'o> for Setxattr {
32    // header, name, value
33    type RequestBody = (&'o proto::SetxattrIn, &'o CStr, &'o [u8]);
34    type ReplyState = ();
35}
36
37impl<'o> Operation<'o> for Getxattr {
38    type RequestBody = (&'o proto::GetxattrIn, &'o CStr);
39    type ReplyState = XattrReadState;
40}
41
42impl<'o> Operation<'o> for Listxattr {
43    type RequestBody = &'o proto::ListxattrIn;
44    type ReplyState = XattrReadState;
45}
46
47impl<'o> Operation<'o> for Removexattr {
48    type RequestBody = &'o CStr;
49    type ReplyState = ();
50}
51
52impl<'o> RequestName<'o> for Setxattr {
53    fn name<'a>(request: &'a Request<'o, Self>) -> &'a OsStr {
54        let (_header, name, _value) = request.body;
55        c_to_os(name)
56    }
57}
58
59//TODO: flags
60impl<'o> RequestData<'o> for Setxattr {
61    fn data<'a>(request: &'a Request<'o, Self>) -> &'a [u8] {
62        let (_header, _name, value) = request.body;
63        value
64    }
65}
66
67impl<'o> ReplyOk<'o> for Setxattr {}
68
69impl<'o> ReplyNotFound<'o> for Setxattr {
70    fn not_found(reply: Reply<'o, Self>) -> Done<'o> {
71        reply.fail(Errno::ENODATA)
72    }
73}
74
75impl<'o> RequestSize<'o> for Getxattr {
76    fn size(request: &Request<'o, Self>) -> u32 {
77        request.body.0.size
78    }
79}
80
81impl<'o> RequestName<'o> for Getxattr {
82    fn name<'a>(request: &'a Request<'o, Self>) -> &'a OsStr {
83        c_to_os(request.body.1)
84    }
85}
86
87impl<'o> ReplyNotFound<'o> for Getxattr {
88    fn not_found(reply: Reply<'o, Self>) -> Done<'o> {
89        reply.fail(Errno::ENODATA)
90    }
91}
92
93impl<'o> ReplyGather<'o> for Getxattr {
94    fn gather(reply: Reply<'o, Self>, fragments: &[&[u8]]) -> Done<'o> {
95        let size = fragments
96            .iter()
97            .map(|fragment| fragment.len())
98            .sum::<usize>()
99            .try_into()
100            .expect("Extremely large xattr");
101
102        if reply.state.size == 0 {
103            return reply.requires_size(size);
104        } else if reply.state.size < size {
105            return reply.buffer_too_small();
106        }
107
108        reply.chain(OutputChain::tail(fragments))
109    }
110}
111
112impl<'o> ReplyXattrRead<'o> for Getxattr {
113    fn requires_size(reply: Reply<'o, Self>, size: u32) -> Done<'o> {
114        assert_eq!(reply.state.size, 0);
115
116        reply.single(&proto::GetxattrOut {
117            size,
118            padding: Default::default(),
119        })
120    }
121}
122
123impl<'o> RequestSize<'o> for Listxattr {
124    fn size(request: &Request<'o, Self>) -> u32 {
125        request.body.getxattr_in.size
126    }
127}
128
129impl<'o> ReplyXattrRead<'o> for Listxattr {
130    //TODO: buffered(), gather()
131
132    fn requires_size(reply: Reply<'o, Self>, size: u32) -> Done<'o> {
133        assert_eq!(reply.state.size, 0);
134
135        reply.single(&proto::ListxattrOut {
136            getxattr_out: proto::GetxattrOut {
137                size,
138                padding: Default::default(),
139            },
140        })
141    }
142}
143
144impl<'o> RequestName<'o> for Removexattr {
145    fn name<'a>(request: &'a Request<'o, Self>) -> &'a OsStr {
146        c_to_os(request.body)
147    }
148}
149
150impl<'o> ReplyOk<'o> for Removexattr {}
151
152impl<'o> ReplyNotFound<'o> for Removexattr {
153    fn not_found(reply: Reply<'o, Self>) -> Done<'o> {
154        reply.fail(Errno::ENODATA)
155    }
156}