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