1use std::collections::BTreeSet;
3use std::ffi::{OsStr, OsString};
4use std::ops::Range;
5
6use bimap::BiBTreeMap;
7use tracing::*;
8
9use crate::{DirEntry, Filesystem};
10
11#[async_trait::async_trait]
12pub trait InodeAllocator {
13 type Error;
14 async fn allocate(&mut self, n: usize) -> Result<u64, Self::Error>;
17}
18#[async_trait::async_trait]
19impl<F: Filesystem + Send + Sync> InodeAllocator for F {
20 type Error = F::Error;
21 async fn allocate(&mut self, _n: usize) -> Result<u64, Self::Error> {
22 Ok(self
23 .inodes()
24 .await?
25 .iter()
26 .last()
27 .copied()
28 .unwrap_or(fuser::FUSE_ROOT_ID)
29 + 1)
30 }
31}
32
33#[async_trait::async_trait]
34impl InodeAllocator for () {
35 type Error = crate::Error;
36 async fn allocate(&mut self, _n: usize) -> Result<u64, Self::Error> {
37 Err(crate::Error::NoInodes)
38 }
39}
40#[async_trait::async_trait]
41impl InodeAllocator for Range<u64> {
43 type Error = crate::Error;
44 async fn allocate(&mut self, n: usize) -> Result<u64, Self::Error> {
45 let Range { start, end } = *self;
46 let remaining = end - start;
47 if remaining < n as u64 {
48 Err(crate::Error::NoInodes)
49 } else {
50 *self = (start + n as u64)..end;
51 Ok(start)
52 }
53 }
54}
55#[async_trait::async_trait]
56impl<A: InodeAllocator + Send + Sync> InodeAllocator for std::sync::Arc<tokio::sync::Mutex<A>> {
57 type Error = A::Error;
58 async fn allocate(&mut self, n: usize) -> Result<u64, Self::Error> {
59 let mut x = self.lock().await;
60 x.allocate(n).await
61 }
62}
63
64pub struct RemappedFilesystem<F, A> {
66 pub inner: F,
67 pub mapping: BiBTreeMap<u64 , u64 >,
68 pub allocator: A,
69}
70impl<F, A: InodeAllocator> RemappedFilesystem<F, A> {
71 pub fn new(inner: F, mapping: BiBTreeMap<u64, u64>, allocator: A) -> Self {
72 Self {
74 inner,
75 mapping,
76 allocator,
77 }
78 }
79 pub fn ext_to_int<E>(&self, ext: u64) -> Result<u64, Error<E>> {
80 self.mapping
81 .get_by_left(&ext)
82 .ok_or(Error::NotFound(ext, "ext"))
83 .copied()
84 }
85 pub fn int_to_ext<E>(&self, int: u64) -> Result<u64, Error<E>> {
86 self.mapping
87 .get_by_right(&int)
88 .ok_or(Error::NotFound(int, "int"))
89 .copied()
90 }
91 pub async fn next_ext_ino<E>(&mut self) -> Result<u64, Error<E>> {
92 self.allocator
93 .allocate(1)
94 .await
95 .map_err(|_| Error::NoExtInodes)
96 }
97}
98#[derive(thiserror::Error, Debug)]
99pub enum RefreshError<R, E> {
100 #[error("{0}")]
101 Remapping(#[from] Error<E>),
102 #[error("{0}")]
103 Refresh(R),
104}
105#[async_trait::async_trait]
106impl<A: InodeAllocator + Send + Sync, F: Filesystem + crate::Refresh + Send + Sync> crate::Refresh
107 for RemappedFilesystem<F, A>
108{
109 type Error = RefreshError<<F as crate::Refresh>::Error, <F as Filesystem>::Error>;
110
111 async fn cleanup(&self) -> Result<(), Self::Error> {
112 self.inner.cleanup().await.map_err(RefreshError::Refresh)
113 }
114 async fn refresh(&mut self) -> Result<(), Self::Error> {
115 self.inner.refresh().await.map_err(RefreshError::Refresh)?;
116 let current_int_inodes: BTreeSet<u64> = self.mapping.right_values().copied().collect();
117 let all_int_inodes = self
118 .inner
119 .inodes()
120 .await
121 .map_err(|e| RefreshError::Remapping(Error::Base(e)))?;
122
123 let new = all_int_inodes.len() - current_int_inodes.len();
124
125 debug!(
126 "{} base inodes tracked, {} base inodes in total, {} new",
127 current_int_inodes.len(),
128 all_int_inodes.len(),
129 new
130 );
131 if new > 0 {
132 let next_ext_ino = self
133 .allocator
134 .allocate(new)
135 .await
136 .map_err(|_| Error::NoExtInodes)?;
137 self.mapping.extend(
138 all_int_inodes
139 .difference(¤t_int_inodes)
140 .enumerate()
141 .map(|(i, ino)| (next_ext_ino + i as u64, *ino)),
142 );
143 }
144
145 Ok(())
146 }
147}
148
149#[derive(thiserror::Error, Debug)]
150pub enum Error<E> {
151 #[error("{0}")]
152 Base(#[from] E),
153 #[error("Inode {0} not found in direction {1}")]
154 NotFound(u64, &'static str),
155 #[error("No more external inodes available")]
156 NoExtInodes,
157}
158impl<E: Into<crate::Error>> From<Error<E>> for crate::Error {
159 fn from(source: Error<E>) -> Self {
160 match source {
161 Error::NotFound(_, _) => crate::Error::NoFileDir,
162 Error::NoExtInodes => crate::Error::NoInodes,
163 Error::Base(b) => b.into(),
164 }
165 }
166}
167
168#[async_trait::async_trait]
169impl<A: InodeAllocator + Send + Sync, F: Filesystem + Send + Sync> Filesystem
170 for RemappedFilesystem<F, A>
171{
172 type Error = Error<F::Error>;
173 async fn inodes(&self) -> Result<BTreeSet<u64>, Self::Error> {
174 Ok(self.mapping.left_values().copied().collect())
175 }
176 async fn destroy(&mut self) -> Result<(), Self::Error> {
177 self.inner.destroy().await.map_err(Error::Base)
178 }
179 async fn lookup(&self, parent: u64, name: &OsStr) -> Result<fuser::FileAttr, Self::Error> {
180 let parent = self.ext_to_int(parent)?;
181 let mut attr = self.inner.lookup(parent, name).await?;
182 attr.ino = self.int_to_ext(attr.ino)?;
183 Ok(attr)
184 }
185 async fn open(&self, ino: u64, flags: i32) -> Result<u64, Self::Error> {
186 let ino = self.ext_to_int(ino)?;
187 Ok(self.inner.open(ino, flags).await?)
188 }
189 async fn release(&self, ino: u64, fh: u64) -> Result<(), Self::Error> {
190 let ino = self.ext_to_int(ino)?;
191 Ok(self.inner.release(ino, fh).await?)
192 }
193 async fn getattr(&self, ino_ext: u64) -> Result<fuser::FileAttr, Self::Error> {
194 let ino_int = self.ext_to_int(ino_ext)?;
195 let mut attr = self.inner.getattr(ino_int).await?;
196 attr.ino = ino_ext;
197 Ok(attr)
198 }
199 async fn setattr(
200 &mut self,
201 ino_ext: u64,
202 size: Option<u64>,
203 ) -> Result<fuser::FileAttr, Self::Error> {
204 let ino_int = self.ext_to_int(ino_ext)?;
205 let mut attr = self.inner.setattr(ino_int, size).await?;
206 attr.ino = ino_ext;
207 Ok(attr)
208 }
209 async fn readdir(
210 &self,
211 ino: u64,
212 offset: u64,
213 ) -> Result<Box<dyn Iterator<Item = DirEntry> + Send + Sync + '_>, Self::Error> {
214 let ino = self.ext_to_int(ino)?;
215 #[allow(clippy::needless_collect)]
216 let dir: Result<Vec<DirEntry>, _> = self
217 .inner
218 .readdir(ino, offset)
219 .await?
220 .map(move |mut e| {
221 e.inode = self.int_to_ext(e.inode)?;
222 Ok::<_, Self::Error>(e)
223 })
224 .collect();
225 Ok(Box::new(dir?.into_iter()))
226 }
227 async fn read(
228 &self,
229 ino: u64,
230 fh: u64,
231 offset: i64,
232 size: u32,
233 ) -> Result<bytes::Bytes, Self::Error> {
234 let ino = self.ext_to_int(ino)?;
235 Ok(self.inner.read(ino, fh, offset, size).await?)
236 }
237 async fn write(
238 &self,
239 ino: u64,
240 fh: u64,
241 data: bytes::Bytes,
242 offset: i64,
243 ) -> Result<u32, Self::Error> {
244 let ino = self.ext_to_int(ino)?;
245 Ok(self.inner.write(ino, fh, data, offset).await?)
246 }
247 async fn create(
248 &mut self,
249 parent: u64,
250 name: std::ffi::OsString,
251 mode: u32,
252 umask: u32,
253 flags: i32,
254 ) -> Result<(fuser::FileAttr, u64), Self::Error> {
255 let parent = self.ext_to_int(parent)?;
256 let (mut attr, fh) = self.inner.create(parent, name, mode, umask, flags).await?;
257 let ext_ino = self.next_ext_ino().await?;
258 self.mapping.insert(ext_ino, attr.ino);
259 attr.ino = ext_ino;
260 Ok((attr, fh))
261 }
262 async fn mkdir(&mut self, parent: u64, name: OsString) -> Result<fuser::FileAttr, Self::Error> {
263 let parent = self.ext_to_int(parent)?;
264 let mut attr = self.inner.mkdir(parent, name).await?;
265 let ext_ino = self.next_ext_ino().await?;
266 self.mapping.insert(ext_ino, attr.ino);
267 attr.ino = ext_ino;
268 Ok(attr)
269 }
270}