blown_fuse/ops/
open.rs

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}