Skip to main content

starnix_core/vfs/
file_object.rs

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