1use crate::common::CreationMode;
10use crate::directory::dirents_sink;
11use crate::directory::entry::{DirectoryEntry, EntryInfo, OpenRequest, RequestFlags};
12use crate::directory::entry_container::{Directory, DirectoryWatcher};
13use crate::directory::helper::{AlreadyExists, DirectlyMutable, NotDirectory};
14use crate::directory::immutable::connection::ImmutableConnection;
15use crate::directory::traversal_position::TraversalPosition;
16use crate::directory::watchers::event_producers::{
17 SingleNameEventProducer, StaticVecEventProducer,
18};
19use crate::directory::watchers::Watchers;
20use crate::execution_scope::ExecutionScope;
21use crate::name::Name;
22use crate::node::Node;
23use crate::path::Path;
24use crate::protocols::ProtocolsExt;
25use crate::{ObjectRequestRef, ToObjectRequest};
26use fidl::endpoints::ServerEnd;
27use fidl_fuchsia_io as fio;
28use fuchsia_sync::Mutex;
29use std::collections::btree_map::Entry;
30use std::collections::BTreeMap;
31use std::iter;
32use std::sync::Arc;
33use zx_status::Status;
34
35use super::entry::GetEntryInfo;
36
37pub struct Simple {
42 inner: Mutex<Inner>,
43
44 inode: u64,
46
47 not_found_handler: Mutex<Option<Box<dyn FnMut(&str) + Send + Sync + 'static>>>,
48}
49
50struct Inner {
51 entries: BTreeMap<Name, Arc<dyn DirectoryEntry>>,
52
53 watchers: Watchers,
54}
55
56impl Simple {
57 pub fn new() -> Arc<Self> {
58 Self::new_with_inode(fio::INO_UNKNOWN)
59 }
60
61 pub(crate) fn new_with_inode(inode: u64) -> Arc<Self> {
62 Arc::new(Simple {
63 inner: Mutex::new(Inner { entries: BTreeMap::new(), watchers: Watchers::new() }),
64 inode,
65 not_found_handler: Mutex::new(None),
66 })
67 }
68
69 pub fn set_not_found_handler(
73 self: Arc<Self>,
74 handler: Box<dyn FnMut(&str) + Send + Sync + 'static>,
75 ) {
76 let mut this = self.not_found_handler.lock();
77 this.replace(handler);
78 }
79
80 pub fn get_entry(&self, name: &str) -> Result<Arc<dyn DirectoryEntry>, Status> {
82 crate::name::validate_name(name)?;
83
84 let this = self.inner.lock();
85 match this.entries.get(name) {
86 Some(entry) => Ok(entry.clone()),
87 None => Err(Status::NOT_FOUND),
88 }
89 }
90
91 pub fn get_or_insert<T: DirectoryEntry>(
93 &self,
94 name: Name,
95 f: impl FnOnce() -> Arc<T>,
96 ) -> Arc<dyn DirectoryEntry> {
97 let mut guard = self.inner.lock();
98 let inner = &mut *guard;
99 match inner.entries.entry(name) {
100 Entry::Vacant(slot) => {
101 inner.watchers.send_event(&mut SingleNameEventProducer::added(""));
102 slot.insert(f()).clone()
103 }
104 Entry::Occupied(entry) => entry.get().clone(),
105 }
106 }
107
108 pub fn remove_all_entries(&self) {
110 let mut inner = self.inner.lock();
111 if !inner.entries.is_empty() {
112 let names = std::mem::take(&mut inner.entries)
113 .into_keys()
114 .map(String::from)
115 .collect::<Vec<String>>();
116 inner.watchers.send_event(&mut StaticVecEventProducer::removed(names));
117 }
118 }
119
120 fn open_impl<'a, P: ProtocolsExt + ToRequestFlags>(
121 self: Arc<Self>,
122 scope: ExecutionScope,
123 mut path: Path,
124 protocols: P,
125 object_request: ObjectRequestRef<'_>,
126 ) -> Result<(), Status> {
127 let (name, path_ref) = match path.next_with_ref() {
130 (path_ref, Some(name)) => (name, path_ref),
131 (_, None) => {
132 if protocols.create_unnamed_temporary_in_directory_path() {
133 return Err(Status::NOT_SUPPORTED);
135 }
136 object_request
137 .take()
138 .create_connection_sync::<ImmutableConnection<_>, _>(scope, self, protocols);
139 return Ok(());
140 }
141 };
142
143 let entry = self.inner.lock().entries.get(name).cloned();
145 match (entry, path_ref.is_empty(), protocols.creation_mode()) {
146 (None, false, _) | (None, true, CreationMode::Never) => {
147 if let Some(not_found_handler) = &mut *self.not_found_handler.lock() {
152 not_found_handler(path_ref.as_str());
153 }
154 Err(Status::NOT_FOUND)
155 }
156 (
157 None,
158 true,
159 CreationMode::Always
160 | CreationMode::AllowExisting
161 | CreationMode::UnnamedTemporary
162 | CreationMode::UnlinkableUnnamedTemporary,
163 ) => {
164 Err(Status::NOT_SUPPORTED)
167 }
168 (
169 Some(_),
170 true,
171 CreationMode::UnnamedTemporary | CreationMode::UnlinkableUnnamedTemporary,
172 ) => {
173 Err(Status::NOT_SUPPORTED)
177 }
178 (Some(_), true, CreationMode::Always) => {
179 Err(Status::ALREADY_EXISTS)
182 }
183 (Some(entry), _, _) => entry.open_entry(OpenRequest::new(
184 scope,
185 protocols.to_request_flags(),
186 path,
187 object_request,
188 )),
189 }
190 }
191}
192
193impl GetEntryInfo for Simple {
194 fn entry_info(&self) -> EntryInfo {
195 EntryInfo::new(self.inode, fio::DirentType::Directory)
196 }
197}
198
199impl DirectoryEntry for Simple {
200 fn open_entry(self: Arc<Self>, request: OpenRequest<'_>) -> Result<(), Status> {
201 request.open_dir(self)
202 }
203}
204
205impl Node for Simple {
206 async fn get_attributes(
207 &self,
208 requested_attributes: fio::NodeAttributesQuery,
209 ) -> Result<fio::NodeAttributes2, Status> {
210 Ok(immutable_attributes!(
211 requested_attributes,
212 Immutable {
213 protocols: fio::NodeProtocolKinds::DIRECTORY,
214 abilities: fio::Operations::GET_ATTRIBUTES
215 | fio::Operations::ENUMERATE
216 | fio::Operations::TRAVERSE,
217 id: self.inode,
218 }
219 ))
220 }
221}
222
223impl Directory for Simple {
224 fn open(
225 self: Arc<Self>,
226 scope: ExecutionScope,
227 flags: fio::OpenFlags,
228 path: Path,
229 server_end: ServerEnd<fio::NodeMarker>,
230 ) {
231 flags
232 .to_object_request(server_end)
233 .handle(|object_request| self.open_impl(scope, path, flags, object_request));
234 }
235
236 fn open3(
237 self: Arc<Self>,
238 scope: ExecutionScope,
239 path: Path,
240 flags: fio::Flags,
241 object_request: ObjectRequestRef<'_>,
242 ) -> Result<(), Status> {
243 self.open_impl(scope, path, flags, object_request)
244 }
245
246 async fn read_dirents<'a>(
247 &'a self,
248 pos: &'a TraversalPosition,
249 sink: Box<dyn dirents_sink::Sink>,
250 ) -> Result<(TraversalPosition, Box<dyn dirents_sink::Sealed>), Status> {
251 use dirents_sink::AppendResult;
252
253 let this = self.inner.lock();
254
255 let (mut sink, entries_iter) = match pos {
256 TraversalPosition::Start => {
257 match sink.append(&EntryInfo::new(self.inode, fio::DirentType::Directory), ".") {
258 AppendResult::Ok(sink) => {
259 (sink, this.entries.range::<Name, _>(..))
274 }
275 AppendResult::Sealed(sealed) => {
276 let new_pos = match this.entries.keys().next() {
277 None => TraversalPosition::End,
278 Some(first_name) => TraversalPosition::Name(first_name.clone().into()),
279 };
280 return Ok((new_pos, sealed));
281 }
282 }
283 }
284
285 TraversalPosition::Name(next_name) => {
286 let next: Name = next_name.to_owned().try_into().unwrap();
290 (sink, this.entries.range::<Name, _>(next..))
291 }
292
293 TraversalPosition::Index(_) => unreachable!(),
294
295 TraversalPosition::End => return Ok((TraversalPosition::End, sink.seal())),
296 };
297
298 for (name, entry) in entries_iter {
299 match sink.append(&entry.entry_info(), &name) {
300 AppendResult::Ok(new_sink) => sink = new_sink,
301 AppendResult::Sealed(sealed) => {
302 return Ok((TraversalPosition::Name(name.clone().into()), sealed));
303 }
304 }
305 }
306
307 Ok((TraversalPosition::End, sink.seal()))
308 }
309
310 fn register_watcher(
311 self: Arc<Self>,
312 scope: ExecutionScope,
313 mask: fio::WatchMask,
314 watcher: DirectoryWatcher,
315 ) -> Result<(), Status> {
316 let mut this = self.inner.lock();
317
318 let mut names = StaticVecEventProducer::existing({
319 let entry_names = this.entries.keys();
320 iter::once(".".to_string()).chain(entry_names.map(|x| x.to_owned().into())).collect()
321 });
322
323 let controller = this.watchers.add(scope, self.clone(), mask, watcher);
324 controller.send_event(&mut names);
325 controller.send_event(&mut SingleNameEventProducer::idle());
326
327 Ok(())
328 }
329
330 fn unregister_watcher(self: Arc<Self>, key: usize) {
331 let mut this = self.inner.lock();
332 this.watchers.remove(key);
333 }
334}
335
336impl DirectlyMutable for Simple {
337 fn add_entry_impl(
338 &self,
339 name: Name,
340 entry: Arc<dyn DirectoryEntry>,
341 overwrite: bool,
342 ) -> Result<(), AlreadyExists> {
343 let mut this = self.inner.lock();
344
345 if !overwrite && this.entries.contains_key(&name) {
346 return Err(AlreadyExists);
347 }
348
349 this.watchers.send_event(&mut SingleNameEventProducer::added(&name));
350
351 let _ = this.entries.insert(name, entry);
352 Ok(())
353 }
354
355 fn remove_entry_impl(
356 &self,
357 name: Name,
358 must_be_directory: bool,
359 ) -> Result<Option<Arc<dyn DirectoryEntry>>, NotDirectory> {
360 let mut this = self.inner.lock();
361
362 match this.entries.entry(name) {
363 Entry::Vacant(_) => Ok(None),
364 Entry::Occupied(occupied) => {
365 if must_be_directory
366 && occupied.get().entry_info().type_() != fio::DirentType::Directory
367 {
368 Err(NotDirectory)
369 } else {
370 let (key, value) = occupied.remove_entry();
371 this.watchers.send_event(&mut SingleNameEventProducer::removed(&key));
372 Ok(Some(value))
373 }
374 }
375 }
376 }
377}
378
379trait ToRequestFlags {
380 fn to_request_flags(&self) -> RequestFlags;
381}
382
383impl ToRequestFlags for fio::OpenFlags {
384 fn to_request_flags(&self) -> RequestFlags {
385 RequestFlags::Open1(*self)
386 }
387}
388
389impl ToRequestFlags for fio::Flags {
390 fn to_request_flags(&self) -> RequestFlags {
391 RequestFlags::Open3(*self)
392 }
393}
394
395#[cfg(test)]
396mod tests {
397 use super::*;
398 use crate::directory::immutable::Simple;
399 use crate::{assert_event, file};
400 use fidl::endpoints::create_proxy;
401
402 #[test]
403 fn add_entry_success() {
404 let dir = Simple::new();
405 assert_eq!(
406 dir.add_entry("path_without_separators", file::read_only(b"test")),
407 Ok(()),
408 "add entry with valid filename should succeed"
409 );
410 }
411
412 #[test]
413 fn add_entry_error_name_with_path_separator() {
414 let dir = Simple::new();
415 let status = dir
416 .add_entry("path/with/separators", file::read_only(b"test"))
417 .expect_err("add entry with path separator should fail");
418 assert_eq!(status, Status::INVALID_ARGS);
419 }
420
421 #[test]
422 fn add_entry_error_name_too_long() {
423 let dir = Simple::new();
424 let status = dir
425 .add_entry("a".repeat(10000), file::read_only(b"test"))
426 .expect_err("add entry whose name is too long should fail");
427 assert_eq!(status, Status::BAD_PATH);
428 }
429
430 #[fuchsia::test]
431 async fn not_found_handler() {
432 let dir = Simple::new();
433 let path_mutex = Arc::new(Mutex::new(None));
434 let path_mutex_clone = path_mutex.clone();
435 dir.clone().set_not_found_handler(Box::new(move |path| {
436 *path_mutex_clone.lock() = Some(path.to_string());
437 }));
438
439 let sub_dir = Simple::new();
440 let path_mutex_clone = path_mutex.clone();
441 sub_dir.clone().set_not_found_handler(Box::new(move |path| {
442 *path_mutex_clone.lock() = Some(path.to_string());
443 }));
444 dir.add_entry("dir", sub_dir).expect("add entry with valid filename should succeed");
445
446 dir.add_entry("file", file::read_only(b"test"))
447 .expect("add entry with valid filename should succeed");
448
449 let scope = ExecutionScope::new();
450
451 for (path, expectation) in vec![
452 (".", None),
453 ("does-not-exist", Some("does-not-exist".to_string())),
454 ("file", None),
455 ("dir", None),
456 ("dir/does-not-exist", Some("dir/does-not-exist".to_string())),
457 ] {
458 let (proxy, server_end) = create_proxy::<fio::NodeMarker>();
459 let flags = fio::OpenFlags::NODE_REFERENCE | fio::OpenFlags::DESCRIBE;
460 let path = Path::validate_and_split(path).unwrap();
461 dir.clone().open(scope.clone(), flags, path, server_end.into_channel().into());
462 assert_event!(proxy, fio::NodeEvent::OnOpen_ { .. }, {});
463
464 assert_eq!(expectation, path_mutex.lock().take());
465 }
466 }
467
468 #[test]
469 fn remove_all_entries() {
470 let dir = Simple::new();
471
472 dir.add_entry("file", file::read_only(""))
473 .expect("add entry with valid filename should succeed");
474
475 dir.remove_all_entries();
476 assert_eq!(
477 dir.get_entry("file").err().expect("file should no longer exist"),
478 Status::NOT_FOUND
479 );
480 }
481}