1use std::collections::HashMap;
10use std::future;
11use std::sync::{Arc, Mutex};
12use std::time::{Duration, SystemTime};
13
14use futures_util::FutureExt;
15use uuid::Uuid;
16use xmltree::Element;
17
18use crate::davpath::DavPath;
19use crate::fs::FsResult;
20use crate::ls::*;
21use crate::tree;
22
23type Tree = tree::Tree<Vec<u8>, Vec<DavLock>>;
24
25#[derive(Debug, Clone)]
27pub struct MemLs(Arc<Mutex<MemLsInner>>);
28
29#[derive(Debug)]
30struct MemLsInner {
31 tree: Tree,
32 #[allow(dead_code)]
33 locks: HashMap<Vec<u8>, u64>,
34}
35
36impl MemLs {
37 pub fn new() -> Box<MemLs> {
39 let inner = MemLsInner {
40 tree: Tree::new(Vec::new()),
41 locks: HashMap::new(),
42 };
43 Box::new(MemLs(Arc::new(Mutex::new(inner))))
44 }
45}
46
47impl DavLockSystem for MemLs {
48 fn lock(
49 &'_ self,
50 path: &DavPath,
51 principal: Option<&str>,
52 owner: Option<&Element>,
53 timeout: Option<Duration>,
54 shared: bool,
55 deep: bool,
56 ) -> LsFuture<'_, Result<DavLock, DavLock>> {
57 let inner = &mut *self.0.lock().unwrap();
58
59 let rc = check_locks_to_path(&inner.tree, path, None, true, &Vec::new(), shared);
61 trace!("lock: check_locks_to_path: {rc:?}");
62 if let Err(err) = rc {
63 return future::ready(Err(err)).boxed();
64 }
65
66 if deep {
68 let rc = check_locks_from_path(&inner.tree, path, None, true, &Vec::new(), shared);
69 trace!("lock: check_locks_from_path: {rc:?}");
70 if let Err(err) = rc {
71 return future::ready(Err(err)).boxed();
72 }
73 }
74
75 let node = get_or_create_path_node(&mut inner.tree, path);
77 let timeout_at = timeout.map(|d| SystemTime::now() + d);
78 let lock = DavLock {
79 token: Uuid::new_v4().urn().to_string(),
80 path: Box::new(path.clone()),
81 principal: principal.map(|s| s.to_string()),
82 owner: owner.map(|o| Box::new(o.clone())),
83 timeout_at,
84 timeout,
85 shared,
86 deep,
87 };
88 trace!("lock {} created", &lock.token);
89 let slock = lock.clone();
90 node.push(slock);
91 future::ready(Ok(lock)).boxed()
92 }
93
94 fn unlock(&'_ self, path: &DavPath, token: &str) -> LsFuture<'_, Result<(), ()>> {
95 let inner = &mut *self.0.lock().unwrap();
96 let node_id = match lookup_lock(&inner.tree, path, token) {
97 None => {
98 trace!("unlock: {token} not found at {path}");
99 return future::ready(Err(())).boxed();
100 }
101 Some(n) => n,
102 };
103 let len = {
104 let node = inner.tree.get_node_mut(node_id).unwrap();
105 let idx = node.iter().position(|n| n.token.as_str() == token).unwrap();
106 node.remove(idx);
107 node.len()
108 };
109 if len == 0 {
110 inner.tree.delete_node(node_id).ok();
111 }
112 future::ready(Ok(())).boxed()
113 }
114
115 fn refresh(
116 &'_ self,
117 path: &DavPath,
118 token: &str,
119 timeout: Option<Duration>,
120 ) -> LsFuture<'_, Result<DavLock, ()>> {
121 trace!("refresh lock {token}");
122 let inner = &mut *self.0.lock().unwrap();
123 let node_id = match lookup_lock(&inner.tree, path, token) {
124 None => {
125 trace!("lock not found");
126 return future::ready(Err(())).boxed();
127 }
128 Some(n) => n,
129 };
130 let node = inner.tree.get_node_mut(node_id).unwrap();
131 let idx = node.iter().position(|n| n.token.as_str() == token).unwrap();
132 let lock = &mut node[idx];
133 let timeout_at = timeout.map(|d| SystemTime::now() + d);
134 lock.timeout = timeout;
135 lock.timeout_at = timeout_at;
136 future::ready(Ok(lock.clone())).boxed()
137 }
138
139 fn check(
140 &'_ self,
141 path: &DavPath,
142 principal: Option<&str>,
143 ignore_principal: bool,
144 deep: bool,
145 submitted_tokens: Vec<&str>,
146 ) -> LsFuture<'_, Result<(), DavLock>> {
147 let inner = &*self.0.lock().unwrap();
148 let _st = submitted_tokens.clone();
149 let rc = check_locks_to_path(
150 &inner.tree,
151 path,
152 principal,
153 ignore_principal,
154 &submitted_tokens,
155 false,
156 );
157 trace!("check: check_lock_to_path: {_st:?}: {rc:?}");
158 if let Err(err) = rc {
159 return future::ready(Err(err)).boxed();
160 }
161
162 if deep {
164 let rc = check_locks_from_path(
165 &inner.tree,
166 path,
167 principal,
168 ignore_principal,
169 &submitted_tokens,
170 false,
171 );
172 trace!("check: check_locks_from_path: {rc:?}");
173 if let Err(err) = rc {
174 return future::ready(Err(err)).boxed();
175 }
176 }
177 future::ready(Ok(())).boxed()
178 }
179
180 fn discover(&'_ self, path: &DavPath) -> LsFuture<'_, Vec<DavLock>> {
181 let inner = &*self.0.lock().unwrap();
182 future::ready(list_locks(&inner.tree, path)).boxed()
183 }
184
185 fn delete(&'_ self, path: &DavPath) -> LsFuture<'_, Result<(), ()>> {
186 let inner = &mut *self.0.lock().unwrap();
187 if let Some(node_id) = lookup_node(&inner.tree, path) {
188 inner.tree.delete_subtree(node_id).ok();
189 }
190 future::ready(Ok(())).boxed()
191 }
192}
193
194fn check_locks_to_path(
196 tree: &Tree,
197 path: &DavPath,
198 principal: Option<&str>,
199 ignore_principal: bool,
200 submitted_tokens: &[&str],
201 shared_ok: bool,
202) -> Result<(), DavLock> {
203 let segs = path_to_segs(path, true);
205 let last_seg = segs.len() - 1;
206
207 let mut holds_lock = false;
209 let mut first_lock_seen: Option<&DavLock> = None;
210
211 let mut node_id = tree::ROOT_ID;
213 for (i, seg) in segs.into_iter().enumerate() {
214 node_id = match get_child(tree, node_id, seg) {
215 Ok(n) => n,
216 Err(_) => break,
217 };
218 let node_locks = match tree.get_node(node_id) {
219 Ok(n) => n,
220 Err(_) => break,
221 };
222
223 for nl in node_locks {
224 if i < last_seg && !nl.deep {
225 continue;
226 }
227 if submitted_tokens.iter().any(|t| &nl.token == t)
228 && (ignore_principal || principal == nl.principal.as_deref())
229 {
230 holds_lock = true;
232 } else {
233 if !nl.shared {
235 return Err(nl.to_owned());
236 }
237 if !shared_ok {
239 first_lock_seen.get_or_insert(nl);
240 }
241 }
242 }
243 }
244
245 if !holds_lock && let Some(first_lock_seen) = first_lock_seen {
247 return Err(first_lock_seen.to_owned());
248 }
249
250 Ok(())
251}
252
253fn check_locks_from_path(
255 tree: &Tree,
256 path: &DavPath,
257 principal: Option<&str>,
258 ignore_principal: bool,
259 submitted_tokens: &[&str],
260 shared_ok: bool,
261) -> Result<(), DavLock> {
262 let node_id = match lookup_node(tree, path) {
263 Some(id) => id,
264 None => return Ok(()),
265 };
266 check_locks_from_node(
267 tree,
268 node_id,
269 principal,
270 ignore_principal,
271 submitted_tokens,
272 shared_ok,
273 )
274}
275
276fn check_locks_from_node(
278 tree: &Tree,
279 node_id: u64,
280 principal: Option<&str>,
281 ignore_principal: bool,
282 submitted_tokens: &[&str],
283 shared_ok: bool,
284) -> Result<(), DavLock> {
285 let node_locks = match tree.get_node(node_id) {
286 Ok(n) => n,
287 Err(_) => return Ok(()),
288 };
289 for nl in node_locks {
290 if (!nl.shared || !shared_ok)
291 && (!submitted_tokens.iter().any(|t| t == &nl.token)
292 || (!ignore_principal && principal != nl.principal.as_deref()))
293 {
294 return Err(nl.to_owned());
295 }
296 }
297 if let Ok(children) = tree.get_children(node_id) {
298 for (_, node_id) in children {
299 check_locks_from_node(
300 tree,
301 node_id,
302 principal,
303 ignore_principal,
304 submitted_tokens,
305 shared_ok,
306 )?;
307 }
308 }
309 Ok(())
310}
311
312fn get_or_create_path_node<'a>(tree: &'a mut Tree, path: &DavPath) -> &'a mut Vec<DavLock> {
314 let mut node_id = tree::ROOT_ID;
315 for seg in path_to_segs(path, false) {
316 node_id = match tree.get_child(node_id, seg) {
317 Ok(n) => n,
318 Err(_) => tree
319 .add_child(node_id, seg.to_vec(), Vec::new(), false)
320 .unwrap(),
321 };
322 }
323 tree.get_node_mut(node_id).unwrap()
324}
325
326fn lookup_lock(tree: &Tree, path: &DavPath, token: &str) -> Option<u64> {
328 trace!("lookup_lock: {token}");
329
330 let mut node_id = tree::ROOT_ID;
331 for seg in path_to_segs(path, true) {
332 trace!(
333 "lookup_lock: node {} seg {}",
334 node_id,
335 String::from_utf8_lossy(seg)
336 );
337 node_id = match get_child(tree, node_id, seg) {
338 Ok(n) => n,
339 Err(_) => break,
340 };
341 let node = tree.get_node(node_id).unwrap();
342 trace!("lookup_lock: locks here: {:?}", &node);
343 if node.iter().any(|n| n.token == token) {
344 return Some(node_id);
345 }
346 }
347 trace!("lookup_lock: fail");
348 None
349}
350
351fn lookup_node(tree: &Tree, path: &DavPath) -> Option<u64> {
353 let mut node_id = tree::ROOT_ID;
354 for seg in path_to_segs(path, false) {
355 node_id = match tree.get_child(node_id, seg) {
356 Ok(n) => n,
357 Err(_) => return None,
358 };
359 }
360 Some(node_id)
361}
362
363fn list_locks(tree: &Tree, path: &DavPath) -> Vec<DavLock> {
365 let mut locks = Vec::new();
366
367 let mut node_id = tree::ROOT_ID;
368 if let Ok(node) = tree.get_node(node_id) {
369 locks.extend_from_slice(node);
370 }
371 for seg in path_to_segs(path, false) {
372 node_id = match tree.get_child(node_id, seg) {
373 Ok(n) => n,
374 Err(_) => break,
375 };
376 if let Ok(node) = tree.get_node(node_id) {
377 locks.extend_from_slice(node);
378 }
379 }
380 locks
381}
382
383fn path_to_segs(path: &DavPath, include_root: bool) -> Vec<&[u8]> {
384 let path = path.as_bytes();
385 let mut segs: Vec<&[u8]> = path
386 .split(|&c| c == b'/')
387 .filter(|s| !s.is_empty())
388 .collect();
389 if include_root {
390 segs.insert(0, b"");
391 }
392 segs
393}
394
395fn get_child(tree: &Tree, node_id: u64, seg: &[u8]) -> FsResult<u64> {
396 if seg.is_empty() {
397 return Ok(node_id);
398 }
399 tree.get_child(node_id, seg)
400}