1use crate::directory::FatDirectory;
8use crate::filesystem::FatFilesystemInner;
9use crate::node::Node;
10use crate::types::{Dir, File};
11use scopeguard::defer;
12use std::cell::{Ref, RefMut};
13use std::ops::{Deref, DerefMut};
14use std::sync::Arc;
15use zx::Status;
16
17pub trait Wrapper<'a> {
18 type Target: 'a;
19
20 fn get(&self, fs: &'a FatFilesystemInner) -> Option<&Self::Target>;
22
23 fn get_mut(&mut self, fs: &'a FatFilesystemInner) -> Option<&mut Self::Target>;
25}
26
27pub struct FatfsDirRef {
28 inner: Option<Dir<'static>>,
29 open_count: usize,
30}
31
32impl FatfsDirRef {
33 pub unsafe fn from(dir: Dir<'_>) -> Self {
36 FatfsDirRef { inner: Some(std::mem::transmute(dir)), open_count: 1 }
37 }
38
39 pub fn empty() -> Self {
40 FatfsDirRef { inner: None, open_count: 0 }
41 }
42
43 pub unsafe fn maybe_reopen(
45 &mut self,
46 fs: &FatFilesystemInner,
47 parent: Option<&Arc<FatDirectory>>,
48 name: &str,
49 ) -> Result<(), Status> {
50 if self.open_count == 0 { Ok(()) } else { self.reopen(fs, parent, name) }
51 }
52
53 unsafe fn reopen(
54 &mut self,
55 fs: &FatFilesystemInner,
56 parent: Option<&Arc<FatDirectory>>,
57 name: &str,
58 ) -> Result<(), Status> {
59 let dir = if let Some(parent) = parent {
60 parent.open_ref(fs)?;
61 defer! { parent.close_ref(fs) }
62 parent.find_child(fs, name)?.ok_or(Status::NOT_FOUND)?.to_dir()
63 } else {
64 fs.root_dir()
65 };
66 self.inner.replace(std::mem::transmute(dir));
67 Ok(())
68 }
69
70 pub unsafe fn open(
72 &mut self,
73 fs: &FatFilesystemInner,
74 parent: Option<&Arc<FatDirectory>>,
75 name: &str,
76 ) -> Result<(), Status> {
77 if self.open_count == std::usize::MAX {
78 Err(Status::UNAVAILABLE)
79 } else {
80 if self.open_count == 0 {
81 self.reopen(fs, parent, name)?;
82 }
83 self.open_count += 1;
84 Ok(())
85 }
86 }
87
88 pub fn close(&mut self, fs: &FatFilesystemInner) {
90 assert!(self.open_count > 0);
91 self.open_count -= 1;
92 if self.open_count == 0 {
93 self.take(&fs);
94 }
95 }
96
97 pub fn take<'a>(&mut self, _fs: &'a FatFilesystemInner) -> Option<Dir<'a>> {
100 unsafe { std::mem::transmute(self.inner.take()) }
101 }
102}
103
104impl<'a> Wrapper<'a> for FatfsDirRef {
105 type Target = Dir<'a>;
106
107 fn get(&self, _fs: &'a FatFilesystemInner) -> Option<&Dir<'a>> {
108 unsafe { std::mem::transmute(self.inner.as_ref()) }
109 }
110
111 fn get_mut(&mut self, _fs: &'a FatFilesystemInner) -> Option<&mut Dir<'a>> {
112 unsafe { std::mem::transmute(self.inner.as_mut()) }
117 }
118}
119
120unsafe impl Sync for FatfsDirRef {}
122unsafe impl Send for FatfsDirRef {}
123
124impl Drop for FatfsDirRef {
125 fn drop(&mut self) {
126 assert_eq!(self.open_count, 0);
127 assert!(self.inner.is_none());
129 }
130}
131
132pub struct FatfsFileRef {
133 inner: Option<File<'static>>,
134 open_count: usize,
135}
136
137impl FatfsFileRef {
138 pub unsafe fn from(file: File<'_>) -> Self {
141 FatfsFileRef { inner: Some(std::mem::transmute(file)), open_count: 1 }
142 }
143
144 pub unsafe fn maybe_reopen(
146 &mut self,
147 fs: &FatFilesystemInner,
148 parent: &FatDirectory,
149 name: &str,
150 ) -> Result<(), Status> {
151 if self.open_count == 0 { Ok(()) } else { self.reopen(fs, parent, name) }
152 }
153
154 unsafe fn reopen(
155 &mut self,
156 fs: &FatFilesystemInner,
157 parent: &FatDirectory,
158 name: &str,
159 ) -> Result<(), Status> {
160 let file = parent.find_child(fs, name)?.ok_or(Status::NOT_FOUND)?.to_file();
161 self.inner.replace(std::mem::transmute(file));
162 Ok(())
163 }
164
165 pub unsafe fn open(
166 &mut self,
167 fs: &FatFilesystemInner,
168 parent: Option<&FatDirectory>,
169 name: &str,
170 ) -> Result<(), Status> {
171 if self.open_count == std::usize::MAX {
172 Err(Status::UNAVAILABLE)
173 } else {
174 if self.open_count == 0 {
175 self.reopen(fs, parent.ok_or(Status::BAD_HANDLE)?, name)?;
176 }
177 self.open_count += 1;
178 Ok(())
179 }
180 }
181
182 pub fn close(&mut self, fs: &FatFilesystemInner) {
183 assert!(self.open_count > 0);
184 self.open_count -= 1;
185 if self.open_count == 0 {
186 self.take(&fs);
187 }
188 }
189
190 pub fn take<'a>(&mut self, _fs: &'a FatFilesystemInner) -> Option<File<'a>> {
193 self.inner.take()
194 }
195}
196
197impl<'a> Wrapper<'a> for FatfsFileRef {
198 type Target = File<'a>;
199
200 fn get(&self, _fs: &'a FatFilesystemInner) -> Option<&File<'a>> {
201 self.inner.as_ref()
202 }
203
204 fn get_mut(&mut self, _fs: &'a FatFilesystemInner) -> Option<&mut File<'a>> {
205 unsafe { std::mem::transmute(self.inner.as_mut()) }
210 }
211}
212
213unsafe impl Sync for FatfsFileRef {}
215unsafe impl Send for FatfsFileRef {}
216
217impl Drop for FatfsFileRef {
218 fn drop(&mut self) {
219 assert_eq!(self.open_count, 0);
221 assert!(self.inner.is_none());
222 }
223}
224
225pub struct Guard<'a, T>(&'a FatFilesystemInner, Ref<'a, T>);
226
227impl<'a, T> Guard<'a, T> {
228 pub fn new(fs: &'a FatFilesystemInner, inner: Ref<'a, T>) -> Self {
229 Self(fs, inner)
230 }
231}
232
233impl<'a, T: Wrapper<'a>> Deref for Guard<'a, T> {
234 type Target = T::Target;
235 fn deref(&self) -> &T::Target {
236 self.1.get(self.0).unwrap()
237 }
238}
239
240pub(crate) struct GuardMut<'a, T>(&'a FatFilesystemInner, RefMut<'a, T>);
241
242impl<'a, T> GuardMut<'a, T> {
243 pub fn new(fs: &'a FatFilesystemInner, inner: RefMut<'a, T>) -> Self {
244 Self(fs, inner)
245 }
246}
247
248impl<'a, T: Wrapper<'a>> Deref for GuardMut<'a, T> {
249 type Target = T::Target;
250 fn deref(&self) -> &T::Target {
251 self.1.get(self.0).unwrap()
252 }
253}
254
255impl<'a, T: Wrapper<'a>> DerefMut for GuardMut<'a, T> {
256 fn deref_mut(&mut self) -> &mut T::Target {
257 self.1.get_mut(self.0).unwrap()
258 }
259}