xref: /linux-6.15/rust/kernel/fs/file.rs (revision e27b0e3c)
185184982SWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0
285184982SWedson Almeida Filho 
385184982SWedson Almeida Filho // Copyright (C) 2024 Google LLC.
485184982SWedson Almeida Filho 
585184982SWedson Almeida Filho //! Files and file descriptors.
685184982SWedson Almeida Filho //!
785184982SWedson Almeida Filho //! C headers: [`include/linux/fs.h`](srctree/include/linux/fs.h) and
885184982SWedson Almeida Filho //! [`include/linux/file.h`](srctree/include/linux/file.h)
985184982SWedson Almeida Filho 
1085184982SWedson Almeida Filho use crate::{
1185184982SWedson Almeida Filho     bindings,
12a3df991dSWedson Almeida Filho     cred::Credential,
1385184982SWedson Almeida Filho     error::{code::*, Error, Result},
145da9857bSWedson Almeida Filho     types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque},
1585184982SWedson Almeida Filho };
1685184982SWedson Almeida Filho use core::ptr;
1785184982SWedson Almeida Filho 
1885184982SWedson Almeida Filho /// Flags associated with a [`File`].
1985184982SWedson Almeida Filho pub mod flags {
2085184982SWedson Almeida Filho     /// File is opened in append mode.
2185184982SWedson Almeida Filho     pub const O_APPEND: u32 = bindings::O_APPEND;
2285184982SWedson Almeida Filho 
2385184982SWedson Almeida Filho     /// Signal-driven I/O is enabled.
2485184982SWedson Almeida Filho     pub const O_ASYNC: u32 = bindings::FASYNC;
2585184982SWedson Almeida Filho 
2685184982SWedson Almeida Filho     /// Close-on-exec flag is set.
2785184982SWedson Almeida Filho     pub const O_CLOEXEC: u32 = bindings::O_CLOEXEC;
2885184982SWedson Almeida Filho 
2985184982SWedson Almeida Filho     /// File was created if it didn't already exist.
3085184982SWedson Almeida Filho     pub const O_CREAT: u32 = bindings::O_CREAT;
3185184982SWedson Almeida Filho 
3285184982SWedson Almeida Filho     /// Direct I/O is enabled for this file.
3385184982SWedson Almeida Filho     pub const O_DIRECT: u32 = bindings::O_DIRECT;
3485184982SWedson Almeida Filho 
3585184982SWedson Almeida Filho     /// File must be a directory.
3685184982SWedson Almeida Filho     pub const O_DIRECTORY: u32 = bindings::O_DIRECTORY;
3785184982SWedson Almeida Filho 
3885184982SWedson Almeida Filho     /// Like [`O_SYNC`] except metadata is not synced.
3985184982SWedson Almeida Filho     pub const O_DSYNC: u32 = bindings::O_DSYNC;
4085184982SWedson Almeida Filho 
4185184982SWedson Almeida Filho     /// Ensure that this file is created with the `open(2)` call.
4285184982SWedson Almeida Filho     pub const O_EXCL: u32 = bindings::O_EXCL;
4385184982SWedson Almeida Filho 
4485184982SWedson Almeida Filho     /// Large file size enabled (`off64_t` over `off_t`).
4585184982SWedson Almeida Filho     pub const O_LARGEFILE: u32 = bindings::O_LARGEFILE;
4685184982SWedson Almeida Filho 
4785184982SWedson Almeida Filho     /// Do not update the file last access time.
4885184982SWedson Almeida Filho     pub const O_NOATIME: u32 = bindings::O_NOATIME;
4985184982SWedson Almeida Filho 
5085184982SWedson Almeida Filho     /// File should not be used as process's controlling terminal.
5185184982SWedson Almeida Filho     pub const O_NOCTTY: u32 = bindings::O_NOCTTY;
5285184982SWedson Almeida Filho 
5385184982SWedson Almeida Filho     /// If basename of path is a symbolic link, fail open.
5485184982SWedson Almeida Filho     pub const O_NOFOLLOW: u32 = bindings::O_NOFOLLOW;
5585184982SWedson Almeida Filho 
5685184982SWedson Almeida Filho     /// File is using nonblocking I/O.
5785184982SWedson Almeida Filho     pub const O_NONBLOCK: u32 = bindings::O_NONBLOCK;
5885184982SWedson Almeida Filho 
5985184982SWedson Almeida Filho     /// File is using nonblocking I/O.
6085184982SWedson Almeida Filho     ///
6185184982SWedson Almeida Filho     /// This is effectively the same flag as [`O_NONBLOCK`] on all architectures
6285184982SWedson Almeida Filho     /// except SPARC64.
6385184982SWedson Almeida Filho     pub const O_NDELAY: u32 = bindings::O_NDELAY;
6485184982SWedson Almeida Filho 
6585184982SWedson Almeida Filho     /// Used to obtain a path file descriptor.
6685184982SWedson Almeida Filho     pub const O_PATH: u32 = bindings::O_PATH;
6785184982SWedson Almeida Filho 
6885184982SWedson Almeida Filho     /// Write operations on this file will flush data and metadata.
6985184982SWedson Almeida Filho     pub const O_SYNC: u32 = bindings::O_SYNC;
7085184982SWedson Almeida Filho 
7185184982SWedson Almeida Filho     /// This file is an unnamed temporary regular file.
7285184982SWedson Almeida Filho     pub const O_TMPFILE: u32 = bindings::O_TMPFILE;
7385184982SWedson Almeida Filho 
7485184982SWedson Almeida Filho     /// File should be truncated to length 0.
7585184982SWedson Almeida Filho     pub const O_TRUNC: u32 = bindings::O_TRUNC;
7685184982SWedson Almeida Filho 
7785184982SWedson Almeida Filho     /// Bitmask for access mode flags.
7885184982SWedson Almeida Filho     ///
7985184982SWedson Almeida Filho     /// # Examples
8085184982SWedson Almeida Filho     ///
8185184982SWedson Almeida Filho     /// ```
8285184982SWedson Almeida Filho     /// use kernel::fs::file;
8385184982SWedson Almeida Filho     /// # fn do_something() {}
8485184982SWedson Almeida Filho     /// # let flags = 0;
8585184982SWedson Almeida Filho     /// if (flags & file::flags::O_ACCMODE) == file::flags::O_RDONLY {
8685184982SWedson Almeida Filho     ///     do_something();
8785184982SWedson Almeida Filho     /// }
8885184982SWedson Almeida Filho     /// ```
8985184982SWedson Almeida Filho     pub const O_ACCMODE: u32 = bindings::O_ACCMODE;
9085184982SWedson Almeida Filho 
9185184982SWedson Almeida Filho     /// File is read only.
9285184982SWedson Almeida Filho     pub const O_RDONLY: u32 = bindings::O_RDONLY;
9385184982SWedson Almeida Filho 
9485184982SWedson Almeida Filho     /// File is write only.
9585184982SWedson Almeida Filho     pub const O_WRONLY: u32 = bindings::O_WRONLY;
9685184982SWedson Almeida Filho 
9785184982SWedson Almeida Filho     /// File can be both read and written.
9885184982SWedson Almeida Filho     pub const O_RDWR: u32 = bindings::O_RDWR;
9985184982SWedson Almeida Filho }
10085184982SWedson Almeida Filho 
10185184982SWedson Almeida Filho /// Wraps the kernel's `struct file`. Thread safe.
10285184982SWedson Almeida Filho ///
10385184982SWedson Almeida Filho /// This represents an open file rather than a file on a filesystem. Processes generally reference
10485184982SWedson Almeida Filho /// open files using file descriptors. However, file descriptors are not the same as files. A file
10585184982SWedson Almeida Filho /// descriptor is just an integer that corresponds to a file, and a single file may be referenced
10685184982SWedson Almeida Filho /// by multiple file descriptors.
10785184982SWedson Almeida Filho ///
10885184982SWedson Almeida Filho /// # Refcounting
10985184982SWedson Almeida Filho ///
11085184982SWedson Almeida Filho /// Instances of this type are reference-counted. The reference count is incremented by the
11185184982SWedson Almeida Filho /// `fget`/`get_file` functions and decremented by `fput`. The Rust type `ARef<File>` represents a
11285184982SWedson Almeida Filho /// pointer that owns a reference count on the file.
11385184982SWedson Almeida Filho ///
11485184982SWedson Almeida Filho /// Whenever a process opens a file descriptor (fd), it stores a pointer to the file in its fd
11585184982SWedson Almeida Filho /// table (`struct files_struct`). This pointer owns a reference count to the file, ensuring the
11685184982SWedson Almeida Filho /// file isn't prematurely deleted while the file descriptor is open. In Rust terminology, the
11785184982SWedson Almeida Filho /// pointers in `struct files_struct` are `ARef<File>` pointers.
11885184982SWedson Almeida Filho ///
11985184982SWedson Almeida Filho /// ## Light refcounts
12085184982SWedson Almeida Filho ///
12185184982SWedson Almeida Filho /// Whenever a process has an fd to a file, it may use something called a "light refcount" as a
12285184982SWedson Almeida Filho /// performance optimization. Light refcounts are acquired by calling `fdget` and released with
12385184982SWedson Almeida Filho /// `fdput`. The idea behind light refcounts is that if the fd is not closed between the calls to
12485184982SWedson Almeida Filho /// `fdget` and `fdput`, then the refcount cannot hit zero during that time, as the `struct
12585184982SWedson Almeida Filho /// files_struct` holds a reference until the fd is closed. This means that it's safe to access the
12685184982SWedson Almeida Filho /// file even if `fdget` does not increment the refcount.
12785184982SWedson Almeida Filho ///
12885184982SWedson Almeida Filho /// The requirement that the fd is not closed during a light refcount applies globally across all
12985184982SWedson Almeida Filho /// threads - not just on the thread using the light refcount. For this reason, light refcounts are
13085184982SWedson Almeida Filho /// only used when the `struct files_struct` is not shared with other threads, since this ensures
13185184982SWedson Almeida Filho /// that other unrelated threads cannot suddenly start using the fd and close it. Therefore,
13285184982SWedson Almeida Filho /// calling `fdget` on a shared `struct files_struct` creates a normal refcount instead of a light
13385184982SWedson Almeida Filho /// refcount.
13485184982SWedson Almeida Filho ///
13585184982SWedson Almeida Filho /// Light reference counts must be released with `fdput` before the system call returns to
13685184982SWedson Almeida Filho /// userspace. This means that if you wait until the current system call returns to userspace, then
13785184982SWedson Almeida Filho /// all light refcounts that existed at the time have gone away.
13885184982SWedson Almeida Filho ///
13985184982SWedson Almeida Filho /// ### The file position
14085184982SWedson Almeida Filho ///
14185184982SWedson Almeida Filho /// Each `struct file` has a position integer, which is protected by the `f_pos_lock` mutex.
14285184982SWedson Almeida Filho /// However, if the `struct file` is not shared, then the kernel may avoid taking the lock as a
14385184982SWedson Almeida Filho /// performance optimization.
14485184982SWedson Almeida Filho ///
14585184982SWedson Almeida Filho /// The condition for avoiding the `f_pos_lock` mutex is different from the condition for using
14685184982SWedson Almeida Filho /// `fdget`. With `fdget`, you may avoid incrementing the refcount as long as the current fd table
14785184982SWedson Almeida Filho /// is not shared; it is okay if there are other fd tables that also reference the same `struct
14885184982SWedson Almeida Filho /// file`. However, `fdget_pos` can only avoid taking the `f_pos_lock` if the entire `struct file`
14985184982SWedson Almeida Filho /// is not shared, as different processes with an fd to the same `struct file` share the same
15085184982SWedson Almeida Filho /// position.
15185184982SWedson Almeida Filho ///
15285184982SWedson Almeida Filho /// To represent files that are not thread safe due to this optimization, the [`LocalFile`] type is
15385184982SWedson Almeida Filho /// used.
15485184982SWedson Almeida Filho ///
15585184982SWedson Almeida Filho /// ## Rust references
15685184982SWedson Almeida Filho ///
15785184982SWedson Almeida Filho /// The reference type `&File` is similar to light refcounts:
15885184982SWedson Almeida Filho ///
15985184982SWedson Almeida Filho /// * `&File` references don't own a reference count. They can only exist as long as the reference
16085184982SWedson Almeida Filho ///   count stays positive, and can only be created when there is some mechanism in place to ensure
16185184982SWedson Almeida Filho ///   this.
16285184982SWedson Almeida Filho ///
16385184982SWedson Almeida Filho /// * The Rust borrow-checker normally ensures this by enforcing that the `ARef<File>` from which
16485184982SWedson Almeida Filho ///   a `&File` is created outlives the `&File`.
16585184982SWedson Almeida Filho ///
16685184982SWedson Almeida Filho /// * Using the unsafe [`File::from_raw_file`] means that it is up to the caller to ensure that the
16785184982SWedson Almeida Filho ///   `&File` only exists while the reference count is positive.
16885184982SWedson Almeida Filho ///
16985184982SWedson Almeida Filho /// * You can think of `fdget` as using an fd to look up an `ARef<File>` in the `struct
17085184982SWedson Almeida Filho ///   files_struct` and create an `&File` from it. The "fd cannot be closed" rule is like the Rust
17185184982SWedson Almeida Filho ///   rule "the `ARef<File>` must outlive the `&File`".
17285184982SWedson Almeida Filho ///
17385184982SWedson Almeida Filho /// # Invariants
17485184982SWedson Almeida Filho ///
17585184982SWedson Almeida Filho /// * All instances of this type are refcounted using the `f_count` field.
17685184982SWedson Almeida Filho /// * There must not be any active calls to `fdget_pos` on this file that did not take the
17785184982SWedson Almeida Filho ///   `f_pos_lock` mutex.
17885184982SWedson Almeida Filho #[repr(transparent)]
17985184982SWedson Almeida Filho pub struct File {
18085184982SWedson Almeida Filho     inner: Opaque<bindings::file>,
18185184982SWedson Almeida Filho }
18285184982SWedson Almeida Filho 
18385184982SWedson Almeida Filho // SAFETY: This file is known to not have any active `fdget_pos` calls that did not take the
18485184982SWedson Almeida Filho // `f_pos_lock` mutex, so it is safe to transfer it between threads.
18585184982SWedson Almeida Filho unsafe impl Send for File {}
18685184982SWedson Almeida Filho 
18785184982SWedson Almeida Filho // SAFETY: This file is known to not have any active `fdget_pos` calls that did not take the
18885184982SWedson Almeida Filho // `f_pos_lock` mutex, so it is safe to access its methods from several threads in parallel.
18985184982SWedson Almeida Filho unsafe impl Sync for File {}
19085184982SWedson Almeida Filho 
19185184982SWedson Almeida Filho // SAFETY: The type invariants guarantee that `File` is always ref-counted. This implementation
19285184982SWedson Almeida Filho // makes `ARef<File>` own a normal refcount.
19385184982SWedson Almeida Filho unsafe impl AlwaysRefCounted for File {
19485184982SWedson Almeida Filho     #[inline]
inc_ref(&self)19585184982SWedson Almeida Filho     fn inc_ref(&self) {
19685184982SWedson Almeida Filho         // SAFETY: The existence of a shared reference means that the refcount is nonzero.
19785184982SWedson Almeida Filho         unsafe { bindings::get_file(self.as_ptr()) };
19885184982SWedson Almeida Filho     }
19985184982SWedson Almeida Filho 
20085184982SWedson Almeida Filho     #[inline]
dec_ref(obj: ptr::NonNull<File>)20185184982SWedson Almeida Filho     unsafe fn dec_ref(obj: ptr::NonNull<File>) {
20285184982SWedson Almeida Filho         // SAFETY: To call this method, the caller passes us ownership of a normal refcount, so we
20385184982SWedson Almeida Filho         // may drop it. The cast is okay since `File` has the same representation as `struct file`.
20485184982SWedson Almeida Filho         unsafe { bindings::fput(obj.cast().as_ptr()) }
20585184982SWedson Almeida Filho     }
20685184982SWedson Almeida Filho }
20785184982SWedson Almeida Filho 
20885184982SWedson Almeida Filho /// Wraps the kernel's `struct file`. Not thread safe.
20985184982SWedson Almeida Filho ///
21085184982SWedson Almeida Filho /// This type represents a file that is not known to be safe to transfer across thread boundaries.
21185184982SWedson Almeida Filho /// To obtain a thread-safe [`File`], use the [`assume_no_fdget_pos`] conversion.
21285184982SWedson Almeida Filho ///
21385184982SWedson Almeida Filho /// See the documentation for [`File`] for more information.
21485184982SWedson Almeida Filho ///
21585184982SWedson Almeida Filho /// # Invariants
21685184982SWedson Almeida Filho ///
21785184982SWedson Almeida Filho /// * All instances of this type are refcounted using the `f_count` field.
21885184982SWedson Almeida Filho /// * If there is an active call to `fdget_pos` that did not take the `f_pos_lock` mutex, then it
21985184982SWedson Almeida Filho ///   must be on the same thread as this file.
22085184982SWedson Almeida Filho ///
22185184982SWedson Almeida Filho /// [`assume_no_fdget_pos`]: LocalFile::assume_no_fdget_pos
22285184982SWedson Almeida Filho pub struct LocalFile {
22385184982SWedson Almeida Filho     inner: Opaque<bindings::file>,
22485184982SWedson Almeida Filho }
22585184982SWedson Almeida Filho 
22685184982SWedson Almeida Filho // SAFETY: The type invariants guarantee that `LocalFile` is always ref-counted. This implementation
22785184982SWedson Almeida Filho // makes `ARef<File>` own a normal refcount.
22885184982SWedson Almeida Filho unsafe impl AlwaysRefCounted for LocalFile {
22985184982SWedson Almeida Filho     #[inline]
inc_ref(&self)23085184982SWedson Almeida Filho     fn inc_ref(&self) {
23185184982SWedson Almeida Filho         // SAFETY: The existence of a shared reference means that the refcount is nonzero.
23285184982SWedson Almeida Filho         unsafe { bindings::get_file(self.as_ptr()) };
23385184982SWedson Almeida Filho     }
23485184982SWedson Almeida Filho 
23585184982SWedson Almeida Filho     #[inline]
dec_ref(obj: ptr::NonNull<LocalFile>)23685184982SWedson Almeida Filho     unsafe fn dec_ref(obj: ptr::NonNull<LocalFile>) {
23785184982SWedson Almeida Filho         // SAFETY: To call this method, the caller passes us ownership of a normal refcount, so we
23885184982SWedson Almeida Filho         // may drop it. The cast is okay since `File` has the same representation as `struct file`.
23985184982SWedson Almeida Filho         unsafe { bindings::fput(obj.cast().as_ptr()) }
24085184982SWedson Almeida Filho     }
24185184982SWedson Almeida Filho }
24285184982SWedson Almeida Filho 
24385184982SWedson Almeida Filho impl LocalFile {
24485184982SWedson Almeida Filho     /// Constructs a new `struct file` wrapper from a file descriptor.
24585184982SWedson Almeida Filho     ///
24685184982SWedson Almeida Filho     /// The file descriptor belongs to the current process, and there might be active local calls
24785184982SWedson Almeida Filho     /// to `fdget_pos` on the same file.
24885184982SWedson Almeida Filho     ///
24985184982SWedson Almeida Filho     /// To obtain an `ARef<File>`, use the [`assume_no_fdget_pos`] function to convert.
25085184982SWedson Almeida Filho     ///
25185184982SWedson Almeida Filho     /// [`assume_no_fdget_pos`]: LocalFile::assume_no_fdget_pos
25285184982SWedson Almeida Filho     #[inline]
fget(fd: u32) -> Result<ARef<LocalFile>, BadFdError>25385184982SWedson Almeida Filho     pub fn fget(fd: u32) -> Result<ARef<LocalFile>, BadFdError> {
25485184982SWedson Almeida Filho         // SAFETY: FFI call, there are no requirements on `fd`.
25585184982SWedson Almeida Filho         let ptr = ptr::NonNull::new(unsafe { bindings::fget(fd) }).ok_or(BadFdError)?;
25685184982SWedson Almeida Filho 
25785184982SWedson Almeida Filho         // SAFETY: `bindings::fget` created a refcount, and we pass ownership of it to the `ARef`.
25885184982SWedson Almeida Filho         //
25985184982SWedson Almeida Filho         // INVARIANT: This file is in the fd table on this thread, so either all `fdget_pos` calls
26085184982SWedson Almeida Filho         // are on this thread, or the file is shared, in which case `fdget_pos` calls took the
26185184982SWedson Almeida Filho         // `f_pos_lock` mutex.
26285184982SWedson Almeida Filho         Ok(unsafe { ARef::from_raw(ptr.cast()) })
26385184982SWedson Almeida Filho     }
26485184982SWedson Almeida Filho 
26585184982SWedson Almeida Filho     /// Creates a reference to a [`LocalFile`] from a valid pointer.
26685184982SWedson Almeida Filho     ///
26785184982SWedson Almeida Filho     /// # Safety
26885184982SWedson Almeida Filho     ///
26985184982SWedson Almeida Filho     /// * The caller must ensure that `ptr` points at a valid file and that the file's refcount is
27085184982SWedson Almeida Filho     ///   positive for the duration of `'a`.
27185184982SWedson Almeida Filho     /// * The caller must ensure that if there is an active call to `fdget_pos` that did not take
27285184982SWedson Almeida Filho     ///   the `f_pos_lock` mutex, then that call is on the current thread.
27385184982SWedson Almeida Filho     #[inline]
from_raw_file<'a>(ptr: *const bindings::file) -> &'a LocalFile27485184982SWedson Almeida Filho     pub unsafe fn from_raw_file<'a>(ptr: *const bindings::file) -> &'a LocalFile {
27585184982SWedson Almeida Filho         // SAFETY: The caller guarantees that the pointer is not dangling and stays valid for the
27685184982SWedson Almeida Filho         // duration of 'a. The cast is okay because `File` is `repr(transparent)`.
27785184982SWedson Almeida Filho         //
27885184982SWedson Almeida Filho         // INVARIANT: The caller guarantees that there are no problematic `fdget_pos` calls.
27985184982SWedson Almeida Filho         unsafe { &*ptr.cast() }
28085184982SWedson Almeida Filho     }
28185184982SWedson Almeida Filho 
28285184982SWedson Almeida Filho     /// Assume that there are no active `fdget_pos` calls that prevent us from sharing this file.
28385184982SWedson Almeida Filho     ///
28485184982SWedson Almeida Filho     /// This makes it safe to transfer this file to other threads. No checks are performed, and
28585184982SWedson Almeida Filho     /// using it incorrectly may lead to a data race on the file position if the file is shared
28685184982SWedson Almeida Filho     /// with another thread.
28785184982SWedson Almeida Filho     ///
28885184982SWedson Almeida Filho     /// This method is intended to be used together with [`LocalFile::fget`] when the caller knows
28985184982SWedson Almeida Filho     /// statically that there are no `fdget_pos` calls on the current thread. For example, you
29085184982SWedson Almeida Filho     /// might use it when calling `fget` from an ioctl, since ioctls usually do not touch the file
29185184982SWedson Almeida Filho     /// position.
29285184982SWedson Almeida Filho     ///
29385184982SWedson Almeida Filho     /// # Safety
29485184982SWedson Almeida Filho     ///
29585184982SWedson Almeida Filho     /// There must not be any active `fdget_pos` calls on the current thread.
29685184982SWedson Almeida Filho     #[inline]
assume_no_fdget_pos(me: ARef<LocalFile>) -> ARef<File>29785184982SWedson Almeida Filho     pub unsafe fn assume_no_fdget_pos(me: ARef<LocalFile>) -> ARef<File> {
29885184982SWedson Almeida Filho         // INVARIANT: There are no `fdget_pos` calls on the current thread, and by the type
29985184982SWedson Almeida Filho         // invariants, if there is a `fdget_pos` call on another thread, then it took the
30085184982SWedson Almeida Filho         // `f_pos_lock` mutex.
30185184982SWedson Almeida Filho         //
30285184982SWedson Almeida Filho         // SAFETY: `LocalFile` and `File` have the same layout.
30385184982SWedson Almeida Filho         unsafe { ARef::from_raw(ARef::into_raw(me).cast()) }
30485184982SWedson Almeida Filho     }
30585184982SWedson Almeida Filho 
30685184982SWedson Almeida Filho     /// Returns a raw pointer to the inner C struct.
30785184982SWedson Almeida Filho     #[inline]
as_ptr(&self) -> *mut bindings::file30885184982SWedson Almeida Filho     pub fn as_ptr(&self) -> *mut bindings::file {
30985184982SWedson Almeida Filho         self.inner.get()
31085184982SWedson Almeida Filho     }
31185184982SWedson Almeida Filho 
312a3df991dSWedson Almeida Filho     /// Returns the credentials of the task that originally opened the file.
cred(&self) -> &Credential313a3df991dSWedson Almeida Filho     pub fn cred(&self) -> &Credential {
314a3df991dSWedson Almeida Filho         // SAFETY: It's okay to read the `f_cred` field without synchronization because `f_cred` is
315a3df991dSWedson Almeida Filho         // never changed after initialization of the file.
316a3df991dSWedson Almeida Filho         let ptr = unsafe { (*self.as_ptr()).f_cred };
317a3df991dSWedson Almeida Filho 
318a3df991dSWedson Almeida Filho         // SAFETY: The signature of this function ensures that the caller will only access the
319a3df991dSWedson Almeida Filho         // returned credential while the file is still valid, and the C side ensures that the
320a3df991dSWedson Almeida Filho         // credential stays valid at least as long as the file.
321a3df991dSWedson Almeida Filho         unsafe { Credential::from_ptr(ptr) }
322a3df991dSWedson Almeida Filho     }
323a3df991dSWedson Almeida Filho 
32485184982SWedson Almeida Filho     /// Returns the flags associated with the file.
32585184982SWedson Almeida Filho     ///
32685184982SWedson Almeida Filho     /// The flags are a combination of the constants in [`flags`].
32785184982SWedson Almeida Filho     #[inline]
flags(&self) -> u3232885184982SWedson Almeida Filho     pub fn flags(&self) -> u32 {
32985184982SWedson Almeida Filho         // This `read_volatile` is intended to correspond to a READ_ONCE call.
33085184982SWedson Almeida Filho         //
33185184982SWedson Almeida Filho         // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount.
33285184982SWedson Almeida Filho         //
33385184982SWedson Almeida Filho         // FIXME(read_once): Replace with `read_once` when available on the Rust side.
33485184982SWedson Almeida Filho         unsafe { core::ptr::addr_of!((*self.as_ptr()).f_flags).read_volatile() }
33585184982SWedson Almeida Filho     }
33685184982SWedson Almeida Filho }
33785184982SWedson Almeida Filho 
33885184982SWedson Almeida Filho impl File {
33985184982SWedson Almeida Filho     /// Creates a reference to a [`File`] from a valid pointer.
34085184982SWedson Almeida Filho     ///
34185184982SWedson Almeida Filho     /// # Safety
34285184982SWedson Almeida Filho     ///
34385184982SWedson Almeida Filho     /// * The caller must ensure that `ptr` points at a valid file and that the file's refcount is
34485184982SWedson Almeida Filho     ///   positive for the duration of `'a`.
34585184982SWedson Almeida Filho     /// * The caller must ensure that if there are active `fdget_pos` calls on this file, then they
34685184982SWedson Almeida Filho     ///   took the `f_pos_lock` mutex.
34785184982SWedson Almeida Filho     #[inline]
from_raw_file<'a>(ptr: *const bindings::file) -> &'a File34885184982SWedson Almeida Filho     pub unsafe fn from_raw_file<'a>(ptr: *const bindings::file) -> &'a File {
34985184982SWedson Almeida Filho         // SAFETY: The caller guarantees that the pointer is not dangling and stays valid for the
35085184982SWedson Almeida Filho         // duration of 'a. The cast is okay because `File` is `repr(transparent)`.
35185184982SWedson Almeida Filho         //
35285184982SWedson Almeida Filho         // INVARIANT: The caller guarantees that there are no problematic `fdget_pos` calls.
35385184982SWedson Almeida Filho         unsafe { &*ptr.cast() }
35485184982SWedson Almeida Filho     }
35585184982SWedson Almeida Filho }
35685184982SWedson Almeida Filho 
35785184982SWedson Almeida Filho // Make LocalFile methods available on File.
35885184982SWedson Almeida Filho impl core::ops::Deref for File {
35985184982SWedson Almeida Filho     type Target = LocalFile;
36085184982SWedson Almeida Filho     #[inline]
deref(&self) -> &LocalFile36185184982SWedson Almeida Filho     fn deref(&self) -> &LocalFile {
36285184982SWedson Almeida Filho         // SAFETY: The caller provides a `&File`, and since it is a reference, it must point at a
36385184982SWedson Almeida Filho         // valid file for the desired duration.
36485184982SWedson Almeida Filho         //
36585184982SWedson Almeida Filho         // By the type invariants, there are no `fdget_pos` calls that did not take the
36685184982SWedson Almeida Filho         // `f_pos_lock` mutex.
36785184982SWedson Almeida Filho         unsafe { LocalFile::from_raw_file(self as *const File as *const bindings::file) }
36885184982SWedson Almeida Filho     }
36985184982SWedson Almeida Filho }
37085184982SWedson Almeida Filho 
3715da9857bSWedson Almeida Filho /// A file descriptor reservation.
3725da9857bSWedson Almeida Filho ///
3735da9857bSWedson Almeida Filho /// This allows the creation of a file descriptor in two steps: first, we reserve a slot for it,
3745da9857bSWedson Almeida Filho /// then we commit or drop the reservation. The first step may fail (e.g., the current process ran
3755da9857bSWedson Almeida Filho /// out of available slots), but commit and drop never fail (and are mutually exclusive).
3765da9857bSWedson Almeida Filho ///
3775da9857bSWedson Almeida Filho /// Dropping the reservation happens in the destructor of this type.
3785da9857bSWedson Almeida Filho ///
3795da9857bSWedson Almeida Filho /// # Invariants
3805da9857bSWedson Almeida Filho ///
3815da9857bSWedson Almeida Filho /// The fd stored in this struct must correspond to a reserved file descriptor of the current task.
3825da9857bSWedson Almeida Filho pub struct FileDescriptorReservation {
3835da9857bSWedson Almeida Filho     fd: u32,
3845da9857bSWedson Almeida Filho     /// Prevent values of this type from being moved to a different task.
3855da9857bSWedson Almeida Filho     ///
3865da9857bSWedson Almeida Filho     /// The `fd_install` and `put_unused_fd` functions assume that the value of `current` is
3875da9857bSWedson Almeida Filho     /// unchanged since the call to `get_unused_fd_flags`. By adding this marker to this type, we
3885da9857bSWedson Almeida Filho     /// prevent it from being moved across task boundaries, which ensures that `current` does not
3895da9857bSWedson Almeida Filho     /// change while this value exists.
3905da9857bSWedson Almeida Filho     _not_send: NotThreadSafe,
3915da9857bSWedson Almeida Filho }
3925da9857bSWedson Almeida Filho 
3935da9857bSWedson Almeida Filho impl FileDescriptorReservation {
3945da9857bSWedson Almeida Filho     /// Creates a new file descriptor reservation.
395*e27b0e3cSKunwu Chan     #[inline]
get_unused_fd_flags(flags: u32) -> Result<Self>3965da9857bSWedson Almeida Filho     pub fn get_unused_fd_flags(flags: u32) -> Result<Self> {
3975da9857bSWedson Almeida Filho         // SAFETY: FFI call, there are no safety requirements on `flags`.
3985da9857bSWedson Almeida Filho         let fd: i32 = unsafe { bindings::get_unused_fd_flags(flags) };
3995da9857bSWedson Almeida Filho         if fd < 0 {
4005da9857bSWedson Almeida Filho             return Err(Error::from_errno(fd));
4015da9857bSWedson Almeida Filho         }
4025da9857bSWedson Almeida Filho         Ok(Self {
4035da9857bSWedson Almeida Filho             fd: fd as u32,
4045da9857bSWedson Almeida Filho             _not_send: NotThreadSafe,
4055da9857bSWedson Almeida Filho         })
4065da9857bSWedson Almeida Filho     }
4075da9857bSWedson Almeida Filho 
4085da9857bSWedson Almeida Filho     /// Returns the file descriptor number that was reserved.
409*e27b0e3cSKunwu Chan     #[inline]
reserved_fd(&self) -> u324105da9857bSWedson Almeida Filho     pub fn reserved_fd(&self) -> u32 {
4115da9857bSWedson Almeida Filho         self.fd
4125da9857bSWedson Almeida Filho     }
4135da9857bSWedson Almeida Filho 
4145da9857bSWedson Almeida Filho     /// Commits the reservation.
4155da9857bSWedson Almeida Filho     ///
4165da9857bSWedson Almeida Filho     /// The previously reserved file descriptor is bound to `file`. This method consumes the
4175da9857bSWedson Almeida Filho     /// [`FileDescriptorReservation`], so it will not be usable after this call.
418*e27b0e3cSKunwu Chan     #[inline]
fd_install(self, file: ARef<File>)4195da9857bSWedson Almeida Filho     pub fn fd_install(self, file: ARef<File>) {
4205da9857bSWedson Almeida Filho         // SAFETY: `self.fd` was previously returned by `get_unused_fd_flags`. We have not yet used
4215da9857bSWedson Almeida Filho         // the fd, so it is still valid, and `current` still refers to the same task, as this type
4225da9857bSWedson Almeida Filho         // cannot be moved across task boundaries.
4235da9857bSWedson Almeida Filho         //
4245da9857bSWedson Almeida Filho         // Furthermore, the file pointer is guaranteed to own a refcount by its type invariants,
4255da9857bSWedson Almeida Filho         // and we take ownership of that refcount by not running the destructor below.
4265da9857bSWedson Almeida Filho         // Additionally, the file is known to not have any non-shared `fdget_pos` calls, so even if
4275da9857bSWedson Almeida Filho         // this process starts using the file position, this will not result in a data race on the
4285da9857bSWedson Almeida Filho         // file position.
4295da9857bSWedson Almeida Filho         unsafe { bindings::fd_install(self.fd, file.as_ptr()) };
4305da9857bSWedson Almeida Filho 
4315da9857bSWedson Almeida Filho         // `fd_install` consumes both the file descriptor and the file reference, so we cannot run
4325da9857bSWedson Almeida Filho         // the destructors.
4335da9857bSWedson Almeida Filho         core::mem::forget(self);
4345da9857bSWedson Almeida Filho         core::mem::forget(file);
4355da9857bSWedson Almeida Filho     }
4365da9857bSWedson Almeida Filho }
4375da9857bSWedson Almeida Filho 
4385da9857bSWedson Almeida Filho impl Drop for FileDescriptorReservation {
439*e27b0e3cSKunwu Chan     #[inline]
drop(&mut self)4405da9857bSWedson Almeida Filho     fn drop(&mut self) {
4415da9857bSWedson Almeida Filho         // SAFETY: By the type invariants of this type, `self.fd` was previously returned by
4425da9857bSWedson Almeida Filho         // `get_unused_fd_flags`. We have not yet used the fd, so it is still valid, and `current`
4435da9857bSWedson Almeida Filho         // still refers to the same task, as this type cannot be moved across task boundaries.
4445da9857bSWedson Almeida Filho         unsafe { bindings::put_unused_fd(self.fd) };
4455da9857bSWedson Almeida Filho     }
4465da9857bSWedson Almeida Filho }
4475da9857bSWedson Almeida Filho 
44885184982SWedson Almeida Filho /// Represents the `EBADF` error code.
44985184982SWedson Almeida Filho ///
45085184982SWedson Almeida Filho /// Used for methods that can only fail with `EBADF`.
45185184982SWedson Almeida Filho #[derive(Copy, Clone, Eq, PartialEq)]
45285184982SWedson Almeida Filho pub struct BadFdError;
45385184982SWedson Almeida Filho 
45485184982SWedson Almeida Filho impl From<BadFdError> for Error {
45585184982SWedson Almeida Filho     #[inline]
from(_: BadFdError) -> Error45685184982SWedson Almeida Filho     fn from(_: BadFdError) -> Error {
45785184982SWedson Almeida Filho         EBADF
45885184982SWedson Almeida Filho     }
45985184982SWedson Almeida Filho }
46085184982SWedson Almeida Filho 
46185184982SWedson Almeida Filho impl core::fmt::Debug for BadFdError {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result46285184982SWedson Almeida Filho     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
46385184982SWedson Almeida Filho         f.pad("EBADF")
46485184982SWedson Almeida Filho     }
46585184982SWedson Almeida Filho }
466