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};
19use crate::vfs::{
20 ActiveNamespaceNode, DirentSink, EpollFileObject, EpollKey, FallocMode, FdTableId, FileMapping,
21 FileSystemHandle, FileWriteGuardMode, FsNodeHandle, FsString, FscryptPolicyFlags,
22 NamespaceNode, RecordLockCommand, RecordLockOwner,
23};
24use starnix_crypt::EncryptionKeyId;
25use starnix_lifecycle::{ObjectReleaser, ReleaserAction};
26use starnix_rcu::RcuAtomic;
27use starnix_types::ownership::ReleaseGuard;
28use starnix_uapi::mount_flags::MountFlags;
29use starnix_uapi::user_address::ArchSpecific;
30
31use fidl::endpoints::ProtocolMarker as _;
32use linux_uapi::{FSCRYPT_MODE_AES_256_CTS, FSCRYPT_MODE_AES_256_XTS};
33use starnix_logging::{CATEGORY_STARNIX_MM, impossible_error, log_error, track_stub};
34use starnix_sync::{
35 FileAsyncOwnerLock, FileEpollFilesLock, FileLeaseLock, FileObjectOffset, LockDepMutex,
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 F_OWNER_PGRP, F_OWNER_PID, F_OWNER_TID, FIBMAP, FIGETBSZ, FIONBIO, FIONREAD, FIOQSIZE,
53 FS_CASEFOLD_FL, FS_IOC_ADD_ENCRYPTION_KEY, FS_IOC_ENABLE_VERITY, FS_IOC_FSGETXATTR,
54 FS_IOC_FSSETXATTR, FS_IOC_GET_ENCRYPTION_POLICY, FS_IOC_GET_ENCRYPTION_POLICY_EX,
55 FS_IOC_MEASURE_VERITY, FS_IOC_READ_VERITY_METADATA, FS_IOC_REMOVE_ENCRYPTION_KEY,
56 FS_IOC_SET_ENCRYPTION_POLICY, FS_VERITY_FL, FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER,
57 FSCRYPT_POLICY_V2, SEEK_CUR, SEEK_DATA, SEEK_END, SEEK_HOLE, SEEK_SET, errno, error,
58 fscrypt_add_key_arg, fscrypt_identifier, fsxattr, off_t, pid_t, uapi,
59};
60use std::collections::HashMap;
61use std::fmt;
62use std::ops::Deref;
63use std::sync::atomic::Ordering;
64use std::sync::{Arc, Weak};
65
66pub const MAX_LFS_FILESIZE: usize = 0x7fff_ffff_ffff_ffff;
67
68pub fn checked_add_offset_and_length(offset: usize, length: usize) -> Result<usize, Errno> {
69 let end = offset.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
70 if end > MAX_LFS_FILESIZE {
71 return error!(EINVAL);
72 }
73 Ok(end)
74}
75
76#[derive(Debug)]
77pub enum SeekTarget {
78 Set(off_t),
80 Cur(off_t),
82 End(off_t),
84 Data(off_t),
86 Hole(off_t),
88}
89
90impl SeekTarget {
91 pub fn from_raw(whence: u32, offset: off_t) -> Result<SeekTarget, Errno> {
92 match whence {
93 SEEK_SET => Ok(SeekTarget::Set(offset)),
94 SEEK_CUR => Ok(SeekTarget::Cur(offset)),
95 SEEK_END => Ok(SeekTarget::End(offset)),
96 SEEK_DATA => Ok(SeekTarget::Data(offset)),
97 SEEK_HOLE => Ok(SeekTarget::Hole(offset)),
98 _ => error!(EINVAL),
99 }
100 }
101
102 pub fn whence(&self) -> u32 {
103 match self {
104 Self::Set(_) => SEEK_SET,
105 Self::Cur(_) => SEEK_CUR,
106 Self::End(_) => SEEK_END,
107 Self::Data(_) => SEEK_DATA,
108 Self::Hole(_) => SEEK_HOLE,
109 }
110 }
111
112 pub fn offset(&self) -> off_t {
113 match self {
114 Self::Set(off)
115 | Self::Cur(off)
116 | Self::End(off)
117 | Self::Data(off)
118 | Self::Hole(off) => *off,
119 }
120 }
121}
122
123pub trait FileOps: Send + Sync + AsAny + 'static {
125 fn open(&self, _file: &FileObject, _current_task: &CurrentTask) -> Result<(), Errno> {
127 Ok(())
128 }
129
130 fn close(self: Box<Self>, _file: &FileObjectState, _current_task: &CurrentTask) {}
132
133 fn flush(&self, _file: &FileObject, _current_task: &CurrentTask) {}
136
137 fn has_persistent_offsets(&self) -> bool {
141 self.is_seekable()
142 }
143
144 fn is_seekable(&self) -> bool;
146
147 fn writes_update_seek_offset(&self) -> bool {
149 self.has_persistent_offsets()
150 }
151
152 fn read(
156 &self,
157 file: &FileObject,
158 current_task: &CurrentTask,
159 offset: usize,
160 data: &mut dyn OutputBuffer,
161 ) -> Result<usize, Errno>;
162
163 fn write(
167 &self,
168 file: &FileObject,
169 current_task: &CurrentTask,
170 offset: usize,
171 data: &mut dyn InputBuffer,
172 ) -> Result<usize, Errno>;
173
174 fn seek(
176 &self,
177 file: &FileObject,
178 current_task: &CurrentTask,
179 current_offset: off_t,
180 target: SeekTarget,
181 ) -> Result<off_t, Errno>;
182
183 fn sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
187 file.node().ops().sync(file.node(), current_task)
188 }
189
190 fn data_sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
194 self.sync(file, current_task)
196 }
197
198 fn get_memory(
205 &self,
206 _file: &FileObject,
207 _current_task: &CurrentTask,
208 _length: Option<usize>,
209 _prot: ProtectionFlags,
210 ) -> Result<Arc<MemoryObject>, Errno> {
211 error!(ENODEV)
212 }
213
214 fn mmap(
219 &self,
220 file: &FileObject,
221 current_task: &CurrentTask,
222 addr: DesiredAddress,
223 memory_offset: u64,
224 length: usize,
225 prot_flags: ProtectionFlags,
226 options: MappingOptions,
227 ) -> Result<UserAddress, Errno> {
228 default_mmap(file, current_task, addr, memory_offset, length, prot_flags, options)
229 }
230
231 fn can_map_executable(&self) -> bool {
238 true
239 }
240
241 fn readdir(
246 &self,
247 _file: &FileObject,
248 _current_task: &CurrentTask,
249 _sink: &mut dyn DirentSink,
250 ) -> Result<(), Errno> {
251 error!(ENOTDIR)
252 }
253
254 fn wait_async(
263 &self,
264 _file: &FileObject,
265 _current_task: &CurrentTask,
266 _waiter: &Waiter,
267 _events: FdEvents,
268 _handler: EventHandler,
269 ) -> Option<WaitCanceler> {
270 None
271 }
272
273 fn query_events(
281 &self,
282 _file: &FileObject,
283 _current_task: &CurrentTask,
284 ) -> Result<FdEvents, Errno> {
285 Ok(FdEvents::POLLIN | FdEvents::POLLOUT)
286 }
287
288 fn ioctl(
289 &self,
290 _file: &FileObject,
291 _current_task: &CurrentTask,
292 _request: u32,
293 _arg: SyscallArg,
294 ) -> Result<SyscallResult, Errno> {
295 error!(ENOTTY)
296 }
297
298 fn fcntl(
299 &self,
300 _file: &FileObject,
301 _current_task: &CurrentTask,
302 cmd: u32,
303 _arg: u64,
304 ) -> Result<SyscallResult, Errno> {
305 default_fcntl(cmd)
306 }
307
308 fn to_handle(
312 &self,
313 file: &FileObject,
314 current_task: &CurrentTask,
315 ) -> Result<Option<zx::NullableHandle>, Errno> {
316 serve_file(current_task, file, current_task.current_creds().clone())
317 .map(|c| Some(c.0.into_channel().into()))
318 }
319
320 fn get_handles(
336 &self,
337 _file: &FileObject,
338 _current_task: &CurrentTask,
339 ) -> Result<Vec<zx::NullableHandle>, Errno> {
340 error!(ENOTSUP)
341 }
342
343 fn as_pid(&self, _file: &FileObject) -> Result<Pid, Errno> {
347 error!(EBADF)
348 }
349
350 fn readahead(
351 &self,
352 _file: &FileObject,
353 _current_task: &CurrentTask,
354 _offset: usize,
355 _length: usize,
356 ) -> Result<(), Errno> {
357 error!(EINVAL)
358 }
359
360 fn extra_fdinfo(&self, _file: &FileHandle, _current_task: &CurrentTask) -> Option<FsString> {
362 None
363 }
364}
365
366pub trait CloseFreeSafe {}
369impl<T: FileOps + CloseFreeSafe, P: Deref<Target = T> + Send + Sync + 'static> FileOps for P {
370 fn close(self: Box<Self>, _file: &FileObjectState, _current_task: &CurrentTask) {
371 }
373
374 fn flush(&self, file: &FileObject, current_task: &CurrentTask) {
375 self.deref().flush(file, current_task)
376 }
377
378 fn has_persistent_offsets(&self) -> bool {
379 self.deref().has_persistent_offsets()
380 }
381
382 fn writes_update_seek_offset(&self) -> bool {
383 self.deref().writes_update_seek_offset()
384 }
385
386 fn is_seekable(&self) -> bool {
387 self.deref().is_seekable()
388 }
389
390 fn read(
391 &self,
392 file: &FileObject,
393 current_task: &CurrentTask,
394 offset: usize,
395 data: &mut dyn OutputBuffer,
396 ) -> Result<usize, Errno> {
397 self.deref().read(file, current_task, offset, data)
398 }
399
400 fn write(
401 &self,
402 file: &FileObject,
403 current_task: &CurrentTask,
404 offset: usize,
405 data: &mut dyn InputBuffer,
406 ) -> Result<usize, Errno> {
407 self.deref().write(file, current_task, offset, data)
408 }
409
410 fn seek(
411 &self,
412 file: &FileObject,
413 current_task: &CurrentTask,
414 current_offset: off_t,
415 target: SeekTarget,
416 ) -> Result<off_t, Errno> {
417 self.deref().seek(file, current_task, current_offset, target)
418 }
419
420 fn sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
421 self.deref().sync(file, current_task)
422 }
423
424 fn data_sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
425 self.deref().data_sync(file, current_task)
426 }
427
428 fn get_memory(
429 &self,
430 file: &FileObject,
431 current_task: &CurrentTask,
432 length: Option<usize>,
433 prot: ProtectionFlags,
434 ) -> Result<Arc<MemoryObject>, Errno> {
435 self.deref().get_memory(file, current_task, length, prot)
436 }
437
438 fn mmap(
439 &self,
440 file: &FileObject,
441 current_task: &CurrentTask,
442 addr: DesiredAddress,
443 memory_offset: u64,
444 length: usize,
445 prot_flags: ProtectionFlags,
446 options: MappingOptions,
447 ) -> Result<UserAddress, Errno> {
448 self.deref().mmap(file, current_task, addr, memory_offset, length, prot_flags, options)
449 }
450
451 fn can_map_executable(&self) -> bool {
452 self.deref().can_map_executable()
453 }
454
455 fn readdir(
456 &self,
457 file: &FileObject,
458 current_task: &CurrentTask,
459 sink: &mut dyn DirentSink,
460 ) -> Result<(), Errno> {
461 self.deref().readdir(file, current_task, sink)
462 }
463
464 fn wait_async(
465 &self,
466 file: &FileObject,
467 current_task: &CurrentTask,
468 waiter: &Waiter,
469 events: FdEvents,
470 handler: EventHandler,
471 ) -> Option<WaitCanceler> {
472 self.deref().wait_async(file, current_task, waiter, events, handler)
473 }
474
475 fn query_events(
476 &self,
477 file: &FileObject,
478 current_task: &CurrentTask,
479 ) -> Result<FdEvents, Errno> {
480 self.deref().query_events(file, current_task)
481 }
482
483 fn ioctl(
484 &self,
485 file: &FileObject,
486 current_task: &CurrentTask,
487 request: u32,
488 arg: SyscallArg,
489 ) -> Result<SyscallResult, Errno> {
490 self.deref().ioctl(file, current_task, request, arg)
491 }
492
493 fn fcntl(
494 &self,
495 file: &FileObject,
496 current_task: &CurrentTask,
497 cmd: u32,
498 arg: u64,
499 ) -> Result<SyscallResult, Errno> {
500 self.deref().fcntl(file, current_task, cmd, arg)
501 }
502
503 fn to_handle(
504 &self,
505 file: &FileObject,
506 current_task: &CurrentTask,
507 ) -> Result<Option<zx::NullableHandle>, Errno> {
508 self.deref().to_handle(file, current_task)
509 }
510
511 fn get_handles(
512 &self,
513 file: &FileObject,
514 current_task: &CurrentTask,
515 ) -> Result<Vec<zx::NullableHandle>, Errno> {
516 self.deref().get_handles(file, current_task)
517 }
518
519 fn as_pid(&self, file: &FileObject) -> Result<Pid, Errno> {
520 self.deref().as_pid(file)
521 }
522
523 fn readahead(
524 &self,
525 file: &FileObject,
526 current_task: &CurrentTask,
527 offset: usize,
528 length: usize,
529 ) -> Result<(), Errno> {
530 self.deref().readahead(file, current_task, offset, length)
531 }
532
533 fn extra_fdinfo(&self, file: &FileHandle, current_task: &CurrentTask) -> Option<FsString> {
534 self.deref().extra_fdinfo(file, current_task)
535 }
536}
537
538pub fn default_eof_offset(file: &FileObject, current_task: &CurrentTask) -> Result<off_t, Errno> {
539 Ok(file.node().get_size(current_task)? as off_t)
540}
541
542pub fn default_seek<F>(
552 current_offset: off_t,
553 target: SeekTarget,
554 compute_end: F,
555) -> Result<off_t, Errno>
556where
557 F: FnOnce() -> Result<off_t, Errno>,
558{
559 let new_offset = match target {
560 SeekTarget::Set(offset) => Some(offset),
561 SeekTarget::Cur(offset) => current_offset.checked_add(offset),
562 SeekTarget::End(offset) => compute_end()?.checked_add(offset),
563 SeekTarget::Data(offset) => {
564 let eof = compute_end().unwrap_or(off_t::MAX);
565 if offset >= eof {
566 return error!(ENXIO);
567 }
568 Some(offset)
569 }
570 SeekTarget::Hole(offset) => {
571 let eof = compute_end()?;
572 if offset >= eof {
573 return error!(ENXIO);
574 }
575 Some(eof)
576 }
577 }
578 .ok_or_else(|| errno!(EINVAL))?;
579
580 if new_offset < 0 {
581 return error!(EINVAL);
582 }
583
584 Ok(new_offset)
585}
586
587pub fn unbounded_seek(current_offset: off_t, target: SeekTarget) -> Result<off_t, Errno> {
596 default_seek(current_offset, target, || Ok(MAX_LFS_FILESIZE as off_t))
597}
598
599#[macro_export]
600macro_rules! fileops_impl_delegate_read_write_and_seek {
601 ($self:ident, $delegate:expr) => {
602 fn is_seekable(&self) -> bool {
603 true
604 }
605
606 fn read(
607 &$self,
608 file: &FileObject,
609 current_task: &$crate::task::CurrentTask,
610 offset: usize,
611 data: &mut dyn $crate::vfs::buffers::OutputBuffer,
612 ) -> Result<usize, starnix_uapi::errors::Errno> {
613 $delegate.read(file, current_task, offset, data)
614 }
615
616 fn write(
617 &$self,
618 file: &FileObject,
619 current_task: &$crate::task::CurrentTask,
620 offset: usize,
621 data: &mut dyn $crate::vfs::buffers::InputBuffer,
622 ) -> Result<usize, starnix_uapi::errors::Errno> {
623 $delegate.write(file, current_task, offset, data)
624 }
625
626 fn seek(
627 &$self,
628 file: &FileObject,
629 current_task: &$crate::task::CurrentTask,
630 current_offset: starnix_uapi::off_t,
631 target: $crate::vfs::SeekTarget,
632 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
633 $delegate.seek(file, current_task, current_offset, target)
634 }
635 };
636}
637
638#[macro_export]
640macro_rules! fileops_impl_seekable {
641 () => {
642 fn is_seekable(&self) -> bool {
643 true
644 }
645
646 fn seek(
647 &self,
648 file: &$crate::vfs::FileObject,
649 current_task: &$crate::task::CurrentTask,
650 current_offset: starnix_uapi::off_t,
651 target: $crate::vfs::SeekTarget,
652 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
653 $crate::vfs::default_seek(current_offset, target, || {
654 $crate::vfs::default_eof_offset(file, current_task)
655 })
656 }
657 };
658}
659
660#[macro_export]
662macro_rules! fileops_impl_nonseekable {
663 () => {
664 fn is_seekable(&self) -> bool {
665 false
666 }
667
668 fn seek(
669 &self,
670 _file: &$crate::vfs::FileObject,
671 _current_task: &$crate::task::CurrentTask,
672 _current_offset: starnix_uapi::off_t,
673 _target: $crate::vfs::SeekTarget,
674 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
675 starnix_uapi::error!(ESPIPE)
676 }
677 };
678}
679
680#[macro_export]
683macro_rules! fileops_impl_seekless {
684 () => {
685 fn has_persistent_offsets(&self) -> bool {
686 false
687 }
688
689 fn is_seekable(&self) -> bool {
690 true
691 }
692
693 fn seek(
694 &self,
695 _file: &$crate::vfs::FileObject,
696 _current_task: &$crate::task::CurrentTask,
697 _current_offset: starnix_uapi::off_t,
698 _target: $crate::vfs::SeekTarget,
699 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
700 Ok(0)
701 }
702 };
703}
704
705#[macro_export]
706macro_rules! fileops_impl_dataless {
707 () => {
708 fn write(
709 &self,
710 _file: &$crate::vfs::FileObject,
711 _current_task: &$crate::task::CurrentTask,
712 _offset: usize,
713 _data: &mut dyn $crate::vfs::buffers::InputBuffer,
714 ) -> Result<usize, starnix_uapi::errors::Errno> {
715 starnix_uapi::error!(EINVAL)
716 }
717
718 fn read(
719 &self,
720 _file: &$crate::vfs::FileObject,
721 _current_task: &$crate::task::CurrentTask,
722 _offset: usize,
723 _data: &mut dyn $crate::vfs::buffers::OutputBuffer,
724 ) -> Result<usize, starnix_uapi::errors::Errno> {
725 starnix_uapi::error!(EINVAL)
726 }
727 };
728}
729
730#[macro_export]
733macro_rules! fileops_impl_directory {
734 () => {
735 fn is_seekable(&self) -> bool {
736 true
737 }
738
739 fn read(
740 &self,
741 _file: &$crate::vfs::FileObject,
742 _current_task: &$crate::task::CurrentTask,
743 _offset: usize,
744 _data: &mut dyn $crate::vfs::buffers::OutputBuffer,
745 ) -> Result<usize, starnix_uapi::errors::Errno> {
746 starnix_uapi::error!(EISDIR)
747 }
748
749 fn write(
750 &self,
751 _file: &$crate::vfs::FileObject,
752 _current_task: &$crate::task::CurrentTask,
753 _offset: usize,
754 _data: &mut dyn $crate::vfs::buffers::InputBuffer,
755 ) -> Result<usize, starnix_uapi::errors::Errno> {
756 starnix_uapi::error!(EISDIR)
757 }
758 };
759}
760
761#[macro_export]
762macro_rules! fileops_impl_unbounded_seek {
763 () => {
764 fn seek(
765 &self,
766 _file: &$crate::vfs::FileObject,
767 _current_task: &$crate::task::CurrentTask,
768 current_offset: starnix_uapi::off_t,
769 target: $crate::vfs::SeekTarget,
770 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
771 $crate::vfs::unbounded_seek(current_offset, target)
772 }
773 };
774}
775
776#[macro_export]
777macro_rules! fileops_impl_noop_sync {
778 () => {
779 fn sync(
780 &self,
781 file: &$crate::vfs::FileObject,
782 _current_task: &$crate::task::CurrentTask,
783 ) -> Result<(), starnix_uapi::errors::Errno> {
784 if !file.node().is_reg() && !file.node().is_dir() {
785 return starnix_uapi::error!(EINVAL);
786 }
787 Ok(())
788 }
789 };
790}
791
792pub use fileops_impl_dataless;
795pub use fileops_impl_delegate_read_write_and_seek;
796pub use fileops_impl_directory;
797pub use fileops_impl_nonseekable;
798pub use fileops_impl_noop_sync;
799pub use fileops_impl_seekable;
800pub use fileops_impl_seekless;
801pub use fileops_impl_unbounded_seek;
802pub const AES256_KEY_SIZE: usize = 32;
803
804pub fn canonicalize_ioctl_request(current_task: &CurrentTask, request: u32) -> u32 {
805 if current_task.is_arch32() {
806 match request {
807 uapi::arch32::FS_IOC_GETFLAGS => uapi::FS_IOC_GETFLAGS,
808 uapi::arch32::FS_IOC_SETFLAGS => uapi::FS_IOC_SETFLAGS,
809 _ => request,
810 }
811 } else {
812 request
813 }
814}
815
816pub fn default_vfs_ioctl(
824 file: &FileObject,
825 current_task: &CurrentTask,
826 request: u32,
827 arg: SyscallArg,
828) -> Result<Option<SyscallResult>, Errno> {
829 match canonicalize_ioctl_request(current_task, request) {
830 FIGETBSZ if file.node().is_reg() || file.node().is_dir() => {
831 let blocksize = file.node().stat(current_task)?.st_blksize;
832 current_task.write_object(arg.into(), &blocksize)?;
833 Ok(Some(SUCCESS))
834 }
835 FIONBIO => {
836 let arg_ref = UserAddress::from(arg).into();
837 let arg: i32 = current_task.read_object(arg_ref)?;
838 let val = if arg == 0 {
839 OpenFlags::empty()
841 } else {
842 OpenFlags::NONBLOCK
844 };
845 file.update_file_flags(val, OpenFlags::NONBLOCK);
846 Ok(Some(SUCCESS))
847 }
848 FIOQSIZE if file.node().is_reg() || file.node().is_dir() => {
849 let size = file.node().stat(current_task)?.st_size;
850 current_task.write_object(arg.into(), &size)?;
851 Ok(Some(SUCCESS))
852 }
853 FIONREAD if file.node().is_reg() => {
854 track_stub!(TODO("https://fxbug.dev/322874897"), "FIONREAD");
855 let size =
856 file.node().fetch_and_refresh_info(current_task).map_err(|_| errno!(EINVAL))?.size;
857 let offset = usize::try_from(file.offset.read()).map_err(|_| errno!(EINVAL))?;
858 let remaining =
859 if size < offset { 0 } else { i32::try_from(size - offset).unwrap_or(i32::MAX) };
860 current_task.write_object(arg.into(), &remaining)?;
861 Ok(Some(SUCCESS))
862 }
863 FS_IOC_FSGETXATTR => {
864 track_stub!(TODO("https://fxbug.dev/322875209"), "FS_IOC_FSGETXATTR");
865 let arg = UserAddress::from(arg).into();
866 current_task.write_object(arg, &fsxattr::default())?;
867 Ok(Some(SUCCESS))
868 }
869 FS_IOC_FSSETXATTR => {
870 track_stub!(TODO("https://fxbug.dev/322875271"), "FS_IOC_FSSETXATTR");
871 let arg = UserAddress::from(arg).into();
872 let _: fsxattr = current_task.read_object(arg)?;
873 Ok(Some(SUCCESS))
874 }
875 uapi::FS_IOC_GETFLAGS => {
876 track_stub!(TODO("https://fxbug.dev/322874935"), "FS_IOC_GETFLAGS");
877 let arg = UserRef::<u32>::from(arg);
878 let mut flags: u32 = 0;
879 if matches!(*file.node().fsverity.lock(), FsVerityState::FsVerity) {
880 flags |= FS_VERITY_FL;
881 }
882 if file.node().info().casefold {
883 flags |= FS_CASEFOLD_FL;
884 }
885 current_task.write_object(arg, &flags)?;
886 Ok(Some(SUCCESS))
887 }
888 uapi::FS_IOC_SETFLAGS => {
889 track_stub!(TODO("https://fxbug.dev/322875367"), "FS_IOC_SETFLAGS");
890 file.name.mount.check_readonly_filesystem()?;
894 let arg = UserRef::<u32>::from(arg);
895 let flags: u32 = current_task.read_object(arg)?;
896 let new_casefold = flags & FS_CASEFOLD_FL != 0;
897 file.name.entry.set_casefold(current_task, new_casefold)?;
898
899 Ok(Some(SUCCESS))
900 }
901 FS_IOC_ENABLE_VERITY => {
902 fsverity::ioctl::enable(current_task, UserAddress::from(arg).into(), file).map(Some)
903 }
904 FS_IOC_MEASURE_VERITY => {
905 fsverity::ioctl::measure(current_task, UserAddress::from(arg).into(), file).map(Some)
906 }
907 FS_IOC_READ_VERITY_METADATA => {
908 fsverity::ioctl::read_metadata(current_task, UserAddress::from(arg).into(), file)
909 .map(Some)
910 }
911 FS_IOC_ADD_ENCRYPTION_KEY => {
912 let fscrypt_add_key_ref = UserRef::<fscrypt_add_key_arg>::from(arg);
913 let key_ref_addr = fscrypt_add_key_ref.next()?.addr();
914 let mut fscrypt_add_key_arg = current_task.read_object(fscrypt_add_key_ref.clone())?;
915 if fscrypt_add_key_arg.key_id != 0 {
916 track_stub!(TODO("https://fxbug.dev/375649227"), "non-zero key ids");
917 return error!(ENOTSUP);
918 }
919 if fscrypt_add_key_arg.key_spec.type_ != FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER {
920 track_stub!(TODO("https://fxbug.dev/375648306"), "fscrypt descriptor type");
921 return error!(ENOTSUP);
922 }
923 let key = current_task
924 .read_memory_to_vec(key_ref_addr, fscrypt_add_key_arg.raw_size as usize)?;
925 let user_id = current_task.current_creds().uid;
926
927 let crypt_service = file.node().fs().crypt_service().ok_or_else(|| errno!(ENOTSUP))?;
928 let key_identifier = crypt_service.add_wrapping_key(&key, user_id)?;
929 fscrypt_add_key_arg.key_spec.u.identifier =
930 fscrypt_identifier { value: key_identifier, ..Default::default() };
931 current_task.write_object(fscrypt_add_key_ref, &fscrypt_add_key_arg)?;
932 Ok(Some(SUCCESS))
933 }
934 FS_IOC_SET_ENCRYPTION_POLICY => {
935 let fscrypt_policy_ref = UserRef::<uapi::fscrypt_policy_v2>::from(arg);
936 let policy = current_task.read_object(fscrypt_policy_ref)?;
937 if policy.version as u32 != FSCRYPT_POLICY_V2 {
938 track_stub!(TODO("https://fxbug.dev/375649656"), "fscrypt policy v1");
939 return error!(ENOTSUP);
940 }
941 if policy.contents_encryption_mode as u32 != FSCRYPT_MODE_AES_256_XTS {
942 track_stub!(
943 TODO("https://fxbug.dev/375684057"),
944 "fscrypt encryption modes",
945 policy.contents_encryption_mode
946 );
947 }
948 if policy.filenames_encryption_mode as u32 != FSCRYPT_MODE_AES_256_CTS {
949 track_stub!(
950 TODO("https://fxbug.dev/375684057"),
951 "fscrypt encryption modes",
952 policy.filenames_encryption_mode
953 );
954 }
955 let user_id = current_task.current_creds().uid;
956 if user_id != file.node().info().uid {
957 security::check_task_capable(current_task, CAP_FOWNER)
958 .map_err(|_| errno!(EACCES))?;
959 }
960
961 let crypt_service = file.node().fs().crypt_service().ok_or_else(|| errno!(ENOTSUP))?;
962 if let Some(users) =
963 crypt_service.get_users_for_key(EncryptionKeyId::from(policy.master_key_identifier))
964 {
965 if !users.contains(&user_id) {
966 return error!(ENOKEY);
967 }
968 } else {
969 track_stub!(
970 TODO("https://fxbug.dev/375067633"),
971 "users with CAP_FOWNER can set encryption policies with unadded keys"
972 );
973 return error!(ENOKEY);
974 }
975
976 let flags =
978 FscryptPolicyFlags::from_bits(policy.flags).ok_or_else(|| errno!(EINVAL))?;
979 let supported_flags = FscryptPolicyFlags::PAD_8
980 | FscryptPolicyFlags::PAD_16
981 | FscryptPolicyFlags::IV_INO_LBLK_64
982 | FscryptPolicyFlags::IV_INO_LBLK_32;
983 if !supported_flags.contains(flags) {
984 track_stub!(
985 TODO("https://fxbug.dev/375700939"),
986 "fscrypt policy flags",
987 policy.flags
988 );
989 return error!(EINVAL);
990 }
991 if flags.contains(FscryptPolicyFlags::IV_INO_LBLK_64)
992 && flags.contains(FscryptPolicyFlags::IV_INO_LBLK_32)
993 {
994 return error!(EINVAL);
995 }
996 let new_policy = crate::vfs::FscryptNodePolicy {
997 key_identifier: policy.master_key_identifier,
998 flags,
999 };
1000
1001 let attributes = file.node().fetch_and_refresh_info(current_task)?;
1002 if let Some(existing_policy) = &attributes.encryption_policy {
1003 let is_legacy_lblk32_fallback = existing_policy.flags == FscryptPolicyFlags::PAD_16
1009 && new_policy.flags
1010 == (FscryptPolicyFlags::PAD_16 | FscryptPolicyFlags::IV_INO_LBLK_32);
1011 if existing_policy.key_identifier != new_policy.key_identifier
1012 || (existing_policy.flags != new_policy.flags && !is_legacy_lblk32_fallback)
1013 {
1014 return error!(EEXIST);
1015 }
1016 } else {
1017 std::mem::drop(attributes);
1019 file.node().update_attributes(current_task, |info| {
1020 info.encryption_policy = Some(new_policy);
1021 Ok(())
1022 })?;
1023 }
1024 Ok(Some(SUCCESS))
1025 }
1026 FS_IOC_GET_ENCRYPTION_POLICY => {
1027 let attributes = file.node().fetch_and_refresh_info(current_task)?;
1028 if attributes.encryption_policy.is_some() {
1029 return error!(EINVAL);
1032 }
1033 error!(ENODATA)
1034 }
1035 FS_IOC_GET_ENCRYPTION_POLICY_EX => {
1036 let Some(node_policy) =
1037 file.node().fetch_and_refresh_info(current_task)?.encryption_policy
1038 else {
1039 return error!(ENODATA);
1040 };
1041
1042 let policy_size_ref = UserRef::<u64>::from(arg);
1043 let policy_size = current_task.read_object(policy_size_ref.clone())?;
1044 let v2_size = std::mem::size_of::<uapi::fscrypt_policy_v2>() as u64;
1045 if policy_size < v2_size {
1046 return error!(EOVERFLOW);
1047 }
1048
1049 let policy = uapi::fscrypt_policy_v2 {
1053 version: FSCRYPT_POLICY_V2 as u8,
1054 contents_encryption_mode: FSCRYPT_MODE_AES_256_XTS as u8,
1055 filenames_encryption_mode: FSCRYPT_MODE_AES_256_CTS as u8,
1056 flags: node_policy.flags.bits(),
1057 log2_data_unit_size: 0,
1058 __reserved: [0; 3],
1059 master_key_identifier: node_policy.key_identifier,
1060 };
1061
1062 current_task.write_object(policy_size_ref.clone(), &v2_size)?;
1063 let policy_ref = policy_size_ref.next()?.cast::<uapi::fscrypt_policy_v2>();
1064 current_task.write_object(policy_ref, &policy)?;
1065 Ok(Some(SUCCESS))
1066 }
1067 FS_IOC_REMOVE_ENCRYPTION_KEY => {
1068 let fscrypt_remove_key_arg_ref = UserRef::<uapi::fscrypt_remove_key_arg>::from(arg);
1069 let fscrypt_remove_key_arg = current_task.read_object(fscrypt_remove_key_arg_ref)?;
1070 if fscrypt_remove_key_arg.key_spec.type_ != FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER {
1071 track_stub!(TODO("https://fxbug.dev/375648306"), "fscrypt descriptor type");
1072 return error!(ENOTSUP);
1073 }
1074 let crypt_service = file.node().fs().crypt_service().ok_or_else(|| errno!(ENOTSUP))?;
1075 let user_id = current_task.current_creds().uid;
1076 #[allow(
1077 clippy::undocumented_unsafe_blocks,
1078 reason = "Force documented unsafe blocks in Starnix"
1079 )]
1080 let identifier = unsafe { fscrypt_remove_key_arg.key_spec.u.identifier.value };
1081 crypt_service.forget_wrapping_key(identifier, user_id)?;
1082 Ok(Some(SUCCESS))
1083 }
1084 linux_uapi::FICLONE | linux_uapi::FICLONERANGE | linux_uapi::FIDEDUPERANGE => {
1085 error!(EOPNOTSUPP)
1086 }
1087 _ => Ok(None),
1088 }
1089}
1090
1091pub fn default_fcntl(cmd: u32) -> Result<SyscallResult, Errno> {
1092 track_stub!(TODO("https://fxbug.dev/322875704"), "default fcntl", cmd);
1093 error!(EINVAL)
1094}
1095
1096pub fn default_mmap(
1097 file: &FileObject,
1098 current_task: &CurrentTask,
1099 addr: DesiredAddress,
1100 memory_offset: u64,
1101 length: usize,
1102 prot_flags: ProtectionFlags,
1103 mut options: MappingOptions,
1104) -> Result<UserAddress, Errno> {
1105 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "FileOpsDefaultMmap");
1106 let min_memory_size = (memory_offset as usize)
1107 .checked_add(round_up_to_system_page_size(length)?)
1108 .ok_or_else(|| errno!(EINVAL))?;
1109 let mut memory = if options.contains(MappingOptions::SHARED) {
1110 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "GetSharedVmo");
1111 file.ops.get_memory(file, current_task, Some(min_memory_size), prot_flags)?
1112 } else {
1113 let base_prot_flags = (prot_flags | ProtectionFlags::READ) - ProtectionFlags::WRITE;
1115 let memory =
1116 file.ops.get_memory(file, current_task, Some(min_memory_size), base_prot_flags)?;
1117 if !prot_flags.contains(ProtectionFlags::WRITE) {
1118 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "GetPrivateReadOnlyVmo");
1119 options |= MappingOptions::LAZY_PRIVATE_FILE;
1123 let write_rights = zx::Rights::WRITE | zx::Rights::RESIZE;
1124 if memory.get_rights().intersects(write_rights) {
1125 Arc::new(
1126 memory
1127 .duplicate_handle(memory.get_rights() - write_rights)
1128 .map_err(impossible_error)?,
1129 )
1130 } else {
1131 memory
1132 }
1133 } else {
1134 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "GetPrivateWritableVmo");
1135 Arc::new(memory.create_private_child().map_err(MemoryManager::get_errno_for_map_err)?)
1136 }
1137 };
1138
1139 let file_write_guard = if options.contains(MappingOptions::SHARED) && file.can_write() {
1142 let node = &file.name.entry.node;
1143 let state = node.write_guard_state.lock();
1144
1145 let seals = state.get_seals().unwrap_or(SealFlags::empty());
1150 if seals.contains(SealFlags::FUTURE_WRITE)
1151 && !seals.contains(SealFlags::WRITE)
1152 && !prot_flags.contains(ProtectionFlags::WRITE)
1153 {
1154 let mut new_rights = zx::Rights::VMO_DEFAULT - zx::Rights::WRITE;
1155 if prot_flags.contains(ProtectionFlags::EXEC) {
1156 new_rights |= zx::Rights::EXECUTE;
1157 }
1158 memory = Arc::new(memory.duplicate_handle(new_rights).map_err(impossible_error)?);
1159
1160 None
1161 } else {
1162 Some(FileWriteGuardMode::WriteMapping)
1163 }
1164 } else {
1165 None
1166 };
1167
1168 current_task.mm()?.map_memory(
1169 addr,
1170 memory,
1171 memory_offset,
1172 length,
1173 prot_flags,
1174 options,
1175 MappingName::File(file.to_mapping(file_write_guard)?),
1176 )
1177}
1178
1179pub struct OPathOps {}
1180
1181impl OPathOps {
1182 pub fn new() -> OPathOps {
1183 OPathOps {}
1184 }
1185}
1186
1187impl FileOps for OPathOps {
1188 fileops_impl_noop_sync!();
1189
1190 fn has_persistent_offsets(&self) -> bool {
1191 false
1192 }
1193 fn is_seekable(&self) -> bool {
1194 true
1195 }
1196 fn read(
1197 &self,
1198 _file: &FileObject,
1199 _current_task: &CurrentTask,
1200 _offset: usize,
1201 _data: &mut dyn OutputBuffer,
1202 ) -> Result<usize, Errno> {
1203 error!(EBADF)
1204 }
1205 fn write(
1206 &self,
1207 _file: &FileObject,
1208 _current_task: &CurrentTask,
1209 _offset: usize,
1210 _data: &mut dyn InputBuffer,
1211 ) -> Result<usize, Errno> {
1212 error!(EBADF)
1213 }
1214 fn seek(
1215 &self,
1216 _file: &FileObject,
1217 _current_task: &CurrentTask,
1218 _current_offset: off_t,
1219 _target: SeekTarget,
1220 ) -> Result<off_t, Errno> {
1221 error!(EBADF)
1222 }
1223 fn get_memory(
1224 &self,
1225 _file: &FileObject,
1226 _current_task: &CurrentTask,
1227 _length: Option<usize>,
1228 _prot: ProtectionFlags,
1229 ) -> Result<Arc<MemoryObject>, Errno> {
1230 error!(EBADF)
1231 }
1232 fn readdir(
1233 &self,
1234 _file: &FileObject,
1235 _current_task: &CurrentTask,
1236 _sink: &mut dyn DirentSink,
1237 ) -> Result<(), Errno> {
1238 error!(EBADF)
1239 }
1240
1241 fn ioctl(
1242 &self,
1243 _file: &FileObject,
1244 _current_task: &CurrentTask,
1245 _request: u32,
1246 _arg: SyscallArg,
1247 ) -> Result<SyscallResult, Errno> {
1248 error!(EBADF)
1249 }
1250}
1251
1252pub struct ProxyFileOps(pub FileHandle);
1253
1254impl FileOps for ProxyFileOps {
1255 fn has_persistent_offsets(&self) -> bool {
1260 self.0.ops().has_persistent_offsets()
1261 }
1262 fn writes_update_seek_offset(&self) -> bool {
1263 self.0.ops().writes_update_seek_offset()
1264 }
1265 fn is_seekable(&self) -> bool {
1266 self.0.ops().is_seekable()
1267 }
1268 fn can_map_executable(&self) -> bool {
1269 self.0.ops().can_map_executable()
1270 }
1271 fn flush(&self, _file: &FileObject, current_task: &CurrentTask) {
1272 self.0.ops().flush(&self.0, current_task);
1273 }
1274 fn wait_async(
1275 &self,
1276 _file: &FileObject,
1277 current_task: &CurrentTask,
1278 waiter: &Waiter,
1279 events: FdEvents,
1280 handler: EventHandler,
1281 ) -> Option<WaitCanceler> {
1282 self.0.ops().wait_async(&self.0, current_task, waiter, events, handler)
1283 }
1284 fn query_events(
1285 &self,
1286 _file: &FileObject,
1287 current_task: &CurrentTask,
1288 ) -> Result<FdEvents, Errno> {
1289 self.0.ops().query_events(&self.0, current_task)
1290 }
1291 fn read(
1292 &self,
1293 _file: &FileObject,
1294 current_task: &CurrentTask,
1295 offset: usize,
1296 data: &mut dyn OutputBuffer,
1297 ) -> Result<usize, Errno> {
1298 self.0.ops().read(&self.0, current_task, offset, data)
1299 }
1300 fn write(
1301 &self,
1302 _file: &FileObject,
1303 current_task: &CurrentTask,
1304 offset: usize,
1305 data: &mut dyn InputBuffer,
1306 ) -> Result<usize, Errno> {
1307 self.0.ops().write(&self.0, current_task, offset, data)
1308 }
1309 fn ioctl(
1310 &self,
1311 _file: &FileObject,
1312 current_task: &CurrentTask,
1313 request: u32,
1314 arg: SyscallArg,
1315 ) -> Result<SyscallResult, Errno> {
1316 self.0.ops().ioctl(&self.0, current_task, request, arg)
1317 }
1318 fn fcntl(
1319 &self,
1320 _file: &FileObject,
1321 current_task: &CurrentTask,
1322 cmd: u32,
1323 arg: u64,
1324 ) -> Result<SyscallResult, Errno> {
1325 self.0.ops().fcntl(&self.0, current_task, cmd, arg)
1326 }
1327 fn readdir(
1328 &self,
1329 _file: &FileObject,
1330 current_task: &CurrentTask,
1331 sink: &mut dyn DirentSink,
1332 ) -> Result<(), Errno> {
1333 self.0.ops().readdir(&self.0, current_task, sink)
1334 }
1335 fn sync(&self, _file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
1336 self.0.ops().sync(&self.0, current_task)
1337 }
1338 fn data_sync(&self, _file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
1339 self.0.ops().sync(&self.0, current_task)
1340 }
1341 fn get_memory(
1342 &self,
1343 _file: &FileObject,
1344 current_task: &CurrentTask,
1345 length: Option<usize>,
1346 prot: ProtectionFlags,
1347 ) -> Result<Arc<MemoryObject>, Errno> {
1348 self.0.ops.get_memory(&self.0, current_task, length, prot)
1349 }
1350 fn mmap(
1351 &self,
1352 _file: &FileObject,
1353 current_task: &CurrentTask,
1354 addr: DesiredAddress,
1355 memory_offset: u64,
1356 length: usize,
1357 prot_flags: ProtectionFlags,
1358 options: MappingOptions,
1359 ) -> Result<UserAddress, Errno> {
1360 self.0.ops.mmap(&self.0, current_task, addr, memory_offset, length, prot_flags, options)
1361 }
1362 fn seek(
1363 &self,
1364 _file: &FileObject,
1365 current_task: &CurrentTask,
1366 offset: off_t,
1367 target: SeekTarget,
1368 ) -> Result<off_t, Errno> {
1369 self.0.ops.seek(&self.0, current_task, offset, target)
1370 }
1371}
1372
1373#[derive(Debug, Default, Clone, PartialEq, Eq)]
1374pub enum FileAsyncOwner {
1375 #[default]
1376 Unowned,
1377 Thread(Option<Pid>),
1378 Process(Option<Pid>),
1379 ProcessGroup(Option<Pid>),
1380}
1381
1382impl FileAsyncOwner {
1383 pub fn new(current_task: &CurrentTask, pid: pid_t) -> Result<Self, Errno> {
1384 if pid == 0 {
1385 Ok(Self::Unowned)
1386 } else if pid > 0 {
1387 let entry = current_task.kernel().pids.get(pid)?;
1388 entry.get_task()?;
1389 Ok(Self::Process(Some(entry)))
1390 } else {
1391 let pgid = pid.checked_neg().ok_or_else(|| errno!(EINVAL))?;
1392 let entry = current_task.kernel().pids.get(pgid)?;
1393 if !entry.is_process_group(&fuchsia_rcu::RcuReadScope::new()) {
1394 return error!(ESRCH);
1395 }
1396 Ok(Self::ProcessGroup(Some(entry)))
1397 }
1398 }
1399
1400 pub fn new_ex(
1401 current_task: &CurrentTask,
1402 requested_owner: uapi::f_owner_ex,
1403 ) -> Result<Self, Errno> {
1404 let pids = ¤t_task.kernel().pids;
1405 let get_pid = |lookup_pg: bool| -> Result<Option<Pid>, Errno> {
1406 if requested_owner.pid == 0 {
1407 Ok(None)
1408 } else {
1409 let entry = pids.get(requested_owner.pid)?;
1410 if lookup_pg {
1411 if !entry.is_process_group(&fuchsia_rcu::RcuReadScope::new()) {
1412 return error!(ESRCH);
1413 }
1414 } else {
1415 entry.get_task()?;
1416 }
1417 Ok(Some(entry))
1418 }
1419 };
1420 match requested_owner.type_ as u32 {
1421 F_OWNER_TID => Ok(Self::Thread(get_pid(false)?)),
1422 F_OWNER_PID => Ok(Self::Process(get_pid(false)?)),
1423 F_OWNER_PGRP => Ok(Self::ProcessGroup(get_pid(true)?)),
1424 _ => error!(EINVAL),
1425 }
1426 }
1427
1428 pub fn get_owner(&self) -> pid_t {
1429 match self {
1430 Self::Unowned | Self::Thread(None) | Self::Process(None) | Self::ProcessGroup(None) => {
1431 0
1432 }
1433 Self::Thread(Some(pid)) | Self::Process(Some(pid)) => pid.id,
1434 Self::ProcessGroup(Some(pid)) => -pid.id,
1435 }
1436 }
1437
1438 pub fn get_owner_ex(&self) -> uapi::f_owner_ex {
1439 match self {
1440 Self::Unowned => uapi::f_owner_ex { type_: F_OWNER_TID as i32, pid: 0 },
1441 Self::Thread(pid) => uapi::f_owner_ex {
1442 type_: F_OWNER_TID as i32,
1443 pid: pid.as_ref().map_or(0, |p| p.id),
1444 },
1445 Self::Process(pid) => uapi::f_owner_ex {
1446 type_: F_OWNER_PID as i32,
1447 pid: pid.as_ref().map_or(0, |p| p.id),
1448 },
1449 Self::ProcessGroup(pid) => uapi::f_owner_ex {
1450 type_: F_OWNER_PGRP as i32,
1451 pid: pid.as_ref().map_or(0, |p| p.id),
1452 },
1453 }
1454 }
1455}
1456
1457#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1458pub struct FileObjectId(u64);
1459
1460impl FileObjectId {
1461 pub fn as_epoll_key(&self) -> EpollKey {
1462 self.0 as EpollKey
1463 }
1464}
1465
1466pub struct FileObject {
1473 ops: Box<dyn FileOps>,
1474 state: FileObjectState,
1475}
1476
1477impl std::ops::Deref for FileObject {
1478 type Target = FileObjectState;
1479 fn deref(&self) -> &Self::Target {
1480 &self.state
1481 }
1482}
1483
1484pub struct FileObjectState {
1485 pub weak_handle: WeakFileHandle,
1488
1489 pub id: FileObjectId,
1491
1492 pub name: ActiveNamespaceNode,
1496
1497 pub fs: FileSystemHandle,
1498
1499 pub offset: RcuAtomic<off_t, FileObjectOffset>,
1500
1501 flags: AtomicOpenFlags,
1502
1503 async_owner: LockDepMutex<FileAsyncOwner, FileAsyncOwnerLock>,
1504
1505 epoll_files: LockDepMutex<HashMap<FileHandleKey, WeakFileHandle>, FileEpollFilesLock>,
1508
1509 lease: LockDepMutex<FileLeaseType, FileLeaseLock>,
1511
1512 _mysterious_node: Option<FsNodeHandle>,
1515
1516 pub security_state: security::FileObjectState,
1518}
1519
1520pub enum FileObjectReleaserAction {}
1521impl ReleaserAction<FileObject> for FileObjectReleaserAction {
1522 fn release(file_object: ReleaseGuard<FileObject>) {
1523 register_delayed_release(file_object);
1524 }
1525}
1526pub type FileReleaser = ObjectReleaser<FileObject, FileObjectReleaserAction>;
1527pub type FileHandle = Arc<FileReleaser>;
1528pub type WeakFileHandle = Weak<FileReleaser>;
1529pub type FileHandleKey = WeakKey<FileReleaser>;
1530
1531impl FileObjectState {
1532 pub fn node(&self) -> &FsNodeHandle {
1534 &self.name.entry.node
1535 }
1536
1537 pub fn flags(&self) -> OpenFlags {
1538 self.flags.load(Ordering::Relaxed)
1539 }
1540
1541 pub fn can_read(&self) -> bool {
1542 self.flags.load(Ordering::Relaxed).can_read()
1543 }
1544
1545 pub fn can_write(&self) -> bool {
1546 self.flags.load(Ordering::Relaxed).can_write()
1547 }
1548
1549 pub fn can_exec(&self) -> bool {
1551 let mounted_no_exec = self.name.to_passive().mount.flags().contains(MountFlags::NOEXEC);
1552 let no_exec_seal = self
1553 .node()
1554 .write_guard_state
1555 .lock()
1556 .get_seals()
1557 .map(|seals| seals.contains(SealFlags::NO_EXEC))
1558 .unwrap_or(false);
1559 !(mounted_no_exec || no_exec_seal)
1560 }
1561
1562 pub fn notify(&self, event_mask: InotifyMask) {
1564 self.name.notify(event_mask)
1565 }
1566}
1567
1568impl FileObject {
1569 pub fn new_anonymous(
1577 current_task: &CurrentTask,
1578 ops: Box<dyn FileOps>,
1579 node: FsNodeHandle,
1580 flags: OpenFlags,
1581 ) -> FileHandle {
1582 assert!(!node.fs().has_permanent_entries());
1583 Self::new(
1584 current_task,
1585 ops,
1586 NamespaceNode::new_anonymous_unrooted(current_task, node),
1587 flags,
1588 )
1589 .expect("Failed to create anonymous FileObject")
1590 }
1591
1592 pub fn new(
1597 current_task: &CurrentTask,
1598 ops: Box<dyn FileOps>,
1599 name: NamespaceNode,
1600 flags: OpenFlags,
1601 ) -> Result<FileHandle, Errno> {
1602 let _mysterious_node = if flags.can_write() {
1603 name.entry.node.write_guard_state.lock().acquire(FileWriteGuardMode::WriteFile)?;
1604 Some(name.entry.node.clone())
1605 } else {
1606 None
1607 };
1608 let fs = name.entry.node.fs();
1609 let id = FileObjectId(current_task.kernel.next_file_object_id.next());
1610 let security_state = security::file_alloc_security(current_task);
1611 let file = FileHandle::new_cyclic(|weak_handle| {
1612 Self {
1613 ops,
1614 state: FileObjectState {
1615 weak_handle: weak_handle.clone(),
1616 id,
1617 name: name.into_active(),
1618 fs,
1619 offset: RcuAtomic::new(0),
1620 flags: AtomicOpenFlags::new(flags - OpenFlags::CREAT),
1621 async_owner: Default::default(),
1622 epoll_files: Default::default(),
1623 lease: Default::default(),
1624 _mysterious_node,
1625 security_state,
1626 },
1627 }
1628 .into()
1629 });
1630 file.notify(InotifyMask::OPEN);
1631
1632 file.ops().open(&file, current_task)?;
1633 Ok(file)
1634 }
1635
1636 pub fn max_access_for_memory_mapping(&self) -> Access {
1637 let mut access = Access::EXIST;
1638 if self.can_exec() {
1639 access |= Access::EXEC;
1640 }
1641 let flags = self.flags.load(Ordering::Relaxed);
1642 if flags.can_read() {
1643 access |= Access::READ;
1644 }
1645 if flags.can_write() {
1646 access |= Access::WRITE;
1647 }
1648 access
1649 }
1650
1651 pub fn ops(&self) -> &dyn FileOps {
1652 self.ops.as_ref()
1653 }
1654
1655 pub fn ops_type_name(&self) -> &'static str {
1656 self.ops().type_name()
1657 }
1658
1659 pub fn is_non_blocking(&self) -> bool {
1660 self.flags().contains(OpenFlags::NONBLOCK)
1661 }
1662
1663 pub fn blocking_op<T, Op>(
1679 &self,
1680 current_task: &CurrentTask,
1681 events: FdEvents,
1682 deadline: Option<zx::MonotonicInstant>,
1683 mut op: Op,
1684 ) -> Result<T, Errno>
1685 where
1686 Op: FnMut() -> Result<T, Errno>,
1687 {
1688 let can_return_eagain = self.flags().contains(OpenFlags::NONBLOCK)
1691 && !self.flags().contains(OpenFlags::DIRECTORY);
1692 match op() {
1694 Err(errno) if errno == EAGAIN && !can_return_eagain => {}
1695 result => return result,
1696 }
1697
1698 let waiter = Waiter::new();
1699 loop {
1700 self.wait_async(current_task, &waiter, events, WaitCallback::none());
1702 match op() {
1703 Err(e) if e == EAGAIN => {}
1704 result => return result,
1705 }
1706 waiter
1707 .wait_until(current_task, deadline.unwrap_or(zx::MonotonicInstant::INFINITE))
1708 .map_err(|e| if e == ETIMEDOUT { errno!(EAGAIN) } else { e })?;
1709 }
1710 }
1711
1712 pub fn is_seekable(&self) -> bool {
1713 self.ops().is_seekable()
1714 }
1715
1716 pub fn has_persistent_offsets(&self) -> bool {
1717 self.ops().has_persistent_offsets()
1718 }
1719
1720 fn read_internal<R>(&self, current_task: &CurrentTask, read: R) -> Result<usize, Errno>
1722 where
1723 R: FnOnce() -> Result<usize, Errno>,
1724 {
1725 if !self.can_read() {
1726 return error!(EBADF);
1727 }
1728
1729 security::file_permission(current_task, self, security::PermissionFlags::READ)?;
1730
1731 let bytes_read = read()?;
1732
1733 self.update_atime();
1736 if bytes_read > 0 {
1737 self.notify(InotifyMask::ACCESS);
1738 }
1739
1740 Ok(bytes_read)
1741 }
1742
1743 pub fn read(
1744 &self,
1745 current_task: &CurrentTask,
1746 data: &mut dyn OutputBuffer,
1747 ) -> Result<usize, Errno> {
1748 self.read_internal(current_task, || {
1749 if !self.ops().has_persistent_offsets() {
1750 if data.available() > MAX_LFS_FILESIZE {
1751 return error!(EINVAL);
1752 }
1753 return self.ops.read(self, current_task, 0, data);
1754 }
1755
1756 let mut offset_guard = self.offset.copy();
1757 let offset = *offset_guard as usize;
1758 checked_add_offset_and_length(offset, data.available())?;
1759 let read = self.ops.read(self, current_task, offset, data)?;
1760 *offset_guard += read as off_t;
1761 offset_guard.update();
1762 Ok(read)
1763 })
1764 }
1765
1766 pub fn read_at(
1767 &self,
1768 current_task: &CurrentTask,
1769 offset: usize,
1770 data: &mut dyn OutputBuffer,
1771 ) -> Result<usize, Errno> {
1772 if !self.ops().is_seekable() {
1773 return error!(ESPIPE);
1774 }
1775 checked_add_offset_and_length(offset, data.available())?;
1776 self.read_internal(current_task, || self.ops.read(self, current_task, offset, data))
1777 }
1778
1779 fn write_common(
1781 &self,
1782 current_task: &CurrentTask,
1783 offset: usize,
1784 data: &mut dyn InputBuffer,
1785 ) -> Result<usize, Errno> {
1786 checked_add_offset_and_length(offset, data.available())?;
1793 self.ops().write(self, current_task, offset, data)
1794 }
1795
1796 fn write_fn<W>(&self, current_task: &CurrentTask, write: W) -> Result<usize, Errno>
1798 where
1799 W: FnOnce() -> Result<usize, Errno>,
1800 {
1801 if !self.can_write() {
1802 return error!(EBADF);
1803 }
1804 security::file_permission(current_task, self, security::PermissionFlags::WRITE)?;
1805 self.node().clear_suid_and_sgid_bits(current_task)?;
1806 let bytes_written = write()?;
1807 self.node().update_ctime_mtime();
1808
1809 if bytes_written > 0 {
1810 self.notify(InotifyMask::MODIFY);
1811 }
1812
1813 Ok(bytes_written)
1814 }
1815
1816 pub fn write(
1817 &self,
1818 current_task: &CurrentTask,
1819 data: &mut dyn InputBuffer,
1820 ) -> Result<usize, Errno> {
1821 self.write_fn(current_task, || {
1822 if !self.ops().has_persistent_offsets() {
1823 return self.write_common(current_task, 0, data);
1824 }
1825 let mut offset = self.offset.copy();
1826 let bytes_written = if self.flags().contains(OpenFlags::APPEND) {
1827 let _guard = self.node().ops().append_lock_write(self.node(), current_task)?;
1828 *offset = self.ops().seek(self, current_task, *offset, SeekTarget::End(0))?;
1829 self.write_common(current_task, *offset as usize, data)
1830 } else {
1831 let _guard = self.node().ops().append_lock_read(self.node(), current_task)?;
1832 self.write_common(current_task, *offset as usize, data)
1833 }?;
1834 if self.ops().writes_update_seek_offset() {
1835 *offset += bytes_written as off_t;
1836 }
1837 offset.update();
1838 Ok(bytes_written)
1839 })
1840 }
1841
1842 pub fn write_at(
1843 &self,
1844 current_task: &CurrentTask,
1845 mut offset: usize,
1846 data: &mut dyn InputBuffer,
1847 ) -> Result<usize, Errno> {
1848 if !self.ops().is_seekable() {
1849 return error!(ESPIPE);
1850 }
1851 self.write_fn(current_task, || {
1852 if self.flags().contains(OpenFlags::APPEND) {
1853 let _guard = self.node().append_lock.write(current_task)?;
1854 if self.ops().is_seekable() {
1860 checked_add_offset_and_length(offset, data.available())?;
1861 offset = default_eof_offset(self, current_task)? as usize;
1862 }
1863 self.write_common(current_task, offset, data)
1864 } else {
1865 let _guard = self.node().append_lock.read(current_task)?;
1866 self.write_common(current_task, offset, data)
1867 }
1868 })
1869 }
1870
1871 pub fn seek(&self, current_task: &CurrentTask, target: SeekTarget) -> Result<off_t, Errno> {
1872 if !self.ops().is_seekable() {
1873 return error!(ESPIPE);
1874 }
1875
1876 if !self.ops().has_persistent_offsets() {
1877 return self.ops().seek(self, current_task, 0, target);
1878 }
1879
1880 let mut offset_guard = self.offset.copy();
1881 let new_offset = self.ops().seek(self, current_task, *offset_guard, target)?;
1882 *offset_guard = new_offset;
1883 offset_guard.update();
1884 Ok(new_offset)
1885 }
1886
1887 pub fn sync(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1888 self.ops().sync(self, current_task)
1889 }
1890
1891 pub fn data_sync(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1892 self.ops().data_sync(self, current_task)
1893 }
1894
1895 pub fn get_memory(
1896 &self,
1897 current_task: &CurrentTask,
1898 length: Option<usize>,
1899 prot: ProtectionFlags,
1900 ) -> Result<Arc<MemoryObject>, Errno> {
1901 if prot.contains(ProtectionFlags::READ) && !self.can_read() {
1902 return error!(EACCES);
1903 }
1904 if prot.contains(ProtectionFlags::WRITE) && !self.can_write() {
1905 return error!(EACCES);
1906 }
1907 if prot.contains(ProtectionFlags::EXEC) && !self.can_exec() {
1908 return error!(EPERM);
1909 }
1910 self.ops().get_memory(self, current_task, length, prot)
1911 }
1912
1913 pub fn mmap(
1914 &self,
1915 current_task: &CurrentTask,
1916 addr: DesiredAddress,
1917 memory_offset: u64,
1918 length: usize,
1919 prot_flags: ProtectionFlags,
1920 options: MappingOptions,
1921 ) -> Result<UserAddress, Errno> {
1922 if !self.can_read() {
1923 return error!(EACCES);
1924 }
1925 if prot_flags.contains(ProtectionFlags::WRITE)
1926 && !self.can_write()
1927 && options.contains(MappingOptions::SHARED)
1928 {
1929 return error!(EACCES);
1930 }
1931 if prot_flags.contains(ProtectionFlags::EXEC) && !self.can_exec() {
1932 return error!(EPERM);
1933 }
1934 self.ops().mmap(self, current_task, addr, memory_offset, length, prot_flags, options)
1935 }
1936
1937 pub fn readdir(
1938 &self,
1939 current_task: &CurrentTask,
1940 sink: &mut dyn DirentSink,
1941 ) -> Result<(), Errno> {
1942 if !self.node().is_dir() {
1943 return error!(ENOTDIR);
1944 }
1945 if !self.can_read() {
1946 return error!(EBADF);
1947 }
1948 if self.name.entry.is_dead() {
1949 return error!(ENOENT);
1950 }
1951
1952 security::file_permission(current_task, self, security::PermissionFlags::READ)?;
1953
1954 self.ops().readdir(self, current_task, sink)?;
1955 self.update_atime();
1956 self.notify(InotifyMask::ACCESS);
1957 Ok(())
1958 }
1959
1960 pub fn ioctl(
1961 &self,
1962 current_task: &CurrentTask,
1963 request: u32,
1964 arg: SyscallArg,
1965 ) -> Result<SyscallResult, Errno> {
1966 security::check_file_ioctl_access(current_task, &self, request)?;
1967
1968 if request == FIBMAP {
1969 security::check_task_capable(current_task, CAP_SYS_RAWIO)?;
1970
1971 if current_task.kernel().features.selinux_test_suite {
1974 let phoney_block = 0xbadf000du32;
1975 current_task.write_object(arg.into(), &phoney_block)?;
1976 return Ok(SUCCESS);
1977 }
1978 }
1979
1980 if let Some(result) = default_vfs_ioctl(self, current_task, request, arg)? {
1981 return Ok(result);
1982 }
1983
1984 self.ops().ioctl(self, current_task, request, arg)
1985 }
1986
1987 pub fn fcntl(
1988 &self,
1989 current_task: &CurrentTask,
1990 cmd: u32,
1991 arg: u64,
1992 ) -> Result<SyscallResult, Errno> {
1993 self.ops().fcntl(self, current_task, cmd, arg)
1994 }
1995
1996 pub fn ftruncate(&self, current_task: &CurrentTask, length: u64) -> Result<(), Errno> {
1997 if !self.can_write() {
2000 return error!(EINVAL);
2001 }
2002 self.node().ftruncate(current_task, length)?;
2003 self.name.entry.notify_ignoring_excl_unlink(InotifyMask::MODIFY);
2004 Ok(())
2005 }
2006
2007 pub fn fallocate(
2008 &self,
2009 current_task: &CurrentTask,
2010 mode: FallocMode,
2011 offset: u64,
2012 length: u64,
2013 ) -> Result<(), Errno> {
2014 if self.node().is_fifo() {
2017 return error!(ESPIPE);
2018 }
2019
2020 if !self.node().is_dir() && !self.node().is_reg() {
2023 return error!(ENODEV);
2024 }
2025
2026 if !self.can_write() {
2029 return error!(EBADF);
2030 }
2031
2032 security::file_permission(current_task, self, security::PermissionFlags::WRITE)?;
2033
2034 self.node().fallocate(current_task, mode, offset, length)?;
2035 self.notify(InotifyMask::MODIFY);
2036 Ok(())
2037 }
2038
2039 pub fn to_handle(
2040 &self,
2041 current_task: &CurrentTask,
2042 ) -> Result<Option<zx::NullableHandle>, Errno> {
2043 self.ops().to_handle(self, current_task)
2044 }
2045
2046 pub fn get_handles(
2047 &self,
2048 current_task: &CurrentTask,
2049 ) -> Result<Vec<zx::NullableHandle>, Errno> {
2050 self.ops().get_handles(self, current_task)
2051 }
2052
2053 pub fn as_pid(&self) -> Result<Pid, Errno> {
2054 self.ops().as_pid(self)
2055 }
2056
2057 pub fn to_file_handle(&self) -> FileHandle {
2060 self.weak_handle.upgrade().expect("FileObject is alive, so weak_handle must upgrade")
2061 }
2062
2063 pub fn to_mapping(&self, mode: Option<FileWriteGuardMode>) -> Result<Arc<FileMapping>, Errno> {
2066 FileMapping::new(self.to_file_handle(), mode)
2067 }
2068
2069 pub fn update_file_flags(&self, value: OpenFlags, mask: OpenFlags) {
2075 self.flags.update(value, mask, Ordering::Relaxed, Ordering::Relaxed);
2076 }
2077
2078 pub fn get_async_owner(&self) -> FileAsyncOwner {
2082 self.async_owner.lock().clone()
2083 }
2084
2085 pub fn set_async_owner(&self, owner: FileAsyncOwner) {
2089 *self.async_owner.lock() = owner;
2090 }
2091
2092 pub fn get_lease(&self) -> FileLeaseType {
2094 *self.lease.lock()
2095 }
2096
2097 pub fn set_lease(&self, current_task: &CurrentTask, lease: FileLeaseType) -> Result<(), Errno> {
2099 if !self.node().is_reg() {
2100 return error!(EINVAL);
2101 }
2102 security::check_file_lock_access(current_task, self)?;
2103 if lease == FileLeaseType::Read && self.can_write() {
2104 return error!(EAGAIN);
2105 }
2106 *self.lease.lock() = lease;
2107 Ok(())
2108 }
2109
2110 pub fn wait_async(
2112 &self,
2113 current_task: &CurrentTask,
2114 waiter: &Waiter,
2115 events: FdEvents,
2116 handler: EventHandler,
2117 ) -> Option<WaitCanceler> {
2118 self.ops().wait_async(self, current_task, waiter, events, handler)
2119 }
2120
2121 pub fn query_events(&self, current_task: &CurrentTask) -> Result<FdEvents, Errno> {
2123 self.ops().query_events(self, current_task).map(FdEvents::add_equivalent_fd_events)
2124 }
2125
2126 pub fn record_lock(
2127 &self,
2128 current_task: &CurrentTask,
2129 cmd: RecordLockCommand,
2130 flock: uapi::flock,
2131 ) -> Result<Option<uapi::flock>, Errno> {
2132 security::check_file_lock_access(current_task, self)?;
2133 self.node().record_lock(current_task, self, cmd, flock)
2134 }
2135
2136 pub fn flush(&self, current_task: &CurrentTask, id: FdTableId) {
2137 self.name.entry.node.record_lock_release(RecordLockOwner::FdTable(id));
2138 self.ops().flush(self, current_task)
2139 }
2140
2141 fn update_atime(&self) {
2142 if !self.flags().contains(OpenFlags::NOATIME) {
2143 self.name.update_atime();
2144 }
2145 }
2146
2147 pub fn readahead(
2148 &self,
2149 current_task: &CurrentTask,
2150 offset: usize,
2151 length: usize,
2152 ) -> Result<(), Errno> {
2153 if !self.can_read() {
2155 return error!(EBADF);
2156 }
2157 checked_add_offset_and_length(offset, length)?;
2158 self.ops().readahead(self, current_task, offset, length)
2159 }
2160
2161 pub fn extra_fdinfo(&self, current_task: &CurrentTask) -> Option<FsString> {
2162 let file = self.weak_handle.upgrade()?;
2163 self.ops().extra_fdinfo(&file, current_task)
2164 }
2165
2166 pub fn register_epfd(&self, file: &FileHandle) {
2169 self.epoll_files.lock().insert(WeakKey::from(file), file.weak_handle.clone());
2170 }
2171
2172 pub fn unregister_epfd(&self, file: &FileHandle) {
2173 self.epoll_files.lock().remove(&WeakKey::from(file));
2174 }
2175}
2176
2177impl Releasable for FileObject {
2178 type Context<'a> = &'a CurrentTask;
2179
2180 fn release<'a>(self, context: &'a CurrentTask) {
2181 let current_task = context;
2182 for (_, file) in self.epoll_files.lock().drain() {
2185 if let Some(file) = file.upgrade() {
2186 if let Some(epoll_object) = file.downcast_file::<EpollFileObject>() {
2187 let _ = epoll_object.delete(current_task, &self);
2188 }
2189 }
2190 }
2191
2192 if self.can_write() {
2193 self.name.entry.node.write_guard_state.lock().release(FileWriteGuardMode::WriteFile);
2194 }
2195
2196 let ops = self.ops;
2197 let state = self.state;
2198 ops.close(&state, current_task);
2199 state.name.entry.node.on_file_closed(&state);
2200 let event =
2201 if state.can_write() { InotifyMask::CLOSE_WRITE } else { InotifyMask::CLOSE_NOWRITE };
2202 state.notify(event);
2203 }
2204}
2205
2206impl fmt::Debug for FileObject {
2207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2208 f.debug_struct("FileObject")
2209 .field("name", &self.name)
2210 .field("fs", &self.fs.name())
2211 .field("offset", &self.offset)
2212 .field("flags", &self.flags)
2213 .field("ops_ty", &self.ops().type_name())
2214 .finish()
2215 }
2216}
2217
2218impl OnWakeOps for FileReleaser {
2219 fn on_wake(&self, _current_task: &CurrentTask, _baton_lease: &zx::NullableHandle) {}
2220}
2221
2222pub struct DowncastedFile<'a, Ops> {
2224 file: &'a FileObject,
2225 ops: &'a Ops,
2226}
2227impl<'a, Ops> Copy for DowncastedFile<'a, Ops> {}
2228impl<'a, Ops> Clone for DowncastedFile<'a, Ops> {
2229 fn clone(&self) -> Self {
2230 *self
2231 }
2232}
2233
2234impl<'a, Ops> DowncastedFile<'a, Ops> {
2235 pub fn file(&self) -> &'a FileObject {
2236 self.file
2237 }
2238}
2239
2240impl<'a, Ops> Deref for DowncastedFile<'a, Ops> {
2241 type Target = &'a Ops;
2242 fn deref(&self) -> &Self::Target {
2243 &self.ops
2244 }
2245}
2246
2247impl FileObject {
2248 pub fn downcast_file<'a, T>(&'a self) -> Option<DowncastedFile<'a, T>>
2253 where
2254 T: 'static,
2255 {
2256 let ops = self.ops().as_any().downcast_ref::<T>()?;
2257 Some(DowncastedFile { file: self, ops })
2258 }
2259}
2260
2261pub fn call_fidl_and_await_close<P, M>(method: M, proxy: &P)
2269where
2270 P: fidl::endpoints::SynchronousProxy,
2271 M: FnOnce(&P) -> Result<(), fidl::Error>,
2272{
2273 if let Err(e) = method(proxy) {
2274 log_error!("call_fidl_and_await_close: call {} failed: {e:?}", P::Protocol::DEBUG_NAME);
2275 return;
2276 }
2277 let channel = proxy.as_channel();
2278 let result = channel.wait_one(zx::Signals::CHANNEL_PEER_CLOSED, zx::MonotonicInstant::INFINITE);
2279 if let Err(status) = result.to_result() {
2280 log_error!(
2281 "call_fidl_and_await_close: wait_one {} failed: {status:?}",
2282 P::Protocol::DEBUG_NAME
2283 );
2284 }
2285}
2286
2287#[cfg(test)]
2288mod tests {
2289 use crate::fs::tmpfs::TmpFs;
2290 use crate::task::CurrentTask;
2291 use crate::task::dynamic_thread_spawner::SpawnRequestBuilder;
2292 use crate::testing::*;
2293 use crate::vfs::MountInfo;
2294 use crate::vfs::buffers::{VecInputBuffer, VecOutputBuffer};
2295 use starnix_uapi::auth::FsCred;
2296 use starnix_uapi::device_id::DeviceId;
2297 use starnix_uapi::file_mode::FileMode;
2298 use starnix_uapi::open_flags::OpenFlags;
2299 use std::sync::Arc;
2300 use std::sync::atomic::{AtomicBool, Ordering};
2301 use zerocopy::{FromBytes, IntoBytes, LE, U64};
2302
2303 #[::fuchsia::test]
2304 async fn test_append_truncate_race() {
2305 spawn_kernel_and_run(async |current_task| {
2306 let kernel = current_task.kernel();
2307 let root_fs = TmpFs::new_fs(&kernel);
2308 let mount = MountInfo::detached();
2309 let root_node = Arc::clone(root_fs.root());
2310 let file = root_node
2311 .create_entry(¤t_task, &mount, "test".into(), |dir, mount, name| {
2312 dir.create_node(
2313 ¤t_task,
2314 mount,
2315 name,
2316 FileMode::IFREG | FileMode::ALLOW_ALL,
2317 DeviceId::NONE,
2318 FsCred::root(),
2319 )
2320 })
2321 .expect("create_node failed");
2322 let file_handle = file
2323 .open_anonymous(¤t_task, OpenFlags::APPEND | OpenFlags::RDWR)
2324 .expect("open failed");
2325 let done = Arc::new(AtomicBool::new(false));
2326
2327 let fh = file_handle.clone();
2328 let done_clone = done.clone();
2329 let closure = move |current_task: &CurrentTask| {
2330 for i in 0..2000 {
2331 fh.write(current_task, &mut VecInputBuffer::new(U64::<LE>::new(i).as_bytes()))
2332 .expect("write failed");
2333 }
2334 done_clone.store(true, Ordering::SeqCst);
2335 let result: Result<(), starnix_uapi::errors::Errno> = Ok(());
2336 result
2337 };
2338 let (write_thread, req) =
2339 SpawnRequestBuilder::new().with_sync_closure(closure).build_with_sync_result();
2340 kernel.kthreads.spawner().spawn_from_request(req);
2341
2342 let fh = file_handle.clone();
2343 let done_clone = done.clone();
2344 let closure = move |current_task: &CurrentTask| {
2345 while !done_clone.load(Ordering::SeqCst) {
2346 fh.ftruncate(current_task, 0).expect("truncate failed");
2347 }
2348 let result: Result<(), starnix_uapi::errors::Errno> = Ok(());
2349 result
2350 };
2351 let (truncate_thread, req) =
2352 SpawnRequestBuilder::new().with_sync_closure(closure).build_with_sync_result();
2353 kernel.kthreads.spawner().spawn_from_request(req);
2354
2355 while !done.load(Ordering::SeqCst) {
2358 let mut buffer = VecOutputBuffer::new(4096);
2359 let amount =
2360 file_handle.read_at(¤t_task, 0, &mut buffer).expect("read failed");
2361 let mut last = None;
2362 let buffer = &Vec::from(buffer)[..amount];
2363 for i in
2364 buffer.chunks_exact(8).map(|chunk| U64::<LE>::read_from_bytes(chunk).unwrap())
2365 {
2366 if let Some(last) = last {
2367 assert!(i.get() > last, "buffer: {:?}", buffer);
2368 }
2369 last = Some(i.get());
2370 }
2371 }
2372
2373 let _ = write_thread().unwrap();
2374 let _ = truncate_thread().unwrap();
2375 })
2376 .await;
2377 }
2378}