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(unsafe { 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 { unsafe { 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(unsafe { 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 unsafe {
82 self.reopen(fs, parent, name)?;
83 }
84 }
85 self.open_count += 1;
86 Ok(())
87 }
88 }
89
90 pub fn close(&mut self, fs: &FatFilesystemInner) {
92 assert!(self.open_count > 0);
93 self.open_count -= 1;
94 if self.open_count == 0 {
95 self.take(&fs);
96 }
97 }
98
99 pub fn take<'a>(&mut self, _fs: &'a FatFilesystemInner) -> Option<Dir<'a>> {
102 unsafe { std::mem::transmute(self.inner.take()) }
103 }
104}
105
106impl<'a> Wrapper<'a> for FatfsDirRef {
107 type Target = Dir<'a>;
108
109 fn get(&self, _fs: &'a FatFilesystemInner) -> Option<&Dir<'a>> {
110 unsafe { std::mem::transmute(self.inner.as_ref()) }
111 }
112
113 fn get_mut(&mut self, _fs: &'a FatFilesystemInner) -> Option<&mut Dir<'a>> {
114 unsafe { std::mem::transmute(self.inner.as_mut()) }
119 }
120}
121
122unsafe impl Sync for FatfsDirRef {}
124unsafe impl Send for FatfsDirRef {}
125
126impl Drop for FatfsDirRef {
127 fn drop(&mut self) {
128 assert_eq!(self.open_count, 0);
129 assert!(self.inner.is_none());
131 }
132}
133
134pub struct FatfsFileRef {
135 inner: Option<File<'static>>,
136 open_count: usize,
137}
138
139impl FatfsFileRef {
140 pub unsafe fn from(file: File<'_>) -> Self {
143 FatfsFileRef { inner: Some(unsafe { std::mem::transmute(file) }), open_count: 1 }
144 }
145
146 pub unsafe fn maybe_reopen(
148 &mut self,
149 fs: &FatFilesystemInner,
150 parent: &FatDirectory,
151 name: &str,
152 ) -> Result<(), Status> {
153 if self.open_count == 0 { Ok(()) } else { unsafe { self.reopen(fs, parent, name) } }
154 }
155
156 unsafe fn reopen(
157 &mut self,
158 fs: &FatFilesystemInner,
159 parent: &FatDirectory,
160 name: &str,
161 ) -> Result<(), Status> {
162 let file = parent.find_child(fs, name)?.ok_or(Status::NOT_FOUND)?.to_file();
163 self.inner.replace(unsafe { std::mem::transmute(file) });
164 Ok(())
165 }
166
167 pub unsafe fn open(
168 &mut self,
169 fs: &FatFilesystemInner,
170 parent: Option<&FatDirectory>,
171 name: &str,
172 ) -> Result<(), Status> {
173 if self.open_count == std::usize::MAX {
174 Err(Status::UNAVAILABLE)
175 } else {
176 if self.open_count == 0 {
177 unsafe {
178 self.reopen(fs, parent.ok_or(Status::BAD_HANDLE)?, name)?;
179 }
180 }
181 self.open_count += 1;
182 Ok(())
183 }
184 }
185
186 pub fn close(&mut self, fs: &FatFilesystemInner) {
187 assert!(self.open_count > 0);
188 self.open_count -= 1;
189 if self.open_count == 0 {
190 self.take(&fs);
191 }
192 }
193
194 pub fn take<'a>(&mut self, _fs: &'a FatFilesystemInner) -> Option<File<'a>> {
197 self.inner.take()
198 }
199}
200
201impl<'a> Wrapper<'a> for FatfsFileRef {
202 type Target = File<'a>;
203
204 fn get(&self, _fs: &'a FatFilesystemInner) -> Option<&File<'a>> {
205 self.inner.as_ref()
206 }
207
208 fn get_mut(&mut self, _fs: &'a FatFilesystemInner) -> Option<&mut File<'a>> {
209 unsafe { std::mem::transmute(self.inner.as_mut()) }
214 }
215}
216
217unsafe impl Sync for FatfsFileRef {}
219unsafe impl Send for FatfsFileRef {}
220
221impl Drop for FatfsFileRef {
222 fn drop(&mut self) {
223 assert_eq!(self.open_count, 0);
225 assert!(self.inner.is_none());
226 }
227}
228
229pub struct Guard<'a, T>(&'a FatFilesystemInner, Ref<'a, T>);
230
231impl<'a, T> Guard<'a, T> {
232 pub fn new(fs: &'a FatFilesystemInner, inner: Ref<'a, T>) -> Self {
233 Self(fs, inner)
234 }
235}
236
237impl<'a, T: Wrapper<'a>> Deref for Guard<'a, T> {
238 type Target = T::Target;
239 fn deref(&self) -> &T::Target {
240 self.1.get(self.0).unwrap()
241 }
242}
243
244pub(crate) struct GuardMut<'a, T>(&'a FatFilesystemInner, RefMut<'a, T>);
245
246impl<'a, T> GuardMut<'a, T> {
247 pub fn new(fs: &'a FatFilesystemInner, inner: RefMut<'a, T>) -> Self {
248 Self(fs, inner)
249 }
250}
251
252impl<'a, T: Wrapper<'a>> Deref for GuardMut<'a, T> {
253 type Target = T::Target;
254 fn deref(&self) -> &T::Target {
255 self.1.get(self.0).unwrap()
256 }
257}
258
259impl<'a, T: Wrapper<'a>> DerefMut for GuardMut<'a, T> {
260 fn deref_mut(&mut self) -> &mut T::Target {
261 self.1.get_mut(self.0).unwrap()
262 }
263}