| 1 | |
| 2 | |
| 3 |
|
| 4 | use super::{
|
| 5 | BinaryReader,
|
| 6 | BinaryWriter,
|
| 7 | Reader,
|
| 8 | Writer, |
| 9 | };
|
| 10 |
|
| 11 | use crate::{
|
| 12 | debugfs::callback_adapters::Adapter,
|
| 13 | fmt,
|
| 14 | fs::file,
|
| 15 | prelude::*,
|
| 16 | seq_file::SeqFile,
|
| 17 | seq_print,
|
| 18 | uaccess::UserSlice, |
| 19 | };
|
| 20 |
|
| 21 | use core::marker::PhantomData;
|
| 22 |
|
| 23 | #[cfg(CONFIG_DEBUG_FS)]
|
| 24 | use core::ops::Deref;
|
| 25 |
|
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | pub(super) struct FileOps<T> {
|
| 32 | #[cfg(CONFIG_DEBUG_FS)]
|
| 33 | operations: bindings::file_operations,
|
| 34 | #[cfg(CONFIG_DEBUG_FS)]
|
| 35 | mode: u16,
|
| 36 | _phantom: PhantomData<T>,
|
| 37 | }
|
| 38 |
|
| 39 | impl<T> FileOps<T> {
|
| 40 | |
| 41 | |
| 42 | |
| 43 | |
| 44 | const unsafe fn new(operations: bindings::file_operations, mode: u16) -> Self {
|
| 45 | Self {
|
| 46 | #[cfg(CONFIG_DEBUG_FS)]
|
| 47 | operations,
|
| 48 | #[cfg(CONFIG_DEBUG_FS)]
|
| 49 | mode,
|
| 50 | _phantom: PhantomData,
|
| 51 | }
|
| 52 | }
|
| 53 |
|
| 54 | #[cfg(CONFIG_DEBUG_FS)]
|
| 55 | pub(crate) const fn mode(&self) -> u16 {
|
| 56 | self.mode
|
| 57 | }
|
| 58 | }
|
| 59 |
|
| 60 | impl<T: Adapter> FileOps<T> {
|
| 61 | pub(super) const fn adapt(&self) -> &FileOps<T::Inner> {
|
| 62 | |
| 63 | unsafe { core::mem::transmute(self) }
|
| 64 | }
|
| 65 | }
|
| 66 |
|
| 67 | #[cfg(CONFIG_DEBUG_FS)]
|
| 68 | impl<T> Deref for FileOps<T> {
|
| 69 | type Target = bindings::file_operations;
|
| 70 |
|
| 71 | fn deref(&self) -> &Self::Target {
|
| 72 | &self.operations
|
| 73 | }
|
| 74 | }
|
| 75 |
|
| 76 | struct WriterAdapter<T>(T);
|
| 77 |
|
| 78 | impl<'a, T: Writer> fmt::Display for WriterAdapter<&'a T> {
|
| 79 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
| 80 | self.0.write(f)
|
| 81 | }
|
| 82 | }
|
| 83 |
|
| 84 | |
| 85 | |
| 86 | |
| 87 | |
| 88 | |
| 89 | |
| 90 | |
| 91 | unsafe extern "C" fn writer_open<T: Writer + Sync>(
|
| 92 | inode: *mut bindings::inode,
|
| 93 | file: *mut bindings::file,
|
| 94 | ) -> c_int {
|
| 95 | |
| 96 | let data = unsafe { (*inode).i_private };
|
| 97 | |
| 98 | |
| 99 | |
| 100 | |
| 101 | |
| 102 | |
| 103 | unsafe { bindings::single_open(file, Some(writer_act::<T>), data) }
|
| 104 | }
|
| 105 |
|
| 106 | |
| 107 | |
| 108 | |
| 109 | |
| 110 | |
| 111 | |
| 112 | unsafe extern "C" fn writer_act<T: Writer + Sync>(
|
| 113 | seq: *mut bindings::seq_file,
|
| 114 | _: *mut c_void,
|
| 115 | ) -> c_int {
|
| 116 | |
| 117 | |
| 118 | let data = unsafe { &*((*seq).private.cast::<T>()) };
|
| 119 | |
| 120 | |
| 121 | let seq_file = unsafe { SeqFile::from_raw(seq) };
|
| 122 | seq_print!(seq_file, "{}", WriterAdapter(data));
|
| 123 | 0
|
| 124 | }
|
| 125 |
|
| 126 | |
| 127 | pub(crate) trait ReadFile<T> {
|
| 128 | const FILE_OPS: FileOps<T>;
|
| 129 | }
|
| 130 |
|
| 131 | impl<T: Writer + Sync> ReadFile<T> for T {
|
| 132 | const FILE_OPS: FileOps<T> = {
|
| 133 | let operations = bindings::file_operations {
|
| 134 | read: Some(bindings::seq_read),
|
| 135 | llseek: Some(bindings::seq_lseek),
|
| 136 | release: Some(bindings::single_release),
|
| 137 | open: Some(writer_open::<Self>),
|
| 138 | ..pin_init::zeroed()
|
| 139 | };
|
| 140 | |
| 141 | |
| 142 | |
| 143 | |
| 144 | unsafe { FileOps::new(operations, 0o400) }
|
| 145 | };
|
| 146 | }
|
| 147 |
|
| 148 | fn read<T: Reader + Sync>(data: &T, buf: *const c_char, count: usize) -> isize {
|
| 149 | let mut reader = UserSlice::new(UserPtr::from_ptr(buf as *mut c_void), count).reader();
|
| 150 |
|
| 151 | if let Err(e) = data.read_from_slice(&mut reader) {
|
| 152 | return e.to_errno() as isize;
|
| 153 | }
|
| 154 |
|
| 155 | count as isize
|
| 156 | }
|
| 157 |
|
| 158 | |
| 159 | |
| 160 | |
| 161 | |
| 162 | |
| 163 | |
| 164 | pub(crate) unsafe extern "C" fn write<T: Reader + Sync>(
|
| 165 | file: *mut bindings::file,
|
| 166 | buf: *const c_char,
|
| 167 | count: usize,
|
| 168 | _ppos: *mut bindings::loff_t,
|
| 169 | ) -> isize {
|
| 170 | |
| 171 | let seq = unsafe { &mut *((*file).private_data.cast::<bindings::seq_file>()) };
|
| 172 | |
| 173 | let data = unsafe { &*(seq.private as *const T) };
|
| 174 | read(data, buf, count)
|
| 175 | }
|
| 176 |
|
| 177 | |
| 178 | pub(crate) trait ReadWriteFile<T> {
|
| 179 | const FILE_OPS: FileOps<T>;
|
| 180 | }
|
| 181 |
|
| 182 | impl<T: Writer + Reader + Sync> ReadWriteFile<T> for T {
|
| 183 | const FILE_OPS: FileOps<T> = {
|
| 184 | let operations = bindings::file_operations {
|
| 185 | open: Some(writer_open::<T>),
|
| 186 | read: Some(bindings::seq_read),
|
| 187 | write: Some(write::<T>),
|
| 188 | llseek: Some(bindings::seq_lseek),
|
| 189 | release: Some(bindings::single_release),
|
| 190 | ..pin_init::zeroed()
|
| 191 | };
|
| 192 | |
| 193 | |
| 194 | |
| 195 | |
| 196 | |
| 197 | |
| 198 | |
| 199 | |
| 200 | unsafe { FileOps::new(operations, 0o600) }
|
| 201 | };
|
| 202 | }
|
| 203 |
|
| 204 | |
| 205 | |
| 206 | |
| 207 | |
| 208 | unsafe extern "C" fn write_only_open(
|
| 209 | inode: *mut bindings::inode,
|
| 210 | file: *mut bindings::file,
|
| 211 | ) -> c_int {
|
| 212 | |
| 213 | unsafe { (*file).private_data = (*inode).i_private };
|
| 214 | 0
|
| 215 | }
|
| 216 |
|
| 217 | |
| 218 | |
| 219 | |
| 220 | |
| 221 | |
| 222 | |
| 223 | pub(crate) unsafe extern "C" fn write_only_write<T: Reader + Sync>(
|
| 224 | file: *mut bindings::file,
|
| 225 | buf: *const c_char,
|
| 226 | count: usize,
|
| 227 | _ppos: *mut bindings::loff_t,
|
| 228 | ) -> isize {
|
| 229 | |
| 230 | |
| 231 | let data = unsafe { &*((*file).private_data as *const T) };
|
| 232 | read(data, buf, count)
|
| 233 | }
|
| 234 |
|
| 235 | pub(crate) trait WriteFile<T> {
|
| 236 | const FILE_OPS: FileOps<T>;
|
| 237 | }
|
| 238 |
|
| 239 | impl<T: Reader + Sync> WriteFile<T> for T {
|
| 240 | const FILE_OPS: FileOps<T> = {
|
| 241 | let operations = bindings::file_operations {
|
| 242 | open: Some(write_only_open),
|
| 243 | write: Some(write_only_write::<T>),
|
| 244 | llseek: Some(bindings::noop_llseek),
|
| 245 | ..pin_init::zeroed()
|
| 246 | };
|
| 247 | |
| 248 | |
| 249 | |
| 250 | |
| 251 | |
| 252 | unsafe { FileOps::new(operations, 0o200) }
|
| 253 | };
|
| 254 | }
|
| 255 |
|
| 256 | extern "C" fn blob_read<T: BinaryWriter>(
|
| 257 | file: *mut bindings::file,
|
| 258 | buf: *mut c_char,
|
| 259 | count: usize,
|
| 260 | ppos: *mut bindings::loff_t,
|
| 261 | ) -> isize {
|
| 262 | |
| 263 | |
| 264 | |
| 265 | let this = unsafe { &*((*file).private_data.cast::<T>()) };
|
| 266 |
|
| 267 | |
| 268 | |
| 269 | |
| 270 | let pos: &mut file::Offset = unsafe { &mut *ppos };
|
| 271 |
|
| 272 | let mut writer = UserSlice::new(UserPtr::from_ptr(buf.cast()), count).writer();
|
| 273 |
|
| 274 | let ret = || -> Result<isize> {
|
| 275 | let written = this.write_to_slice(&mut writer, pos)?;
|
| 276 |
|
| 277 | Ok(written.try_into()?)
|
| 278 | }();
|
| 279 |
|
| 280 | match ret {
|
| 281 | Ok(n) => n,
|
| 282 | Err(e) => e.to_errno() as isize,
|
| 283 | }
|
| 284 | }
|
| 285 |
|
| 286 | |
| 287 | pub(crate) trait BinaryReadFile<T> {
|
| 288 | const FILE_OPS: FileOps<T>;
|
| 289 | }
|
| 290 |
|
| 291 | impl<T: BinaryWriter + Sync> BinaryReadFile<T> for T {
|
| 292 | const FILE_OPS: FileOps<T> = {
|
| 293 | let operations = bindings::file_operations {
|
| 294 | read: Some(blob_read::<T>),
|
| 295 | llseek: Some(bindings::default_llseek),
|
| 296 | open: Some(bindings::simple_open),
|
| 297 | ..pin_init::zeroed()
|
| 298 | };
|
| 299 |
|
| 300 | |
| 301 | |
| 302 | |
| 303 | |
| 304 | |
| 305 | |
| 306 | unsafe { FileOps::new(operations, 0o400) }
|
| 307 | };
|
| 308 | }
|
| 309 |
|
| 310 | extern "C" fn blob_write<T: BinaryReader>(
|
| 311 | file: *mut bindings::file,
|
| 312 | buf: *const c_char,
|
| 313 | count: usize,
|
| 314 | ppos: *mut bindings::loff_t,
|
| 315 | ) -> isize {
|
| 316 | |
| 317 | |
| 318 | |
| 319 | let this = unsafe { &*((*file).private_data.cast::<T>()) };
|
| 320 |
|
| 321 | |
| 322 | |
| 323 | |
| 324 | let pos: &mut file::Offset = unsafe { &mut *ppos };
|
| 325 |
|
| 326 | let mut reader = UserSlice::new(UserPtr::from_ptr(buf.cast_mut().cast()), count).reader();
|
| 327 |
|
| 328 | let ret = || -> Result<isize> {
|
| 329 | let read = this.read_from_slice(&mut reader, pos)?;
|
| 330 |
|
| 331 | Ok(read.try_into()?)
|
| 332 | }();
|
| 333 |
|
| 334 | match ret {
|
| 335 | Ok(n) => n,
|
| 336 | Err(e) => e.to_errno() as isize,
|
| 337 | }
|
| 338 | }
|
| 339 |
|
| 340 | |
| 341 | pub(crate) trait BinaryWriteFile<T> {
|
| 342 | const FILE_OPS: FileOps<T>;
|
| 343 | }
|
| 344 |
|
| 345 | impl<T: BinaryReader + Sync> BinaryWriteFile<T> for T {
|
| 346 | const FILE_OPS: FileOps<T> = {
|
| 347 | let operations = bindings::file_operations {
|
| 348 | write: Some(blob_write::<T>),
|
| 349 | llseek: Some(bindings::default_llseek),
|
| 350 | open: Some(bindings::simple_open),
|
| 351 | ..pin_init::zeroed()
|
| 352 | };
|
| 353 |
|
| 354 | |
| 355 | |
| 356 | |
| 357 | |
| 358 | |
| 359 | |
| 360 | unsafe { FileOps::new(operations, 0o200) }
|
| 361 | };
|
| 362 | }
|
| 363 |
|
| 364 | |
| 365 | pub(crate) trait BinaryReadWriteFile<T> {
|
| 366 | const FILE_OPS: FileOps<T>;
|
| 367 | }
|
| 368 |
|
| 369 | impl<T: BinaryWriter + BinaryReader + Sync> BinaryReadWriteFile<T> for T {
|
| 370 | const FILE_OPS: FileOps<T> = {
|
| 371 | let operations = bindings::file_operations {
|
| 372 | read: Some(blob_read::<T>),
|
| 373 | write: Some(blob_write::<T>),
|
| 374 | llseek: Some(bindings::default_llseek),
|
| 375 | open: Some(bindings::simple_open),
|
| 376 | ..pin_init::zeroed()
|
| 377 | };
|
| 378 |
|
| 379 | |
| 380 | |
| 381 | |
| 382 | |
| 383 | |
| 384 | |
| 385 | |
| 386 | unsafe { FileOps::new(operations, 0o600) }
|
| 387 | };
|
| 388 | }
|