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 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
59impl<'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 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}