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