|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 2 | + |
| 3 | +//! File System Interfaces. |
| 4 | +
|
| 5 | +use super::file_operations::{FileOpenAdapter, FileOpener, FileOperationsVtable}; |
| 6 | +use crate::bindings::{ |
| 7 | + dentry, file, file_operations, file_system_type, inode, mount_bdev, mount_nodev, mount_single, |
| 8 | + register_filesystem, super_block, unregister_filesystem, |
| 9 | +}; |
| 10 | +use crate::str::*; |
| 11 | +use crate::{c_str, c_types, error::Error, Result, ThisModule}; |
| 12 | +use alloc::boxed::Box; |
| 13 | +use alloc::vec::Vec; |
| 14 | +use core::ptr; |
| 15 | + |
| 16 | +pub const S_IRWXU: i32 = crate::bindings::S_IRWXU as i32; |
| 17 | +pub const S_IRUSR: i32 = crate::bindings::S_IRUSR as i32; |
| 18 | +pub const S_IWUSR: i32 = crate::bindings::S_IWUSR as i32; |
| 19 | +pub const S_IXUSR: i32 = crate::bindings::S_IXUSR as i32; |
| 20 | +pub const S_IRWXG: i32 = crate::bindings::S_IRWXG as i32; |
| 21 | +pub const S_IRGRP: i32 = crate::bindings::S_IRGRP as i32; |
| 22 | +pub const S_IWGRP: i32 = crate::bindings::S_IWGRP as i32; |
| 23 | +pub const S_IXGRP: i32 = crate::bindings::S_IXGRP as i32; |
| 24 | +pub const S_IRWXO: i32 = crate::bindings::S_IRWXO as i32; |
| 25 | +pub const S_IROTH: i32 = crate::bindings::S_IROTH as i32; |
| 26 | +pub const S_IWOTH: i32 = crate::bindings::S_IWOTH as i32; |
| 27 | +pub const S_IXOTH: i32 = crate::bindings::S_IXOTH as i32; |
| 28 | + |
| 29 | +unsafe extern "C" fn mount_callback<T: FileSystem>( |
| 30 | + fs_type: *mut file_system_type, |
| 31 | + flags: c_types::c_int, |
| 32 | + dev_name: *const c_types::c_char, |
| 33 | + data: *mut c_types::c_void, |
| 34 | +) -> *mut dentry { |
| 35 | + let r_fs_type = FSType::from_c_fs_type(fs_type).unwrap(); |
| 36 | + let r_dev_name = if dev_name.is_null() { |
| 37 | + c_str!("") |
| 38 | + } else { |
| 39 | + unsafe { CStr::from_char_ptr(dev_name) } |
| 40 | + }; |
| 41 | + let r_data = if data.is_null() { |
| 42 | + c_str!("") |
| 43 | + } else { |
| 44 | + unsafe { CStr::from_char_ptr(data as *const c_types::c_char) } |
| 45 | + }; |
| 46 | + |
| 47 | + let rt: Result<Dentry> = match T::MOUNT_TYPE { |
| 48 | + MountType::Custom => T::mount(&r_fs_type, flags, r_dev_name, r_data), |
| 49 | + MountType::Single => Dentry::from_c_dentry(unsafe { |
| 50 | + mount_single(fs_type, flags, data, Some(fill_super_callback::<T>)) |
| 51 | + }), |
| 52 | + MountType::BDev => Dentry::from_c_dentry(unsafe { |
| 53 | + mount_bdev( |
| 54 | + fs_type, |
| 55 | + flags, |
| 56 | + dev_name, |
| 57 | + data, |
| 58 | + Some(fill_super_callback::<T>), |
| 59 | + ) |
| 60 | + }), |
| 61 | + MountType::NoDev => Dentry::from_c_dentry(unsafe { |
| 62 | + mount_nodev(fs_type, flags, data, Some(fill_super_callback::<T>)) |
| 63 | + }), |
| 64 | + }; |
| 65 | + |
| 66 | + if let Err(e) = rt { |
| 67 | + //TODO wrap ETR_PTR |
| 68 | + return e.to_kernel_errno() as *mut dentry; |
| 69 | + } |
| 70 | + |
| 71 | + rt.unwrap().to_c_dentry() |
| 72 | +} |
| 73 | + |
| 74 | +unsafe extern "C" fn fill_super_callback<T: FileSystem>( |
| 75 | + sb: *mut super_block, |
| 76 | + data: *mut c_types::c_void, |
| 77 | + silent: c_types::c_int, |
| 78 | +) -> c_types::c_int { |
| 79 | + let r_sb_rs = SuperBlock::from_c_super_block(sb); |
| 80 | + if let Err(e) = r_sb_rs { |
| 81 | + return e.to_kernel_errno(); |
| 82 | + } |
| 83 | + |
| 84 | + let mut r_sb = r_sb_rs.unwrap(); |
| 85 | + let r_data = if data.is_null() { |
| 86 | + c_str!("") |
| 87 | + } else { |
| 88 | + unsafe { CStr::from_char_ptr(data as *const c_types::c_char) } |
| 89 | + }; |
| 90 | + |
| 91 | + let rs = T::fill_super(&mut r_sb, r_data, silent as i32); |
| 92 | + if let Err(e) = rs { |
| 93 | + return e.to_kernel_errno(); |
| 94 | + } |
| 95 | + |
| 96 | + 0 |
| 97 | +} |
| 98 | + |
| 99 | +unsafe extern "C" fn kill_sb_callback<T: FileSystem>(sb: *mut super_block) { |
| 100 | + let r_sb_rs = SuperBlock::from_c_super_block(sb); |
| 101 | + |
| 102 | + if let Ok(r_sb) = r_sb_rs { |
| 103 | + T::kill_sb(&r_sb); |
| 104 | + } |
| 105 | +} |
| 106 | + |
| 107 | +pub struct Dentry { |
| 108 | + c_dentry: *mut dentry, |
| 109 | +} |
| 110 | + |
| 111 | +impl Dentry { |
| 112 | + pub fn default() -> Dentry { |
| 113 | + Dentry { |
| 114 | + c_dentry: ptr::null_mut(), |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + pub fn from_c_dentry(c_dentry: *mut dentry) -> Result<Self> { |
| 119 | + if c_dentry.is_null() { |
| 120 | + return Err(Error::EINVAL); |
| 121 | + } |
| 122 | + |
| 123 | + //TODO inc refcnt, and dec in dtor |
| 124 | + let mut d = Dentry::default(); |
| 125 | + d.c_dentry = c_dentry; |
| 126 | + |
| 127 | + Ok(d) |
| 128 | + } |
| 129 | + |
| 130 | + pub fn to_c_dentry(&self) -> *mut dentry { |
| 131 | + return self.c_dentry; |
| 132 | + } |
| 133 | +} |
| 134 | + |
| 135 | +pub struct Inode { |
| 136 | + c_inode: *mut inode, |
| 137 | +} |
| 138 | + |
| 139 | +impl Inode { |
| 140 | + pub fn default() -> Inode { |
| 141 | + Inode { |
| 142 | + c_inode: ptr::null_mut(), |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + pub fn from_c_inode(c_inode: *mut inode) -> Result<Self> { |
| 147 | + if c_inode.is_null() { |
| 148 | + return Err(Error::EINVAL); |
| 149 | + } |
| 150 | + |
| 151 | + //TODO inc refcnt, and dec in dtor |
| 152 | + let mut i = Inode::default(); |
| 153 | + i.c_inode = c_inode; |
| 154 | + |
| 155 | + Ok(i) |
| 156 | + } |
| 157 | + |
| 158 | + pub fn to_c_inode(&self) -> *mut inode { |
| 159 | + return self.c_inode; |
| 160 | + } |
| 161 | +} |
| 162 | + |
| 163 | +pub struct SuperBlock { |
| 164 | + c_sb: *mut super_block, |
| 165 | +} |
| 166 | + |
| 167 | +impl SuperBlock { |
| 168 | + pub fn default() -> SuperBlock { |
| 169 | + SuperBlock { |
| 170 | + c_sb: ptr::null_mut(), |
| 171 | + } |
| 172 | + } |
| 173 | + |
| 174 | + pub fn from_c_super_block(c_sb: *mut super_block) -> Result<Self> { |
| 175 | + if c_sb.is_null() { |
| 176 | + return Err(Error::EINVAL); |
| 177 | + } |
| 178 | + |
| 179 | + let mut sb = SuperBlock::default(); |
| 180 | + sb.c_sb = c_sb; |
| 181 | + |
| 182 | + Ok(sb) |
| 183 | + } |
| 184 | + |
| 185 | + pub fn to_c_super_block(&mut self) -> *mut super_block { |
| 186 | + self.c_sb |
| 187 | + } |
| 188 | +} |
| 189 | + |
| 190 | +pub struct FSType { |
| 191 | + c_fs_type: *mut file_system_type, |
| 192 | +} |
| 193 | + |
| 194 | +impl FSType { |
| 195 | + pub fn default() -> FSType { |
| 196 | + FSType { |
| 197 | + c_fs_type: ptr::null_mut(), |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + pub fn from_c_fs_type(c_fs_type: *mut file_system_type) -> Result<Self> { |
| 202 | + if c_fs_type.is_null() { |
| 203 | + return Err(Error::EINVAL); |
| 204 | + } |
| 205 | + |
| 206 | + let mut fs_type = FSType::default(); |
| 207 | + fs_type.c_fs_type = c_fs_type; |
| 208 | + |
| 209 | + Ok(fs_type) |
| 210 | + } |
| 211 | + |
| 212 | + pub fn to_c_fs_type(&mut self) -> *mut file_system_type { |
| 213 | + self.c_fs_type |
| 214 | + } |
| 215 | +} |
| 216 | + |
| 217 | +pub enum MountType { |
| 218 | + // Call user provided mount function instead of [`fill_super()`] |
| 219 | + Custom, |
| 220 | + |
| 221 | + // Mount a filesystem residing on a block device |
| 222 | + BDev, |
| 223 | + |
| 224 | + // Mount a filesystem that is not backed by a device |
| 225 | + NoDev, |
| 226 | + |
| 227 | + // Mount a filesystem which shares the instance between all mounts |
| 228 | + Single, |
| 229 | +} |
| 230 | + |
| 231 | +impl<T: FileOpener<()>> FileOpenAdapter for T { |
| 232 | + type Arg = (); |
| 233 | + |
| 234 | + unsafe fn convert(_inode: *mut inode, _file: *mut file) -> *const Self::Arg { |
| 235 | + &() |
| 236 | + } |
| 237 | +} |
| 238 | + |
| 239 | +pub fn build_fops<A: FileOpenAdapter, T: FileOpener<A::Arg>>() -> &'static file_operations { |
| 240 | + return unsafe { FileOperationsVtable::<A, T>::build() }; |
| 241 | +} |
| 242 | + |
| 243 | +// export tree_descr |
| 244 | +pub use crate::bindings::tree_descr; |
| 245 | + |
| 246 | +#[macro_export] |
| 247 | +macro_rules! treedescr { |
| 248 | + ( |
| 249 | + $($name:literal,$ops:ident,$mode:expr;)+ |
| 250 | + ) => { |
| 251 | + { |
| 252 | + let mut v = Vec::<tree_descr>::new(); |
| 253 | + |
| 254 | + // Because the root inode is 1, the files array must not contain an |
| 255 | + // entry at index 1. We make them start at index 2. |
| 256 | + v.push(tree_descr::default()); // index 0 skipped |
| 257 | + v.push(tree_descr::default()); // index 1 skipped |
| 258 | + |
| 259 | + $( |
| 260 | + let mut tdesc = tree_descr::default(); |
| 261 | + tdesc.name = c_str!($name).as_char_ptr(); |
| 262 | + tdesc.ops = build_fops::<$ops, $ops>(); |
| 263 | + tdesc.mode = $mode; |
| 264 | + |
| 265 | + v.push(tdesc); |
| 266 | + )+ |
| 267 | + |
| 268 | + // Add ending mark |
| 269 | + let mut tdesc = tree_descr::default(); |
| 270 | + tdesc.name = c_str!("").as_char_ptr(); |
| 271 | + v.push(tdesc); |
| 272 | + |
| 273 | + v |
| 274 | + } |
| 275 | + }; |
| 276 | + () => { |
| 277 | + { |
| 278 | + let mut v = Vec::<tree_descr>::new(); |
| 279 | + |
| 280 | + let mut tdesc = tree_descr::default(); |
| 281 | + tdesc.name = c_str!("").as_char_ptr(); |
| 282 | + |
| 283 | + v.push(tdesc); |
| 284 | + v |
| 285 | + } |
| 286 | + }; |
| 287 | +} |
| 288 | + |
| 289 | +pub fn simple_fill_super(sb: &mut SuperBlock, magic: usize, vec: &Vec<tree_descr>) -> Result<()> { |
| 290 | + let rt = unsafe { |
| 291 | + crate::bindings::simple_fill_super( |
| 292 | + sb.to_c_super_block(), |
| 293 | + magic as c_types::c_ulong, |
| 294 | + vec.as_ptr(), |
| 295 | + ) |
| 296 | + }; |
| 297 | + if rt != 0 { |
| 298 | + return Err(Error::from_kernel_errno(rt)); |
| 299 | + } |
| 300 | + |
| 301 | + Ok(()) |
| 302 | +} |
| 303 | + |
| 304 | +pub type FSHandle = Box<file_system_type>; |
| 305 | + |
| 306 | +pub trait FileSystem: Sized + Sync { |
| 307 | + const MOUNT_TYPE: MountType; |
| 308 | + |
| 309 | + fn mount(_fs_type: &FSType, _flags: i32, _dev_name: &CStr, _data: &CStr) -> Result<Dentry> { |
| 310 | + Err(Error::EINVAL) |
| 311 | + } |
| 312 | + |
| 313 | + fn fill_super(_sb: &mut SuperBlock, _data: &CStr, _silent: i32) -> Result<()> { |
| 314 | + Err(Error::EINVAL) |
| 315 | + } |
| 316 | + |
| 317 | + fn kill_sb(_sb: &SuperBlock) {} |
| 318 | + |
| 319 | + fn register_self(name: &'static CStr, owner: &ThisModule) -> Result<FSHandle> |
| 320 | + where |
| 321 | + Self: Sized, |
| 322 | + { |
| 323 | + let mut c_fs_type = Box::new(file_system_type::default()); |
| 324 | + c_fs_type.mount = Some(mount_callback::<Self>); |
| 325 | + c_fs_type.kill_sb = Some(kill_sb_callback::<Self>); |
| 326 | + c_fs_type.owner = owner.0; |
| 327 | + c_fs_type.name = name.as_char_ptr(); |
| 328 | + |
| 329 | + let err = unsafe { register_filesystem(c_fs_type.as_mut() as *mut _) }; |
| 330 | + if err != 0 { |
| 331 | + return Err(Error::from_kernel_errno(err)); |
| 332 | + } |
| 333 | + |
| 334 | + Ok(c_fs_type) |
| 335 | + } |
| 336 | + |
| 337 | + fn unregister_self(c_fs_type: &mut FSHandle) -> Result<()> { |
| 338 | + let err = unsafe { unregister_filesystem(c_fs_type.as_mut() as *mut _) }; |
| 339 | + if err != 0 { |
| 340 | + return Err(Error::from_kernel_errno(err)); |
| 341 | + } |
| 342 | + |
| 343 | + Ok(()) |
| 344 | + } |
| 345 | +} |
0 commit comments