1use crate::mm::memory::MemoryObject;
6use crate::mm::{DesiredAddress, MappingName, MappingOptions, MemoryAccessorExt, ProtectionFlags};
7use crate::power::OnWakeOps;
8use crate::security;
9use crate::task::{
10 CurrentTask, CurrentTaskAndLocked, EventHandler, ThreadGroupKey, WaitCallback, WaitCanceler,
11 Waiter, register_delayed_release,
12};
13use crate::vfs::buffers::{InputBuffer, OutputBuffer};
14use crate::vfs::file_server::serve_file;
15use crate::vfs::fsverity::{
16 FsVerityState, {self},
17};
18use crate::vfs::{
19 ActiveNamespaceNode, DirentSink, EpollFileObject, EpollKey, FallocMode, FdTableId,
20 FileSystemHandle, FileWriteGuardMode, FsNodeHandle, FsString, NamespaceNode, RecordLockCommand,
21 RecordLockOwner,
22};
23use starnix_crypt::EncryptionKeyId;
24use starnix_lifecycle::{ObjectReleaser, ReleaserAction};
25use starnix_rcu::RcuAtomic;
26use starnix_types::ownership::ReleaseGuard;
27use starnix_uapi::mount_flags::MountFlags;
28use starnix_uapi::user_address::ArchSpecific;
29
30use fidl::endpoints::ProtocolMarker as _;
31use linux_uapi::{FSCRYPT_MODE_AES_256_CTS, FSCRYPT_MODE_AES_256_XTS};
32use starnix_logging::{CATEGORY_STARNIX_MM, impossible_error, log_error, track_stub};
33use starnix_sync::{
34 BeforeFsNodeAppend, FileAsyncOwnerLock, FileEpollFilesLock, FileLeaseLock, FileObjectOffset,
35 FileOpsCore, LockBefore, LockDepMutex, LockEqualOrBefore, Locked, Unlocked,
36};
37use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
38use starnix_types::math::round_up_to_system_page_size;
39use starnix_types::ownership::Releasable;
40use starnix_uapi::arc_key::WeakKey;
41use starnix_uapi::as_any::AsAny;
42use starnix_uapi::auth::{CAP_FOWNER, CAP_SYS_RAWIO};
43use starnix_uapi::errors::{EAGAIN, ETIMEDOUT, Errno};
44use starnix_uapi::file_lease::FileLeaseType;
45use starnix_uapi::file_mode::Access;
46use starnix_uapi::inotify_mask::InotifyMask;
47use starnix_uapi::open_flags::{AtomicOpenFlags, OpenFlags};
48use starnix_uapi::seal_flags::SealFlags;
49use starnix_uapi::user_address::{UserAddress, UserRef};
50use starnix_uapi::vfs::FdEvents;
51use starnix_uapi::{
52 FIBMAP, FIGETBSZ, FIONBIO, FIONREAD, FIOQSIZE, FS_CASEFOLD_FL, FS_IOC_ADD_ENCRYPTION_KEY,
53 FS_IOC_ENABLE_VERITY, FS_IOC_FSGETXATTR, FS_IOC_FSSETXATTR, FS_IOC_MEASURE_VERITY,
54 FS_IOC_READ_VERITY_METADATA, FS_IOC_REMOVE_ENCRYPTION_KEY, FS_IOC_SET_ENCRYPTION_POLICY,
55 FS_VERITY_FL, FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER, FSCRYPT_POLICY_V2, SEEK_CUR, SEEK_DATA,
56 SEEK_END, SEEK_HOLE, SEEK_SET, errno, error, fscrypt_add_key_arg, fscrypt_identifier, fsxattr,
57 off_t, pid_t, uapi,
58};
59use std::collections::HashMap;
60use std::fmt;
61use std::ops::Deref;
62use std::sync::atomic::Ordering;
63use std::sync::{Arc, Weak};
64
65pub const MAX_LFS_FILESIZE: usize = 0x7fff_ffff_ffff_ffff;
66
67pub fn checked_add_offset_and_length(offset: usize, length: usize) -> Result<usize, Errno> {
68 let end = offset.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
69 if end > MAX_LFS_FILESIZE {
70 return error!(EINVAL);
71 }
72 Ok(end)
73}
74
75#[derive(Debug)]
76pub enum SeekTarget {
77 Set(off_t),
79 Cur(off_t),
81 End(off_t),
83 Data(off_t),
85 Hole(off_t),
87}
88
89impl SeekTarget {
90 pub fn from_raw(whence: u32, offset: off_t) -> Result<SeekTarget, Errno> {
91 match whence {
92 SEEK_SET => Ok(SeekTarget::Set(offset)),
93 SEEK_CUR => Ok(SeekTarget::Cur(offset)),
94 SEEK_END => Ok(SeekTarget::End(offset)),
95 SEEK_DATA => Ok(SeekTarget::Data(offset)),
96 SEEK_HOLE => Ok(SeekTarget::Hole(offset)),
97 _ => error!(EINVAL),
98 }
99 }
100
101 pub fn whence(&self) -> u32 {
102 match self {
103 Self::Set(_) => SEEK_SET,
104 Self::Cur(_) => SEEK_CUR,
105 Self::End(_) => SEEK_END,
106 Self::Data(_) => SEEK_DATA,
107 Self::Hole(_) => SEEK_HOLE,
108 }
109 }
110
111 pub fn offset(&self) -> off_t {
112 match self {
113 Self::Set(off)
114 | Self::Cur(off)
115 | Self::End(off)
116 | Self::Data(off)
117 | Self::Hole(off) => *off,
118 }
119 }
120}
121
122pub trait FileOps: Send + Sync + AsAny + 'static {
124 fn open(
126 &self,
127 _locked: &mut Locked<FileOpsCore>,
128 _file: &FileObject,
129 _current_task: &CurrentTask,
130 ) -> Result<(), Errno> {
131 Ok(())
132 }
133
134 fn close(
136 self: Box<Self>,
137 _locked: &mut Locked<FileOpsCore>,
138 _file: &FileObjectState,
139 _current_task: &CurrentTask,
140 ) {
141 }
142
143 fn flush(
146 &self,
147 _locked: &mut Locked<FileOpsCore>,
148 _file: &FileObject,
149 _current_task: &CurrentTask,
150 ) {
151 }
152
153 fn has_persistent_offsets(&self) -> bool {
157 self.is_seekable()
158 }
159
160 fn is_seekable(&self) -> bool;
162
163 fn writes_update_seek_offset(&self) -> bool {
165 self.has_persistent_offsets()
166 }
167
168 fn read(
172 &self,
173 locked: &mut Locked<FileOpsCore>,
174 file: &FileObject,
175 current_task: &CurrentTask,
176 offset: usize,
177 data: &mut dyn OutputBuffer,
178 ) -> Result<usize, Errno>;
179
180 fn write(
184 &self,
185 locked: &mut Locked<FileOpsCore>,
186 file: &FileObject,
187 current_task: &CurrentTask,
188 offset: usize,
189 data: &mut dyn InputBuffer,
190 ) -> Result<usize, Errno>;
191
192 fn seek(
194 &self,
195 locked: &mut Locked<FileOpsCore>,
196 file: &FileObject,
197 current_task: &CurrentTask,
198 current_offset: off_t,
199 target: SeekTarget,
200 ) -> Result<off_t, Errno>;
201
202 fn sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
206 file.node().ops().sync(file.node(), current_task)
207 }
208
209 fn data_sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
213 self.sync(file, current_task)
215 }
216
217 fn get_memory(
224 &self,
225 _locked: &mut Locked<FileOpsCore>,
226 _file: &FileObject,
227 _current_task: &CurrentTask,
228 _length: Option<usize>,
229 _prot: ProtectionFlags,
230 ) -> Result<Arc<MemoryObject>, Errno> {
231 error!(ENODEV)
232 }
233
234 fn mmap(
239 &self,
240 locked: &mut Locked<FileOpsCore>,
241 file: &FileObject,
242 current_task: &CurrentTask,
243 addr: DesiredAddress,
244 memory_offset: u64,
245 length: usize,
246 prot_flags: ProtectionFlags,
247 options: MappingOptions,
248 filename: NamespaceNode,
249 ) -> Result<UserAddress, Errno> {
250 default_mmap(
251 locked,
252 file,
253 current_task,
254 addr,
255 memory_offset,
256 length,
257 prot_flags,
258 options,
259 filename,
260 )
261 }
262
263 fn readdir(
268 &self,
269 _locked: &mut Locked<FileOpsCore>,
270 _file: &FileObject,
271 _current_task: &CurrentTask,
272 _sink: &mut dyn DirentSink,
273 ) -> Result<(), Errno> {
274 error!(ENOTDIR)
275 }
276
277 fn wait_async(
286 &self,
287 _locked: &mut Locked<FileOpsCore>,
288 _file: &FileObject,
289 _current_task: &CurrentTask,
290 _waiter: &Waiter,
291 _events: FdEvents,
292 _handler: EventHandler,
293 ) -> Option<WaitCanceler> {
294 None
295 }
296
297 fn query_events(
305 &self,
306 _locked: &mut Locked<FileOpsCore>,
307 _file: &FileObject,
308 _current_task: &CurrentTask,
309 ) -> Result<FdEvents, Errno> {
310 Ok(FdEvents::POLLIN | FdEvents::POLLOUT)
311 }
312
313 fn ioctl(
314 &self,
315 _locked: &mut Locked<Unlocked>,
316 _file: &FileObject,
317 _current_task: &CurrentTask,
318 _request: u32,
319 _arg: SyscallArg,
320 ) -> Result<SyscallResult, Errno> {
321 error!(ENOTTY)
322 }
323
324 fn fcntl(
325 &self,
326 _file: &FileObject,
327 _current_task: &CurrentTask,
328 cmd: u32,
329 _arg: u64,
330 ) -> Result<SyscallResult, Errno> {
331 default_fcntl(cmd)
332 }
333
334 fn to_handle(
338 &self,
339 file: &FileObject,
340 current_task: &CurrentTask,
341 ) -> Result<Option<zx::NullableHandle>, Errno> {
342 serve_file(current_task, file, current_task.current_creds().clone())
343 .map(|c| Some(c.0.into_channel().into()))
344 }
345
346 fn get_handles(
362 &self,
363 _file: &FileObject,
364 _current_task: &CurrentTask,
365 ) -> Result<Vec<zx::NullableHandle>, Errno> {
366 error!(ENOTSUP)
367 }
368
369 fn as_thread_group_key(&self, _file: &FileObject) -> Result<ThreadGroupKey, Errno> {
373 error!(EBADF)
374 }
375
376 fn readahead(
377 &self,
378 _file: &FileObject,
379 _current_task: &CurrentTask,
380 _offset: usize,
381 _length: usize,
382 ) -> Result<(), Errno> {
383 error!(EINVAL)
384 }
385
386 fn extra_fdinfo(
388 &self,
389 _locked: &mut Locked<FileOpsCore>,
390 _file: &FileHandle,
391 _current_task: &CurrentTask,
392 ) -> Option<FsString> {
393 None
394 }
395}
396
397pub trait CloseFreeSafe {}
400impl<T: FileOps + CloseFreeSafe, P: Deref<Target = T> + Send + Sync + 'static> FileOps for P {
401 fn close(
402 self: Box<Self>,
403 _locked: &mut Locked<FileOpsCore>,
404 _file: &FileObjectState,
405 _current_task: &CurrentTask,
406 ) {
407 }
409
410 fn flush(
411 &self,
412 locked: &mut Locked<FileOpsCore>,
413 file: &FileObject,
414 current_task: &CurrentTask,
415 ) {
416 self.deref().flush(locked, file, current_task)
417 }
418
419 fn has_persistent_offsets(&self) -> bool {
420 self.deref().has_persistent_offsets()
421 }
422
423 fn writes_update_seek_offset(&self) -> bool {
424 self.deref().writes_update_seek_offset()
425 }
426
427 fn is_seekable(&self) -> bool {
428 self.deref().is_seekable()
429 }
430
431 fn read(
432 &self,
433 locked: &mut Locked<FileOpsCore>,
434 file: &FileObject,
435 current_task: &CurrentTask,
436 offset: usize,
437 data: &mut dyn OutputBuffer,
438 ) -> Result<usize, Errno> {
439 self.deref().read(locked, file, current_task, offset, data)
440 }
441
442 fn write(
443 &self,
444 locked: &mut Locked<FileOpsCore>,
445 file: &FileObject,
446 current_task: &CurrentTask,
447 offset: usize,
448 data: &mut dyn InputBuffer,
449 ) -> Result<usize, Errno> {
450 self.deref().write(locked, file, current_task, offset, data)
451 }
452
453 fn seek(
454 &self,
455 locked: &mut Locked<FileOpsCore>,
456 file: &FileObject,
457 current_task: &CurrentTask,
458 current_offset: off_t,
459 target: SeekTarget,
460 ) -> Result<off_t, Errno> {
461 self.deref().seek(locked, file, current_task, current_offset, target)
462 }
463
464 fn sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
465 self.deref().sync(file, current_task)
466 }
467
468 fn data_sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
469 self.deref().data_sync(file, current_task)
470 }
471
472 fn get_memory(
473 &self,
474 locked: &mut Locked<FileOpsCore>,
475 file: &FileObject,
476 current_task: &CurrentTask,
477 length: Option<usize>,
478 prot: ProtectionFlags,
479 ) -> Result<Arc<MemoryObject>, Errno> {
480 self.deref().get_memory(locked, file, current_task, length, prot)
481 }
482
483 fn mmap(
484 &self,
485 locked: &mut Locked<FileOpsCore>,
486 file: &FileObject,
487 current_task: &CurrentTask,
488 addr: DesiredAddress,
489 memory_offset: u64,
490 length: usize,
491 prot_flags: ProtectionFlags,
492 options: MappingOptions,
493 filename: NamespaceNode,
494 ) -> Result<UserAddress, Errno> {
495 self.deref().mmap(
496 locked,
497 file,
498 current_task,
499 addr,
500 memory_offset,
501 length,
502 prot_flags,
503 options,
504 filename,
505 )
506 }
507
508 fn readdir(
509 &self,
510 locked: &mut Locked<FileOpsCore>,
511 file: &FileObject,
512 current_task: &CurrentTask,
513 sink: &mut dyn DirentSink,
514 ) -> Result<(), Errno> {
515 self.deref().readdir(locked, file, current_task, sink)
516 }
517
518 fn wait_async(
519 &self,
520 locked: &mut Locked<FileOpsCore>,
521 file: &FileObject,
522 current_task: &CurrentTask,
523 waiter: &Waiter,
524 events: FdEvents,
525 handler: EventHandler,
526 ) -> Option<WaitCanceler> {
527 self.deref().wait_async(locked, file, current_task, waiter, events, handler)
528 }
529
530 fn query_events(
531 &self,
532 locked: &mut Locked<FileOpsCore>,
533 file: &FileObject,
534 current_task: &CurrentTask,
535 ) -> Result<FdEvents, Errno> {
536 self.deref().query_events(locked, file, current_task)
537 }
538
539 fn ioctl(
540 &self,
541 locked: &mut Locked<Unlocked>,
542 file: &FileObject,
543 current_task: &CurrentTask,
544 request: u32,
545 arg: SyscallArg,
546 ) -> Result<SyscallResult, Errno> {
547 self.deref().ioctl(locked, file, current_task, request, arg)
548 }
549
550 fn fcntl(
551 &self,
552 file: &FileObject,
553 current_task: &CurrentTask,
554 cmd: u32,
555 arg: u64,
556 ) -> Result<SyscallResult, Errno> {
557 self.deref().fcntl(file, current_task, cmd, arg)
558 }
559
560 fn to_handle(
561 &self,
562 file: &FileObject,
563 current_task: &CurrentTask,
564 ) -> Result<Option<zx::NullableHandle>, Errno> {
565 self.deref().to_handle(file, current_task)
566 }
567
568 fn get_handles(
569 &self,
570 file: &FileObject,
571 current_task: &CurrentTask,
572 ) -> Result<Vec<zx::NullableHandle>, Errno> {
573 self.deref().get_handles(file, current_task)
574 }
575
576 fn as_thread_group_key(&self, file: &FileObject) -> Result<ThreadGroupKey, Errno> {
577 self.deref().as_thread_group_key(file)
578 }
579
580 fn readahead(
581 &self,
582 file: &FileObject,
583 current_task: &CurrentTask,
584 offset: usize,
585 length: usize,
586 ) -> Result<(), Errno> {
587 self.deref().readahead(file, current_task, offset, length)
588 }
589
590 fn extra_fdinfo(
591 &self,
592 locked: &mut Locked<FileOpsCore>,
593 file: &FileHandle,
594 current_task: &CurrentTask,
595 ) -> Option<FsString> {
596 self.deref().extra_fdinfo(locked, file, current_task)
597 }
598}
599
600pub fn default_eof_offset<L>(
601 locked: &mut Locked<L>,
602 file: &FileObject,
603 current_task: &CurrentTask,
604) -> Result<off_t, Errno>
605where
606 L: LockEqualOrBefore<FileOpsCore>,
607{
608 Ok(file.node().get_size(locked, current_task)? as off_t)
609}
610
611pub fn default_seek<F>(
621 current_offset: off_t,
622 target: SeekTarget,
623 compute_end: F,
624) -> Result<off_t, Errno>
625where
626 F: FnOnce() -> Result<off_t, Errno>,
627{
628 let new_offset = match target {
629 SeekTarget::Set(offset) => Some(offset),
630 SeekTarget::Cur(offset) => current_offset.checked_add(offset),
631 SeekTarget::End(offset) => compute_end()?.checked_add(offset),
632 SeekTarget::Data(offset) => {
633 let eof = compute_end().unwrap_or(off_t::MAX);
634 if offset >= eof {
635 return error!(ENXIO);
636 }
637 Some(offset)
638 }
639 SeekTarget::Hole(offset) => {
640 let eof = compute_end()?;
641 if offset >= eof {
642 return error!(ENXIO);
643 }
644 Some(eof)
645 }
646 }
647 .ok_or_else(|| errno!(EINVAL))?;
648
649 if new_offset < 0 {
650 return error!(EINVAL);
651 }
652
653 Ok(new_offset)
654}
655
656pub fn unbounded_seek(current_offset: off_t, target: SeekTarget) -> Result<off_t, Errno> {
665 default_seek(current_offset, target, || Ok(MAX_LFS_FILESIZE as off_t))
666}
667
668#[macro_export]
669macro_rules! fileops_impl_delegate_read_write_and_seek {
670 ($self:ident, $delegate:expr) => {
671 fn is_seekable(&self) -> bool {
672 true
673 }
674
675 fn read(
676 &$self,
677 locked: &mut starnix_sync::Locked<starnix_sync::FileOpsCore>,
678 file: &FileObject,
679 current_task: &$crate::task::CurrentTask,
680 offset: usize,
681 data: &mut dyn $crate::vfs::buffers::OutputBuffer,
682 ) -> Result<usize, starnix_uapi::errors::Errno> {
683 $delegate.read(locked, file, current_task, offset, data)
684 }
685
686 fn write(
687 &$self,
688 locked: &mut starnix_sync::Locked<starnix_sync::FileOpsCore>,
689 file: &FileObject,
690 current_task: &$crate::task::CurrentTask,
691 offset: usize,
692 data: &mut dyn $crate::vfs::buffers::InputBuffer,
693 ) -> Result<usize, starnix_uapi::errors::Errno> {
694 $delegate.write(locked, file, current_task, offset, data)
695 }
696
697 fn seek(
698 &$self,
699 locked: &mut starnix_sync::Locked<starnix_sync::FileOpsCore>,
700 file: &FileObject,
701 current_task: &$crate::task::CurrentTask,
702 current_offset: starnix_uapi::off_t,
703 target: $crate::vfs::SeekTarget,
704 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
705 $delegate.seek(locked, file, current_task, current_offset, target)
706 }
707 };
708}
709
710#[macro_export]
712macro_rules! fileops_impl_seekable {
713 () => {
714 fn is_seekable(&self) -> bool {
715 true
716 }
717
718 fn seek(
719 &self,
720 locked: &mut starnix_sync::Locked<starnix_sync::FileOpsCore>,
721 file: &$crate::vfs::FileObject,
722 current_task: &$crate::task::CurrentTask,
723 current_offset: starnix_uapi::off_t,
724 target: $crate::vfs::SeekTarget,
725 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
726 $crate::vfs::default_seek(current_offset, target, || {
727 $crate::vfs::default_eof_offset(locked, file, current_task)
728 })
729 }
730 };
731}
732
733#[macro_export]
735macro_rules! fileops_impl_nonseekable {
736 () => {
737 fn is_seekable(&self) -> bool {
738 false
739 }
740
741 fn seek(
742 &self,
743 _locked: &mut starnix_sync::Locked<starnix_sync::FileOpsCore>,
744 _file: &$crate::vfs::FileObject,
745 _current_task: &$crate::task::CurrentTask,
746 _current_offset: starnix_uapi::off_t,
747 _target: $crate::vfs::SeekTarget,
748 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
749 starnix_uapi::error!(ESPIPE)
750 }
751 };
752}
753
754#[macro_export]
757macro_rules! fileops_impl_seekless {
758 () => {
759 fn has_persistent_offsets(&self) -> bool {
760 false
761 }
762
763 fn is_seekable(&self) -> bool {
764 true
765 }
766
767 fn seek(
768 &self,
769 _locked: &mut starnix_sync::Locked<starnix_sync::FileOpsCore>,
770 _file: &$crate::vfs::FileObject,
771 _current_task: &$crate::task::CurrentTask,
772 _current_offset: starnix_uapi::off_t,
773 _target: $crate::vfs::SeekTarget,
774 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
775 Ok(0)
776 }
777 };
778}
779
780#[macro_export]
781macro_rules! fileops_impl_dataless {
782 () => {
783 fn write(
784 &self,
785 _locked: &mut starnix_sync::Locked<starnix_sync::FileOpsCore>,
786 _file: &$crate::vfs::FileObject,
787 _current_task: &$crate::task::CurrentTask,
788 _offset: usize,
789 _data: &mut dyn $crate::vfs::buffers::InputBuffer,
790 ) -> Result<usize, starnix_uapi::errors::Errno> {
791 starnix_uapi::error!(EINVAL)
792 }
793
794 fn read(
795 &self,
796 _locked: &mut starnix_sync::Locked<starnix_sync::FileOpsCore>,
797 _file: &$crate::vfs::FileObject,
798 _current_task: &$crate::task::CurrentTask,
799 _offset: usize,
800 _data: &mut dyn $crate::vfs::buffers::OutputBuffer,
801 ) -> Result<usize, starnix_uapi::errors::Errno> {
802 starnix_uapi::error!(EINVAL)
803 }
804 };
805}
806
807#[macro_export]
810macro_rules! fileops_impl_directory {
811 () => {
812 fn is_seekable(&self) -> bool {
813 true
814 }
815
816 fn read(
817 &self,
818 _locked: &mut starnix_sync::Locked<starnix_sync::FileOpsCore>,
819 _file: &$crate::vfs::FileObject,
820 _current_task: &$crate::task::CurrentTask,
821 _offset: usize,
822 _data: &mut dyn $crate::vfs::buffers::OutputBuffer,
823 ) -> Result<usize, starnix_uapi::errors::Errno> {
824 starnix_uapi::error!(EISDIR)
825 }
826
827 fn write(
828 &self,
829 _locked: &mut starnix_sync::Locked<starnix_sync::FileOpsCore>,
830 _file: &$crate::vfs::FileObject,
831 _current_task: &$crate::task::CurrentTask,
832 _offset: usize,
833 _data: &mut dyn $crate::vfs::buffers::InputBuffer,
834 ) -> Result<usize, starnix_uapi::errors::Errno> {
835 starnix_uapi::error!(EISDIR)
836 }
837 };
838}
839
840#[macro_export]
841macro_rules! fileops_impl_unbounded_seek {
842 () => {
843 fn seek(
844 &self,
845 _locked: &mut starnix_sync::Locked<starnix_sync::FileOpsCore>,
846 _file: &$crate::vfs::FileObject,
847 _current_task: &$crate::task::CurrentTask,
848 current_offset: starnix_uapi::off_t,
849 target: $crate::vfs::SeekTarget,
850 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
851 $crate::vfs::unbounded_seek(current_offset, target)
852 }
853 };
854}
855
856#[macro_export]
857macro_rules! fileops_impl_noop_sync {
858 () => {
859 fn sync(
860 &self,
861 file: &$crate::vfs::FileObject,
862 _current_task: &$crate::task::CurrentTask,
863 ) -> Result<(), starnix_uapi::errors::Errno> {
864 if !file.node().is_reg() && !file.node().is_dir() {
865 return starnix_uapi::error!(EINVAL);
866 }
867 Ok(())
868 }
869 };
870}
871
872pub use fileops_impl_dataless;
875pub use fileops_impl_delegate_read_write_and_seek;
876pub use fileops_impl_directory;
877pub use fileops_impl_nonseekable;
878pub use fileops_impl_noop_sync;
879pub use fileops_impl_seekable;
880pub use fileops_impl_seekless;
881pub use fileops_impl_unbounded_seek;
882pub const AES256_KEY_SIZE: usize = 32;
883
884pub fn canonicalize_ioctl_request(current_task: &CurrentTask, request: u32) -> u32 {
885 if current_task.is_arch32() {
886 match request {
887 uapi::arch32::FS_IOC_GETFLAGS => uapi::FS_IOC_GETFLAGS,
888 uapi::arch32::FS_IOC_SETFLAGS => uapi::FS_IOC_SETFLAGS,
889 _ => request,
890 }
891 } else {
892 request
893 }
894}
895
896pub fn default_vfs_ioctl(
904 file: &FileObject,
905 locked: &mut Locked<Unlocked>,
906 current_task: &CurrentTask,
907 request: u32,
908 arg: SyscallArg,
909) -> Result<Option<SyscallResult>, Errno> {
910 match canonicalize_ioctl_request(current_task, request) {
911 FIGETBSZ if file.node().is_reg() || file.node().is_dir() => {
912 let blocksize = file.node().stat(locked, current_task)?.st_blksize;
913 current_task.write_object(arg.into(), &blocksize)?;
914 Ok(Some(SUCCESS))
915 }
916 FIONBIO => {
917 let arg_ref = UserAddress::from(arg).into();
918 let arg: i32 = current_task.read_object(arg_ref)?;
919 let val = if arg == 0 {
920 OpenFlags::empty()
922 } else {
923 OpenFlags::NONBLOCK
925 };
926 file.update_file_flags(val, OpenFlags::NONBLOCK);
927 Ok(Some(SUCCESS))
928 }
929 FIOQSIZE if file.node().is_reg() || file.node().is_dir() => {
930 let size = file.node().stat(locked, current_task)?.st_size;
931 current_task.write_object(arg.into(), &size)?;
932 Ok(Some(SUCCESS))
933 }
934 FIONREAD if file.node().is_reg() => {
935 track_stub!(TODO("https://fxbug.dev/322874897"), "FIONREAD");
936 let size = file
937 .node()
938 .fetch_and_refresh_info(locked, current_task)
939 .map_err(|_| errno!(EINVAL))?
940 .size;
941 let offset = usize::try_from(file.offset.read()).map_err(|_| errno!(EINVAL))?;
942 let remaining =
943 if size < offset { 0 } else { i32::try_from(size - offset).unwrap_or(i32::MAX) };
944 current_task.write_object(arg.into(), &remaining)?;
945 Ok(Some(SUCCESS))
946 }
947 FS_IOC_FSGETXATTR => {
948 track_stub!(TODO("https://fxbug.dev/322875209"), "FS_IOC_FSGETXATTR");
949 let arg = UserAddress::from(arg).into();
950 current_task.write_object(arg, &fsxattr::default())?;
951 Ok(Some(SUCCESS))
952 }
953 FS_IOC_FSSETXATTR => {
954 track_stub!(TODO("https://fxbug.dev/322875271"), "FS_IOC_FSSETXATTR");
955 let arg = UserAddress::from(arg).into();
956 let _: fsxattr = current_task.read_object(arg)?;
957 Ok(Some(SUCCESS))
958 }
959 uapi::FS_IOC_GETFLAGS => {
960 track_stub!(TODO("https://fxbug.dev/322874935"), "FS_IOC_GETFLAGS");
961 let arg = UserRef::<u32>::from(arg);
962 let mut flags: u32 = 0;
963 if matches!(*file.node().fsverity.lock(), FsVerityState::FsVerity) {
964 flags |= FS_VERITY_FL;
965 }
966 if file.node().info().casefold {
967 flags |= FS_CASEFOLD_FL;
968 }
969 current_task.write_object(arg, &flags)?;
970 Ok(Some(SUCCESS))
971 }
972 uapi::FS_IOC_SETFLAGS => {
973 track_stub!(TODO("https://fxbug.dev/322875367"), "FS_IOC_SETFLAGS");
974 let arg = UserRef::<u32>::from(arg);
975 let flags: u32 = current_task.read_object(arg)?;
976 file.node().update_attributes(locked, current_task, |info| {
977 info.casefold = flags & FS_CASEFOLD_FL != 0;
978 Ok(())
979 })?;
980 Ok(Some(SUCCESS))
981 }
982 FS_IOC_ENABLE_VERITY => {
983 fsverity::ioctl::enable(locked, current_task, UserAddress::from(arg).into(), file)
984 .map(Some)
985 }
986 FS_IOC_MEASURE_VERITY => {
987 fsverity::ioctl::measure(locked, current_task, UserAddress::from(arg).into(), file)
988 .map(Some)
989 }
990 FS_IOC_READ_VERITY_METADATA => {
991 fsverity::ioctl::read_metadata(current_task, UserAddress::from(arg).into(), file)
992 .map(Some)
993 }
994 FS_IOC_ADD_ENCRYPTION_KEY => {
995 let fscrypt_add_key_ref = UserRef::<fscrypt_add_key_arg>::from(arg);
996 let key_ref_addr = fscrypt_add_key_ref.next()?.addr();
997 let mut fscrypt_add_key_arg = current_task.read_object(fscrypt_add_key_ref.clone())?;
998 if fscrypt_add_key_arg.key_id != 0 {
999 track_stub!(TODO("https://fxbug.dev/375649227"), "non-zero key ids");
1000 return error!(ENOTSUP);
1001 }
1002 if fscrypt_add_key_arg.key_spec.type_ != FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER {
1003 track_stub!(TODO("https://fxbug.dev/375648306"), "fscrypt descriptor type");
1004 return error!(ENOTSUP);
1005 }
1006 let key = current_task
1007 .read_memory_to_vec(key_ref_addr, fscrypt_add_key_arg.raw_size as usize)?;
1008 let user_id = current_task.current_creds().uid;
1009
1010 let crypt_service = file.node().fs().crypt_service().ok_or_else(|| errno!(ENOTSUP))?;
1011 let key_identifier = crypt_service.add_wrapping_key(&key, user_id)?;
1012 fscrypt_add_key_arg.key_spec.u.identifier =
1013 fscrypt_identifier { value: key_identifier, ..Default::default() };
1014 current_task.write_object(fscrypt_add_key_ref, &fscrypt_add_key_arg)?;
1015 Ok(Some(SUCCESS))
1016 }
1017 FS_IOC_SET_ENCRYPTION_POLICY => {
1018 let fscrypt_policy_ref = UserRef::<uapi::fscrypt_policy_v2>::from(arg);
1019 let policy = current_task.read_object(fscrypt_policy_ref)?;
1020 if policy.version as u32 != FSCRYPT_POLICY_V2 {
1021 track_stub!(TODO("https://fxbug.dev/375649656"), "fscrypt policy v1");
1022 return error!(ENOTSUP);
1023 }
1024 if policy.flags != 0 {
1025 track_stub!(
1026 TODO("https://fxbug.dev/375700939"),
1027 "fscrypt policy flags",
1028 policy.flags
1029 );
1030 }
1031 if policy.contents_encryption_mode as u32 != FSCRYPT_MODE_AES_256_XTS {
1032 track_stub!(
1033 TODO("https://fxbug.dev/375684057"),
1034 "fscrypt encryption modes",
1035 policy.contents_encryption_mode
1036 );
1037 }
1038 if policy.filenames_encryption_mode as u32 != FSCRYPT_MODE_AES_256_CTS {
1039 track_stub!(
1040 TODO("https://fxbug.dev/375684057"),
1041 "fscrypt encryption modes",
1042 policy.filenames_encryption_mode
1043 );
1044 }
1045 let user_id = current_task.current_creds().uid;
1046 if user_id != file.node().info().uid {
1047 security::check_task_capable(current_task, CAP_FOWNER)
1048 .map_err(|_| errno!(EACCES))?;
1049 }
1050
1051 let crypt_service = file.node().fs().crypt_service().ok_or_else(|| errno!(ENOTSUP))?;
1052 if let Some(users) =
1053 crypt_service.get_users_for_key(EncryptionKeyId::from(policy.master_key_identifier))
1054 {
1055 if !users.contains(&user_id) {
1056 return error!(ENOKEY);
1057 }
1058 } else {
1059 track_stub!(
1060 TODO("https://fxbug.dev/375067633"),
1061 "users with CAP_FOWNER can set encryption policies with unadded keys"
1062 );
1063 return error!(ENOKEY);
1064 }
1065
1066 let attributes = file.node().fetch_and_refresh_info(locked, current_task)?;
1067 if let Some(wrapping_key_id) = &attributes.wrapping_key_id {
1068 if wrapping_key_id != &policy.master_key_identifier {
1069 return error!(EEXIST);
1070 }
1071 } else {
1072 std::mem::drop(attributes);
1074 file.node().update_attributes(locked, current_task, |info| {
1075 info.wrapping_key_id = Some(policy.master_key_identifier);
1076 Ok(())
1077 })?;
1078 }
1079 Ok(Some(SUCCESS))
1080 }
1081 FS_IOC_REMOVE_ENCRYPTION_KEY => {
1082 let fscrypt_remove_key_arg_ref = UserRef::<uapi::fscrypt_remove_key_arg>::from(arg);
1083 let fscrypt_remove_key_arg = current_task.read_object(fscrypt_remove_key_arg_ref)?;
1084 if fscrypt_remove_key_arg.key_spec.type_ != FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER {
1085 track_stub!(TODO("https://fxbug.dev/375648306"), "fscrypt descriptor type");
1086 return error!(ENOTSUP);
1087 }
1088 let crypt_service = file.node().fs().crypt_service().ok_or_else(|| errno!(ENOTSUP))?;
1089 let user_id = current_task.current_creds().uid;
1090 #[allow(
1091 clippy::undocumented_unsafe_blocks,
1092 reason = "Force documented unsafe blocks in Starnix"
1093 )]
1094 let identifier = unsafe { fscrypt_remove_key_arg.key_spec.u.identifier.value };
1095 crypt_service.forget_wrapping_key(identifier, user_id)?;
1096 Ok(Some(SUCCESS))
1097 }
1098 linux_uapi::FICLONE | linux_uapi::FICLONERANGE | linux_uapi::FIDEDUPERANGE => {
1099 error!(EOPNOTSUPP)
1100 }
1101 _ => Ok(None),
1102 }
1103}
1104
1105pub fn default_fcntl(cmd: u32) -> Result<SyscallResult, Errno> {
1106 track_stub!(TODO("https://fxbug.dev/322875704"), "default fcntl", cmd);
1107 error!(EINVAL)
1108}
1109
1110pub fn default_mmap(
1111 locked: &mut Locked<FileOpsCore>,
1112 file: &FileObject,
1113 current_task: &CurrentTask,
1114 addr: DesiredAddress,
1115 memory_offset: u64,
1116 length: usize,
1117 prot_flags: ProtectionFlags,
1118 options: MappingOptions,
1119 filename: NamespaceNode,
1120) -> Result<UserAddress, Errno> {
1121 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "FileOpsDefaultMmap");
1122 let min_memory_size = (memory_offset as usize)
1123 .checked_add(round_up_to_system_page_size(length)?)
1124 .ok_or_else(|| errno!(EINVAL))?;
1125 let mut memory = if options.contains(MappingOptions::SHARED) {
1126 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "GetSharedVmo");
1127 file.ops.get_memory(locked, file, current_task, Some(min_memory_size), prot_flags)?
1128 } else {
1129 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "GetPrivateVmo");
1130 let base_prot_flags = (prot_flags | ProtectionFlags::READ) - ProtectionFlags::WRITE;
1132 let memory = file.ops.get_memory(
1133 locked,
1134 file,
1135 current_task,
1136 Some(min_memory_size),
1137 base_prot_flags,
1138 )?;
1139 let mut clone_flags = zx::VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE;
1140 if !prot_flags.contains(ProtectionFlags::WRITE) {
1141 clone_flags |= zx::VmoChildOptions::NO_WRITE;
1142 }
1143 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "CreatePrivateChildVmo");
1144 Arc::new(memory.create_child(clone_flags, 0, memory.get_size()).map_err(impossible_error)?)
1145 };
1146
1147 let file_write_guard = if options.contains(MappingOptions::SHARED) && file.can_write() {
1150 let node = &file.name.entry.node;
1151 let state = node.write_guard_state.lock();
1152
1153 let seals = state.get_seals().unwrap_or(SealFlags::empty());
1158 if seals.contains(SealFlags::FUTURE_WRITE)
1159 && !seals.contains(SealFlags::WRITE)
1160 && !prot_flags.contains(ProtectionFlags::WRITE)
1161 {
1162 let mut new_rights = zx::Rights::VMO_DEFAULT - zx::Rights::WRITE;
1163 if prot_flags.contains(ProtectionFlags::EXEC) {
1164 new_rights |= zx::Rights::EXECUTE;
1165 }
1166 memory = Arc::new(memory.duplicate_handle(new_rights).map_err(impossible_error)?);
1167
1168 None
1169 } else {
1170 Some(FileWriteGuardMode::WriteMapping)
1171 }
1172 } else {
1173 None
1174 };
1175
1176 current_task.mm()?.map_memory(
1177 addr,
1178 memory,
1179 memory_offset,
1180 length,
1181 prot_flags,
1182 file.max_access_for_memory_mapping(),
1183 options,
1184 MappingName::File(filename.into_mapping(file_write_guard)?),
1185 )
1186}
1187
1188pub struct OPathOps {}
1189
1190impl OPathOps {
1191 pub fn new() -> OPathOps {
1192 OPathOps {}
1193 }
1194}
1195
1196impl FileOps for OPathOps {
1197 fileops_impl_noop_sync!();
1198
1199 fn has_persistent_offsets(&self) -> bool {
1200 false
1201 }
1202 fn is_seekable(&self) -> bool {
1203 true
1204 }
1205 fn read(
1206 &self,
1207 _locked: &mut Locked<FileOpsCore>,
1208 _file: &FileObject,
1209 _current_task: &CurrentTask,
1210 _offset: usize,
1211 _data: &mut dyn OutputBuffer,
1212 ) -> Result<usize, Errno> {
1213 error!(EBADF)
1214 }
1215 fn write(
1216 &self,
1217 _locked: &mut Locked<FileOpsCore>,
1218 _file: &FileObject,
1219 _current_task: &CurrentTask,
1220 _offset: usize,
1221 _data: &mut dyn InputBuffer,
1222 ) -> Result<usize, Errno> {
1223 error!(EBADF)
1224 }
1225 fn seek(
1226 &self,
1227 _locked: &mut Locked<FileOpsCore>,
1228 _file: &FileObject,
1229 _current_task: &CurrentTask,
1230 _current_offset: off_t,
1231 _target: SeekTarget,
1232 ) -> Result<off_t, Errno> {
1233 error!(EBADF)
1234 }
1235 fn get_memory(
1236 &self,
1237 _locked: &mut Locked<FileOpsCore>,
1238 _file: &FileObject,
1239 _current_task: &CurrentTask,
1240 _length: Option<usize>,
1241 _prot: ProtectionFlags,
1242 ) -> Result<Arc<MemoryObject>, Errno> {
1243 error!(EBADF)
1244 }
1245 fn readdir(
1246 &self,
1247 _locked: &mut Locked<FileOpsCore>,
1248 _file: &FileObject,
1249 _current_task: &CurrentTask,
1250 _sink: &mut dyn DirentSink,
1251 ) -> Result<(), Errno> {
1252 error!(EBADF)
1253 }
1254
1255 fn ioctl(
1256 &self,
1257 _locked: &mut Locked<Unlocked>,
1258 _file: &FileObject,
1259 _current_task: &CurrentTask,
1260 _request: u32,
1261 _arg: SyscallArg,
1262 ) -> Result<SyscallResult, Errno> {
1263 error!(EBADF)
1264 }
1265}
1266
1267pub struct ProxyFileOps(pub FileHandle);
1268
1269impl FileOps for ProxyFileOps {
1270 fn has_persistent_offsets(&self) -> bool {
1275 self.0.ops().has_persistent_offsets()
1276 }
1277 fn writes_update_seek_offset(&self) -> bool {
1278 self.0.ops().writes_update_seek_offset()
1279 }
1280 fn is_seekable(&self) -> bool {
1281 self.0.ops().is_seekable()
1282 }
1283 fn flush(
1285 &self,
1286 locked: &mut Locked<FileOpsCore>,
1287 _file: &FileObject,
1288 current_task: &CurrentTask,
1289 ) {
1290 self.0.ops().flush(locked, &self.0, current_task);
1291 }
1292 fn wait_async(
1293 &self,
1294 locked: &mut Locked<FileOpsCore>,
1295 _file: &FileObject,
1296 current_task: &CurrentTask,
1297 waiter: &Waiter,
1298 events: FdEvents,
1299 handler: EventHandler,
1300 ) -> Option<WaitCanceler> {
1301 self.0.ops().wait_async(locked, &self.0, current_task, waiter, events, handler)
1302 }
1303 fn query_events(
1304 &self,
1305 locked: &mut Locked<FileOpsCore>,
1306 _file: &FileObject,
1307 current_task: &CurrentTask,
1308 ) -> Result<FdEvents, Errno> {
1309 self.0.ops().query_events(locked, &self.0, current_task)
1310 }
1311 fn read(
1312 &self,
1313 locked: &mut Locked<FileOpsCore>,
1314 _file: &FileObject,
1315 current_task: &CurrentTask,
1316 offset: usize,
1317 data: &mut dyn OutputBuffer,
1318 ) -> Result<usize, Errno> {
1319 self.0.ops().read(locked, &self.0, current_task, offset, data)
1320 }
1321 fn write(
1322 &self,
1323 locked: &mut Locked<FileOpsCore>,
1324 _file: &FileObject,
1325 current_task: &CurrentTask,
1326 offset: usize,
1327 data: &mut dyn InputBuffer,
1328 ) -> Result<usize, Errno> {
1329 self.0.ops().write(locked, &self.0, current_task, offset, data)
1330 }
1331 fn ioctl(
1332 &self,
1333 locked: &mut Locked<Unlocked>,
1334 _file: &FileObject,
1335 current_task: &CurrentTask,
1336 request: u32,
1337 arg: SyscallArg,
1338 ) -> Result<SyscallResult, Errno> {
1339 self.0.ops().ioctl(locked, &self.0, current_task, request, arg)
1340 }
1341 fn fcntl(
1342 &self,
1343 _file: &FileObject,
1344 current_task: &CurrentTask,
1345 cmd: u32,
1346 arg: u64,
1347 ) -> Result<SyscallResult, Errno> {
1348 self.0.ops().fcntl(&self.0, current_task, cmd, arg)
1349 }
1350 fn readdir(
1351 &self,
1352 locked: &mut Locked<FileOpsCore>,
1353 _file: &FileObject,
1354 current_task: &CurrentTask,
1355 sink: &mut dyn DirentSink,
1356 ) -> Result<(), Errno> {
1357 self.0.ops().readdir(locked, &self.0, current_task, sink)
1358 }
1359 fn sync(&self, _file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
1360 self.0.ops().sync(&self.0, current_task)
1361 }
1362 fn data_sync(&self, _file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
1363 self.0.ops().sync(&self.0, current_task)
1364 }
1365 fn get_memory(
1366 &self,
1367 locked: &mut Locked<FileOpsCore>,
1368 _file: &FileObject,
1369 current_task: &CurrentTask,
1370 length: Option<usize>,
1371 prot: ProtectionFlags,
1372 ) -> Result<Arc<MemoryObject>, Errno> {
1373 self.0.ops.get_memory(locked, &self.0, current_task, length, prot)
1374 }
1375 fn mmap(
1376 &self,
1377 locked: &mut Locked<FileOpsCore>,
1378 _file: &FileObject,
1379 current_task: &CurrentTask,
1380 addr: DesiredAddress,
1381 memory_offset: u64,
1382 length: usize,
1383 prot_flags: ProtectionFlags,
1384 options: MappingOptions,
1385 filename: NamespaceNode,
1386 ) -> Result<UserAddress, Errno> {
1387 self.0.ops.mmap(
1388 locked,
1389 &self.0,
1390 current_task,
1391 addr,
1392 memory_offset,
1393 length,
1394 prot_flags,
1395 options,
1396 filename,
1397 )
1398 }
1399 fn seek(
1400 &self,
1401 locked: &mut Locked<FileOpsCore>,
1402 _file: &FileObject,
1403 current_task: &CurrentTask,
1404 offset: off_t,
1405 target: SeekTarget,
1406 ) -> Result<off_t, Errno> {
1407 self.0.ops.seek(locked, &self.0, current_task, offset, target)
1408 }
1409}
1410
1411#[derive(Debug, Default, Copy, Clone)]
1412pub enum FileAsyncOwner {
1413 #[default]
1414 Unowned,
1415 Thread(pid_t),
1416 Process(pid_t),
1417 ProcessGroup(pid_t),
1418}
1419
1420impl FileAsyncOwner {
1421 pub fn validate(self, current_task: &CurrentTask) -> Result<(), Errno> {
1422 match self {
1423 FileAsyncOwner::Unowned => (),
1424 FileAsyncOwner::Thread(id) | FileAsyncOwner::Process(id) => {
1425 if id != 0 {
1426 current_task.get_task(id)?;
1427 }
1428 }
1429 FileAsyncOwner::ProcessGroup(pgid) => {
1430 if pgid != 0 {
1431 current_task
1432 .kernel()
1433 .pids
1434 .read()
1435 .get_process_group(pgid)
1436 .ok_or_else(|| errno!(ESRCH))?;
1437 }
1438 }
1439 }
1440 Ok(())
1441 }
1442}
1443
1444#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1445pub struct FileObjectId(u64);
1446
1447impl FileObjectId {
1448 pub fn as_epoll_key(&self) -> EpollKey {
1449 self.0 as EpollKey
1450 }
1451}
1452
1453pub struct FileObject {
1460 ops: Box<dyn FileOps>,
1461 state: FileObjectState,
1462}
1463
1464impl std::ops::Deref for FileObject {
1465 type Target = FileObjectState;
1466 fn deref(&self) -> &Self::Target {
1467 &self.state
1468 }
1469}
1470
1471pub struct FileObjectState {
1472 pub weak_handle: WeakFileHandle,
1475
1476 pub id: FileObjectId,
1478
1479 pub name: ActiveNamespaceNode,
1483
1484 pub fs: FileSystemHandle,
1485
1486 pub offset: RcuAtomic<off_t, FileObjectOffset>,
1487
1488 flags: AtomicOpenFlags,
1489
1490 async_owner: LockDepMutex<FileAsyncOwner, FileAsyncOwnerLock>,
1491
1492 epoll_files: LockDepMutex<HashMap<FileHandleKey, WeakFileHandle>, FileEpollFilesLock>,
1495
1496 lease: LockDepMutex<FileLeaseType, FileLeaseLock>,
1498
1499 _mysterious_node: Option<FsNodeHandle>,
1502
1503 pub security_state: security::FileObjectState,
1505}
1506
1507pub enum FileObjectReleaserAction {}
1508impl ReleaserAction<FileObject> for FileObjectReleaserAction {
1509 fn release(file_object: ReleaseGuard<FileObject>) {
1510 register_delayed_release(file_object);
1511 }
1512}
1513pub type FileReleaser = ObjectReleaser<FileObject, FileObjectReleaserAction>;
1514pub type FileHandle = Arc<FileReleaser>;
1515pub type WeakFileHandle = Weak<FileReleaser>;
1516pub type FileHandleKey = WeakKey<FileReleaser>;
1517
1518impl FileObjectState {
1519 pub fn node(&self) -> &FsNodeHandle {
1521 &self.name.entry.node
1522 }
1523
1524 pub fn flags(&self) -> OpenFlags {
1525 self.flags.load(Ordering::Relaxed)
1526 }
1527
1528 pub fn can_read(&self) -> bool {
1529 self.flags.load(Ordering::Relaxed).can_read()
1530 }
1531
1532 pub fn can_write(&self) -> bool {
1533 self.flags.load(Ordering::Relaxed).can_write()
1534 }
1535
1536 pub fn can_exec(&self) -> bool {
1538 let mounted_no_exec = self.name.to_passive().mount.flags().contains(MountFlags::NOEXEC);
1539 let no_exec_seal = self
1540 .node()
1541 .write_guard_state
1542 .lock()
1543 .get_seals()
1544 .map(|seals| seals.contains(SealFlags::NO_EXEC))
1545 .unwrap_or(false);
1546 !(mounted_no_exec || no_exec_seal)
1547 }
1548
1549 pub fn notify(&self, event_mask: InotifyMask) {
1551 self.name.notify(event_mask)
1552 }
1553}
1554
1555impl FileObject {
1556 pub fn new_anonymous<L>(
1564 locked: &mut Locked<L>,
1565 current_task: &CurrentTask,
1566 ops: Box<dyn FileOps>,
1567 node: FsNodeHandle,
1568 flags: OpenFlags,
1569 ) -> FileHandle
1570 where
1571 L: LockEqualOrBefore<FileOpsCore>,
1572 {
1573 assert!(!node.fs().has_permanent_entries());
1574 Self::new(
1575 locked,
1576 current_task,
1577 ops,
1578 NamespaceNode::new_anonymous_unrooted(current_task, node),
1579 flags,
1580 )
1581 .expect("Failed to create anonymous FileObject")
1582 }
1583
1584 pub fn new<L>(
1589 locked: &mut Locked<L>,
1590 current_task: &CurrentTask,
1591 ops: Box<dyn FileOps>,
1592 name: NamespaceNode,
1593 flags: OpenFlags,
1594 ) -> Result<FileHandle, Errno>
1595 where
1596 L: LockEqualOrBefore<FileOpsCore>,
1597 {
1598 let _mysterious_node = if flags.can_write() {
1599 name.entry.node.write_guard_state.lock().acquire(FileWriteGuardMode::WriteFile)?;
1600 Some(name.entry.node.clone())
1601 } else {
1602 None
1603 };
1604 let fs = name.entry.node.fs();
1605 let id = FileObjectId(current_task.kernel.next_file_object_id.next());
1606 let security_state = security::file_alloc_security(current_task);
1607 let file = FileHandle::new_cyclic(|weak_handle| {
1608 Self {
1609 ops,
1610 state: FileObjectState {
1611 weak_handle: weak_handle.clone(),
1612 id,
1613 name: name.into_active(),
1614 fs,
1615 offset: RcuAtomic::new(0),
1616 flags: AtomicOpenFlags::new(flags - OpenFlags::CREAT),
1617 async_owner: Default::default(),
1618 epoll_files: Default::default(),
1619 lease: Default::default(),
1620 _mysterious_node,
1621 security_state,
1622 },
1623 }
1624 .into()
1625 });
1626 file.notify(InotifyMask::OPEN);
1627
1628 file.ops().open(locked.cast_locked::<FileOpsCore>(), &file, current_task)?;
1629 Ok(file)
1630 }
1631
1632 pub fn max_access_for_memory_mapping(&self) -> Access {
1633 let mut access = Access::EXIST;
1634 if self.can_exec() {
1635 access |= Access::EXEC;
1636 }
1637 let flags = self.flags.load(Ordering::Relaxed);
1638 if flags.can_read() {
1639 access |= Access::READ;
1640 }
1641 if flags.can_write() {
1642 access |= Access::WRITE;
1643 }
1644 access
1645 }
1646
1647 pub fn ops(&self) -> &dyn FileOps {
1648 self.ops.as_ref()
1649 }
1650
1651 pub fn ops_type_name(&self) -> &'static str {
1652 self.ops().type_name()
1653 }
1654
1655 pub fn is_non_blocking(&self) -> bool {
1656 self.flags().contains(OpenFlags::NONBLOCK)
1657 }
1658
1659 pub fn blocking_op<L, T, Op>(
1675 &self,
1676 locked: &mut Locked<L>,
1677 current_task: &CurrentTask,
1678 events: FdEvents,
1679 deadline: Option<zx::MonotonicInstant>,
1680 mut op: Op,
1681 ) -> Result<T, Errno>
1682 where
1683 L: LockEqualOrBefore<FileOpsCore>,
1684 Op: FnMut(&mut Locked<L>) -> Result<T, Errno>,
1685 {
1686 let can_return_eagain = self.flags().contains(OpenFlags::NONBLOCK)
1689 && !self.flags().contains(OpenFlags::DIRECTORY);
1690 match op(locked) {
1692 Err(errno) if errno == EAGAIN && !can_return_eagain => {}
1693 result => return result,
1694 }
1695
1696 let waiter = Waiter::new();
1697 loop {
1698 self.wait_async(locked, current_task, &waiter, events, WaitCallback::none());
1700 match op(locked) {
1701 Err(e) if e == EAGAIN => {}
1702 result => return result,
1703 }
1704 let locked = locked.cast_locked::<FileOpsCore>();
1705 waiter
1706 .wait_until(
1707 locked,
1708 current_task,
1709 deadline.unwrap_or(zx::MonotonicInstant::INFINITE),
1710 )
1711 .map_err(|e| if e == ETIMEDOUT { errno!(EAGAIN) } else { e })?;
1712 }
1713 }
1714
1715 pub fn is_seekable(&self) -> bool {
1716 self.ops().is_seekable()
1717 }
1718
1719 pub fn has_persistent_offsets(&self) -> bool {
1720 self.ops().has_persistent_offsets()
1721 }
1722
1723 fn read_internal<R>(&self, current_task: &CurrentTask, read: R) -> Result<usize, Errno>
1725 where
1726 R: FnOnce() -> Result<usize, Errno>,
1727 {
1728 security::file_permission(current_task, self, security::PermissionFlags::READ)?;
1729
1730 if !self.can_read() {
1731 return error!(EBADF);
1732 }
1733 let bytes_read = read()?;
1734
1735 self.update_atime();
1738 if bytes_read > 0 {
1739 self.notify(InotifyMask::ACCESS);
1740 }
1741
1742 Ok(bytes_read)
1743 }
1744
1745 pub fn read<L>(
1746 &self,
1747 locked: &mut Locked<L>,
1748 current_task: &CurrentTask,
1749 data: &mut dyn OutputBuffer,
1750 ) -> Result<usize, Errno>
1751 where
1752 L: LockEqualOrBefore<FileOpsCore>,
1753 {
1754 self.read_internal(current_task, || {
1755 let locked = locked.cast_locked::<FileOpsCore>();
1756 if !self.ops().has_persistent_offsets() {
1757 if data.available() > MAX_LFS_FILESIZE {
1758 return error!(EINVAL);
1759 }
1760 return self.ops.read(locked, self, current_task, 0, data);
1761 }
1762
1763 let mut offset_guard = self.offset.copy();
1764 let offset = *offset_guard as usize;
1765 checked_add_offset_and_length(offset, data.available())?;
1766 let read = self.ops.read(locked, self, current_task, offset, data)?;
1767 *offset_guard += read as off_t;
1768 offset_guard.update();
1769 Ok(read)
1770 })
1771 }
1772
1773 pub fn read_at<L>(
1774 &self,
1775 locked: &mut Locked<L>,
1776 current_task: &CurrentTask,
1777 offset: usize,
1778 data: &mut dyn OutputBuffer,
1779 ) -> Result<usize, Errno>
1780 where
1781 L: LockEqualOrBefore<FileOpsCore>,
1782 {
1783 if !self.ops().is_seekable() {
1784 return error!(ESPIPE);
1785 }
1786 checked_add_offset_and_length(offset, data.available())?;
1787 let locked = locked.cast_locked::<FileOpsCore>();
1788 self.read_internal(current_task, || self.ops.read(locked, self, current_task, offset, data))
1789 }
1790
1791 fn write_common<L>(
1793 &self,
1794 locked: &mut Locked<L>,
1795 current_task: &CurrentTask,
1796 offset: usize,
1797 data: &mut dyn InputBuffer,
1798 ) -> Result<usize, Errno>
1799 where
1800 L: LockEqualOrBefore<FileOpsCore>,
1801 {
1802 security::file_permission(current_task, self, security::PermissionFlags::WRITE)?;
1803
1804 checked_add_offset_and_length(offset, data.available())?;
1811 let locked = locked.cast_locked::<FileOpsCore>();
1812 self.ops().write(locked, self, current_task, offset, data)
1813 }
1814
1815 fn write_fn<W, L>(
1817 &self,
1818 locked: &mut Locked<L>,
1819 current_task: &CurrentTask,
1820 write: W,
1821 ) -> Result<usize, Errno>
1822 where
1823 L: LockEqualOrBefore<FileOpsCore>,
1824 W: FnOnce(&mut Locked<L>) -> Result<usize, Errno>,
1825 {
1826 if !self.can_write() {
1827 return error!(EBADF);
1828 }
1829 self.node().clear_suid_and_sgid_bits(locked, current_task)?;
1830 let bytes_written = write(locked)?;
1831 self.node().update_ctime_mtime();
1832
1833 if bytes_written > 0 {
1834 self.notify(InotifyMask::MODIFY);
1835 }
1836
1837 Ok(bytes_written)
1838 }
1839
1840 pub fn write<L>(
1841 &self,
1842 locked: &mut Locked<L>,
1843 current_task: &CurrentTask,
1844 data: &mut dyn InputBuffer,
1845 ) -> Result<usize, Errno>
1846 where
1847 L: LockEqualOrBefore<FileOpsCore>,
1848 {
1849 self.write_fn(locked, current_task, |locked| {
1850 if !self.ops().has_persistent_offsets() {
1851 return self.write_common(locked, current_task, 0, data);
1852 }
1853 #[allow(
1856 clippy::undocumented_unsafe_blocks,
1857 reason = "Force documented unsafe blocks in Starnix"
1858 )]
1859 let locked = unsafe { Unlocked::new() };
1860 let mut offset = self.offset.copy();
1861 let bytes_written = if self.flags().contains(OpenFlags::APPEND) {
1862 let (_guard, locked) = self.node().ops().append_lock_write(
1863 locked.cast_locked::<BeforeFsNodeAppend>(),
1864 self.node(),
1865 current_task,
1866 )?;
1867 *offset = self.ops().seek(
1868 locked.cast_locked::<FileOpsCore>(),
1869 self,
1870 current_task,
1871 *offset,
1872 SeekTarget::End(0),
1873 )?;
1874 self.write_common(locked, current_task, *offset as usize, data)
1875 } else {
1876 let (_guard, locked) = self.node().ops().append_lock_read(
1877 locked.cast_locked::<BeforeFsNodeAppend>(),
1878 self.node(),
1879 current_task,
1880 )?;
1881 self.write_common(locked, current_task, *offset as usize, data)
1882 }?;
1883 if self.ops().writes_update_seek_offset() {
1884 *offset += bytes_written as off_t;
1885 }
1886 offset.update();
1887 Ok(bytes_written)
1888 })
1889 }
1890
1891 pub fn write_at<L>(
1892 &self,
1893 locked: &mut Locked<L>,
1894 current_task: &CurrentTask,
1895 mut offset: usize,
1896 data: &mut dyn InputBuffer,
1897 ) -> Result<usize, Errno>
1898 where
1899 L: LockEqualOrBefore<FileOpsCore>,
1900 {
1901 if !self.ops().is_seekable() {
1902 return error!(ESPIPE);
1903 }
1904 self.write_fn(locked, current_task, |_locked| {
1905 #[allow(
1908 clippy::undocumented_unsafe_blocks,
1909 reason = "Force documented unsafe blocks in Starnix"
1910 )]
1911 let locked = unsafe { Unlocked::new() };
1912 if self.flags().contains(OpenFlags::APPEND) {
1913 let (_guard, locked) = self.node().append_lock.write_and(locked, current_task)?;
1914 if self.ops().is_seekable() {
1920 checked_add_offset_and_length(offset, data.available())?;
1921 offset = default_eof_offset(locked, self, current_task)? as usize;
1922 }
1923 self.write_common(locked, current_task, offset, data)
1924 } else {
1925 let (_guard, locked) = self.node().append_lock.read_and(locked, current_task)?;
1926 self.write_common(locked, current_task, offset, data)
1927 }
1928 })
1929 }
1930
1931 pub fn seek<L>(
1932 &self,
1933 locked: &mut Locked<L>,
1934 current_task: &CurrentTask,
1935 target: SeekTarget,
1936 ) -> Result<off_t, Errno>
1937 where
1938 L: LockEqualOrBefore<FileOpsCore>,
1939 {
1940 let locked = locked.cast_locked::<FileOpsCore>();
1941 let locked = locked;
1942
1943 if !self.ops().is_seekable() {
1944 return error!(ESPIPE);
1945 }
1946
1947 if !self.ops().has_persistent_offsets() {
1948 return self.ops().seek(locked, self, current_task, 0, target);
1949 }
1950
1951 let mut offset_guard = self.offset.copy();
1952 let new_offset = self.ops().seek(locked, self, current_task, *offset_guard, target)?;
1953 *offset_guard = new_offset;
1954 offset_guard.update();
1955 Ok(new_offset)
1956 }
1957
1958 pub fn sync(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1959 self.ops().sync(self, current_task)
1960 }
1961
1962 pub fn data_sync(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1963 self.ops().data_sync(self, current_task)
1964 }
1965
1966 pub fn get_memory<L>(
1967 &self,
1968 locked: &mut Locked<L>,
1969 current_task: &CurrentTask,
1970 length: Option<usize>,
1971 prot: ProtectionFlags,
1972 ) -> Result<Arc<MemoryObject>, Errno>
1973 where
1974 L: LockEqualOrBefore<FileOpsCore>,
1975 {
1976 if prot.contains(ProtectionFlags::READ) && !self.can_read() {
1977 return error!(EACCES);
1978 }
1979 if prot.contains(ProtectionFlags::WRITE) && !self.can_write() {
1980 return error!(EACCES);
1981 }
1982 if prot.contains(ProtectionFlags::EXEC) && !self.can_exec() {
1983 return error!(EPERM);
1984 }
1985 self.ops().get_memory(locked.cast_locked::<FileOpsCore>(), self, current_task, length, prot)
1986 }
1987
1988 pub fn mmap<L>(
1989 &self,
1990 locked: &mut Locked<L>,
1991 current_task: &CurrentTask,
1992 addr: DesiredAddress,
1993 memory_offset: u64,
1994 length: usize,
1995 prot_flags: ProtectionFlags,
1996 options: MappingOptions,
1997 filename: NamespaceNode,
1998 ) -> Result<UserAddress, Errno>
1999 where
2000 L: LockEqualOrBefore<FileOpsCore>,
2001 {
2002 let locked = locked.cast_locked::<FileOpsCore>();
2003 if !self.can_read() {
2004 return error!(EACCES);
2005 }
2006 if prot_flags.contains(ProtectionFlags::WRITE)
2007 && !self.can_write()
2008 && options.contains(MappingOptions::SHARED)
2009 {
2010 return error!(EACCES);
2011 }
2012 if prot_flags.contains(ProtectionFlags::EXEC) && !self.can_exec() {
2013 return error!(EPERM);
2014 }
2015 self.ops().mmap(
2016 locked,
2017 self,
2018 current_task,
2019 addr,
2020 memory_offset,
2021 length,
2022 prot_flags,
2023 options,
2024 filename,
2025 )
2026 }
2027
2028 pub fn readdir<L>(
2029 &self,
2030 locked: &mut Locked<L>,
2031 current_task: &CurrentTask,
2032 sink: &mut dyn DirentSink,
2033 ) -> Result<(), Errno>
2034 where
2035 L: LockEqualOrBefore<FileOpsCore>,
2036 {
2037 let locked = locked.cast_locked::<FileOpsCore>();
2038 if self.name.entry.is_dead() {
2039 return error!(ENOENT);
2040 }
2041
2042 security::file_permission(current_task, self, security::PermissionFlags::READ)?;
2043
2044 self.ops().readdir(locked, self, current_task, sink)?;
2045 self.update_atime();
2046 self.notify(InotifyMask::ACCESS);
2047 Ok(())
2048 }
2049
2050 pub fn ioctl(
2051 &self,
2052 locked: &mut Locked<Unlocked>,
2053 current_task: &CurrentTask,
2054 request: u32,
2055 arg: SyscallArg,
2056 ) -> Result<SyscallResult, Errno> {
2057 security::check_file_ioctl_access(current_task, &self, request)?;
2058
2059 if request == FIBMAP {
2060 security::check_task_capable(current_task, CAP_SYS_RAWIO)?;
2061
2062 if current_task.kernel().features.selinux_test_suite {
2065 let phoney_block = 0xbadf000du32;
2066 current_task.write_object(arg.into(), &phoney_block)?;
2067 return Ok(SUCCESS);
2068 }
2069 }
2070
2071 if let Some(result) = default_vfs_ioctl(self, locked, current_task, request, arg)? {
2072 return Ok(result);
2073 }
2074
2075 self.ops().ioctl(locked, self, current_task, request, arg)
2076 }
2077
2078 pub fn fcntl(
2079 &self,
2080 current_task: &CurrentTask,
2081 cmd: u32,
2082 arg: u64,
2083 ) -> Result<SyscallResult, Errno> {
2084 self.ops().fcntl(self, current_task, cmd, arg)
2085 }
2086
2087 pub fn ftruncate<L>(
2088 &self,
2089 locked: &mut Locked<L>,
2090 current_task: &CurrentTask,
2091 length: u64,
2092 ) -> Result<(), Errno>
2093 where
2094 L: LockBefore<BeforeFsNodeAppend>,
2095 {
2096 if !self.can_write() {
2099 return error!(EINVAL);
2100 }
2101 self.node().ftruncate(locked, current_task, length)?;
2102 self.name.entry.notify_ignoring_excl_unlink(InotifyMask::MODIFY);
2103 Ok(())
2104 }
2105
2106 pub fn fallocate<L>(
2107 &self,
2108 locked: &mut Locked<L>,
2109 current_task: &CurrentTask,
2110 mode: FallocMode,
2111 offset: u64,
2112 length: u64,
2113 ) -> Result<(), Errno>
2114 where
2115 L: LockBefore<BeforeFsNodeAppend>,
2116 {
2117 if self.node().is_fifo() {
2120 return error!(ESPIPE);
2121 }
2122
2123 if !self.node().is_dir() && !self.node().is_reg() {
2126 return error!(ENODEV);
2127 }
2128
2129 if !self.can_write() {
2132 return error!(EBADF);
2133 }
2134
2135 security::file_permission(current_task, self, security::PermissionFlags::WRITE)?;
2136
2137 self.node().fallocate(locked, current_task, mode, offset, length)?;
2138 self.notify(InotifyMask::MODIFY);
2139 Ok(())
2140 }
2141
2142 pub fn to_handle(
2143 &self,
2144 current_task: &CurrentTask,
2145 ) -> Result<Option<zx::NullableHandle>, Errno> {
2146 self.ops().to_handle(self, current_task)
2147 }
2148
2149 pub fn get_handles(
2150 &self,
2151 current_task: &CurrentTask,
2152 ) -> Result<Vec<zx::NullableHandle>, Errno> {
2153 self.ops().get_handles(self, current_task)
2154 }
2155
2156 pub fn as_thread_group_key(&self) -> Result<ThreadGroupKey, Errno> {
2157 self.ops().as_thread_group_key(self)
2158 }
2159
2160 pub fn update_file_flags(&self, value: OpenFlags, mask: OpenFlags) {
2166 self.flags.update(value, mask, Ordering::Relaxed, Ordering::Relaxed);
2167 }
2168
2169 pub fn get_async_owner(&self) -> FileAsyncOwner {
2173 *self.async_owner.lock()
2174 }
2175
2176 pub fn set_async_owner(&self, owner: FileAsyncOwner) {
2180 *self.async_owner.lock() = owner;
2181 }
2182
2183 pub fn get_lease(&self, _current_task: &CurrentTask) -> FileLeaseType {
2185 *self.lease.lock()
2186 }
2187
2188 pub fn set_lease(&self, current_task: &CurrentTask, lease: FileLeaseType) -> Result<(), Errno> {
2190 if !self.node().is_reg() {
2191 return error!(EINVAL);
2192 }
2193 security::check_file_lock_access(current_task, self)?;
2194 if lease == FileLeaseType::Read && self.can_write() {
2195 return error!(EAGAIN);
2196 }
2197 *self.lease.lock() = lease;
2198 Ok(())
2199 }
2200
2201 pub fn wait_async<L>(
2203 &self,
2204 locked: &mut Locked<L>,
2205 current_task: &CurrentTask,
2206 waiter: &Waiter,
2207 events: FdEvents,
2208 handler: EventHandler,
2209 ) -> Option<WaitCanceler>
2210 where
2211 L: LockEqualOrBefore<FileOpsCore>,
2212 {
2213 self.ops().wait_async(
2214 locked.cast_locked::<FileOpsCore>(),
2215 self,
2216 current_task,
2217 waiter,
2218 events,
2219 handler,
2220 )
2221 }
2222
2223 pub fn query_events<L>(
2225 &self,
2226 locked: &mut Locked<L>,
2227 current_task: &CurrentTask,
2228 ) -> Result<FdEvents, Errno>
2229 where
2230 L: LockEqualOrBefore<FileOpsCore>,
2231 {
2232 self.ops()
2233 .query_events(locked.cast_locked::<FileOpsCore>(), self, current_task)
2234 .map(FdEvents::add_equivalent_fd_events)
2235 }
2236
2237 pub fn record_lock(
2238 &self,
2239 locked: &mut Locked<Unlocked>,
2240 current_task: &CurrentTask,
2241 cmd: RecordLockCommand,
2242 flock: uapi::flock,
2243 ) -> Result<Option<uapi::flock>, Errno> {
2244 security::check_file_lock_access(current_task, self)?;
2245 self.node().record_lock(locked, current_task, self, cmd, flock)
2246 }
2247
2248 pub fn flush<L>(&self, locked: &mut Locked<L>, current_task: &CurrentTask, id: FdTableId)
2249 where
2250 L: LockEqualOrBefore<FileOpsCore>,
2251 {
2252 self.name.entry.node.record_lock_release(RecordLockOwner::FdTable(id));
2253 self.ops().flush(locked.cast_locked::<FileOpsCore>(), self, current_task)
2254 }
2255
2256 fn update_atime(&self) {
2257 if !self.flags().contains(OpenFlags::NOATIME) {
2258 self.name.update_atime();
2259 }
2260 }
2261
2262 pub fn readahead(
2263 &self,
2264 current_task: &CurrentTask,
2265 offset: usize,
2266 length: usize,
2267 ) -> Result<(), Errno> {
2268 if !self.can_read() {
2270 return error!(EBADF);
2271 }
2272 checked_add_offset_and_length(offset, length)?;
2273 self.ops().readahead(self, current_task, offset, length)
2274 }
2275
2276 pub fn extra_fdinfo(
2277 &self,
2278 locked: &mut Locked<FileOpsCore>,
2279 current_task: &CurrentTask,
2280 ) -> Option<FsString> {
2281 let file = self.weak_handle.upgrade()?;
2282 self.ops().extra_fdinfo(locked, &file, current_task)
2283 }
2284
2285 pub fn register_epfd(&self, file: &FileHandle) {
2288 self.epoll_files.lock().insert(WeakKey::from(file), file.weak_handle.clone());
2289 }
2290
2291 pub fn unregister_epfd(&self, file: &FileHandle) {
2292 self.epoll_files.lock().remove(&WeakKey::from(file));
2293 }
2294}
2295
2296impl Releasable for FileObject {
2297 type Context<'a> = CurrentTaskAndLocked<'a>;
2298
2299 fn release<'a>(self, context: CurrentTaskAndLocked<'a>) {
2300 let (locked, current_task) = context;
2301 for (_, file) in self.epoll_files.lock().drain() {
2304 if let Some(file) = file.upgrade() {
2305 if let Some(epoll_object) = file.downcast_file::<EpollFileObject>() {
2306 let _ = epoll_object.delete(current_task, &self);
2307 }
2308 }
2309 }
2310
2311 if self.can_write() {
2312 self.name.entry.node.write_guard_state.lock().release(FileWriteGuardMode::WriteFile);
2313 }
2314
2315 let locked = locked.cast_locked::<FileOpsCore>();
2316 let ops = self.ops;
2317 let state = self.state;
2318 ops.close(locked, &state, current_task);
2319 state.name.entry.node.on_file_closed(&state);
2320 let event =
2321 if state.can_write() { InotifyMask::CLOSE_WRITE } else { InotifyMask::CLOSE_NOWRITE };
2322 state.notify(event);
2323 }
2324}
2325
2326impl fmt::Debug for FileObject {
2327 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2328 f.debug_struct("FileObject")
2329 .field("name", &self.name)
2330 .field("fs", &self.fs.name())
2331 .field("offset", &self.offset)
2332 .field("flags", &self.flags)
2333 .field("ops_ty", &self.ops().type_name())
2334 .finish()
2335 }
2336}
2337
2338impl OnWakeOps for FileReleaser {
2339 fn on_wake(&self, _current_task: &CurrentTask, _baton_lease: &zx::NullableHandle) {}
2340}
2341
2342pub struct DowncastedFile<'a, Ops> {
2344 file: &'a FileObject,
2345 ops: &'a Ops,
2346}
2347impl<'a, Ops> Copy for DowncastedFile<'a, Ops> {}
2348impl<'a, Ops> Clone for DowncastedFile<'a, Ops> {
2349 fn clone(&self) -> Self {
2350 *self
2351 }
2352}
2353
2354impl<'a, Ops> DowncastedFile<'a, Ops> {
2355 pub fn file(&self) -> &'a FileObject {
2356 self.file
2357 }
2358}
2359
2360impl<'a, Ops> Deref for DowncastedFile<'a, Ops> {
2361 type Target = &'a Ops;
2362 fn deref(&self) -> &Self::Target {
2363 &self.ops
2364 }
2365}
2366
2367impl FileObject {
2368 pub fn downcast_file<'a, T>(&'a self) -> Option<DowncastedFile<'a, T>>
2373 where
2374 T: 'static,
2375 {
2376 let ops = self.ops().as_any().downcast_ref::<T>()?;
2377 Some(DowncastedFile { file: self, ops })
2378 }
2379}
2380
2381pub fn call_fidl_and_await_close<P, M>(method: M, proxy: &P)
2389where
2390 P: fidl::endpoints::SynchronousProxy,
2391 M: FnOnce(&P) -> Result<(), fidl::Error>,
2392{
2393 if let Err(e) = method(proxy) {
2394 log_error!("call_fidl_and_await_close: call {} failed: {e:?}", P::Protocol::DEBUG_NAME);
2395 return;
2396 }
2397 let channel = proxy.as_channel();
2398 let result = channel.wait_one(zx::Signals::CHANNEL_PEER_CLOSED, zx::MonotonicInstant::INFINITE);
2399 if let Err(status) = result.to_result() {
2400 log_error!(
2401 "call_fidl_and_await_close: wait_one {} failed: {status:?}",
2402 P::Protocol::DEBUG_NAME
2403 );
2404 }
2405}
2406
2407#[cfg(test)]
2408mod tests {
2409 use crate::fs::tmpfs::TmpFs;
2410 use crate::task::CurrentTask;
2411 use crate::task::dynamic_thread_spawner::SpawnRequestBuilder;
2412 use crate::testing::*;
2413 use crate::vfs::MountInfo;
2414 use crate::vfs::buffers::{VecInputBuffer, VecOutputBuffer};
2415 use starnix_sync::{Locked, Unlocked};
2416 use starnix_uapi::auth::FsCred;
2417 use starnix_uapi::device_id::DeviceId;
2418 use starnix_uapi::file_mode::FileMode;
2419 use starnix_uapi::open_flags::OpenFlags;
2420 use std::sync::Arc;
2421 use std::sync::atomic::{AtomicBool, Ordering};
2422 use zerocopy::{FromBytes, IntoBytes, LE, U64};
2423
2424 #[::fuchsia::test]
2425 async fn test_append_truncate_race() {
2426 spawn_kernel_and_run(async |locked, current_task| {
2427 let kernel = current_task.kernel();
2428 let root_fs = TmpFs::new_fs(locked, &kernel);
2429 let mount = MountInfo::detached();
2430 let root_node = Arc::clone(root_fs.root());
2431 let file = root_node
2432 .create_entry(
2433 locked,
2434 ¤t_task,
2435 &mount,
2436 "test".into(),
2437 |locked, dir, mount, name| {
2438 dir.create_node(
2439 locked,
2440 ¤t_task,
2441 mount,
2442 name,
2443 FileMode::IFREG | FileMode::ALLOW_ALL,
2444 DeviceId::NONE,
2445 FsCred::root(),
2446 )
2447 },
2448 )
2449 .expect("create_node failed");
2450 let file_handle = file
2451 .open_anonymous(locked, ¤t_task, OpenFlags::APPEND | OpenFlags::RDWR)
2452 .expect("open failed");
2453 let done = Arc::new(AtomicBool::new(false));
2454
2455 let fh = file_handle.clone();
2456 let done_clone = done.clone();
2457 let closure = move |locked: &mut Locked<Unlocked>, current_task: &CurrentTask| {
2458 for i in 0..2000 {
2459 fh.write(
2460 locked,
2461 current_task,
2462 &mut VecInputBuffer::new(U64::<LE>::new(i).as_bytes()),
2463 )
2464 .expect("write failed");
2465 }
2466 done_clone.store(true, Ordering::SeqCst);
2467 let result: Result<(), starnix_uapi::errors::Errno> = Ok(());
2468 result
2469 };
2470 let (write_thread, req) =
2471 SpawnRequestBuilder::new().with_sync_closure(closure).build_with_sync_result();
2472 kernel.kthreads.spawner().spawn_from_request(req);
2473
2474 let fh = file_handle.clone();
2475 let done_clone = done.clone();
2476 let closure = move |locked: &mut Locked<Unlocked>, current_task: &CurrentTask| {
2477 while !done_clone.load(Ordering::SeqCst) {
2478 fh.ftruncate(locked, current_task, 0).expect("truncate failed");
2479 }
2480 let result: Result<(), starnix_uapi::errors::Errno> = Ok(());
2481 result
2482 };
2483 let (truncate_thread, req) =
2484 SpawnRequestBuilder::new().with_sync_closure(closure).build_with_sync_result();
2485 kernel.kthreads.spawner().spawn_from_request(req);
2486
2487 while !done.load(Ordering::SeqCst) {
2490 let mut buffer = VecOutputBuffer::new(4096);
2491 let amount = file_handle
2492 .read_at(locked, ¤t_task, 0, &mut buffer)
2493 .expect("read failed");
2494 let mut last = None;
2495 let buffer = &Vec::from(buffer)[..amount];
2496 for i in
2497 buffer.chunks_exact(8).map(|chunk| U64::<LE>::read_from_bytes(chunk).unwrap())
2498 {
2499 if let Some(last) = last {
2500 assert!(i.get() > last, "buffer: {:?}", buffer);
2501 }
2502 last = Some(i.get());
2503 }
2504 }
2505
2506 let _ = write_thread().unwrap();
2507 let _ = truncate_thread().unwrap();
2508 })
2509 .await;
2510 }
2511}