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