1pub mod traits {
25 use crate::vfs::traits;
26
27 pub trait RecvErr<Err> {
28 fn signal(&self, err: Err);
29 }
30
31 pub trait RecvStat<'vfs, VFS, Err>: RecvErr<Err>
32 where
33 VFS: traits::VFS,
34 Err: From<VFS::Err>,
35 {
36 fn stat<'s>(&self, ctx: VFS::Ctx<'vfs>, rel: VFS::PathRef<'s>) -> Result<VFS::Stat, VFS::Err>;
37 }
38
39 #[derive(Clone, Debug)]
40 pub struct HydratedLink<P> {
41 pub relpath: P,
42 pub target: P,
43 }
44
45 #[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
46 pub enum BrokenLinkBehavior {
47 #[default]
48 IgnoreBroken,
49 ErrorOnBroken,
50 }
51
52 pub trait RecvLink<'vfs, VFS, Err>: RecvStat<'vfs, VFS, Err>
53 where
54 VFS: traits::VFS,
55 Err: From<VFS::Err>,
56 {
57 fn read_link<'s>(
58 &self,
59 ctx: VFS::Ctx<'vfs>,
60 rel: VFS::PathRef<'s>,
61 ) -> Result<VFS::OwnedPath, VFS::Err>;
62 fn send_link(
63 &self,
64 ctx: VFS::Ctx<'vfs>,
65 link: HydratedLink<VFS::OwnedPath>,
66 opts: BrokenLinkBehavior,
67 );
68 }
69
70 pub trait RecvFile<'vfs, VFS, Err>: RecvStat<'vfs, VFS, Err>
71 where
72 VFS: traits::VFS,
73 Err: From<VFS::Err>,
74 {
75 fn send_file(
76 &self,
77 ctx: VFS::Ctx<'vfs>,
78 rel: VFS::OwnedPath,
79 stat: Option<VFS::Stat>,
80 opts: VFS::FileOptions,
81 );
82 }
83
84 pub trait RecvDir<'vfs, VFS, Err>: RecvStat<'vfs, VFS, Err>
85 where
86 VFS: traits::VFS,
87 Err: From<VFS::Err>,
88 {
89 fn send_dir(&self, ctx: VFS::Ctx<'vfs>, rel: VFS::OwnedPath, stat: Option<VFS::Stat>);
90 }
91
92 pub trait RecvDirEntry<'vfs, VFS, Err>: RecvStat<'vfs, VFS, Err>
93 where
94 VFS: traits::VFS,
95 Err: From<VFS::Err>,
96 {
97 fn owned_name<'dir, 's>(
98 name: <<VFS::Dir<'vfs> as traits::DirectoryStream>::DirEntry<'dir> as traits::DirectoryEntry>::PathRef<'s>,
99 ) -> <<VFS::Dir<'vfs> as traits::DirectoryStream>::DirEntry<'dir> as traits::DirectoryEntry>::OwnedPath;
100 fn send_dir_entry(
101 &self,
102 ctx: VFS::Ctx<'vfs>,
103 file_type: traits::FileType,
104 name: <<VFS::Dir<'vfs> as traits::DirectoryStream>::DirEntry<'static> as traits::DirectoryEntry>::OwnedPath,
105 stat: Option<VFS::Stat>,
106 );
107 }
108}
109
110
111pub mod channels {
112 use std::sync::mpsc;
113
114 use super::traits;
115
116 #[derive(Debug, Clone)]
117 pub struct RecvErr<Err> {
118 sender: mpsc::SyncSender<Err>,
119 }
120
121 impl<Err> traits::RecvErr<Err> for RecvErr<Err> {
122 fn signal(&self, err: Err) { self.sender.send(err).unwrap(); }
123 }
124
125 #[derive(Debug, Clone)]
126 pub struct RecvStat<'vfs, VFS, Err> {
127 vfs: &'vfs VFS,
128 err: RecvErr<Err>,
129 }
130
131 impl<'vfs, VFS, Err> traits::RecvErr<Err> for RecvStat<'vfs, VFS, Err> {
132 fn signal(&self, err: Err) { self.err.signal(err); }
133 }
134
135 impl<'vfs, VFS, Err> traits::RecvStat<'vfs, VFS, Err> for RecvStat<'vfs, VFS, Err>
136 where
137 VFS: crate::vfs::traits::VFS,
138 Err: From<VFS::Err>,
139 {
140 fn stat<'s>(&self, ctx: VFS::Ctx<'vfs>, rel: VFS::PathRef<'s>) -> Result<VFS::Stat, VFS::Err> {
141 self.vfs.stat(ctx, rel)
142 }
143 }
144
145 #[derive(Debug, Clone)]
146 pub struct RecvLink<'vfs, VFS, Err, Link> {
147 stat: RecvStat<'vfs, VFS, Err>,
148 sender: mpsc::Sender<Link>,
149 }
150
151 impl<'vfs, VFS, Err, Link> traits::RecvErr<Err> for RecvLink<'vfs, VFS, Err, Link> {
152 fn signal(&self, err: Err) { self.stat.signal(err); }
153 }
154
155 impl<'vfs, VFS, Err, Link> traits::RecvStat<'vfs, VFS, Err> for RecvLink<'vfs, VFS, Err, Link>
156 where
157 VFS: crate::vfs::traits::VFS,
158 Err: From<VFS::Err>,
159 {
160 fn stat<'s>(&self, ctx: VFS::Ctx<'vfs>, rel: VFS::PathRef<'s>) -> Result<VFS::Stat, VFS::Err> {
161 self.stat.stat(ctx, rel)
162 }
163 }
164
165 impl<'vfs, VFS, Err> traits::RecvLink<'vfs, VFS, Err>
166 for RecvLink<
167 'vfs,
168 VFS,
169 Err,
170 (
171 VFS::Ctx<'vfs>,
172 traits::HydratedLink<VFS::OwnedPath>,
173 traits::BrokenLinkBehavior,
174 ),
175 >
176 where
177 VFS: crate::vfs::traits::VFS,
178 Err: From<VFS::Err>,
179 {
180 fn read_link<'s>(
181 &self,
182 ctx: VFS::Ctx<'vfs>,
183 rel: VFS::PathRef<'s>,
184 ) -> Result<VFS::OwnedPath, VFS::Err> {
185 self.stat.vfs.read_link(ctx, rel)
186 }
187 fn send_link(
188 &self,
189 ctx: VFS::Ctx<'vfs>,
190 link: traits::HydratedLink<VFS::OwnedPath>,
191 opts: traits::BrokenLinkBehavior,
192 ) {
193 self.sender.send((ctx, link, opts)).unwrap();
194 }
195 }
196
197 #[derive(Debug, Clone)]
198 pub struct RecvFile<'vfs, VFS, Err, File> {
199 stat: RecvStat<'vfs, VFS, Err>,
200 sender: mpsc::Sender<File>,
201 }
202
203 impl<'vfs, VFS, Err, File> traits::RecvErr<Err> for RecvFile<'vfs, VFS, Err, File> {
204 fn signal(&self, err: Err) { self.stat.signal(err); }
205 }
206
207 impl<'vfs, VFS, Err, File> traits::RecvStat<'vfs, VFS, Err> for RecvFile<'vfs, VFS, Err, File>
208 where
209 VFS: crate::vfs::traits::VFS,
210 Err: From<VFS::Err>,
211 {
212 fn stat<'s>(&self, ctx: VFS::Ctx<'vfs>, rel: VFS::PathRef<'s>) -> Result<VFS::Stat, VFS::Err> {
213 self.stat.stat(ctx, rel)
214 }
215 }
216
217 impl<'vfs, VFS, Err> traits::RecvFile<'vfs, VFS, Err>
218 for RecvFile<
219 'vfs,
220 VFS,
221 Err,
222 (
223 VFS::Ctx<'vfs>,
224 VFS::OwnedPath,
225 Option<VFS::Stat>,
226 VFS::FileOptions,
227 ),
228 >
229 where
230 VFS: crate::vfs::traits::VFS,
231 Err: From<VFS::Err>,
232 {
233 fn send_file(
234 &self,
235 ctx: VFS::Ctx<'vfs>,
236 rel: VFS::OwnedPath,
237 stat: Option<VFS::Stat>,
238 opts: VFS::FileOptions,
239 ) {
240 self.sender.send((ctx, rel, stat, opts)).unwrap();
241 }
242 }
243
244 #[derive(Debug, Clone)]
245 pub struct RecvDir<'vfs, VFS, Err, Dir> {
246 stat: RecvStat<'vfs, VFS, Err>,
247 sender: mpsc::Sender<Dir>,
248 }
249
250 impl<'vfs, VFS, Err, Dir> traits::RecvErr<Err> for RecvDir<'vfs, VFS, Err, Dir> {
251 fn signal(&self, err: Err) { self.stat.signal(err); }
252 }
253
254 impl<'vfs, VFS, Err, Dir> traits::RecvStat<'vfs, VFS, Err> for RecvDir<'vfs, VFS, Err, Dir>
255 where
256 VFS: crate::vfs::traits::VFS,
257 Err: From<VFS::Err>,
258 {
259 fn stat<'s>(&self, ctx: VFS::Ctx<'vfs>, rel: VFS::PathRef<'s>) -> Result<VFS::Stat, VFS::Err> {
260 self.stat.stat(ctx, rel)
261 }
262 }
263
264 impl<'vfs, VFS, Err> traits::RecvDir<'vfs, VFS, Err>
265 for RecvDir<'vfs, VFS, Err, (VFS::Ctx<'vfs>, VFS::OwnedPath, Option<VFS::Stat>)>
266 where
267 VFS: crate::vfs::traits::VFS,
268 Err: From<VFS::Err>,
269 {
270 fn send_dir(&self, ctx: VFS::Ctx<'vfs>, rel: VFS::OwnedPath, stat: Option<VFS::Stat>) {
271 self.sender.send((ctx, rel, stat)).unwrap();
272 }
273 }
274
275 #[derive(Debug, Clone)]
276 pub struct RecvDirEntry<'vfs, VFS, Err, DirEntry> {
277 stat: RecvStat<'vfs, VFS, Err>,
278 sender: mpsc::Sender<DirEntry>,
279 }
280
281 impl<'vfs, VFS, Err, DirEntry> traits::RecvErr<Err> for RecvDirEntry<'vfs, VFS, Err, DirEntry> {
282 fn signal(&self, err: Err) { self.stat.signal(err); }
283 }
284
285 impl<'vfs, VFS, Err, DirEntry> traits::RecvStat<'vfs, VFS, Err>
286 for RecvDirEntry<'vfs, VFS, Err, DirEntry>
287 where
288 VFS: crate::vfs::traits::VFS,
289 Err: From<VFS::Err>,
290 {
291 fn stat<'s>(&self, ctx: VFS::Ctx<'vfs>, rel: VFS::PathRef<'s>) -> Result<VFS::Stat, VFS::Err> {
292 self.stat.stat(ctx, rel)
293 }
294 }
295
296 impl<'vfs, VFS, Err> traits::RecvDirEntry<'vfs, VFS, Err>
297 for RecvDirEntry<
298 'vfs,
299 VFS,
300 Err,
301 (
302 VFS::Ctx<'vfs>,
303 crate::vfs::traits::FileType,
304 <<VFS::Dir<'vfs> as crate::vfs::traits::DirectoryStream>::DirEntry<'static> as crate::vfs::traits::DirectoryEntry>::OwnedPath,
305 Option<VFS::Stat>,
306 ),
307 >
308 where
309 VFS: crate::vfs::traits::VFS,
310 Err: From<VFS::Err>,
311 {
312 fn owned_name<'dir, 's>(
313 name: <<VFS::Dir<'vfs> as crate::vfs::traits::DirectoryStream>::DirEntry<'dir> as crate::vfs::traits::DirectoryEntry>::PathRef<'s>,
314 ) -> <<VFS::Dir<'vfs> as crate::vfs::traits::DirectoryStream>::DirEntry<'dir> as crate::vfs::traits::DirectoryEntry>::OwnedPath {
315 <<VFS::Dir<'vfs> as crate::vfs::traits::DirectoryStream>::DirEntry<'dir> as crate::vfs::traits::DirectoryEntry>::owned_name(name)
316 }
317 fn send_dir_entry(
318 &self,
319 ctx: VFS::Ctx<'vfs>,
320 file_type: crate::vfs::traits::FileType,
321 name: <<VFS::Dir<'vfs> as crate::vfs::traits::DirectoryStream>::DirEntry<'static> as crate::vfs::traits::DirectoryEntry>::OwnedPath,
322 stat: Option<VFS::Stat>,
323 ) {
324 self.sender.send((ctx, file_type, name, stat)).unwrap();
325 }
326 }
327}
328
329
330pub mod dir_handles {
331 use std::{
332 os::fd,
333 sync::atomic::{AtomicUsize, Ordering},
334 };
335
336 use indexmap::IndexMap;
337 use parking_lot::RwLock;
338
339 use crate::handles::DirFd;
340
341
342 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
343 pub struct DirToken(fd::RawFd);
344
345 pub struct DirState<R, Ctx> {
346 dir: DirFd<R>,
347 num_entries: AtomicUsize,
348 ctx: Ctx,
349 }
350
351 impl<R, Ctx> DirState<R, Ctx> {
352 pub const fn new(dir: DirFd<R>, ctx: Ctx) -> Self {
353 Self {
354 dir,
355 num_entries: AtomicUsize::new(0),
356 ctx,
357 }
358 }
359 }
360
361 pub struct OpenDirHandles<R, Ctx> {
362 handles: RwLock<IndexMap<DirToken, DirState<R, Ctx>>>,
363 }
364
365 pub struct DirEntry<Info> {
366 token: DirToken,
367 info: Info,
368 }
369}