@@ -3,7 +3,7 @@ use std::os::unix::ffi::OsStrExt;
3
3
use std:: {
4
4
fmt:: { Debug , Formatter } ,
5
5
io:: SeekFrom ,
6
- sync:: { Arc , OnceLock } ,
6
+ sync:: OnceLock ,
7
7
time:: SystemTime ,
8
8
} ;
9
9
@@ -16,9 +16,10 @@ use dav_server::{
16
16
} ,
17
17
} ;
18
18
use futures:: FutureExt ;
19
+ use tokio:: sync:: { mpsc, oneshot} ;
19
20
20
21
use rustic_core:: {
21
- repofile :: Node ,
22
+ refile :: Node ,
22
23
vfs:: { FilePolicy , OpenFile , Vfs } ,
23
24
IndexedFull , Repository ,
24
25
} ;
@@ -40,6 +41,102 @@ struct DavFsInner<P, S> {
40
41
file_policy : FilePolicy ,
41
42
}
42
43
44
+ impl < P , S : IndexedFull > DavFsInner < P , S > {
45
+ /// Get a [`Node`] from the specified [`DavPath`].
46
+ ///
47
+ /// # Arguments
48
+ ///
49
+ /// * `path` - The path to get the [`Tree`] at
50
+ ///
51
+ /// # Errors
52
+ ///
53
+ /// * If the [`Tree`] could not be found
54
+ ///
55
+ /// # Returns
56
+ ///
57
+ /// The [`Node`] at the specified path
58
+ ///
59
+ /// [`Tree`]: crate::repofile::Tree
60
+ fn node_from_path ( & self , path : & DavPath ) -> Result < Node , FsError > {
61
+ self . vfs
62
+ . node_from_path ( & self . repo , & path. as_pathbuf ( ) )
63
+ . map_err ( |_| FsError :: GeneralFailure )
64
+ }
65
+
66
+ /// Get a list of [`Node`]s from the specified directory path.
67
+ ///
68
+ /// # Arguments
69
+ ///
70
+ /// * `path` - The path to get the [`Tree`] at
71
+ ///
72
+ /// # Errors
73
+ ///
74
+ /// * If the [`Tree`] could not be found
75
+ ///
76
+ /// # Returns
77
+ ///
78
+ /// The list of [`Node`]s at the specified path
79
+ ///
80
+ /// [`Tree`]: crate::repofile::Tree
81
+ fn dir_entries_from_path ( & self , path : & DavPath ) -> Result < Vec < Node > , FsError > {
82
+ self . vfs
83
+ . dir_entries_from_path ( & self . repo , & path. as_pathbuf ( ) )
84
+ . map_err ( |_| FsError :: GeneralFailure )
85
+ }
86
+
87
+ fn open ( & self , node : & Node , options : OpenOptions ) -> Result < OpenFile , FsError > {
88
+ if options. write
89
+ || options. append
90
+ || options. truncate
91
+ || options. create
92
+ || options. create_new
93
+ {
94
+ return Err ( FsError :: Forbidden ) ;
95
+ }
96
+
97
+ if matches ! ( self . file_policy, FilePolicy :: Forbidden ) {
98
+ return Err ( FsError :: Forbidden ) ;
99
+ }
100
+
101
+ let open = self
102
+ . repo
103
+ . open_file ( node)
104
+ . map_err ( |_err| FsError :: GeneralFailure ) ?;
105
+ Ok ( open)
106
+ }
107
+
108
+ fn read_bytes (
109
+ & self ,
110
+ file : OpenFile ,
111
+ seek : usize ,
112
+ count : usize ,
113
+ ) -> Result < ( Bytes , OpenFile ) , FsError > {
114
+ let data = self
115
+ . repo
116
+ . read_file_at ( & file, seek, count)
117
+ . map_err ( |_err| FsError :: GeneralFailure ) ?;
118
+ Ok ( ( data, file) )
119
+ }
120
+ }
121
+
122
+ /// Messages used
123
+ #[ allow( clippy:: large_enum_variant) ]
124
+ enum DavFsInnerCommand {
125
+ Node ( DavPath , oneshot:: Sender < Result < Node , FsError > > ) ,
126
+ DirEntries ( DavPath , oneshot:: Sender < Result < Vec < Node > , FsError > > ) ,
127
+ Open (
128
+ Node ,
129
+ OpenOptions ,
130
+ oneshot:: Sender < Result < OpenFile , FsError > > ,
131
+ ) ,
132
+ ReadBytes (
133
+ OpenFile ,
134
+ usize ,
135
+ usize ,
136
+ oneshot:: Sender < Result < ( Bytes , OpenFile ) , FsError > > ,
137
+ ) ,
138
+ }
139
+
43
140
impl < P , S > Debug for DavFsInner < P , S > {
44
141
fn fmt ( & self , f : & mut Formatter < ' _ > ) -> Result < ( ) , std:: fmt:: Error > {
45
142
write ! ( f, "DavFS" )
@@ -50,12 +147,12 @@ impl<P, S> Debug for DavFsInner<P, S> {
50
147
///
51
148
/// This is the main entry point for the DAV filesystem.
52
149
/// It implements [`DavFileSystem`] and can be used to serve a [`Repository`] via DAV.
53
- #[ derive( Debug ) ]
54
- pub struct WebDavFS < P , S > {
55
- inner : Arc < DavFsInner < P , S > > ,
150
+ #[ derive( Debug , Clone ) ]
151
+ pub struct WebDavFS {
152
+ send : mpsc :: Sender < DavFsInnerCommand > ,
56
153
}
57
154
58
- impl < P , S : IndexedFull > WebDavFS < P , S > {
155
+ impl WebDavFS {
59
156
/// Create a new [`WebDavFS`] instance.
60
157
///
61
158
/// # Arguments
@@ -67,16 +164,44 @@ impl<P, S: IndexedFull> WebDavFS<P, S> {
67
164
/// # Returns
68
165
///
69
166
/// A new [`WebDavFS`] instance
70
- pub ( crate ) fn new ( repo : Repository < P , S > , vfs : Vfs , file_policy : FilePolicy ) -> Self {
167
+ pub ( crate ) fn new < P : Send + ' static , S : IndexedFull + Send + ' static > (
168
+ repo : Repository < P , S > ,
169
+ vfs : Vfs ,
170
+ file_policy : FilePolicy ,
171
+ ) -> Self {
71
172
let inner = DavFsInner {
72
173
repo,
73
174
vfs,
74
175
file_policy,
75
176
} ;
76
177
77
- Self {
78
- inner : Arc :: new ( inner) ,
79
- }
178
+ let ( send, mut rcv) = mpsc:: channel ( 1 ) ;
179
+
180
+ let _ = std:: thread:: spawn ( move || -> Result < _ , FsError > {
181
+ while let Some ( task) = rcv. blocking_recv ( ) {
182
+ match task {
183
+ DavFsInnerCommand :: Node ( path, res) => {
184
+ res. send ( inner. node_from_path ( & path) )
185
+ . map_err ( |_err| FsError :: GeneralFailure ) ?;
186
+ }
187
+ DavFsInnerCommand :: DirEntries ( path, res) => {
188
+ res. send ( inner. dir_entries_from_path ( & path) )
189
+ . map_err ( |_err| FsError :: GeneralFailure ) ?;
190
+ }
191
+ DavFsInnerCommand :: Open ( path, open_options, res) => {
192
+ res. send ( inner. open ( & path, open_options) )
193
+ . map_err ( |_err| FsError :: GeneralFailure ) ?;
194
+ }
195
+ DavFsInnerCommand :: ReadBytes ( file, seek, count, res) => {
196
+ res. send ( inner. read_bytes ( file, seek, count) )
197
+ . map_err ( |_err| FsError :: GeneralFailure ) ?;
198
+ }
199
+ }
200
+ }
201
+ Ok ( ( ) )
202
+ } ) ;
203
+
204
+ Self { send }
80
205
}
81
206
82
207
/// Get a [`Node`] from the specified [`DavPath`].
@@ -94,11 +219,13 @@ impl<P, S: IndexedFull> WebDavFS<P, S> {
94
219
/// The [`Node`] at the specified path
95
220
///
96
221
/// [`Tree`]: crate::repofile::Tree
97
- fn node_from_path ( & self , path : & DavPath ) -> Result < Node , FsError > {
98
- self . inner
99
- . vfs
100
- . node_from_path ( & self . inner . repo , & path. as_pathbuf ( ) )
101
- . map_err ( |_| FsError :: GeneralFailure )
222
+ async fn node_from_path ( & self , path : & DavPath ) -> Result < Node , FsError > {
223
+ let ( send, rcv) = oneshot:: channel ( ) ;
224
+ self . send
225
+ . send ( DavFsInnerCommand :: Node ( path. clone ( ) , send) )
226
+ . await
227
+ . map_err ( |_err| FsError :: GeneralFailure ) ?;
228
+ rcv. await . map_err ( |_err| FsError :: GeneralFailure ) ?
102
229
}
103
230
104
231
/// Get a list of [`Node`]s from the specified directory path.
@@ -116,32 +243,46 @@ impl<P, S: IndexedFull> WebDavFS<P, S> {
116
243
/// The list of [`Node`]s at the specified path
117
244
///
118
245
/// [`Tree`]: crate::repofile::Tree
119
- fn dir_entries_from_path ( & self , path : & DavPath ) -> Result < Vec < Node > , FsError > {
120
- self . inner
121
- . vfs
122
- . dir_entries_from_path ( & self . inner . repo , & path. as_pathbuf ( ) )
123
- . map_err ( |_| FsError :: GeneralFailure )
246
+ async fn dir_entries_from_path ( & self , path : & DavPath ) -> Result < Vec < Node > , FsError > {
247
+ let ( send, rcv) = oneshot:: channel ( ) ;
248
+ self . send
249
+ . send ( DavFsInnerCommand :: DirEntries ( path. clone ( ) , send) )
250
+ . await
251
+ . map_err ( |_err| FsError :: GeneralFailure ) ?;
252
+ rcv. await . map_err ( |_err| FsError :: GeneralFailure ) ?
124
253
}
125
- }
126
254
127
- impl < P , S : IndexedFull > Clone for WebDavFS < P , S > {
128
- fn clone ( & self ) -> Self {
129
- Self {
130
- inner : self . inner . clone ( ) ,
131
- }
255
+ async fn open ( & self , node : & Node , options : OpenOptions ) -> Result < OpenFile , FsError > {
256
+ let ( send, rcv) = oneshot:: channel ( ) ;
257
+ self . send
258
+ . send ( DavFsInnerCommand :: Open ( node. clone ( ) , options, send) )
259
+ . await
260
+ . map_err ( |_err| FsError :: GeneralFailure ) ?;
261
+ rcv. await . map_err ( |_err| FsError :: GeneralFailure ) ?
262
+ }
263
+ async fn read_bytes (
264
+ & self ,
265
+ file : OpenFile ,
266
+ seek : usize ,
267
+ count : usize ,
268
+ ) -> Result < ( Bytes , OpenFile ) , FsError > {
269
+ let ( send, rcv) = oneshot:: channel ( ) ;
270
+ self . send
271
+ . send ( DavFsInnerCommand :: ReadBytes ( file, seek, count, send) )
272
+ . await
273
+ . map_err ( |_err| FsError :: GeneralFailure ) ?;
274
+ rcv. await . map_err ( |_err| FsError :: GeneralFailure ) ?
132
275
}
133
276
}
134
277
135
- impl < P : Debug + Send + Sync + ' static , S : IndexedFull + Debug + Send + Sync + ' static > DavFileSystem
136
- for WebDavFS < P , S >
137
- {
278
+ impl DavFileSystem for WebDavFS {
138
279
fn metadata < ' a > ( & ' a self , davpath : & ' a DavPath ) -> FsFuture < ' _ , Box < dyn DavMetaData > > {
139
280
self . symlink_metadata ( davpath)
140
281
}
141
282
142
283
fn symlink_metadata < ' a > ( & ' a self , davpath : & ' a DavPath ) -> FsFuture < ' _ , Box < dyn DavMetaData > > {
143
284
async move {
144
- let node = self . node_from_path ( davpath) ?;
285
+ let node = self . node_from_path ( davpath) . await ?;
145
286
let meta: Box < dyn DavMetaData > = Box :: new ( DavFsMetaData ( node) ) ;
146
287
Ok ( meta)
147
288
}
@@ -154,7 +295,7 @@ impl<P: Debug + Send + Sync + 'static, S: IndexedFull + Debug + Send + Sync + 's
154
295
_meta : ReadDirMeta ,
155
296
) -> FsFuture < ' _ , FsStream < Box < dyn DavDirEntry > > > {
156
297
async move {
157
- let entries = self . dir_entries_from_path ( davpath) ?;
298
+ let entries = self . dir_entries_from_path ( davpath) . await ?;
158
299
let entry_iter = entries. into_iter ( ) . map ( |e| {
159
300
let entry: Box < dyn DavDirEntry > = Box :: new ( DavFsDirEntry ( e) ) ;
160
301
Ok ( entry)
@@ -171,30 +312,13 @@ impl<P: Debug + Send + Sync + 'static, S: IndexedFull + Debug + Send + Sync + 's
171
312
options : OpenOptions ,
172
313
) -> FsFuture < ' _ , Box < dyn DavFile > > {
173
314
async move {
174
- if options. write
175
- || options. append
176
- || options. truncate
177
- || options. create
178
- || options. create_new
179
- {
180
- return Err ( FsError :: Forbidden ) ;
181
- }
182
-
183
- let node = self . node_from_path ( path) ?;
184
- if matches ! ( self . inner. file_policy, FilePolicy :: Forbidden ) {
185
- return Err ( FsError :: Forbidden ) ;
186
- }
187
-
188
- let open = self
189
- . inner
190
- . repo
191
- . open_file ( & node)
192
- . map_err ( |_err| FsError :: GeneralFailure ) ?;
315
+ let node = self . node_from_path ( path) . await ?;
316
+ let file = self . open ( & node, options) . await ?;
193
317
let file: Box < dyn DavFile > = Box :: new ( DavFsFile {
194
- node,
195
- open,
196
- fs : self . inner . clone ( ) ,
318
+ open : Some ( file) ,
197
319
seek : 0 ,
320
+ fs : self . clone ( ) ,
321
+ node,
198
322
} ) ;
199
323
Ok ( file)
200
324
}
@@ -234,27 +358,25 @@ impl DavDirEntry for DavFsDirEntry {
234
358
/// A [`DavFile`] implementation for [`Node`]s.
235
359
///
236
360
/// This is a read-only file.
237
- struct DavFsFile < P , S > {
361
+ struct DavFsFile {
238
362
/// The [`Node`] this file is for
239
363
node : Node ,
240
364
241
365
/// The [`OpenFile`] for this file
242
- open : OpenFile ,
243
-
244
- /// The [`DavFsInner`] this file belongs to
245
- fs : Arc < DavFsInner < P , S > > ,
366
+ open : Option < OpenFile > ,
246
367
247
368
/// The current seek position
248
369
seek : usize ,
370
+ fs : WebDavFS ,
249
371
}
250
372
251
- impl < P , S > Debug for DavFsFile < P , S > {
373
+ impl Debug for DavFsFile {
252
374
fn fmt ( & self , f : & mut Formatter < ' _ > ) -> Result < ( ) , std:: fmt:: Error > {
253
375
write ! ( f, "DavFile" )
254
376
}
255
377
}
256
378
257
- impl < P : Debug + Send + Sync , S : IndexedFull + Debug + Send + Sync > DavFile for DavFsFile < P , S > {
379
+ impl DavFile for DavFsFile {
258
380
fn metadata ( & mut self ) -> FsFuture < ' _ , Box < dyn DavMetaData > > {
259
381
async move {
260
382
let meta: Box < dyn DavMetaData > = Box :: new ( DavFsMetaData ( self . node . clone ( ) ) ) ;
@@ -273,12 +395,16 @@ impl<P: Debug + Send + Sync, S: IndexedFull + Debug + Send + Sync> DavFile for D
273
395
274
396
fn read_bytes ( & mut self , count : usize ) -> FsFuture < ' _ , Bytes > {
275
397
async move {
276
- let data = self
398
+ let ( data, open ) = self
277
399
. fs
278
- . repo
279
- . read_file_at ( & self . open , self . seek , count)
280
- . map_err ( |_err| FsError :: GeneralFailure ) ?;
400
+ . read_bytes (
401
+ self . open . take ( ) . ok_or ( FsError :: GeneralFailure ) ?,
402
+ self . seek ,
403
+ count,
404
+ )
405
+ . await ?;
281
406
self . seek += data. len ( ) ;
407
+ self . open = Some ( open) ;
282
408
Ok ( data)
283
409
}
284
410
. boxed ( )
0 commit comments