rustix/fs/
ioctl.rs

1//! Filesystem-oriented `ioctl` functions.
2
3#![allow(unsafe_code)]
4
5#[cfg(linux_kernel)]
6use {
7    crate::fd::AsFd,
8    crate::{backend, io, ioctl},
9    backend::c,
10};
11
12use bitflags::bitflags;
13
14#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))]
15use crate::fd::{AsRawFd, BorrowedFd};
16
17/// `ioctl(fd, BLKSSZGET)`—Returns the logical block size of a block device.
18///
19/// This is mentioned in the [Linux `openat` manual page].
20///
21/// [Linux `openat` manual page]: https://man7.org/linux/man-pages/man2/openat.2.html
22#[cfg(linux_kernel)]
23#[inline]
24#[doc(alias = "BLKSSZGET")]
25pub fn ioctl_blksszget<Fd: AsFd>(fd: Fd) -> io::Result<u32> {
26    // SAFETY: `BLZSSZGET` is a getter opcode that gets a u32.
27    unsafe {
28        let ctl = ioctl::Getter::<ioctl::BadOpcode<{ c::BLKSSZGET }>, c::c_uint>::new();
29        ioctl::ioctl(fd, ctl)
30    }
31}
32
33/// `ioctl(fd, BLKPBSZGET)`—Returns the physical block size of a block device.
34#[cfg(linux_kernel)]
35#[inline]
36#[doc(alias = "BLKPBSZGET")]
37pub fn ioctl_blkpbszget<Fd: AsFd>(fd: Fd) -> io::Result<u32> {
38    // SAFETY: `BLKPBSZGET` is a getter opcode that gets a u32.
39    unsafe {
40        let ctl = ioctl::Getter::<ioctl::BadOpcode<{ c::BLKPBSZGET }>, c::c_uint>::new();
41        ioctl::ioctl(fd, ctl)
42    }
43}
44
45/// `ioctl(fd, FICLONE, src_fd)`—Share data between open files.
46///
47/// This ioctl is not available on SPARC platforms.
48///
49/// # References
50///  - [Linux]
51///
52/// [Linux]: https://man7.org/linux/man-pages/man2/ioctl_ficlone.2.html
53#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))]
54#[inline]
55#[doc(alias = "FICLONE")]
56pub fn ioctl_ficlone<Fd: AsFd, SrcFd: AsFd>(fd: Fd, src_fd: SrcFd) -> io::Result<()> {
57    unsafe { ioctl::ioctl(fd, Ficlone(src_fd.as_fd())) }
58}
59
60/// `ioctl(fd, EXT4_IOC_RESIZE_FS, blocks)`—Resize ext4 filesystem on fd.
61#[cfg(linux_kernel)]
62#[inline]
63#[doc(alias = "EXT4_IOC_RESIZE_FS")]
64pub fn ext4_ioc_resize_fs<Fd: AsFd>(fd: Fd, blocks: u64) -> io::Result<()> {
65    // SAFETY: `EXT4_IOC_RESIZE_FS` is a pointer setter opcode.
66    unsafe {
67        let ctl = ioctl::Setter::<ioctl::BadOpcode<{ backend::fs::EXT4_IOC_RESIZE_FS }>, u64>::new(
68            blocks,
69        );
70        ioctl::ioctl(fd, ctl)
71    }
72}
73
74#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))]
75struct Ficlone<'a>(BorrowedFd<'a>);
76
77#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))]
78unsafe impl ioctl::Ioctl for Ficlone<'_> {
79    type Output = ();
80
81    const IS_MUTATING: bool = false;
82    const OPCODE: ioctl::Opcode = ioctl::Opcode::old(c::FICLONE as ioctl::RawOpcode);
83
84    fn as_ptr(&mut self) -> *mut c::c_void {
85        self.0.as_raw_fd() as *mut c::c_void
86    }
87
88    unsafe fn output_from_ptr(
89        _: ioctl::IoctlOutput,
90        _: *mut c::c_void,
91    ) -> io::Result<Self::Output> {
92        Ok(())
93    }
94}
95
96#[cfg(linux_kernel)]
97bitflags! {
98    /// `FS_*` constants for use with [`ioctl_getflags`].
99    ///
100    /// [`ioctl_getflags`]: crate::fs::ioctl::ioctl_getflags
101    pub struct IFlags: c::c_uint {
102        /// `FS_APPEND_FL`
103        const APPEND = linux_raw_sys::general::FS_APPEND_FL;
104        /// `FS_COMPR_FL`
105        const COMPRESSED = linux_raw_sys::general::FS_COMPR_FL;
106        /// `FS_DIRSYNC_FL`
107        const DIRSYNC = linux_raw_sys::general::FS_DIRSYNC_FL;
108        /// `FS_IMMUTABLE_FL`
109        const IMMUTABLE = linux_raw_sys::general::FS_IMMUTABLE_FL;
110        /// `FS_JOURNAL_DATA_FL`
111        const JOURNALING = linux_raw_sys::general::FS_JOURNAL_DATA_FL;
112        /// `FS_NOATIME_FL`
113        const NOATIME = linux_raw_sys::general::FS_NOATIME_FL;
114        /// `FS_NOCOW_FL`
115        const NOCOW = linux_raw_sys::general::FS_NOCOW_FL;
116        /// `FS_NODUMP_FL`
117        const NODUMP = linux_raw_sys::general::FS_NODUMP_FL;
118        /// `FS_NOTAIL_FL`
119        const NOTAIL = linux_raw_sys::general::FS_NOTAIL_FL;
120        /// `FS_PROJINHERIT_FL`
121        const PROJECT_INHERIT = linux_raw_sys::general::FS_PROJINHERIT_FL;
122        /// `FS_SECRM_FL`
123        const SECURE_REMOVAL = linux_raw_sys::general::FS_SECRM_FL;
124        /// `FS_SYNC_FL`
125        const SYNC = linux_raw_sys::general::FS_SYNC_FL;
126        /// `FS_TOPDIR_FL`
127        const TOPDIR = linux_raw_sys::general::FS_TOPDIR_FL;
128        /// `FS_UNRM_FL`
129        const UNRM = linux_raw_sys::general::FS_UNRM_FL;
130    }
131}
132
133/// `ioctl(fd, FS_IOC_GETFLAGS)`—Returns the [inode flags] attributes
134///
135/// [inode flags]: https://man7.org/linux/man-pages/man2/ioctl_iflags.2.html
136#[cfg(linux_kernel)]
137#[inline]
138#[doc(alias = "FS_IOC_GETFLAGS")]
139pub fn ioctl_getflags<Fd: AsFd>(fd: Fd) -> io::Result<IFlags> {
140    unsafe {
141        #[cfg(target_pointer_width = "32")]
142        let ctl = ioctl::Getter::<ioctl::BadOpcode<{ c::FS_IOC32_GETFLAGS }>, u32>::new();
143        #[cfg(target_pointer_width = "64")]
144        let ctl = ioctl::Getter::<ioctl::BadOpcode<{ c::FS_IOC_GETFLAGS }>, u32>::new();
145
146        ioctl::ioctl(fd, ctl).map(IFlags::from_bits_retain)
147    }
148}
149
150/// `ioctl(fd, FS_IOC_SETFLAGS)`—Modify the [inode flags] attributes
151///
152/// [inode flags]: https://man7.org/linux/man-pages/man2/ioctl_iflags.2.html
153#[cfg(linux_kernel)]
154#[inline]
155#[doc(alias = "FS_IOC_SETFLAGS")]
156pub fn ioctl_setflags<Fd: AsFd>(fd: Fd, flags: IFlags) -> io::Result<()> {
157    unsafe {
158        #[cfg(target_pointer_width = "32")]
159        let ctl =
160            ioctl::Setter::<ioctl::BadOpcode<{ c::FS_IOC32_SETFLAGS }>, u32>::new(flags.bits());
161
162        #[cfg(target_pointer_width = "64")]
163        let ctl = ioctl::Setter::<ioctl::BadOpcode<{ c::FS_IOC_SETFLAGS }>, u32>::new(flags.bits());
164
165        ioctl::ioctl(fd, ctl)
166    }
167}