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