squashfs_async/
squashfuse.rs1use std::collections::BTreeSet;
3use std::time::UNIX_EPOCH;
4
5use fuser_async::Error as ErrorFuse;
6use fuser_async::{utils::BLOCK_SIZE, DirEntry};
7
8use crate::{Error, SquashFs};
9
10impl From<&super::directory_table::Entry> for DirEntry {
11 fn from(e: &super::directory_table::Entry) -> Self {
12 DirEntry {
13 inode: e.inode as u64,
14 name: e.name.clone(),
15 file_type: if e.is_dir() {
16 fuser::FileType::Directory
17 } else {
18 fuser::FileType::RegularFile
19 },
20 }
21 }
22}
23
24impl<R: deadpool::managed::Manager> SquashFs<R> {
25 fn ino_from_fuse(&self, ino: u64) -> Result<u32, Error> {
27 if ino == fuser::FUSE_ROOT_ID {
28 Ok(self.root_inode)
29 } else if ino == self.inode_extra as u64 {
30 let fuse_root: u32 = fuser::FUSE_ROOT_ID.try_into().unwrap();
31 Ok(fuse_root)
32 } else {
33 ino.try_into().map_err(|_| Error::InvalidInode)
34 }
35 }
36 pub fn ino_to_fuse(&self, ino: u32) -> u64 {
38 let fuse_root: u32 = fuser::FUSE_ROOT_ID.try_into().unwrap();
39 if ino == self.root_inode {
40 fuser::FUSE_ROOT_ID
41 } else if ino == fuse_root {
42 self.inode_extra as u64
43 } else {
44 ino as u64
45 }
46 }
47 fn getattr_inode(&self, ino: u32) -> Result<fuser::FileAttr, Error> {
48 if let Some(f) = self.inode_table.files.get(&ino) {
49 Ok(fuser_async::utils::file_attr(
50 self.ino_to_fuse(ino),
51 f.file_size(),
52 UNIX_EPOCH,
53 ))
54 } else {
55 let directory = self
56 .inode_table
57 .directories
58 .get(&ino)
59 .ok_or(Error::DirectoryNotFound)?;
60 Ok(fuser::FileAttr {
61 ino: self.ino_to_fuse(ino),
62 size: 0,
63 blocks: 0,
64 atime: UNIX_EPOCH,
66 mtime: UNIX_EPOCH,
67 ctime: UNIX_EPOCH,
68 crtime: UNIX_EPOCH,
69 kind: fuser::FileType::Directory,
70 perm: 0o755,
71 nlink: directory.hard_link_count(),
72 uid: 501,
73 gid: 20,
74 rdev: 0,
75 flags: 0,
76 blksize: BLOCK_SIZE,
77 })
78 }
79 }
80}
81
82#[async_trait::async_trait]
83impl<
84 T: crate::AsyncSeekBufRead,
85 R: deadpool::managed::Manager<Type = T, Error = tokio::io::Error> + Send + Sync,
86 > fuser_async::Filesystem for SquashFs<R>
87{
88 type Error = Error;
89 async fn inodes(&self) -> Result<BTreeSet<u64>, Error> {
90 Ok(self.inodes().map(|ino| self.ino_to_fuse(ino)).collect())
91 }
92
93 async fn open(&self, _ino: u64, flags: i32) -> Result<u64, Self::Error> {
94 let mut handles = self.handles.write().await;
95 let fh = handles.keys().last().copied().unwrap_or_default() + 1;
96 handles.insert(fh, flags);
97 Ok(fh)
98 }
99 async fn release(&self, _ino: u64, fh: u64) -> Result<(), Self::Error> {
100 let mut handles = self.handles.write().await;
101 handles
102 .remove(&fh)
103 .ok_or(Error::Fuse(fuser_async::Error::BadFileDescriptor))?;
104 Ok(())
105 }
106
107 async fn lookup(&self, parent: u64, name: &std::ffi::OsStr) -> Result<fuser::FileAttr, Error> {
108 let ino = self.ino_from_fuse(parent)?;
109 let d = self
110 .directory_tables
111 .get(&ino)
112 .ok_or(Error::DirectoryNotFound)?;
113 let name = name.to_str().ok_or(Error::Encoding)?;
114 let f = d
115 .find(name)
116 .ok_or_else(|| Error::FileNotFound(Some(name.into())))?;
117 Ok(self.getattr_inode(f.inode)?)
118 }
119 async fn getattr(&self, ino_fuse: u64) -> Result<fuser::FileAttr, Error> {
120 let ino = self.ino_from_fuse(ino_fuse)?;
121 self.getattr_inode(ino)
122 }
123 async fn setattr(
124 &mut self,
125 _ino: u64,
126 _size: Option<u64>,
127 ) -> Result<fuser::FileAttr, Self::Error> {
128 Err(ErrorFuse::Unimplemented.into())
129 }
130 async fn readdir(
131 &self,
132 ino_fuse: u64,
133 offset: u64,
134 ) -> Result<Box<dyn Iterator<Item = fuser_async::DirEntry> + Send + Sync + '_>, Error> {
135 let ino = self.ino_from_fuse(ino_fuse).unwrap();
136 let d = self
137 .directory_tables
138 .get(&ino)
139 .ok_or(Error::DirectoryNotFound)?;
140 Ok(Box::new(
141 d.entries
142 .iter()
143 .skip(offset as usize)
144 .map(fuser_async::DirEntry::from)
145 .map(|mut e| {
146 e.inode = self.ino_to_fuse(e.inode as u32);
147 e
148 }),
149 ))
150 }
151 async fn read(
152 &self,
153 ino_fuse: u64,
154 fh: u64,
155 offset: i64,
156 size: u32,
157 ) -> Result<bytes::Bytes, Error> {
158 let ino = self.ino_from_fuse(ino_fuse)?;
159 let flags = {
160 let handles = self.handles.read().await;
161 *handles
162 .get(&fh)
163 .ok_or(Error::Fuse(fuser_async::Error::BadFileDescriptor))?
164 };
165 Ok(self
166 .read_file(
167 ino,
168 offset as usize,
169 size as usize,
170 flags,
171 self.superblock.compression,
172 )
173 .await?)
174 }
175 async fn write(
176 &self,
177 _ino: u64,
178 _fh: u64,
179 _data: bytes::Bytes,
180 _offset: i64,
181 ) -> Result<u32, Self::Error> {
182 Err(ErrorFuse::ReadOnly.into())
183 }
184 async fn create(
185 &mut self,
186 _parent: u64,
187 _name: std::ffi::OsString,
188 _mode: u32,
189 _umask: u32,
190 _flags: i32,
191 ) -> Result<(fuser::FileAttr, u64), Self::Error> {
192 Err(ErrorFuse::ReadOnly.into())
193 }
194 async fn mkdir(
195 &mut self,
196 _parent: u64,
197 _name: std::ffi::OsString,
198 ) -> Result<fuser::FileAttr, Self::Error> {
199 Err(ErrorFuse::ReadOnly.into())
200 }
201}