1//! Filesystem-oriented `ioctl` functions.
2
3#![allow(unsafe_code)]
4
5#[cfg(linux_kernel)]
6use {
7 crate::backend::c,
8 crate::fd::AsFd,
9 crate::{backend, ffi, io, ioctl},
10};
11
12use bitflags::bitflags;
13
14#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))]
15use crate::fd::{AsRawFd as _, 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: Getter<_, u32> = ioctl::Getter::<{ c::BLKSSZGET }, c::c_uint>::new();
29 ioctl::ioctl(fd, ioctl: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: Getter<_, u32> = ioctl::Getter::<{ c::BLKPBSZGET }, c::c_uint>::new();
41 ioctl::ioctl(fd, ioctl: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, ioctl: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: Setter<_, u64> = ioctl::Setter::<{ backend::fs::EXT4_IOC_RESIZE_FS }, u64>::new(input:blocks);
68 ioctl::ioctl(fd, ioctl:ctl)
69 }
70}
71
72#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))]
73struct Ficlone<'a>(BorrowedFd<'a>);
74
75#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))]
76unsafe impl ioctl::Ioctl for Ficlone<'_> {
77 type Output = ();
78
79 const IS_MUTATING: bool = false;
80
81 fn opcode(&self) -> ioctl::Opcode {
82 c::FICLONE as ioctl::Opcode
83 }
84
85 fn as_ptr(&mut self) -> *mut c::c_void {
86 self.0.as_raw_fd() as *mut c::c_void
87 }
88
89 unsafe fn output_from_ptr(
90 _: ioctl::IoctlOutput,
91 _: *mut c::c_void,
92 ) -> io::Result<Self::Output> {
93 Ok(())
94 }
95}
96
97#[cfg(linux_kernel)]
98bitflags! {
99 /// `FS_*` constants for use with [`ioctl_getflags`].
100 ///
101 /// [`ioctl_getflags`]: crate::fs::ioctl::ioctl_getflags
102 #[repr(transparent)]
103 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
104 pub struct IFlags: ffi::c_uint {
105 /// `FS_APPEND_FL`
106 const APPEND = linux_raw_sys::general::FS_APPEND_FL;
107 /// `FS_COMPR_FL`
108 const COMPRESSED = linux_raw_sys::general::FS_COMPR_FL;
109 /// `FS_DIRSYNC_FL`
110 const DIRSYNC = linux_raw_sys::general::FS_DIRSYNC_FL;
111 /// `FS_IMMUTABLE_FL`
112 const IMMUTABLE = linux_raw_sys::general::FS_IMMUTABLE_FL;
113 /// `FS_JOURNAL_DATA_FL`
114 const JOURNALING = linux_raw_sys::general::FS_JOURNAL_DATA_FL;
115 /// `FS_NOATIME_FL`
116 const NOATIME = linux_raw_sys::general::FS_NOATIME_FL;
117 /// `FS_NOCOW_FL`
118 const NOCOW = linux_raw_sys::general::FS_NOCOW_FL;
119 /// `FS_NODUMP_FL`
120 const NODUMP = linux_raw_sys::general::FS_NODUMP_FL;
121 /// `FS_NOTAIL_FL`
122 const NOTAIL = linux_raw_sys::general::FS_NOTAIL_FL;
123 /// `FS_PROJINHERIT_FL`
124 const PROJECT_INHERIT = linux_raw_sys::general::FS_PROJINHERIT_FL;
125 /// `FS_SECRM_FL`
126 const SECURE_REMOVAL = linux_raw_sys::general::FS_SECRM_FL;
127 /// `FS_SYNC_FL`
128 const SYNC = linux_raw_sys::general::FS_SYNC_FL;
129 /// `FS_TOPDIR_FL`
130 const TOPDIR = linux_raw_sys::general::FS_TOPDIR_FL;
131 /// `FS_UNRM_FL`
132 const UNRM = linux_raw_sys::general::FS_UNRM_FL;
133 }
134}
135
136/// `ioctl(fd, FS_IOC_GETFLAGS)`—Returns the [inode flags] attributes
137///
138/// [inode flags]: https://man7.org/linux/man-pages/man2/ioctl_iflags.2.html
139#[cfg(linux_kernel)]
140#[inline]
141#[doc(alias = "FS_IOC_GETFLAGS")]
142pub fn ioctl_getflags<Fd: AsFd>(fd: Fd) -> io::Result<IFlags> {
143 unsafe {
144 #[cfg(target_pointer_width = "32")]
145 let ctl = ioctl::Getter::<{ c::FS_IOC32_GETFLAGS }, u32>::new();
146 #[cfg(target_pointer_width = "64")]
147 let ctl: Getter<_, u32> = ioctl::Getter::<{ c::FS_IOC_GETFLAGS }, u32>::new();
148
149 ioctl::ioctl(fd, ctl).map(op:IFlags::from_bits_retain)
150 }
151}
152
153/// `ioctl(fd, FS_IOC_SETFLAGS)`—Modify the [inode flags] attributes
154///
155/// [inode flags]: https://man7.org/linux/man-pages/man2/ioctl_iflags.2.html
156#[cfg(linux_kernel)]
157#[inline]
158#[doc(alias = "FS_IOC_SETFLAGS")]
159pub fn ioctl_setflags<Fd: AsFd>(fd: Fd, flags: IFlags) -> io::Result<()> {
160 unsafe {
161 #[cfg(target_pointer_width = "32")]
162 let ctl = ioctl::Setter::<{ c::FS_IOC32_SETFLAGS }, u32>::new(flags.bits());
163
164 #[cfg(target_pointer_width = "64")]
165 let ctl: Setter<_, u32> = ioctl::Setter::<{ c::FS_IOC_SETFLAGS }, u32>::new(input:flags.bits());
166
167 ioctl::ioctl(fd, ioctl:ctl)
168 }
169}
170