1use crate::{
2 io::{AccessFlags, Known, Mode, OpenFlags, Stat, Ttl},
3 proto::{self, OpenOutFlags},
4 sealed::Sealed,
5 util::OutputChain,
6 Done, Errno, Operation, Reply, Request,
7};
8
9use super::{
10 c_to_os, make_entry,
11 traits::{ReplyKnown, ReplyOk, RequestFlags, RequestHandle, RequestMode, RequestName},
12 FromRequest,
13};
14
15use bytemuck::bytes_of;
16use std::ffi::{CStr, OsStr};
17
18pub enum Open {}
19pub enum Release {}
20pub enum Opendir {}
21pub enum Releasedir {}
22pub enum Access {}
23pub enum Create {}
24
25pub trait ReplyOpen<'o>: Operation<'o, ReplyState = OpenOutFlags> {
26 fn ok_with_handle(reply: Reply<'o, Self>, handle: u64) -> Done<'o>
27 where
28 Self: ReplyOk<'o>,
29 {
30 let open_flags = open_flags_bits(reply.state);
31
32 reply.single(&proto::OpenOut {
33 fh: handle,
34 open_flags,
35 padding: Default::default(),
36 })
37 }
38
39 fn known_with_handle(
40 reply: Reply<'o, Self>,
41 known: impl Known,
42 ttl: Ttl,
43 handle: u64,
44 ) -> Done<'o>
45 where
46 Self: ReplyKnown<'o>,
47 {
48 let (attrs, attrs_ttl) = known.inode().attrs();
49 let attrs = attrs.finish(known.inode());
50
51 let entry = make_entry((known.inode().ino(), ttl), (attrs, attrs_ttl));
52 let open = proto::OpenOut {
53 fh: handle,
54 open_flags: open_flags_bits(reply.state),
55 padding: Default::default(),
56 };
57
58 let done = reply.chain(OutputChain::tail(&[bytes_of(&entry), bytes_of(&open)]));
59 known.unveil();
60
61 done
62 }
63
64 fn force_direct_io(reply: &mut Reply<'o, Self>) {
65 reply.state |= OpenOutFlags::DIRECT_IO;
66 }
67
68 fn non_seekable(reply: &mut Reply<'o, Self>) {
69 reply.state |= OpenOutFlags::NONSEEKABLE;
70 }
71
72 fn is_stream(reply: &mut Reply<'o, Self>) {
73 reply.state |= OpenOutFlags::STREAM;
74 }
75}
76
77pub trait ReplyPermissionDenied<'o>: Operation<'o> {
78 fn permission_denied(reply: Reply<'o, Self>) -> Done<'o> {
79 reply.fail(Errno::EACCES)
80 }
81}
82
83impl Sealed for Open {}
84impl Sealed for Release {}
85impl Sealed for Opendir {}
86impl Sealed for Releasedir {}
87impl Sealed for Access {}
88impl Sealed for Create {}
89
90impl<'o> Operation<'o> for Open {
91 type RequestBody = &'o proto::OpenIn;
92 type ReplyState = OpenOutFlags;
93}
94
95impl<'o> Operation<'o> for Release {
96 type RequestBody = &'o proto::ReleaseIn;
97 type ReplyState = ();
98}
99
100impl<'o> Operation<'o> for Opendir {
101 type RequestBody = &'o proto::OpendirIn;
102 type ReplyState = OpenOutFlags;
103}
104
105impl<'o> Operation<'o> for Releasedir {
106 type RequestBody = &'o proto::ReleasedirIn;
107 type ReplyState = ();
108}
109
110impl<'o> Operation<'o> for Access {
111 type RequestBody = &'o proto::AccessIn;
112 type ReplyState = ();
113}
114
115impl<'o> Operation<'o> for Create {
116 type RequestBody = (&'o proto::CreateIn, &'o CStr);
117 type ReplyState = OpenOutFlags;
118}
119
120impl<'o> RequestFlags<'o> for Open {
121 type Flags = OpenFlags;
122
123 fn flags(request: &Request<'o, Self>) -> Self::Flags {
124 OpenFlags::from_bits_truncate(request.body.flags as _)
125 }
126}
127
128impl<'o> ReplyOk<'o> for Open {
129 fn ok(reply: Reply<'o, Self>) -> Done<'o> {
130 reply.ok_with_handle(0)
131 }
132}
133
134impl<'o> ReplyOpen<'o> for Open {}
135impl<'o> ReplyPermissionDenied<'o> for Open {}
136
137impl<'o> RequestHandle<'o> for Release {
138 fn handle(request: &Request<'o, Self>) -> u64 {
139 request.body.fh
140 }
141}
142
143impl<'o> ReplyOk<'o> for Release {}
144
145impl<'o> ReplyOk<'o> for Opendir {
146 fn ok(reply: Reply<'o, Self>) -> Done<'o> {
147 reply.ok_with_handle(0)
148 }
149}
150
151impl<'o> ReplyPermissionDenied<'o> for Opendir {}
152impl<'o> ReplyOpen<'o> for Opendir {}
153
154impl<'o> RequestHandle<'o> for Releasedir {
155 fn handle(request: &Request<'o, Self>) -> u64 {
156 request.body.release_in.fh
157 }
158}
159
160impl<'o> ReplyOk<'o> for Releasedir {}
161
162impl<'o> RequestFlags<'o> for Access {
163 type Flags = AccessFlags;
164
165 fn flags(request: &Request<'o, Self>) -> Self::Flags {
166 AccessFlags::from_bits_truncate(request.body.mask as i32)
167 }
168}
169
170impl<'o> ReplyOk<'o> for Access {}
171
172impl<'o> ReplyPermissionDenied<'o> for Access {}
173
174impl<'o, O: ReplyOpen<'o>> FromRequest<'o, O> for OpenOutFlags {
175 fn from_request(_request: &Request<'o, O>) -> Self {
176 OpenOutFlags::empty()
177 }
178}
179
180impl<'o> RequestName<'o> for Create {
181 fn name<'a>(request: &'a Request<'o, Self>) -> &'a OsStr {
182 let (_header, name) = request.body;
183 c_to_os(name)
184 }
185}
186
187impl<'o> RequestMode<'o> for Create {
188 fn mode(request: &Request<'o, Self>) -> Mode {
189 let (header, _name) = request.body;
190 Mode::from_bits_truncate(header.mode)
191 }
192
193 fn umask(request: &Request<'o, Self>) -> Mode {
194 let (header, _name) = request.body;
195 Mode::from_bits_truncate(header.umask)
196 }
197}
198
199impl<'o> RequestFlags<'o> for Create {
200 type Flags = OpenFlags;
201
202 fn flags(request: &Request<'o, Self>) -> Self::Flags {
203 let (header, _name) = request.body;
204 OpenFlags::from_bits_truncate(header.flags as _)
205 }
206}
207
208impl<'o> ReplyKnown<'o> for Create {
209 fn known(reply: Reply<'o, Self>, entry: impl Known, ttl: Ttl) -> Done<'o> {
210 reply.known_with_handle(entry, ttl, 0)
211 }
212}
213
214impl<'o> ReplyOpen<'o> for Create {}
215impl<'o> ReplyPermissionDenied<'o> for Create {}
216
217fn open_flags_bits(flags: OpenOutFlags) -> u32 {
218 (flags | OpenOutFlags::KEEP_CACHE | OpenOutFlags::CACHE_DIR).bits()
219}