1use crate::server::{
2 DirEntry, FileType, LinuxOpenMode, LinuxStat, LinuxStatValidity, Lock, LockCommand, LockKind,
3 LockStatus, Metadata, SimpleOpenMode, Stat, Tag, FID, QID,
4};
5use lawn_constants::Error;
6use lawn_fs::backend as fsbackend;
7use std::collections::BTreeMap;
8use std::fs;
9use std::sync::atomic::{AtomicU32, Ordering};
10use std::sync::Mutex;
11use std::time::SystemTime;
12
13type Result<T> = std::result::Result<T, Error>;
14
15#[cfg(feature = "unix")]
16pub mod libc;
17
18pub trait Backend {
20 fn version(&self, meta: &Metadata, max_size: u32, version: &[u8]) -> Result<(u32, Vec<u8>)>;
21 fn auth(
22 &self,
23 meta: &Metadata,
24 afid: FID,
25 uname: &[u8],
26 aname: &[u8],
27 nuname: Option<u32>,
28 ) -> Result<QID>;
29 fn attach(
30 &self,
31 meta: &Metadata,
32 fid: FID,
33 afid: FID,
34 uname: &[u8],
35 aname: &[u8],
36 nuname: Option<u32>,
37 ) -> Result<QID>;
38 fn clunk(&self, meta: &Metadata, fid: FID) -> Result<()>;
39 fn clunk_all(&self, meta: &Metadata) -> Result<()>;
40 fn flush(&self, meta: &Metadata, tag: Tag) -> Result<()>;
41 fn open(&self, meta: &Metadata, fid: FID, mode: SimpleOpenMode) -> Result<(QID, u32)>;
42 fn lopen(&self, meta: &Metadata, fid: FID, flags: LinuxOpenMode) -> Result<(QID, u32)>;
43 fn create(
44 &self,
45 meta: &Metadata,
46 fid: FID,
47 name: &[u8],
48 perm: FileType,
49 mode: SimpleOpenMode,
50 extension: Option<&[u8]>,
51 ) -> Result<(QID, u32)>;
52 #[allow(clippy::too_many_arguments)]
53 fn lcreate(
54 &self,
55 meta: &Metadata,
56 fid: FID,
57 name: &[u8],
58 flags: u32,
59 mode: u32,
60 gid: u32,
61 ) -> Result<(QID, u32)>;
62 fn read(&self, meta: &Metadata, fid: FID, offset: u64, data: &mut [u8]) -> Result<u32>;
63 fn write(&self, meta: &Metadata, fid: FID, offset: u64, data: &[u8]) -> Result<u32>;
64 fn remove(&self, meta: &Metadata, fid: FID) -> Result<()>;
68 fn fsync(&self, meta: &Metadata, fid: FID);
69 fn stat(&self, meta: &Metadata, fid: FID) -> Result<Box<dyn Stat>>;
70 fn wstat(&self, meta: &Metadata, fid: FID, stat: &dyn Stat) -> Result<()>;
71 fn walk(&self, meta: &Metadata, fid: FID, newfid: FID, name: &[&[u8]]) -> Result<Vec<QID>>;
72 fn symlink(
73 &self,
74 meta: &Metadata,
75 fid: FID,
76 name: &[u8],
77 target: &[u8],
78 gid: u32,
79 ) -> Result<QID>;
80 #[allow(clippy::too_many_arguments)]
81 fn mknod(
82 &self,
83 meta: &Metadata,
84 fid: FID,
85 name: &[u8],
86 mode: u32,
87 major: u32,
88 minor: u32,
89 gid: u32,
90 ) -> Result<QID>;
91 fn rename(&self, meta: &Metadata, fid: FID, dfid: FID, name: &[u8]) -> Result<()>;
92 fn readlink(&self, meta: &Metadata, fid: FID) -> Result<Vec<u8>>;
93 fn getattr(&self, meta: &Metadata, fid: FID, mask: LinuxStatValidity) -> Result<LinuxStat>;
94 #[allow(clippy::too_many_arguments)]
103 fn setattr(
104 &self,
105 meta: &Metadata,
106 fid: FID,
107 mode: Option<u32>,
108 uid: Option<u32>,
109 gid: Option<u32>,
110 size: Option<u64>,
111 atime: Option<SystemTime>,
112 mtime: Option<SystemTime>,
113 set_atime: bool,
114 set_mtime: bool,
115 ) -> Result<()>;
116 fn xattrwalk(&self, meta: &Metadata, fid: FID, newfid: FID, name: &[u8]) -> Result<u64>;
117 fn xattrcreate(
118 &self,
119 meta: &Metadata,
120 fid: FID,
121 name: &[u8],
122 size: u64,
123 flags: u32,
124 ) -> Result<()>;
125 fn readdir(&self, meta: &Metadata, fid: FID, offset: u64, count: u32) -> Result<Vec<DirEntry>>;
126 #[allow(clippy::too_many_arguments)]
127 fn lock(
128 &self,
129 meta: &Metadata,
130 fid: FID,
131 kind: LockCommand,
132 flags: u32,
133 start: u64,
134 length: u64,
135 proc_id: u32,
136 client_id: &[u8],
137 ) -> Result<LockStatus>;
138 #[allow(clippy::too_many_arguments)]
139 fn getlock(
140 &self,
141 meta: &Metadata,
142 fid: FID,
143 kind: LockKind,
144 start: u64,
145 length: u64,
146 proc_id: u32,
147 client_id: &[u8],
148 ) -> Result<Lock>;
149 fn link(&self, meta: &Metadata, dfid: FID, fid: FID, nane: &[u8]) -> Result<()>;
150 fn mkdir(&self, meta: &Metadata, dfid: FID, name: &[u8], mode: u32, gid: u32) -> Result<QID>;
151 fn renameat(
152 &self,
153 meta: &Metadata,
154 olddirfid: FID,
155 oldname: &[u8],
156 newdirfid: FID,
157 newname: &[u8],
158 ) -> Result<()>;
159 fn unlinkat(&self, meta: &Metadata, dirfd: FID, name: &[u8], flags: u32) -> Result<()>;
160}
161
162pub trait ToIdentifier: Ord {
163 fn to_identifier(&self) -> Vec<u8>;
164}
165
166impl<T: Ord + AsRef<[u8]>> ToIdentifier for T {
167 fn to_identifier(&self) -> Vec<u8> {
168 self.as_ref().into()
169 }
170}
171
172#[derive(Eq, PartialEq, Ord, PartialOrd)]
173pub enum FIDKind<AH: ToIdentifier, FH: ToIdentifier, DH: ToIdentifier, SH: ToIdentifier> {
174 Auth(AH),
175 File(FH),
176 Dir(DH),
177 Symlink(SH),
178 Special(SH),
179}
180
181#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
182pub enum FileKind {
183 Auth = 0x08,
184 File = 0x00,
185 Dir = 0x80,
186 Symlink = 0x02,
187 Special = 0xff,
188}
189
190impl From<fsbackend::QIDKind> for FileKind {
191 fn from(k: fsbackend::QIDKind) -> FileKind {
192 match k {
193 fsbackend::QIDKind::Directory => FileKind::Dir,
194 fsbackend::QIDKind::Regular => FileKind::File,
195 fsbackend::QIDKind::FIFO => FileKind::Special,
196 fsbackend::QIDKind::Symlink => FileKind::Symlink,
197 fsbackend::QIDKind::BlockDevice => FileKind::Special,
198 fsbackend::QIDKind::CharacterDevice => FileKind::Special,
199 fsbackend::QIDKind::Socket => FileKind::Special,
200 fsbackend::QIDKind::Authentication => FileKind::Auth,
201 fsbackend::QIDKind::Unknown => FileKind::Special,
202 }
203 }
204}
205
206impl FileKind {
207 #[cfg(feature = "unix")]
208 pub fn from_metadata(metadata: &fs::Metadata) -> Self {
209 use std::os::unix::fs::FileTypeExt;
210
211 let ft = metadata.file_type();
212 if ft.is_fifo() || ft.is_socket() || ft.is_block_device() || ft.is_char_device() {
213 Self::Special
214 } else if ft.is_dir() {
215 Self::Dir
216 } else if ft.is_symlink() {
217 Self::Symlink
218 } else {
219 Self::File
220 }
221 }
222}
223
224#[derive(Default)]
225pub struct QIDMapper {
226 next: AtomicU32,
227 tree: Mutex<BTreeMap<u64, u32>>,
228}
229
230impl QIDMapper {
231 pub fn new() -> QIDMapper {
232 Self {
233 next: AtomicU32::new(0),
234 tree: Mutex::new(BTreeMap::new()),
235 }
236 }
237 pub fn qid(&self, q: fsbackend::QID) -> QID {
238 let id = {
239 let mut g = self.tree.lock().unwrap();
240 *g.entry(q.dev())
241 .or_insert_with(|| self.next.fetch_add(1, Ordering::AcqRel))
242 };
243 let mut data = [0u8; 13];
244 data[0] = FileKind::from(q.kind()) as u8;
245 data[1..5].copy_from_slice(&id.to_le_bytes());
246 data[5..].copy_from_slice(&q.ino().to_le_bytes());
247 QID(data)
248 }
249}