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