Skip to main content

starnix_core/vfs/
file_object.rs

1// Cmpyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::mm::memory::MemoryObject;
6use crate::mm::{DesiredAddress, MappingName, MappingOptions, MemoryAccessorExt, ProtectionFlags};
7use crate::power::OnWakeOps;
8use crate::security;
9use crate::task::{
10    CurrentTask, EventHandler, ThreadGroupKey, WaitCallback, WaitCanceler, Waiter,
11    register_delayed_release,
12};
13use crate::vfs::buffers::{InputBuffer, OutputBuffer};
14use crate::vfs::file_server::serve_file;
15use crate::vfs::fsverity::{
16    FsVerityState, {self},
17};
18use crate::vfs::{
19    ActiveNamespaceNode, DirentSink, EpollFileObject, EpollKey, FallocMode, FdTableId,
20    FileSystemHandle, FileWriteGuardMode, FsNodeHandle, FsString, NamespaceNode, RecordLockCommand,
21    RecordLockOwner,
22};
23use starnix_crypt::EncryptionKeyId;
24use starnix_lifecycle::{ObjectReleaser, ReleaserAction};
25use starnix_rcu::RcuAtomic;
26use starnix_types::ownership::ReleaseGuard;
27use starnix_uapi::mount_flags::MountFlags;
28use starnix_uapi::user_address::ArchSpecific;
29
30use fidl::endpoints::ProtocolMarker as _;
31use linux_uapi::{FSCRYPT_MODE_AES_256_CTS, FSCRYPT_MODE_AES_256_XTS};
32use starnix_logging::{CATEGORY_STARNIX_MM, impossible_error, log_error, track_stub};
33use starnix_sync::{
34    FileAsyncOwnerLock, FileEpollFilesLock, FileLeaseLock, FileObjectOffset, LockDepMutex,
35};
36use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
37use starnix_types::math::round_up_to_system_page_size;
38use starnix_types::ownership::Releasable;
39use starnix_uapi::arc_key::WeakKey;
40use starnix_uapi::as_any::AsAny;
41use starnix_uapi::auth::{CAP_FOWNER, CAP_SYS_RAWIO};
42use starnix_uapi::errors::{EAGAIN, ETIMEDOUT, Errno};
43use starnix_uapi::file_lease::FileLeaseType;
44use starnix_uapi::file_mode::Access;
45use starnix_uapi::inotify_mask::InotifyMask;
46use starnix_uapi::open_flags::{AtomicOpenFlags, OpenFlags};
47use starnix_uapi::seal_flags::SealFlags;
48use starnix_uapi::user_address::{UserAddress, UserRef};
49use starnix_uapi::vfs::FdEvents;
50use starnix_uapi::{
51    FIBMAP, FIGETBSZ, FIONBIO, FIONREAD, FIOQSIZE, FS_CASEFOLD_FL, FS_IOC_ADD_ENCRYPTION_KEY,
52    FS_IOC_ENABLE_VERITY, FS_IOC_FSGETXATTR, FS_IOC_FSSETXATTR, FS_IOC_MEASURE_VERITY,
53    FS_IOC_READ_VERITY_METADATA, FS_IOC_REMOVE_ENCRYPTION_KEY, FS_IOC_SET_ENCRYPTION_POLICY,
54    FS_VERITY_FL, FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER, FSCRYPT_POLICY_V2, SEEK_CUR, SEEK_DATA,
55    SEEK_END, SEEK_HOLE, SEEK_SET, errno, error, fscrypt_add_key_arg, fscrypt_identifier, fsxattr,
56    off_t, pid_t, uapi,
57};
58use std::collections::HashMap;
59use std::fmt;
60use std::ops::Deref;
61use std::sync::atomic::Ordering;
62use std::sync::{Arc, Weak};
63
64pub const MAX_LFS_FILESIZE: usize = 0x7fff_ffff_ffff_ffff;
65
66pub fn checked_add_offset_and_length(offset: usize, length: usize) -> Result<usize, Errno> {
67    let end = offset.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
68    if end > MAX_LFS_FILESIZE {
69        return error!(EINVAL);
70    }
71    Ok(end)
72}
73
74#[derive(Debug)]
75pub enum SeekTarget {
76    /// Seek to the given offset relative to the start of the file.
77    Set(off_t),
78    /// Seek to the given offset relative to the current position.
79    Cur(off_t),
80    /// Seek to the given offset relative to the end of the file.
81    End(off_t),
82    /// Seek for the first data after the given offset,
83    Data(off_t),
84    /// Seek for the first hole after the given offset,
85    Hole(off_t),
86}
87
88impl SeekTarget {
89    pub fn from_raw(whence: u32, offset: off_t) -> Result<SeekTarget, Errno> {
90        match whence {
91            SEEK_SET => Ok(SeekTarget::Set(offset)),
92            SEEK_CUR => Ok(SeekTarget::Cur(offset)),
93            SEEK_END => Ok(SeekTarget::End(offset)),
94            SEEK_DATA => Ok(SeekTarget::Data(offset)),
95            SEEK_HOLE => Ok(SeekTarget::Hole(offset)),
96            _ => error!(EINVAL),
97        }
98    }
99
100    pub fn whence(&self) -> u32 {
101        match self {
102            Self::Set(_) => SEEK_SET,
103            Self::Cur(_) => SEEK_CUR,
104            Self::End(_) => SEEK_END,
105            Self::Data(_) => SEEK_DATA,
106            Self::Hole(_) => SEEK_HOLE,
107        }
108    }
109
110    pub fn offset(&self) -> off_t {
111        match self {
112            Self::Set(off)
113            | Self::Cur(off)
114            | Self::End(off)
115            | Self::Data(off)
116            | Self::Hole(off) => *off,
117        }
118    }
119}
120
121/// Corresponds to struct file_operations in Linux, plus any filesystem-specific data.
122pub trait FileOps: Send + Sync + AsAny + 'static {
123    /// Called when the FileObject is opened/created
124    fn open(&self, _file: &FileObject, _current_task: &CurrentTask) -> Result<(), Errno> {
125        Ok(())
126    }
127
128    /// Called when the FileObject is destroyed.
129    fn close(self: Box<Self>, _file: &FileObjectState, _current_task: &CurrentTask) {}
130
131    /// Called every time close() is called on this file, even if the file is not ready to be
132    /// released.
133    fn flush(&self, _file: &FileObject, _current_task: &CurrentTask) {}
134
135    /// Returns whether the file has meaningful seek offsets. Returning `false` is only
136    /// optimization and will makes `FileObject` never hold the offset lock when calling `read` and
137    /// `write`.
138    fn has_persistent_offsets(&self) -> bool {
139        self.is_seekable()
140    }
141
142    /// Returns whether the file is seekable.
143    fn is_seekable(&self) -> bool;
144
145    /// Returns true if `write()` operations on the file will update the seek offset.
146    fn writes_update_seek_offset(&self) -> bool {
147        self.has_persistent_offsets()
148    }
149
150    /// Read from the file at an offset. If the file does not have persistent offsets (either
151    /// directly, or because it is not seekable), offset will be 0 and can be ignored.
152    /// Returns the number of bytes read.
153    fn read(
154        &self,
155        file: &FileObject,
156        current_task: &CurrentTask,
157        offset: usize,
158        data: &mut dyn OutputBuffer,
159    ) -> Result<usize, Errno>;
160
161    /// Write to the file with an offset. If the file does not have persistent offsets (either
162    /// directly, or because it is not seekable), offset will be 0 and can be ignored.
163    /// Returns the number of bytes written.
164    fn write(
165        &self,
166        file: &FileObject,
167        current_task: &CurrentTask,
168        offset: usize,
169        data: &mut dyn InputBuffer,
170    ) -> Result<usize, Errno>;
171
172    /// Adjust the `current_offset` if the file is seekable.
173    fn seek(
174        &self,
175        file: &FileObject,
176        current_task: &CurrentTask,
177        current_offset: off_t,
178        target: SeekTarget,
179    ) -> Result<off_t, Errno>;
180
181    /// Syncs cached state associated with the file descriptor to persistent storage.
182    ///
183    /// The method blocks until the synchronization is complete.
184    fn sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
185        file.node().ops().sync(file.node(), current_task)
186    }
187
188    /// Syncs cached data, and only enough metadata to retrieve said data, to persistent storage.
189    ///
190    /// The method blocks until the synchronization is complete.
191    fn data_sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
192        // TODO(https://fxbug.dev/297305634) make a default macro once data can be done separately
193        self.sync(file, current_task)
194    }
195
196    /// Returns a VMO representing this file. At least the requested protection flags must
197    /// be set on the VMO. Reading or writing the VMO must read or write the file. If this is not
198    /// possible given the requested protection, an error must be returned.
199    /// The `length` is a hint for the desired size of the VMO. The returned VMO may be larger or
200    /// smaller than the requested length.
201    /// This method is typically called by [`Self::mmap`].
202    fn get_memory(
203        &self,
204        _file: &FileObject,
205        _current_task: &CurrentTask,
206        _length: Option<usize>,
207        _prot: ProtectionFlags,
208    ) -> Result<Arc<MemoryObject>, Errno> {
209        error!(ENODEV)
210    }
211
212    /// Responds to an mmap call. The default implementation calls [`Self::get_memory`] to get a VMO
213    /// and then maps it with [`crate::mm::MemoryManager::map`].
214    /// Only implement this trait method if your file needs to control mapping, or record where
215    /// a VMO gets mapped.
216    fn mmap(
217        &self,
218        file: &FileObject,
219        current_task: &CurrentTask,
220        addr: DesiredAddress,
221        memory_offset: u64,
222        length: usize,
223        prot_flags: ProtectionFlags,
224        options: MappingOptions,
225        filename: NamespaceNode,
226    ) -> Result<UserAddress, Errno> {
227        default_mmap(file, current_task, addr, memory_offset, length, prot_flags, options, filename)
228    }
229
230    /// Respond to a `getdents` or `getdents64` calls.
231    ///
232    /// The `file.offset` lock will be held while entering this method. The implementation must look
233    /// at `sink.offset()` to read the current offset into the file.
234    fn readdir(
235        &self,
236        _file: &FileObject,
237        _current_task: &CurrentTask,
238        _sink: &mut dyn DirentSink,
239    ) -> Result<(), Errno> {
240        error!(ENOTDIR)
241    }
242
243    /// Establish a one-shot, edge-triggered, asynchronous wait for the given FdEvents for the
244    /// given file and task. Returns `None` if this file does not support blocking waits.
245    ///
246    /// Active events are not considered. This is similar to the semantics of the
247    /// ZX_WAIT_ASYNC_EDGE flag on zx_wait_async. To avoid missing events, the caller must call
248    /// query_events after calling this.
249    ///
250    /// If your file does not support blocking waits, leave this as the default implementation.
251    fn wait_async(
252        &self,
253        _file: &FileObject,
254        _current_task: &CurrentTask,
255        _waiter: &Waiter,
256        _events: FdEvents,
257        _handler: EventHandler,
258    ) -> Option<WaitCanceler> {
259        None
260    }
261
262    /// The events currently active on this file.
263    ///
264    /// If this function returns `POLLIN` or `POLLOUT`, then FileObject will
265    /// add `POLLRDNORM` and `POLLWRNORM`, respective, which are equivalent in
266    /// the Linux UAPI.
267    ///
268    /// See https://linux.die.net/man/2/poll
269    fn query_events(
270        &self,
271        _file: &FileObject,
272        _current_task: &CurrentTask,
273    ) -> Result<FdEvents, Errno> {
274        Ok(FdEvents::POLLIN | FdEvents::POLLOUT)
275    }
276
277    fn ioctl(
278        &self,
279        _file: &FileObject,
280        _current_task: &CurrentTask,
281        _request: u32,
282        _arg: SyscallArg,
283    ) -> Result<SyscallResult, Errno> {
284        error!(ENOTTY)
285    }
286
287    fn fcntl(
288        &self,
289        _file: &FileObject,
290        _current_task: &CurrentTask,
291        cmd: u32,
292        _arg: u64,
293    ) -> Result<SyscallResult, Errno> {
294        default_fcntl(cmd)
295    }
296
297    /// Return a handle that allows access to this file descritor through the zxio protocols.
298    ///
299    /// If None is returned, the file will act as if it was a fd to `/dev/null`.
300    fn to_handle(
301        &self,
302        file: &FileObject,
303        current_task: &CurrentTask,
304    ) -> Result<Option<zx::NullableHandle>, Errno> {
305        serve_file(current_task, file, current_task.current_creds().clone())
306            .map(|c| Some(c.0.into_channel().into()))
307    }
308
309    // Return a vector of handles. This is used in situations where there is more than one handle
310    // associated with this file descriptor.
311    //
312    // In Fuchsia, there is an expectation that there is a 1:1 mapping between a file descriptor and
313    // a handle. In general, we do not want to violate that rule. This function is intended to used
314    // in very limited circumstances (compatibility with Linux and Binder), where we need to violate
315    // rule.
316    //
317    // Specifically, we are using this to implement SyncFiles correctly, where a single SyncFile can
318    // represent multiple SyncPoints. Each SyncPoint contains a zx::Counter.
319    //
320    // If you chose to implement this function, to_handle() should return an error. You must also be
321    // aware that if these handles are passed to Fuchsia over Binder, they will be represented as
322    // single file descriptor, and you should use the composite_fd library to manage that file
323    // descriptor.
324    fn get_handles(
325        &self,
326        _file: &FileObject,
327        _current_task: &CurrentTask,
328    ) -> Result<Vec<zx::NullableHandle>, Errno> {
329        error!(ENOTSUP)
330    }
331
332    /// Returns the associated pid_t.
333    ///
334    /// Used by pidfd and `/proc/<pid>`. Unlikely to be used by other files.
335    fn as_thread_group_key(&self, _file: &FileObject) -> Result<ThreadGroupKey, Errno> {
336        error!(EBADF)
337    }
338
339    fn readahead(
340        &self,
341        _file: &FileObject,
342        _current_task: &CurrentTask,
343        _offset: usize,
344        _length: usize,
345    ) -> Result<(), Errno> {
346        error!(EINVAL)
347    }
348
349    /// Extra information that is included in the /proc/<pid>/fdfino/<fd> entry.
350    fn extra_fdinfo(&self, _file: &FileHandle, _current_task: &CurrentTask) -> Option<FsString> {
351        None
352    }
353}
354
355/// Marker trait for implementation of FileOps that do not need to implement `close` and can
356/// then pass a wrapper object as the `FileOps` implementation.
357pub trait CloseFreeSafe {}
358impl<T: FileOps + CloseFreeSafe, P: Deref<Target = T> + Send + Sync + 'static> FileOps for P {
359    fn close(self: Box<Self>, _file: &FileObjectState, _current_task: &CurrentTask) {
360        // This method cannot be delegated. T being `CloseFreeSafe` this is fine.
361    }
362
363    fn flush(&self, file: &FileObject, current_task: &CurrentTask) {
364        self.deref().flush(file, current_task)
365    }
366
367    fn has_persistent_offsets(&self) -> bool {
368        self.deref().has_persistent_offsets()
369    }
370
371    fn writes_update_seek_offset(&self) -> bool {
372        self.deref().writes_update_seek_offset()
373    }
374
375    fn is_seekable(&self) -> bool {
376        self.deref().is_seekable()
377    }
378
379    fn read(
380        &self,
381        file: &FileObject,
382        current_task: &CurrentTask,
383        offset: usize,
384        data: &mut dyn OutputBuffer,
385    ) -> Result<usize, Errno> {
386        self.deref().read(file, current_task, offset, data)
387    }
388
389    fn write(
390        &self,
391        file: &FileObject,
392        current_task: &CurrentTask,
393        offset: usize,
394        data: &mut dyn InputBuffer,
395    ) -> Result<usize, Errno> {
396        self.deref().write(file, current_task, offset, data)
397    }
398
399    fn seek(
400        &self,
401        file: &FileObject,
402        current_task: &CurrentTask,
403        current_offset: off_t,
404        target: SeekTarget,
405    ) -> Result<off_t, Errno> {
406        self.deref().seek(file, current_task, current_offset, target)
407    }
408
409    fn sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
410        self.deref().sync(file, current_task)
411    }
412
413    fn data_sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
414        self.deref().data_sync(file, current_task)
415    }
416
417    fn get_memory(
418        &self,
419        file: &FileObject,
420        current_task: &CurrentTask,
421        length: Option<usize>,
422        prot: ProtectionFlags,
423    ) -> Result<Arc<MemoryObject>, Errno> {
424        self.deref().get_memory(file, current_task, length, prot)
425    }
426
427    fn mmap(
428        &self,
429        file: &FileObject,
430        current_task: &CurrentTask,
431        addr: DesiredAddress,
432        memory_offset: u64,
433        length: usize,
434        prot_flags: ProtectionFlags,
435        options: MappingOptions,
436        filename: NamespaceNode,
437    ) -> Result<UserAddress, Errno> {
438        self.deref().mmap(
439            file,
440            current_task,
441            addr,
442            memory_offset,
443            length,
444            prot_flags,
445            options,
446            filename,
447        )
448    }
449
450    fn readdir(
451        &self,
452        file: &FileObject,
453        current_task: &CurrentTask,
454        sink: &mut dyn DirentSink,
455    ) -> Result<(), Errno> {
456        self.deref().readdir(file, current_task, sink)
457    }
458
459    fn wait_async(
460        &self,
461        file: &FileObject,
462        current_task: &CurrentTask,
463        waiter: &Waiter,
464        events: FdEvents,
465        handler: EventHandler,
466    ) -> Option<WaitCanceler> {
467        self.deref().wait_async(file, current_task, waiter, events, handler)
468    }
469
470    fn query_events(
471        &self,
472        file: &FileObject,
473        current_task: &CurrentTask,
474    ) -> Result<FdEvents, Errno> {
475        self.deref().query_events(file, current_task)
476    }
477
478    fn ioctl(
479        &self,
480        file: &FileObject,
481        current_task: &CurrentTask,
482        request: u32,
483        arg: SyscallArg,
484    ) -> Result<SyscallResult, Errno> {
485        self.deref().ioctl(file, current_task, request, arg)
486    }
487
488    fn fcntl(
489        &self,
490        file: &FileObject,
491        current_task: &CurrentTask,
492        cmd: u32,
493        arg: u64,
494    ) -> Result<SyscallResult, Errno> {
495        self.deref().fcntl(file, current_task, cmd, arg)
496    }
497
498    fn to_handle(
499        &self,
500        file: &FileObject,
501        current_task: &CurrentTask,
502    ) -> Result<Option<zx::NullableHandle>, Errno> {
503        self.deref().to_handle(file, current_task)
504    }
505
506    fn get_handles(
507        &self,
508        file: &FileObject,
509        current_task: &CurrentTask,
510    ) -> Result<Vec<zx::NullableHandle>, Errno> {
511        self.deref().get_handles(file, current_task)
512    }
513
514    fn as_thread_group_key(&self, file: &FileObject) -> Result<ThreadGroupKey, Errno> {
515        self.deref().as_thread_group_key(file)
516    }
517
518    fn readahead(
519        &self,
520        file: &FileObject,
521        current_task: &CurrentTask,
522        offset: usize,
523        length: usize,
524    ) -> Result<(), Errno> {
525        self.deref().readahead(file, current_task, offset, length)
526    }
527
528    fn extra_fdinfo(&self, file: &FileHandle, current_task: &CurrentTask) -> Option<FsString> {
529        self.deref().extra_fdinfo(file, current_task)
530    }
531}
532
533pub fn default_eof_offset(file: &FileObject, current_task: &CurrentTask) -> Result<off_t, Errno> {
534    Ok(file.node().get_size(current_task)? as off_t)
535}
536
537/// Implement the seek method for a file. The computation from the end of the file must be provided
538/// through a callback.
539///
540/// Errors if the calculated offset is invalid.
541///
542/// - `current_offset`: The current position
543/// - `target`: The location to seek to.
544/// - `compute_end`: Compute the new offset from the end. Return an error if the operation is not
545///    supported.
546pub fn default_seek<F>(
547    current_offset: off_t,
548    target: SeekTarget,
549    compute_end: F,
550) -> Result<off_t, Errno>
551where
552    F: FnOnce() -> Result<off_t, Errno>,
553{
554    let new_offset = match target {
555        SeekTarget::Set(offset) => Some(offset),
556        SeekTarget::Cur(offset) => current_offset.checked_add(offset),
557        SeekTarget::End(offset) => compute_end()?.checked_add(offset),
558        SeekTarget::Data(offset) => {
559            let eof = compute_end().unwrap_or(off_t::MAX);
560            if offset >= eof {
561                return error!(ENXIO);
562            }
563            Some(offset)
564        }
565        SeekTarget::Hole(offset) => {
566            let eof = compute_end()?;
567            if offset >= eof {
568                return error!(ENXIO);
569            }
570            Some(eof)
571        }
572    }
573    .ok_or_else(|| errno!(EINVAL))?;
574
575    if new_offset < 0 {
576        return error!(EINVAL);
577    }
578
579    Ok(new_offset)
580}
581
582/// Implement the seek method for a file without an upper bound on the resulting offset.
583///
584/// This is useful for files without a defined size.
585///
586/// Errors if the calculated offset is invalid.
587///
588/// - `current_offset`: The current position
589/// - `target`: The location to seek to.
590pub fn unbounded_seek(current_offset: off_t, target: SeekTarget) -> Result<off_t, Errno> {
591    default_seek(current_offset, target, || Ok(MAX_LFS_FILESIZE as off_t))
592}
593
594#[macro_export]
595macro_rules! fileops_impl_delegate_read_write_and_seek {
596    ($self:ident, $delegate:expr) => {
597        fn is_seekable(&self) -> bool {
598            true
599        }
600
601        fn read(
602            &$self,
603            file: &FileObject,
604            current_task: &$crate::task::CurrentTask,
605            offset: usize,
606            data: &mut dyn $crate::vfs::buffers::OutputBuffer,
607        ) -> Result<usize, starnix_uapi::errors::Errno> {
608            $delegate.read(file, current_task, offset, data)
609        }
610
611        fn write(
612            &$self,
613            file: &FileObject,
614            current_task: &$crate::task::CurrentTask,
615            offset: usize,
616            data: &mut dyn $crate::vfs::buffers::InputBuffer,
617        ) -> Result<usize, starnix_uapi::errors::Errno> {
618            $delegate.write(file, current_task, offset, data)
619        }
620
621        fn seek(
622            &$self,
623            file: &FileObject,
624            current_task: &$crate::task::CurrentTask,
625            current_offset: starnix_uapi::off_t,
626            target: $crate::vfs::SeekTarget,
627        ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
628            $delegate.seek(file, current_task, current_offset, target)
629        }
630    };
631}
632
633/// Implements [`FileOps::seek`] in a way that makes sense for seekable files.
634#[macro_export]
635macro_rules! fileops_impl_seekable {
636    () => {
637        fn is_seekable(&self) -> bool {
638            true
639        }
640
641        fn seek(
642            &self,
643            file: &$crate::vfs::FileObject,
644            current_task: &$crate::task::CurrentTask,
645            current_offset: starnix_uapi::off_t,
646            target: $crate::vfs::SeekTarget,
647        ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
648            $crate::vfs::default_seek(current_offset, target, || {
649                $crate::vfs::default_eof_offset(file, current_task)
650            })
651        }
652    };
653}
654
655/// Implements [`FileOps`] methods in a way that makes sense for non-seekable files.
656#[macro_export]
657macro_rules! fileops_impl_nonseekable {
658    () => {
659        fn is_seekable(&self) -> bool {
660            false
661        }
662
663        fn seek(
664            &self,
665            _file: &$crate::vfs::FileObject,
666            _current_task: &$crate::task::CurrentTask,
667            _current_offset: starnix_uapi::off_t,
668            _target: $crate::vfs::SeekTarget,
669        ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
670            starnix_uapi::error!(ESPIPE)
671        }
672    };
673}
674
675/// Implements [`FileOps::seek`] methods in a way that makes sense for files that ignore
676/// seeking operations and always read/write at offset 0.
677#[macro_export]
678macro_rules! fileops_impl_seekless {
679    () => {
680        fn has_persistent_offsets(&self) -> bool {
681            false
682        }
683
684        fn is_seekable(&self) -> bool {
685            true
686        }
687
688        fn seek(
689            &self,
690            _file: &$crate::vfs::FileObject,
691            _current_task: &$crate::task::CurrentTask,
692            _current_offset: starnix_uapi::off_t,
693            _target: $crate::vfs::SeekTarget,
694        ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
695            Ok(0)
696        }
697    };
698}
699
700#[macro_export]
701macro_rules! fileops_impl_dataless {
702    () => {
703        fn write(
704            &self,
705            _file: &$crate::vfs::FileObject,
706            _current_task: &$crate::task::CurrentTask,
707            _offset: usize,
708            _data: &mut dyn $crate::vfs::buffers::InputBuffer,
709        ) -> Result<usize, starnix_uapi::errors::Errno> {
710            starnix_uapi::error!(EINVAL)
711        }
712
713        fn read(
714            &self,
715            _file: &$crate::vfs::FileObject,
716            _current_task: &$crate::task::CurrentTask,
717            _offset: usize,
718            _data: &mut dyn $crate::vfs::buffers::OutputBuffer,
719        ) -> Result<usize, starnix_uapi::errors::Errno> {
720            starnix_uapi::error!(EINVAL)
721        }
722    };
723}
724
725/// Implements [`FileOps`] methods in a way that makes sense for directories. You must implement
726/// [`FileOps::seek`] and [`FileOps::readdir`].
727#[macro_export]
728macro_rules! fileops_impl_directory {
729    () => {
730        fn is_seekable(&self) -> bool {
731            true
732        }
733
734        fn read(
735            &self,
736            _file: &$crate::vfs::FileObject,
737            _current_task: &$crate::task::CurrentTask,
738            _offset: usize,
739            _data: &mut dyn $crate::vfs::buffers::OutputBuffer,
740        ) -> Result<usize, starnix_uapi::errors::Errno> {
741            starnix_uapi::error!(EISDIR)
742        }
743
744        fn write(
745            &self,
746            _file: &$crate::vfs::FileObject,
747            _current_task: &$crate::task::CurrentTask,
748            _offset: usize,
749            _data: &mut dyn $crate::vfs::buffers::InputBuffer,
750        ) -> Result<usize, starnix_uapi::errors::Errno> {
751            starnix_uapi::error!(EISDIR)
752        }
753    };
754}
755
756#[macro_export]
757macro_rules! fileops_impl_unbounded_seek {
758    () => {
759        fn seek(
760            &self,
761            _file: &$crate::vfs::FileObject,
762            _current_task: &$crate::task::CurrentTask,
763            current_offset: starnix_uapi::off_t,
764            target: $crate::vfs::SeekTarget,
765        ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
766            $crate::vfs::unbounded_seek(current_offset, target)
767        }
768    };
769}
770
771#[macro_export]
772macro_rules! fileops_impl_noop_sync {
773    () => {
774        fn sync(
775            &self,
776            file: &$crate::vfs::FileObject,
777            _current_task: &$crate::task::CurrentTask,
778        ) -> Result<(), starnix_uapi::errors::Errno> {
779            if !file.node().is_reg() && !file.node().is_dir() {
780                return starnix_uapi::error!(EINVAL);
781            }
782            Ok(())
783        }
784    };
785}
786
787// Public re-export of macros allows them to be used like regular rust items.
788
789pub use fileops_impl_dataless;
790pub use fileops_impl_delegate_read_write_and_seek;
791pub use fileops_impl_directory;
792pub use fileops_impl_nonseekable;
793pub use fileops_impl_noop_sync;
794pub use fileops_impl_seekable;
795pub use fileops_impl_seekless;
796pub use fileops_impl_unbounded_seek;
797pub const AES256_KEY_SIZE: usize = 32;
798
799pub fn canonicalize_ioctl_request(current_task: &CurrentTask, request: u32) -> u32 {
800    if current_task.is_arch32() {
801        match request {
802            uapi::arch32::FS_IOC_GETFLAGS => uapi::FS_IOC_GETFLAGS,
803            uapi::arch32::FS_IOC_SETFLAGS => uapi::FS_IOC_SETFLAGS,
804            _ => request,
805        }
806    } else {
807        request
808    }
809}
810
811/// Universal VFS ioctl dispatcher for [`FileObject`].
812///
813/// Handles generic file system ioctls (such as non-blocking mode toggles, block size queries,
814/// and file cloning) at the VFS layer without delegating to underlying device drivers.
815///
816/// Returns `Some(result)` if the ioctl command is handled by the VFS layer, or `None` if the
817/// command is unhandled and should be dispatched to [`FileOps::ioctl`].
818pub fn default_vfs_ioctl(
819    file: &FileObject,
820    current_task: &CurrentTask,
821    request: u32,
822    arg: SyscallArg,
823) -> Result<Option<SyscallResult>, Errno> {
824    match canonicalize_ioctl_request(current_task, request) {
825        FIGETBSZ if file.node().is_reg() || file.node().is_dir() => {
826            let blocksize = file.node().stat(current_task)?.st_blksize;
827            current_task.write_object(arg.into(), &blocksize)?;
828            Ok(Some(SUCCESS))
829        }
830        FIONBIO => {
831            let arg_ref = UserAddress::from(arg).into();
832            let arg: i32 = current_task.read_object(arg_ref)?;
833            let val = if arg == 0 {
834                // Clear the NONBLOCK flag
835                OpenFlags::empty()
836            } else {
837                // Set the NONBLOCK flag
838                OpenFlags::NONBLOCK
839            };
840            file.update_file_flags(val, OpenFlags::NONBLOCK);
841            Ok(Some(SUCCESS))
842        }
843        FIOQSIZE if file.node().is_reg() || file.node().is_dir() => {
844            let size = file.node().stat(current_task)?.st_size;
845            current_task.write_object(arg.into(), &size)?;
846            Ok(Some(SUCCESS))
847        }
848        FIONREAD if file.node().is_reg() => {
849            track_stub!(TODO("https://fxbug.dev/322874897"), "FIONREAD");
850            let size =
851                file.node().fetch_and_refresh_info(current_task).map_err(|_| errno!(EINVAL))?.size;
852            let offset = usize::try_from(file.offset.read()).map_err(|_| errno!(EINVAL))?;
853            let remaining =
854                if size < offset { 0 } else { i32::try_from(size - offset).unwrap_or(i32::MAX) };
855            current_task.write_object(arg.into(), &remaining)?;
856            Ok(Some(SUCCESS))
857        }
858        FS_IOC_FSGETXATTR => {
859            track_stub!(TODO("https://fxbug.dev/322875209"), "FS_IOC_FSGETXATTR");
860            let arg = UserAddress::from(arg).into();
861            current_task.write_object(arg, &fsxattr::default())?;
862            Ok(Some(SUCCESS))
863        }
864        FS_IOC_FSSETXATTR => {
865            track_stub!(TODO("https://fxbug.dev/322875271"), "FS_IOC_FSSETXATTR");
866            let arg = UserAddress::from(arg).into();
867            let _: fsxattr = current_task.read_object(arg)?;
868            Ok(Some(SUCCESS))
869        }
870        uapi::FS_IOC_GETFLAGS => {
871            track_stub!(TODO("https://fxbug.dev/322874935"), "FS_IOC_GETFLAGS");
872            let arg = UserRef::<u32>::from(arg);
873            let mut flags: u32 = 0;
874            if matches!(*file.node().fsverity.lock(), FsVerityState::FsVerity) {
875                flags |= FS_VERITY_FL;
876            }
877            if file.node().info().casefold {
878                flags |= FS_CASEFOLD_FL;
879            }
880            current_task.write_object(arg, &flags)?;
881            Ok(Some(SUCCESS))
882        }
883        uapi::FS_IOC_SETFLAGS => {
884            track_stub!(TODO("https://fxbug.dev/322875367"), "FS_IOC_SETFLAGS");
885            let arg = UserRef::<u32>::from(arg);
886            let flags: u32 = current_task.read_object(arg)?;
887            file.node().update_attributes(current_task, |info| {
888                info.casefold = flags & FS_CASEFOLD_FL != 0;
889                Ok(())
890            })?;
891            Ok(Some(SUCCESS))
892        }
893        FS_IOC_ENABLE_VERITY => {
894            fsverity::ioctl::enable(current_task, UserAddress::from(arg).into(), file).map(Some)
895        }
896        FS_IOC_MEASURE_VERITY => {
897            fsverity::ioctl::measure(current_task, UserAddress::from(arg).into(), file).map(Some)
898        }
899        FS_IOC_READ_VERITY_METADATA => {
900            fsverity::ioctl::read_metadata(current_task, UserAddress::from(arg).into(), file)
901                .map(Some)
902        }
903        FS_IOC_ADD_ENCRYPTION_KEY => {
904            let fscrypt_add_key_ref = UserRef::<fscrypt_add_key_arg>::from(arg);
905            let key_ref_addr = fscrypt_add_key_ref.next()?.addr();
906            let mut fscrypt_add_key_arg = current_task.read_object(fscrypt_add_key_ref.clone())?;
907            if fscrypt_add_key_arg.key_id != 0 {
908                track_stub!(TODO("https://fxbug.dev/375649227"), "non-zero key ids");
909                return error!(ENOTSUP);
910            }
911            if fscrypt_add_key_arg.key_spec.type_ != FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER {
912                track_stub!(TODO("https://fxbug.dev/375648306"), "fscrypt descriptor type");
913                return error!(ENOTSUP);
914            }
915            let key = current_task
916                .read_memory_to_vec(key_ref_addr, fscrypt_add_key_arg.raw_size as usize)?;
917            let user_id = current_task.current_creds().uid;
918
919            let crypt_service = file.node().fs().crypt_service().ok_or_else(|| errno!(ENOTSUP))?;
920            let key_identifier = crypt_service.add_wrapping_key(&key, user_id)?;
921            fscrypt_add_key_arg.key_spec.u.identifier =
922                fscrypt_identifier { value: key_identifier, ..Default::default() };
923            current_task.write_object(fscrypt_add_key_ref, &fscrypt_add_key_arg)?;
924            Ok(Some(SUCCESS))
925        }
926        FS_IOC_SET_ENCRYPTION_POLICY => {
927            let fscrypt_policy_ref = UserRef::<uapi::fscrypt_policy_v2>::from(arg);
928            let policy = current_task.read_object(fscrypt_policy_ref)?;
929            if policy.version as u32 != FSCRYPT_POLICY_V2 {
930                track_stub!(TODO("https://fxbug.dev/375649656"), "fscrypt policy v1");
931                return error!(ENOTSUP);
932            }
933            if policy.flags != 0 {
934                track_stub!(
935                    TODO("https://fxbug.dev/375700939"),
936                    "fscrypt policy flags",
937                    policy.flags
938                );
939            }
940            if policy.contents_encryption_mode as u32 != FSCRYPT_MODE_AES_256_XTS {
941                track_stub!(
942                    TODO("https://fxbug.dev/375684057"),
943                    "fscrypt encryption modes",
944                    policy.contents_encryption_mode
945                );
946            }
947            if policy.filenames_encryption_mode as u32 != FSCRYPT_MODE_AES_256_CTS {
948                track_stub!(
949                    TODO("https://fxbug.dev/375684057"),
950                    "fscrypt encryption modes",
951                    policy.filenames_encryption_mode
952                );
953            }
954            let user_id = current_task.current_creds().uid;
955            if user_id != file.node().info().uid {
956                security::check_task_capable(current_task, CAP_FOWNER)
957                    .map_err(|_| errno!(EACCES))?;
958            }
959
960            let crypt_service = file.node().fs().crypt_service().ok_or_else(|| errno!(ENOTSUP))?;
961            if let Some(users) =
962                crypt_service.get_users_for_key(EncryptionKeyId::from(policy.master_key_identifier))
963            {
964                if !users.contains(&user_id) {
965                    return error!(ENOKEY);
966                }
967            } else {
968                track_stub!(
969                    TODO("https://fxbug.dev/375067633"),
970                    "users with CAP_FOWNER can set encryption policies with unadded keys"
971                );
972                return error!(ENOKEY);
973            }
974
975            let attributes = file.node().fetch_and_refresh_info(current_task)?;
976            if let Some(wrapping_key_id) = &attributes.wrapping_key_id {
977                if wrapping_key_id != &policy.master_key_identifier {
978                    return error!(EEXIST);
979                }
980            } else {
981                // Don't deadlock! update_attributes will also lock the attributes.
982                std::mem::drop(attributes);
983                file.node().update_attributes(current_task, |info| {
984                    info.wrapping_key_id = Some(policy.master_key_identifier);
985                    Ok(())
986                })?;
987            }
988            Ok(Some(SUCCESS))
989        }
990        FS_IOC_REMOVE_ENCRYPTION_KEY => {
991            let fscrypt_remove_key_arg_ref = UserRef::<uapi::fscrypt_remove_key_arg>::from(arg);
992            let fscrypt_remove_key_arg = current_task.read_object(fscrypt_remove_key_arg_ref)?;
993            if fscrypt_remove_key_arg.key_spec.type_ != FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER {
994                track_stub!(TODO("https://fxbug.dev/375648306"), "fscrypt descriptor type");
995                return error!(ENOTSUP);
996            }
997            let crypt_service = file.node().fs().crypt_service().ok_or_else(|| errno!(ENOTSUP))?;
998            let user_id = current_task.current_creds().uid;
999            #[allow(
1000                clippy::undocumented_unsafe_blocks,
1001                reason = "Force documented unsafe blocks in Starnix"
1002            )]
1003            let identifier = unsafe { fscrypt_remove_key_arg.key_spec.u.identifier.value };
1004            crypt_service.forget_wrapping_key(identifier, user_id)?;
1005            Ok(Some(SUCCESS))
1006        }
1007        linux_uapi::FICLONE | linux_uapi::FICLONERANGE | linux_uapi::FIDEDUPERANGE => {
1008            error!(EOPNOTSUPP)
1009        }
1010        _ => Ok(None),
1011    }
1012}
1013
1014pub fn default_fcntl(cmd: u32) -> Result<SyscallResult, Errno> {
1015    track_stub!(TODO("https://fxbug.dev/322875704"), "default fcntl", cmd);
1016    error!(EINVAL)
1017}
1018
1019pub fn default_mmap(
1020    file: &FileObject,
1021    current_task: &CurrentTask,
1022    addr: DesiredAddress,
1023    memory_offset: u64,
1024    length: usize,
1025    prot_flags: ProtectionFlags,
1026    options: MappingOptions,
1027    filename: NamespaceNode,
1028) -> Result<UserAddress, Errno> {
1029    fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "FileOpsDefaultMmap");
1030    let min_memory_size = (memory_offset as usize)
1031        .checked_add(round_up_to_system_page_size(length)?)
1032        .ok_or_else(|| errno!(EINVAL))?;
1033    let mut memory = if options.contains(MappingOptions::SHARED) {
1034        fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "GetSharedVmo");
1035        file.ops.get_memory(file, current_task, Some(min_memory_size), prot_flags)?
1036    } else {
1037        fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "GetPrivateVmo");
1038        // TODO(tbodt): Use PRIVATE_CLONE to have the filesystem server do the clone for us.
1039        let base_prot_flags = (prot_flags | ProtectionFlags::READ) - ProtectionFlags::WRITE;
1040        let memory =
1041            file.ops.get_memory(file, current_task, Some(min_memory_size), base_prot_flags)?;
1042        let mut clone_flags = zx::VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE;
1043        if !prot_flags.contains(ProtectionFlags::WRITE) {
1044            clone_flags |= zx::VmoChildOptions::NO_WRITE;
1045        }
1046        fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "CreatePrivateChildVmo");
1047        Arc::new(memory.create_child(clone_flags, 0, memory.get_size()).map_err(impossible_error)?)
1048    };
1049
1050    // Write guard is necessary only for shared mappings. Note that this doesn't depend on
1051    // `prot_flags` since these can be changed later with `mprotect()`.
1052    let file_write_guard = if options.contains(MappingOptions::SHARED) && file.can_write() {
1053        let node = &file.name.entry.node;
1054        let state = node.write_guard_state.lock();
1055
1056        // `F_SEAL_FUTURE_WRITE` should allow `mmap(PROT_READ)`, but block
1057        // `mprotect(PROT_WRITE)`. This is different from `F_SEAL_WRITE`, which blocks
1058        // `mmap(PROT_READ)`. To handle this case correctly remove `WRITE` right from the
1059        // VMO handle to ensure `mprotect(PROT_WRITE)` fails.
1060        let seals = state.get_seals().unwrap_or(SealFlags::empty());
1061        if seals.contains(SealFlags::FUTURE_WRITE)
1062            && !seals.contains(SealFlags::WRITE)
1063            && !prot_flags.contains(ProtectionFlags::WRITE)
1064        {
1065            let mut new_rights = zx::Rights::VMO_DEFAULT - zx::Rights::WRITE;
1066            if prot_flags.contains(ProtectionFlags::EXEC) {
1067                new_rights |= zx::Rights::EXECUTE;
1068            }
1069            memory = Arc::new(memory.duplicate_handle(new_rights).map_err(impossible_error)?);
1070
1071            None
1072        } else {
1073            Some(FileWriteGuardMode::WriteMapping)
1074        }
1075    } else {
1076        None
1077    };
1078
1079    current_task.mm()?.map_memory(
1080        addr,
1081        memory,
1082        memory_offset,
1083        length,
1084        prot_flags,
1085        file.max_access_for_memory_mapping(),
1086        options,
1087        MappingName::File(filename.into_mapping(file_write_guard)?),
1088    )
1089}
1090
1091pub struct OPathOps {}
1092
1093impl OPathOps {
1094    pub fn new() -> OPathOps {
1095        OPathOps {}
1096    }
1097}
1098
1099impl FileOps for OPathOps {
1100    fileops_impl_noop_sync!();
1101
1102    fn has_persistent_offsets(&self) -> bool {
1103        false
1104    }
1105    fn is_seekable(&self) -> bool {
1106        true
1107    }
1108    fn read(
1109        &self,
1110        _file: &FileObject,
1111        _current_task: &CurrentTask,
1112        _offset: usize,
1113        _data: &mut dyn OutputBuffer,
1114    ) -> Result<usize, Errno> {
1115        error!(EBADF)
1116    }
1117    fn write(
1118        &self,
1119        _file: &FileObject,
1120        _current_task: &CurrentTask,
1121        _offset: usize,
1122        _data: &mut dyn InputBuffer,
1123    ) -> Result<usize, Errno> {
1124        error!(EBADF)
1125    }
1126    fn seek(
1127        &self,
1128        _file: &FileObject,
1129        _current_task: &CurrentTask,
1130        _current_offset: off_t,
1131        _target: SeekTarget,
1132    ) -> Result<off_t, Errno> {
1133        error!(EBADF)
1134    }
1135    fn get_memory(
1136        &self,
1137        _file: &FileObject,
1138        _current_task: &CurrentTask,
1139        _length: Option<usize>,
1140        _prot: ProtectionFlags,
1141    ) -> Result<Arc<MemoryObject>, Errno> {
1142        error!(EBADF)
1143    }
1144    fn readdir(
1145        &self,
1146        _file: &FileObject,
1147        _current_task: &CurrentTask,
1148        _sink: &mut dyn DirentSink,
1149    ) -> Result<(), Errno> {
1150        error!(EBADF)
1151    }
1152
1153    fn ioctl(
1154        &self,
1155        _file: &FileObject,
1156        _current_task: &CurrentTask,
1157        _request: u32,
1158        _arg: SyscallArg,
1159    ) -> Result<SyscallResult, Errno> {
1160        error!(EBADF)
1161    }
1162}
1163
1164pub struct ProxyFileOps(pub FileHandle);
1165
1166impl FileOps for ProxyFileOps {
1167    // `close` is not delegated because the last reference to a `ProxyFileOps` is not
1168    // necessarily the last reference of the proxied file. If this is the case, the
1169    // releaser will handle it.
1170    // These don't take &FileObject making it too hard to handle them properly in the macro
1171    fn has_persistent_offsets(&self) -> bool {
1172        self.0.ops().has_persistent_offsets()
1173    }
1174    fn writes_update_seek_offset(&self) -> bool {
1175        self.0.ops().writes_update_seek_offset()
1176    }
1177    fn is_seekable(&self) -> bool {
1178        self.0.ops().is_seekable()
1179    }
1180    fn flush(&self, _file: &FileObject, current_task: &CurrentTask) {
1181        self.0.ops().flush(&self.0, current_task);
1182    }
1183    fn wait_async(
1184        &self,
1185        _file: &FileObject,
1186        current_task: &CurrentTask,
1187        waiter: &Waiter,
1188        events: FdEvents,
1189        handler: EventHandler,
1190    ) -> Option<WaitCanceler> {
1191        self.0.ops().wait_async(&self.0, current_task, waiter, events, handler)
1192    }
1193    fn query_events(
1194        &self,
1195        _file: &FileObject,
1196        current_task: &CurrentTask,
1197    ) -> Result<FdEvents, Errno> {
1198        self.0.ops().query_events(&self.0, current_task)
1199    }
1200    fn read(
1201        &self,
1202        _file: &FileObject,
1203        current_task: &CurrentTask,
1204        offset: usize,
1205        data: &mut dyn OutputBuffer,
1206    ) -> Result<usize, Errno> {
1207        self.0.ops().read(&self.0, current_task, offset, data)
1208    }
1209    fn write(
1210        &self,
1211        _file: &FileObject,
1212        current_task: &CurrentTask,
1213        offset: usize,
1214        data: &mut dyn InputBuffer,
1215    ) -> Result<usize, Errno> {
1216        self.0.ops().write(&self.0, current_task, offset, data)
1217    }
1218    fn ioctl(
1219        &self,
1220        _file: &FileObject,
1221        current_task: &CurrentTask,
1222        request: u32,
1223        arg: SyscallArg,
1224    ) -> Result<SyscallResult, Errno> {
1225        self.0.ops().ioctl(&self.0, current_task, request, arg)
1226    }
1227    fn fcntl(
1228        &self,
1229        _file: &FileObject,
1230        current_task: &CurrentTask,
1231        cmd: u32,
1232        arg: u64,
1233    ) -> Result<SyscallResult, Errno> {
1234        self.0.ops().fcntl(&self.0, current_task, cmd, arg)
1235    }
1236    fn readdir(
1237        &self,
1238        _file: &FileObject,
1239        current_task: &CurrentTask,
1240        sink: &mut dyn DirentSink,
1241    ) -> Result<(), Errno> {
1242        self.0.ops().readdir(&self.0, current_task, sink)
1243    }
1244    fn sync(&self, _file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
1245        self.0.ops().sync(&self.0, current_task)
1246    }
1247    fn data_sync(&self, _file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
1248        self.0.ops().sync(&self.0, current_task)
1249    }
1250    fn get_memory(
1251        &self,
1252        _file: &FileObject,
1253        current_task: &CurrentTask,
1254        length: Option<usize>,
1255        prot: ProtectionFlags,
1256    ) -> Result<Arc<MemoryObject>, Errno> {
1257        self.0.ops.get_memory(&self.0, current_task, length, prot)
1258    }
1259    fn mmap(
1260        &self,
1261        _file: &FileObject,
1262        current_task: &CurrentTask,
1263        addr: DesiredAddress,
1264        memory_offset: u64,
1265        length: usize,
1266        prot_flags: ProtectionFlags,
1267        options: MappingOptions,
1268        filename: NamespaceNode,
1269    ) -> Result<UserAddress, Errno> {
1270        self.0.ops.mmap(
1271            &self.0,
1272            current_task,
1273            addr,
1274            memory_offset,
1275            length,
1276            prot_flags,
1277            options,
1278            filename,
1279        )
1280    }
1281    fn seek(
1282        &self,
1283        _file: &FileObject,
1284        current_task: &CurrentTask,
1285        offset: off_t,
1286        target: SeekTarget,
1287    ) -> Result<off_t, Errno> {
1288        self.0.ops.seek(&self.0, current_task, offset, target)
1289    }
1290}
1291
1292#[derive(Debug, Default, Copy, Clone)]
1293pub enum FileAsyncOwner {
1294    #[default]
1295    Unowned,
1296    Thread(pid_t),
1297    Process(pid_t),
1298    ProcessGroup(pid_t),
1299}
1300
1301impl FileAsyncOwner {
1302    pub fn validate(self, current_task: &CurrentTask) -> Result<(), Errno> {
1303        match self {
1304            FileAsyncOwner::Unowned => (),
1305            FileAsyncOwner::Thread(id) | FileAsyncOwner::Process(id) => {
1306                if id != 0 {
1307                    current_task.get_task(id)?;
1308                }
1309            }
1310            FileAsyncOwner::ProcessGroup(pgid) => {
1311                if pgid != 0 {
1312                    current_task
1313                        .kernel()
1314                        .pids
1315                        .read()
1316                        .get_process_group(pgid)
1317                        .ok_or_else(|| errno!(ESRCH))?;
1318                }
1319            }
1320        }
1321        Ok(())
1322    }
1323}
1324
1325#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1326pub struct FileObjectId(u64);
1327
1328impl FileObjectId {
1329    pub fn as_epoll_key(&self) -> EpollKey {
1330        self.0 as EpollKey
1331    }
1332}
1333
1334/// A session with a file object.
1335///
1336/// Each time a client calls open(), we create a new FileObject from the
1337/// underlying FsNode that receives the open(). This object contains the state
1338/// that is specific to this sessions whereas the underlying FsNode contains
1339/// the state that is shared between all the sessions.
1340pub struct FileObject {
1341    ops: Box<dyn FileOps>,
1342    state: FileObjectState,
1343}
1344
1345impl std::ops::Deref for FileObject {
1346    type Target = FileObjectState;
1347    fn deref(&self) -> &Self::Target {
1348        &self.state
1349    }
1350}
1351
1352pub struct FileObjectState {
1353    /// Weak reference to the `FileHandle` of this `FileObject`. This allows to retrieve the
1354    /// `FileHandle` from a `FileObject`.
1355    pub weak_handle: WeakFileHandle,
1356
1357    /// A unique identifier for this file object.
1358    pub id: FileObjectId,
1359
1360    /// The NamespaceNode associated with this FileObject.
1361    ///
1362    /// Represents the name the process used to open this file.
1363    pub name: ActiveNamespaceNode,
1364
1365    pub fs: FileSystemHandle,
1366
1367    pub offset: RcuAtomic<off_t, FileObjectOffset>,
1368
1369    flags: AtomicOpenFlags,
1370
1371    async_owner: LockDepMutex<FileAsyncOwner, FileAsyncOwnerLock>,
1372
1373    /// A set of epoll file descriptor numbers that tracks which `EpollFileObject`s add this
1374    /// `FileObject` as the control file.
1375    epoll_files: LockDepMutex<HashMap<FileHandleKey, WeakFileHandle>, FileEpollFilesLock>,
1376
1377    /// See fcntl F_SETLEASE and F_GETLEASE.
1378    lease: LockDepMutex<FileLeaseType, FileLeaseLock>,
1379
1380    // This extra reference to the FsNode should not be needed, but it is needed to make
1381    // Inotify.ExcludeUnlinkInodeEvents pass.
1382    _mysterious_node: Option<FsNodeHandle>,
1383
1384    /// Opaque security state associated this file object.
1385    pub security_state: security::FileObjectState,
1386}
1387
1388pub enum FileObjectReleaserAction {}
1389impl ReleaserAction<FileObject> for FileObjectReleaserAction {
1390    fn release(file_object: ReleaseGuard<FileObject>) {
1391        register_delayed_release(file_object);
1392    }
1393}
1394pub type FileReleaser = ObjectReleaser<FileObject, FileObjectReleaserAction>;
1395pub type FileHandle = Arc<FileReleaser>;
1396pub type WeakFileHandle = Weak<FileReleaser>;
1397pub type FileHandleKey = WeakKey<FileReleaser>;
1398
1399impl FileObjectState {
1400    /// The FsNode from which this FileObject was created.
1401    pub fn node(&self) -> &FsNodeHandle {
1402        &self.name.entry.node
1403    }
1404
1405    pub fn flags(&self) -> OpenFlags {
1406        self.flags.load(Ordering::Relaxed)
1407    }
1408
1409    pub fn can_read(&self) -> bool {
1410        self.flags.load(Ordering::Relaxed).can_read()
1411    }
1412
1413    pub fn can_write(&self) -> bool {
1414        self.flags.load(Ordering::Relaxed).can_write()
1415    }
1416
1417    /// Returns false if the file is not allowed to be executed.
1418    pub fn can_exec(&self) -> bool {
1419        let mounted_no_exec = self.name.to_passive().mount.flags().contains(MountFlags::NOEXEC);
1420        let no_exec_seal = self
1421            .node()
1422            .write_guard_state
1423            .lock()
1424            .get_seals()
1425            .map(|seals| seals.contains(SealFlags::NO_EXEC))
1426            .unwrap_or(false);
1427        !(mounted_no_exec || no_exec_seal)
1428    }
1429
1430    // Notifies watchers on the current node and its parent about an event.
1431    pub fn notify(&self, event_mask: InotifyMask) {
1432        self.name.notify(event_mask)
1433    }
1434}
1435
1436impl FileObject {
1437    /// Create a FileObject that is not mounted in a namespace.
1438    ///
1439    /// In particular, this will create a new unrooted entries. This should not be used on
1440    /// file system with persistent entries, as the created entry will be out of sync with the one
1441    /// from the file system.
1442    ///
1443    /// The returned FileObject does not have a name.
1444    pub fn new_anonymous(
1445        current_task: &CurrentTask,
1446        ops: Box<dyn FileOps>,
1447        node: FsNodeHandle,
1448        flags: OpenFlags,
1449    ) -> FileHandle {
1450        assert!(!node.fs().has_permanent_entries());
1451        Self::new(
1452            current_task,
1453            ops,
1454            NamespaceNode::new_anonymous_unrooted(current_task, node),
1455            flags,
1456        )
1457        .expect("Failed to create anonymous FileObject")
1458    }
1459
1460    /// Create a FileObject with an associated NamespaceNode.
1461    ///
1462    /// This function is not typically called directly. Instead, consider
1463    /// calling NamespaceNode::open.
1464    pub fn new(
1465        current_task: &CurrentTask,
1466        ops: Box<dyn FileOps>,
1467        name: NamespaceNode,
1468        flags: OpenFlags,
1469    ) -> Result<FileHandle, Errno> {
1470        let _mysterious_node = if flags.can_write() {
1471            name.entry.node.write_guard_state.lock().acquire(FileWriteGuardMode::WriteFile)?;
1472            Some(name.entry.node.clone())
1473        } else {
1474            None
1475        };
1476        let fs = name.entry.node.fs();
1477        let id = FileObjectId(current_task.kernel.next_file_object_id.next());
1478        let security_state = security::file_alloc_security(current_task);
1479        let file = FileHandle::new_cyclic(|weak_handle| {
1480            Self {
1481                ops,
1482                state: FileObjectState {
1483                    weak_handle: weak_handle.clone(),
1484                    id,
1485                    name: name.into_active(),
1486                    fs,
1487                    offset: RcuAtomic::new(0),
1488                    flags: AtomicOpenFlags::new(flags - OpenFlags::CREAT),
1489                    async_owner: Default::default(),
1490                    epoll_files: Default::default(),
1491                    lease: Default::default(),
1492                    _mysterious_node,
1493                    security_state,
1494                },
1495            }
1496            .into()
1497        });
1498        file.notify(InotifyMask::OPEN);
1499
1500        file.ops().open(&file, current_task)?;
1501        Ok(file)
1502    }
1503
1504    pub fn max_access_for_memory_mapping(&self) -> Access {
1505        let mut access = Access::EXIST;
1506        if self.can_exec() {
1507            access |= Access::EXEC;
1508        }
1509        let flags = self.flags.load(Ordering::Relaxed);
1510        if flags.can_read() {
1511            access |= Access::READ;
1512        }
1513        if flags.can_write() {
1514            access |= Access::WRITE;
1515        }
1516        access
1517    }
1518
1519    pub fn ops(&self) -> &dyn FileOps {
1520        self.ops.as_ref()
1521    }
1522
1523    pub fn ops_type_name(&self) -> &'static str {
1524        self.ops().type_name()
1525    }
1526
1527    pub fn is_non_blocking(&self) -> bool {
1528        self.flags().contains(OpenFlags::NONBLOCK)
1529    }
1530
1531    /// Common implementation for blocking operations.
1532    ///
1533    /// This function is used to implement the blocking operations for file objects. FileOps
1534    /// implementations should call this function to handle the blocking logic.
1535    ///
1536    /// The `op` parameter is a function that implements the non-blocking version of the operation.
1537    /// The function is called once without registering a waiter in case no wait is needed. If the
1538    /// operation returns EAGAIN and the file object is non-blocking, the function returns EAGAIN.
1539    ///
1540    /// If the operation returns EAGAIN and the file object is blocking, the function will block
1541    /// until the given events are triggered. At that time, the operation is retried. Notice that
1542    /// the `op` function can be called multiple times before the operation completes.
1543    ///
1544    /// The `deadline` parameter is the deadline for the operation. If the operation does not
1545    /// complete before the deadline, the function will return ETIMEDOUT.
1546    pub fn blocking_op<T, Op>(
1547        &self,
1548        current_task: &CurrentTask,
1549        events: FdEvents,
1550        deadline: Option<zx::MonotonicInstant>,
1551        mut op: Op,
1552    ) -> Result<T, Errno>
1553    where
1554        Op: FnMut() -> Result<T, Errno>,
1555    {
1556        // Don't return EAGAIN for directories. This can happen because glibc always opens a
1557        // directory with O_NONBLOCK.
1558        let can_return_eagain = self.flags().contains(OpenFlags::NONBLOCK)
1559            && !self.flags().contains(OpenFlags::DIRECTORY);
1560        // Run the operation a first time without registering a waiter in case no wait is needed.
1561        match op() {
1562            Err(errno) if errno == EAGAIN && !can_return_eagain => {}
1563            result => return result,
1564        }
1565
1566        let waiter = Waiter::new();
1567        loop {
1568            // Register the waiter before running the operation to prevent a race.
1569            self.wait_async(current_task, &waiter, events, WaitCallback::none());
1570            match op() {
1571                Err(e) if e == EAGAIN => {}
1572                result => return result,
1573            }
1574            waiter
1575                .wait_until(current_task, deadline.unwrap_or(zx::MonotonicInstant::INFINITE))
1576                .map_err(|e| if e == ETIMEDOUT { errno!(EAGAIN) } else { e })?;
1577        }
1578    }
1579
1580    pub fn is_seekable(&self) -> bool {
1581        self.ops().is_seekable()
1582    }
1583
1584    pub fn has_persistent_offsets(&self) -> bool {
1585        self.ops().has_persistent_offsets()
1586    }
1587
1588    /// Common implementation for `read` and `read_at`.
1589    fn read_internal<R>(&self, current_task: &CurrentTask, read: R) -> Result<usize, Errno>
1590    where
1591        R: FnOnce() -> Result<usize, Errno>,
1592    {
1593        security::file_permission(current_task, self, security::PermissionFlags::READ)?;
1594
1595        if !self.can_read() {
1596            return error!(EBADF);
1597        }
1598        let bytes_read = read()?;
1599
1600        // TODO(steveaustin) - omit updating time_access to allow info to be immutable
1601        // and thus allow simultaneous reads.
1602        self.update_atime();
1603        if bytes_read > 0 {
1604            self.notify(InotifyMask::ACCESS);
1605        }
1606
1607        Ok(bytes_read)
1608    }
1609
1610    pub fn read(
1611        &self,
1612        current_task: &CurrentTask,
1613        data: &mut dyn OutputBuffer,
1614    ) -> Result<usize, Errno> {
1615        self.read_internal(current_task, || {
1616            if !self.ops().has_persistent_offsets() {
1617                if data.available() > MAX_LFS_FILESIZE {
1618                    return error!(EINVAL);
1619                }
1620                return self.ops.read(self, current_task, 0, data);
1621            }
1622
1623            let mut offset_guard = self.offset.copy();
1624            let offset = *offset_guard as usize;
1625            checked_add_offset_and_length(offset, data.available())?;
1626            let read = self.ops.read(self, current_task, offset, data)?;
1627            *offset_guard += read as off_t;
1628            offset_guard.update();
1629            Ok(read)
1630        })
1631    }
1632
1633    pub fn read_at(
1634        &self,
1635        current_task: &CurrentTask,
1636        offset: usize,
1637        data: &mut dyn OutputBuffer,
1638    ) -> Result<usize, Errno> {
1639        if !self.ops().is_seekable() {
1640            return error!(ESPIPE);
1641        }
1642        checked_add_offset_and_length(offset, data.available())?;
1643        self.read_internal(current_task, || self.ops.read(self, current_task, offset, data))
1644    }
1645
1646    /// Common checks before calling ops().write.
1647    fn write_common(
1648        &self,
1649        current_task: &CurrentTask,
1650        offset: usize,
1651        data: &mut dyn InputBuffer,
1652    ) -> Result<usize, Errno> {
1653        security::file_permission(current_task, self, security::PermissionFlags::WRITE)?;
1654
1655        // We need to cap the size of `data` to prevent us from growing the file too large,
1656        // according to <https://man7.org/linux/man-pages/man2/write.2.html>:
1657        //
1658        //   The number of bytes written may be less than count if, for example, there is
1659        //   insufficient space on the underlying physical medium, or the RLIMIT_FSIZE resource
1660        //   limit is encountered (see setrlimit(2)),
1661        checked_add_offset_and_length(offset, data.available())?;
1662        self.ops().write(self, current_task, offset, data)
1663    }
1664
1665    /// Common wrapper work for `write` and `write_at`.
1666    fn write_fn<W>(&self, current_task: &CurrentTask, write: W) -> Result<usize, Errno>
1667    where
1668        W: FnOnce() -> Result<usize, Errno>,
1669    {
1670        if !self.can_write() {
1671            return error!(EBADF);
1672        }
1673        self.node().clear_suid_and_sgid_bits(current_task)?;
1674        let bytes_written = write()?;
1675        self.node().update_ctime_mtime();
1676
1677        if bytes_written > 0 {
1678            self.notify(InotifyMask::MODIFY);
1679        }
1680
1681        Ok(bytes_written)
1682    }
1683
1684    pub fn write(
1685        &self,
1686        current_task: &CurrentTask,
1687        data: &mut dyn InputBuffer,
1688    ) -> Result<usize, Errno> {
1689        self.write_fn(current_task, || {
1690            if !self.ops().has_persistent_offsets() {
1691                return self.write_common(current_task, 0, data);
1692            }
1693            let mut offset = self.offset.copy();
1694            let bytes_written = if self.flags().contains(OpenFlags::APPEND) {
1695                let _guard = self.node().ops().append_lock_write(self.node(), current_task)?;
1696                *offset = self.ops().seek(self, current_task, *offset, SeekTarget::End(0))?;
1697                self.write_common(current_task, *offset as usize, data)
1698            } else {
1699                let _guard = self.node().ops().append_lock_read(self.node(), current_task)?;
1700                self.write_common(current_task, *offset as usize, data)
1701            }?;
1702            if self.ops().writes_update_seek_offset() {
1703                *offset += bytes_written as off_t;
1704            }
1705            offset.update();
1706            Ok(bytes_written)
1707        })
1708    }
1709
1710    pub fn write_at(
1711        &self,
1712        current_task: &CurrentTask,
1713        mut offset: usize,
1714        data: &mut dyn InputBuffer,
1715    ) -> Result<usize, Errno> {
1716        if !self.ops().is_seekable() {
1717            return error!(ESPIPE);
1718        }
1719        self.write_fn(current_task, || {
1720            if self.flags().contains(OpenFlags::APPEND) {
1721                let _guard = self.node().append_lock.write(current_task)?;
1722                // According to LTP test pwrite04:
1723                //
1724                //   POSIX requires that opening a file with the O_APPEND flag should have no effect on the
1725                //   location at which pwrite() writes data. However, on Linux, if a file is opened with
1726                //   O_APPEND, pwrite() appends data to the end of the file, regardless of the value of offset.
1727                if self.ops().is_seekable() {
1728                    checked_add_offset_and_length(offset, data.available())?;
1729                    offset = default_eof_offset(self, current_task)? as usize;
1730                }
1731                self.write_common(current_task, offset, data)
1732            } else {
1733                let _guard = self.node().append_lock.read(current_task)?;
1734                self.write_common(current_task, offset, data)
1735            }
1736        })
1737    }
1738
1739    pub fn seek(&self, current_task: &CurrentTask, target: SeekTarget) -> Result<off_t, Errno> {
1740        if !self.ops().is_seekable() {
1741            return error!(ESPIPE);
1742        }
1743
1744        if !self.ops().has_persistent_offsets() {
1745            return self.ops().seek(self, current_task, 0, target);
1746        }
1747
1748        let mut offset_guard = self.offset.copy();
1749        let new_offset = self.ops().seek(self, current_task, *offset_guard, target)?;
1750        *offset_guard = new_offset;
1751        offset_guard.update();
1752        Ok(new_offset)
1753    }
1754
1755    pub fn sync(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1756        self.ops().sync(self, current_task)
1757    }
1758
1759    pub fn data_sync(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1760        self.ops().data_sync(self, current_task)
1761    }
1762
1763    pub fn get_memory(
1764        &self,
1765        current_task: &CurrentTask,
1766        length: Option<usize>,
1767        prot: ProtectionFlags,
1768    ) -> Result<Arc<MemoryObject>, Errno> {
1769        if prot.contains(ProtectionFlags::READ) && !self.can_read() {
1770            return error!(EACCES);
1771        }
1772        if prot.contains(ProtectionFlags::WRITE) && !self.can_write() {
1773            return error!(EACCES);
1774        }
1775        if prot.contains(ProtectionFlags::EXEC) && !self.can_exec() {
1776            return error!(EPERM);
1777        }
1778        self.ops().get_memory(self, current_task, length, prot)
1779    }
1780
1781    pub fn mmap(
1782        &self,
1783        current_task: &CurrentTask,
1784        addr: DesiredAddress,
1785        memory_offset: u64,
1786        length: usize,
1787        prot_flags: ProtectionFlags,
1788        options: MappingOptions,
1789        filename: NamespaceNode,
1790    ) -> Result<UserAddress, Errno> {
1791        if !self.can_read() {
1792            return error!(EACCES);
1793        }
1794        if prot_flags.contains(ProtectionFlags::WRITE)
1795            && !self.can_write()
1796            && options.contains(MappingOptions::SHARED)
1797        {
1798            return error!(EACCES);
1799        }
1800        if prot_flags.contains(ProtectionFlags::EXEC) && !self.can_exec() {
1801            return error!(EPERM);
1802        }
1803        self.ops().mmap(
1804            self,
1805            current_task,
1806            addr,
1807            memory_offset,
1808            length,
1809            prot_flags,
1810            options,
1811            filename,
1812        )
1813    }
1814
1815    pub fn readdir(
1816        &self,
1817        current_task: &CurrentTask,
1818        sink: &mut dyn DirentSink,
1819    ) -> Result<(), Errno> {
1820        if self.name.entry.is_dead() {
1821            return error!(ENOENT);
1822        }
1823
1824        security::file_permission(current_task, self, security::PermissionFlags::READ)?;
1825
1826        self.ops().readdir(self, current_task, sink)?;
1827        self.update_atime();
1828        self.notify(InotifyMask::ACCESS);
1829        Ok(())
1830    }
1831
1832    pub fn ioctl(
1833        &self,
1834        current_task: &CurrentTask,
1835        request: u32,
1836        arg: SyscallArg,
1837    ) -> Result<SyscallResult, Errno> {
1838        security::check_file_ioctl_access(current_task, &self, request)?;
1839
1840        if request == FIBMAP {
1841            security::check_task_capable(current_task, CAP_SYS_RAWIO)?;
1842
1843            // TODO: https://fxbug.dev/404795644 - eliminate this phoney response when the SELinux
1844            // Test Suite no longer requires it.
1845            if current_task.kernel().features.selinux_test_suite {
1846                let phoney_block = 0xbadf000du32;
1847                current_task.write_object(arg.into(), &phoney_block)?;
1848                return Ok(SUCCESS);
1849            }
1850        }
1851
1852        if let Some(result) = default_vfs_ioctl(self, current_task, request, arg)? {
1853            return Ok(result);
1854        }
1855
1856        self.ops().ioctl(self, current_task, request, arg)
1857    }
1858
1859    pub fn fcntl(
1860        &self,
1861        current_task: &CurrentTask,
1862        cmd: u32,
1863        arg: u64,
1864    ) -> Result<SyscallResult, Errno> {
1865        self.ops().fcntl(self, current_task, cmd, arg)
1866    }
1867
1868    pub fn ftruncate(&self, current_task: &CurrentTask, length: u64) -> Result<(), Errno> {
1869        // The file must be opened with write permissions. Otherwise
1870        // truncating it is forbidden.
1871        if !self.can_write() {
1872            return error!(EINVAL);
1873        }
1874        self.node().ftruncate(current_task, length)?;
1875        self.name.entry.notify_ignoring_excl_unlink(InotifyMask::MODIFY);
1876        Ok(())
1877    }
1878
1879    pub fn fallocate(
1880        &self,
1881        current_task: &CurrentTask,
1882        mode: FallocMode,
1883        offset: u64,
1884        length: u64,
1885    ) -> Result<(), Errno> {
1886        // If the file is a pipe or FIFO, ESPIPE is returned.
1887        // See https://man7.org/linux/man-pages/man2/fallocate.2.html#ERRORS
1888        if self.node().is_fifo() {
1889            return error!(ESPIPE);
1890        }
1891
1892        // Must be a regular file or directory.
1893        // See https://man7.org/linux/man-pages/man2/fallocate.2.html#ERRORS
1894        if !self.node().is_dir() && !self.node().is_reg() {
1895            return error!(ENODEV);
1896        }
1897
1898        // The file must be opened with write permissions. Otherwise operation is forbidden.
1899        // See https://man7.org/linux/man-pages/man2/fallocate.2.html#ERRORS
1900        if !self.can_write() {
1901            return error!(EBADF);
1902        }
1903
1904        security::file_permission(current_task, self, security::PermissionFlags::WRITE)?;
1905
1906        self.node().fallocate(current_task, mode, offset, length)?;
1907        self.notify(InotifyMask::MODIFY);
1908        Ok(())
1909    }
1910
1911    pub fn to_handle(
1912        &self,
1913        current_task: &CurrentTask,
1914    ) -> Result<Option<zx::NullableHandle>, Errno> {
1915        self.ops().to_handle(self, current_task)
1916    }
1917
1918    pub fn get_handles(
1919        &self,
1920        current_task: &CurrentTask,
1921    ) -> Result<Vec<zx::NullableHandle>, Errno> {
1922        self.ops().get_handles(self, current_task)
1923    }
1924
1925    pub fn as_thread_group_key(&self) -> Result<ThreadGroupKey, Errno> {
1926        self.ops().as_thread_group_key(self)
1927    }
1928
1929    /// Update the file flags.
1930    ///
1931    /// Writes the bits in `value` that are set in `mask` into the file flags.
1932    ///
1933    /// Does not provide any synchronization.
1934    pub fn update_file_flags(&self, value: OpenFlags, mask: OpenFlags) {
1935        self.flags.update(value, mask, Ordering::Relaxed, Ordering::Relaxed);
1936    }
1937
1938    /// Get the async owner of this file.
1939    ///
1940    /// See fcntl(F_GETOWN)
1941    pub fn get_async_owner(&self) -> FileAsyncOwner {
1942        *self.async_owner.lock()
1943    }
1944
1945    /// Set the async owner of this file.
1946    ///
1947    /// See fcntl(F_SETOWN)
1948    pub fn set_async_owner(&self, owner: FileAsyncOwner) {
1949        *self.async_owner.lock() = owner;
1950    }
1951
1952    /// See fcntl(F_GETLEASE)
1953    pub fn get_lease(&self) -> FileLeaseType {
1954        *self.lease.lock()
1955    }
1956
1957    /// See fcntl(F_SETLEASE)
1958    pub fn set_lease(&self, current_task: &CurrentTask, lease: FileLeaseType) -> Result<(), Errno> {
1959        if !self.node().is_reg() {
1960            return error!(EINVAL);
1961        }
1962        security::check_file_lock_access(current_task, self)?;
1963        if lease == FileLeaseType::Read && self.can_write() {
1964            return error!(EAGAIN);
1965        }
1966        *self.lease.lock() = lease;
1967        Ok(())
1968    }
1969
1970    /// Wait on the specified events and call the EventHandler when ready
1971    pub fn wait_async(
1972        &self,
1973        current_task: &CurrentTask,
1974        waiter: &Waiter,
1975        events: FdEvents,
1976        handler: EventHandler,
1977    ) -> Option<WaitCanceler> {
1978        self.ops().wait_async(self, current_task, waiter, events, handler)
1979    }
1980
1981    /// The events currently active on this file.
1982    pub fn query_events(&self, current_task: &CurrentTask) -> Result<FdEvents, Errno> {
1983        self.ops().query_events(self, current_task).map(FdEvents::add_equivalent_fd_events)
1984    }
1985
1986    pub fn record_lock(
1987        &self,
1988        current_task: &CurrentTask,
1989        cmd: RecordLockCommand,
1990        flock: uapi::flock,
1991    ) -> Result<Option<uapi::flock>, Errno> {
1992        security::check_file_lock_access(current_task, self)?;
1993        self.node().record_lock(current_task, self, cmd, flock)
1994    }
1995
1996    pub fn flush(&self, current_task: &CurrentTask, id: FdTableId) {
1997        self.name.entry.node.record_lock_release(RecordLockOwner::FdTable(id));
1998        self.ops().flush(self, current_task)
1999    }
2000
2001    fn update_atime(&self) {
2002        if !self.flags().contains(OpenFlags::NOATIME) {
2003            self.name.update_atime();
2004        }
2005    }
2006
2007    pub fn readahead(
2008        &self,
2009        current_task: &CurrentTask,
2010        offset: usize,
2011        length: usize,
2012    ) -> Result<(), Errno> {
2013        // readfile() fails with EBADF if the file was not open for read.
2014        if !self.can_read() {
2015            return error!(EBADF);
2016        }
2017        checked_add_offset_and_length(offset, length)?;
2018        self.ops().readahead(self, current_task, offset, length)
2019    }
2020
2021    pub fn extra_fdinfo(&self, current_task: &CurrentTask) -> Option<FsString> {
2022        let file = self.weak_handle.upgrade()?;
2023        self.ops().extra_fdinfo(&file, current_task)
2024    }
2025
2026    /// Register the fd number of an `EpollFileObject` that listens to events from this
2027    /// `FileObject`.
2028    pub fn register_epfd(&self, file: &FileHandle) {
2029        self.epoll_files.lock().insert(WeakKey::from(file), file.weak_handle.clone());
2030    }
2031
2032    pub fn unregister_epfd(&self, file: &FileHandle) {
2033        self.epoll_files.lock().remove(&WeakKey::from(file));
2034    }
2035}
2036
2037impl Releasable for FileObject {
2038    type Context<'a> = &'a CurrentTask;
2039
2040    fn release<'a>(self, context: &'a CurrentTask) {
2041        let current_task = context;
2042        // Release all wake leases associated with this file in the corresponding `WaitObject`
2043        // of each registered epfd.
2044        for (_, file) in self.epoll_files.lock().drain() {
2045            if let Some(file) = file.upgrade() {
2046                if let Some(epoll_object) = file.downcast_file::<EpollFileObject>() {
2047                    let _ = epoll_object.delete(current_task, &self);
2048                }
2049            }
2050        }
2051
2052        if self.can_write() {
2053            self.name.entry.node.write_guard_state.lock().release(FileWriteGuardMode::WriteFile);
2054        }
2055
2056        let ops = self.ops;
2057        let state = self.state;
2058        ops.close(&state, current_task);
2059        state.name.entry.node.on_file_closed(&state);
2060        let event =
2061            if state.can_write() { InotifyMask::CLOSE_WRITE } else { InotifyMask::CLOSE_NOWRITE };
2062        state.notify(event);
2063    }
2064}
2065
2066impl fmt::Debug for FileObject {
2067    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2068        f.debug_struct("FileObject")
2069            .field("name", &self.name)
2070            .field("fs", &self.fs.name())
2071            .field("offset", &self.offset)
2072            .field("flags", &self.flags)
2073            .field("ops_ty", &self.ops().type_name())
2074            .finish()
2075    }
2076}
2077
2078impl OnWakeOps for FileReleaser {
2079    fn on_wake(&self, _current_task: &CurrentTask, _baton_lease: &zx::NullableHandle) {}
2080}
2081
2082/// A FileObject with the type of its FileOps known. Dereferencing it returns the FileOps.
2083pub struct DowncastedFile<'a, Ops> {
2084    file: &'a FileObject,
2085    ops: &'a Ops,
2086}
2087impl<'a, Ops> Copy for DowncastedFile<'a, Ops> {}
2088impl<'a, Ops> Clone for DowncastedFile<'a, Ops> {
2089    fn clone(&self) -> Self {
2090        *self
2091    }
2092}
2093
2094impl<'a, Ops> DowncastedFile<'a, Ops> {
2095    pub fn file(&self) -> &'a FileObject {
2096        self.file
2097    }
2098}
2099
2100impl<'a, Ops> Deref for DowncastedFile<'a, Ops> {
2101    type Target = &'a Ops;
2102    fn deref(&self) -> &Self::Target {
2103        &self.ops
2104    }
2105}
2106
2107impl FileObject {
2108    /// Returns the `FileObject`'s `FileOps` as a `DowncastedFile<T>`, or `None` if the downcast
2109    /// fails.
2110    ///
2111    /// This is useful for syscalls that only operate on a certain type of file.
2112    pub fn downcast_file<'a, T>(&'a self) -> Option<DowncastedFile<'a, T>>
2113    where
2114        T: 'static,
2115    {
2116        let ops = self.ops().as_any().downcast_ref::<T>()?;
2117        Some(DowncastedFile { file: self, ops })
2118    }
2119}
2120
2121/// Invokes the specified one-way `method` on the `proxy` and waits until the `proxy`'s underlying
2122/// channel has been closed by the peer.
2123///
2124/// This is used in `close()` implementations when the `FileOps` wraps a FIDL resource that provides
2125/// a one-way API to request teardown, and acknowledges completion of teardown by closing the FIDL
2126/// channel, to ensure that the `close()` call does not return until the FIDL server has actually
2127/// processed the teardown request.
2128pub fn call_fidl_and_await_close<P, M>(method: M, proxy: &P)
2129where
2130    P: fidl::endpoints::SynchronousProxy,
2131    M: FnOnce(&P) -> Result<(), fidl::Error>,
2132{
2133    if let Err(e) = method(proxy) {
2134        log_error!("call_fidl_and_await_close: call {} failed: {e:?}", P::Protocol::DEBUG_NAME);
2135        return;
2136    }
2137    let channel = proxy.as_channel();
2138    let result = channel.wait_one(zx::Signals::CHANNEL_PEER_CLOSED, zx::MonotonicInstant::INFINITE);
2139    if let Err(status) = result.to_result() {
2140        log_error!(
2141            "call_fidl_and_await_close: wait_one {} failed: {status:?}",
2142            P::Protocol::DEBUG_NAME
2143        );
2144    }
2145}
2146
2147#[cfg(test)]
2148mod tests {
2149    use crate::fs::tmpfs::TmpFs;
2150    use crate::task::CurrentTask;
2151    use crate::task::dynamic_thread_spawner::SpawnRequestBuilder;
2152    use crate::testing::*;
2153    use crate::vfs::MountInfo;
2154    use crate::vfs::buffers::{VecInputBuffer, VecOutputBuffer};
2155    use starnix_uapi::auth::FsCred;
2156    use starnix_uapi::device_id::DeviceId;
2157    use starnix_uapi::file_mode::FileMode;
2158    use starnix_uapi::open_flags::OpenFlags;
2159    use std::sync::Arc;
2160    use std::sync::atomic::{AtomicBool, Ordering};
2161    use zerocopy::{FromBytes, IntoBytes, LE, U64};
2162
2163    #[::fuchsia::test]
2164    async fn test_append_truncate_race() {
2165        spawn_kernel_and_run(async |current_task| {
2166            let kernel = current_task.kernel();
2167            let root_fs = TmpFs::new_fs(&kernel);
2168            let mount = MountInfo::detached();
2169            let root_node = Arc::clone(root_fs.root());
2170            let file = root_node
2171                .create_entry(&current_task, &mount, "test".into(), |dir, mount, name| {
2172                    dir.create_node(
2173                        &current_task,
2174                        mount,
2175                        name,
2176                        FileMode::IFREG | FileMode::ALLOW_ALL,
2177                        DeviceId::NONE,
2178                        FsCred::root(),
2179                    )
2180                })
2181                .expect("create_node failed");
2182            let file_handle = file
2183                .open_anonymous(&current_task, OpenFlags::APPEND | OpenFlags::RDWR)
2184                .expect("open failed");
2185            let done = Arc::new(AtomicBool::new(false));
2186
2187            let fh = file_handle.clone();
2188            let done_clone = done.clone();
2189            let closure = move |current_task: &CurrentTask| {
2190                for i in 0..2000 {
2191                    fh.write(current_task, &mut VecInputBuffer::new(U64::<LE>::new(i).as_bytes()))
2192                        .expect("write failed");
2193                }
2194                done_clone.store(true, Ordering::SeqCst);
2195                let result: Result<(), starnix_uapi::errors::Errno> = Ok(());
2196                result
2197            };
2198            let (write_thread, req) =
2199                SpawnRequestBuilder::new().with_sync_closure(closure).build_with_sync_result();
2200            kernel.kthreads.spawner().spawn_from_request(req);
2201
2202            let fh = file_handle.clone();
2203            let done_clone = done.clone();
2204            let closure = move |current_task: &CurrentTask| {
2205                while !done_clone.load(Ordering::SeqCst) {
2206                    fh.ftruncate(current_task, 0).expect("truncate failed");
2207                }
2208                let result: Result<(), starnix_uapi::errors::Errno> = Ok(());
2209                result
2210            };
2211            let (truncate_thread, req) =
2212                SpawnRequestBuilder::new().with_sync_closure(closure).build_with_sync_result();
2213            kernel.kthreads.spawner().spawn_from_request(req);
2214
2215            // If we read from the file, we should always find an increasing sequence. If there are
2216            // races, then we might unexpectedly see zeroes.
2217            while !done.load(Ordering::SeqCst) {
2218                let mut buffer = VecOutputBuffer::new(4096);
2219                let amount =
2220                    file_handle.read_at(&current_task, 0, &mut buffer).expect("read failed");
2221                let mut last = None;
2222                let buffer = &Vec::from(buffer)[..amount];
2223                for i in
2224                    buffer.chunks_exact(8).map(|chunk| U64::<LE>::read_from_bytes(chunk).unwrap())
2225                {
2226                    if let Some(last) = last {
2227                        assert!(i.get() > last, "buffer: {:?}", buffer);
2228                    }
2229                    last = Some(i.get());
2230                }
2231            }
2232
2233            let _ = write_thread().unwrap();
2234            let _ = truncate_thread().unwrap();
2235        })
2236        .await;
2237    }
2238}