1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45use crate::directory::FatDirectory;
6use crate::file::FatFile;
7use crate::filesystem::{FatFilesystem, FatFilesystemInner};
8use std::ops::Deref;
9use std::sync::{Arc, Weak};
10use zx::Status;
1112pub trait Node {
13/// Attach this FatNode to the given FatDirectory, with the given name.
14fn attach(
15&self,
16 parent: Arc<FatDirectory>,
17 name: &str,
18 fs: &FatFilesystemInner,
19 ) -> Result<(), Status>;
2021/// Detach this FatNode from its parent.
22fn detach<'a>(&self, fs: &'a FatFilesystemInner);
2324/// Takes an open count and opens the underlying node if not already open.
25fn open_ref<'a>(&'a self, fs: &'a FatFilesystemInner) -> Result<(), Status>;
2627/// Releases an open count.
28fn close_ref(&self, fs: &FatFilesystemInner);
2930/// Close the underlying node and all of its children, regardless of the number of open
31 /// connections.
32fn shut_down(&self, fs: &FatFilesystemInner) -> Result<(), Status>;
3334/// Flushes the directory entry for this node.
35fn flush_dir_entry(&self, fs: &FatFilesystemInner) -> Result<(), Status>;
3637/// Called when the node has been successfully deleted.
38fn did_delete(&self);
39}
4041#[derive(Clone, Debug)]
42/// This enum is used to represent values which could be either a FatDirectory
43/// or a FatFile. This holds a strong reference to the contained file/directory.
44pub enum FatNode {
45 Dir(Arc<FatDirectory>),
46 File(Arc<FatFile>),
47}
4849impl FatNode {
50/// Downgrade this FatNode into a WeakFatNode.
51pub fn downgrade(&self) -> WeakFatNode {
52match self {
53 FatNode::Dir(a) => WeakFatNode::Dir(Arc::downgrade(a)),
54 FatNode::File(b) => WeakFatNode::File(Arc::downgrade(b)),
55 }
56 }
5758pub fn as_node(&self) -> &(dyn Node + 'static) {
59match self {
60 FatNode::Dir(ref a) => a.as_ref() as &dyn Node,
61 FatNode::File(ref b) => b.as_ref() as &dyn Node,
62 }
63 }
64}
6566impl<'a> Deref for FatNode {
67type Target = dyn Node;
6869fn deref(&self) -> &Self::Target {
70self.as_node()
71 }
72}
7374/// The same as FatNode, but using a weak reference.
75#[derive(Debug)]
76pub enum WeakFatNode {
77 Dir(Weak<FatDirectory>),
78 File(Weak<FatFile>),
79}
8081impl WeakFatNode {
82/// Try and upgrade this WeakFatNode to a FatNode. Returns None
83 /// if the referenced object has been destroyed.
84pub fn upgrade(&self) -> Option<FatNode> {
85match self {
86 WeakFatNode::Dir(a) => a.upgrade().map(|val| FatNode::Dir(val)),
87 WeakFatNode::File(b) => b.upgrade().map(|val| FatNode::File(val)),
88 }
89 }
90}
9192/// RAII class that will close nodes when dropped. This should be created whilst the filesystem
93/// lock is not held since when it drops, it takes the filesystem lock. This class is useful
94/// for instances where temporary open counts are required.
95pub struct Closer<'a> {
96 filesystem: &'a FatFilesystem,
97 nodes: std::vec::Vec<FatNode>,
98}
99100impl<'a> Closer<'a> {
101pub fn new(filesystem: &'a FatFilesystem) -> Self {
102 Closer { filesystem, nodes: Vec::new() }
103 }
104105pub fn add(&mut self, node: FatNode) -> FatNode {
106self.nodes.push(node.clone());
107 node
108 }
109}
110111impl Drop for Closer<'_> {
112fn drop(&mut self) {
113let lock = self.filesystem.lock();
114self.nodes.drain(..).for_each(|n: FatNode| n.close_ref(&lock));
115 }
116}