rustix/fs/fd.rs
1//! Functions which operate on file descriptors.
2
3#[cfg(not(target_os = "wasi"))]
4use crate::fs::Mode;
5#[cfg(not(target_os = "wasi"))]
6use crate::fs::{Gid, Uid};
7use crate::fs::{OFlags, SeekFrom, Timespec};
8use crate::{backend, io};
9use backend::fd::{AsFd, BorrowedFd};
10#[cfg(not(any(
11 netbsdlike,
12 target_os = "dragonfly",
13 target_os = "espidf",
14 target_os = "nto",
15 target_os = "redox",
16 target_os = "vita",
17)))]
18use backend::fs::types::FallocateFlags;
19#[cfg(not(any(
20 target_os = "espidf",
21 target_os = "solaris",
22 target_os = "vita",
23 target_os = "wasi"
24)))]
25use backend::fs::types::FlockOperation;
26#[cfg(linux_kernel)]
27use backend::fs::types::FsWord;
28use backend::fs::types::Stat;
29#[cfg(not(any(
30 solarish,
31 target_os = "espidf",
32 target_os = "haiku",
33 target_os = "netbsd",
34 target_os = "nto",
35 target_os = "redox",
36 target_os = "vita",
37 target_os = "wasi",
38)))]
39use backend::fs::types::StatFs;
40#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
41use backend::fs::types::StatVfs;
42use core::fmt;
43
44/// Timestamps used by [`utimensat`] and [`futimens`].
45///
46/// [`utimensat`]: crate::fs::utimensat
47/// [`futimens`]: crate::fs::futimens
48// This is `repr(C)` and specifically laid out to match the representation used
49// by `utimensat` and `futimens`, which expect 2-element arrays of timestamps.
50#[repr(C)]
51#[derive(Clone)]
52pub struct Timestamps {
53 /// The timestamp of the last access to a filesystem object.
54 pub last_access: Timespec,
55
56 /// The timestamp of the last modification of a filesystem object.
57 pub last_modification: Timespec,
58}
59
60impl fmt::Debug for Timestamps {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 f.debug_struct("Timestamps")
63 .field("last_access.tv_sec", &self.last_access.tv_sec)
64 .field("last_access.tv_nsec", &self.last_access.tv_nsec)
65 .field("last_modification.tv_sec", &self.last_modification.tv_sec)
66 .field("last_modification.tv_nsec", &self.last_modification.tv_nsec)
67 .finish()
68 }
69}
70
71/// The filesystem magic number for procfs.
72///
73/// See [the `fstatfs` manual page] for more information.
74///
75/// [the `fstatfs` manual page]: https://man7.org/linux/man-pages/man2/fstatfs.2.html#DESCRIPTION
76#[cfg(linux_kernel)]
77pub const PROC_SUPER_MAGIC: FsWord = backend::c::PROC_SUPER_MAGIC as FsWord;
78
79/// The filesystem magic number for NFS.
80///
81/// See [the `fstatfs` manual page] for more information.
82///
83/// [the `fstatfs` manual page]: https://man7.org/linux/man-pages/man2/fstatfs.2.html#DESCRIPTION
84#[cfg(linux_kernel)]
85pub const NFS_SUPER_MAGIC: FsWord = backend::c::NFS_SUPER_MAGIC as FsWord;
86
87/// `lseek(fd, offset, whence)`—Repositions a file descriptor within a file.
88///
89/// # References
90/// - [POSIX]
91/// - [Linux]
92///
93/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/lseek.html
94/// [Linux]: https://man7.org/linux/man-pages/man2/lseek.2.html
95#[inline]
96#[doc(alias = "lseek")]
97pub fn seek<Fd: AsFd>(fd: Fd, pos: SeekFrom) -> io::Result<u64> {
98 backend::fs::syscalls::seek(fd.as_fd(), pos)
99}
100
101/// `lseek(fd, 0, SEEK_CUR)`—Returns the current position within a file.
102///
103/// Return the current position of the file descriptor. This is a subset of
104/// the functionality of `seek`, but this interface makes it easier for users
105/// to declare their intent not to mutate any state.
106///
107/// # References
108/// - [POSIX]
109/// - [Linux]
110///
111/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/lseek.html
112/// [Linux]: https://man7.org/linux/man-pages/man2/lseek.2.html
113#[inline]
114#[doc(alias = "lseek")]
115pub fn tell<Fd: AsFd>(fd: Fd) -> io::Result<u64> {
116 backend::fs::syscalls::tell(fd.as_fd())
117}
118
119/// `fchmod(fd, mode)`—Sets open file or directory permissions.
120///
121/// This implementation does not support [`OFlags::PATH`] file descriptors,
122/// even on platforms where the host libc emulates it.
123///
124/// # References
125/// - [POSIX]
126/// - [Linux]
127///
128/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fchmod.html
129/// [Linux]: https://man7.org/linux/man-pages/man2/fchmod.2.html
130#[cfg(not(target_os = "wasi"))]
131#[inline]
132pub fn fchmod<Fd: AsFd>(fd: Fd, mode: Mode) -> io::Result<()> {
133 backend::fs::syscalls::fchmod(fd.as_fd(), mode)
134}
135
136/// `fchown(fd, owner, group)`—Sets open file or directory ownership.
137///
138/// # References
139/// - [POSIX]
140/// - [Linux]
141///
142/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fchown.html
143/// [Linux]: https://man7.org/linux/man-pages/man2/fchown.2.html
144#[cfg(not(target_os = "wasi"))]
145#[inline]
146pub fn fchown<Fd: AsFd>(fd: Fd, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> {
147 backend::fs::syscalls::fchown(fd.as_fd(), owner, group)
148}
149
150/// `fstat(fd)`—Queries metadata for an open file or directory.
151///
152/// [`Mode::from_raw_mode`] and [`FileType::from_raw_mode`] may be used to
153/// interpret the `st_mode` field.
154///
155/// # References
156/// - [POSIX]
157/// - [Linux]
158///
159/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fstat.html
160/// [Linux]: https://man7.org/linux/man-pages/man2/fstat.2.html
161/// [`Mode::from_raw_mode`]: Mode::from_raw_mode
162/// [`FileType::from_raw_mode`]: crate::fs::FileType::from_raw_mode
163#[inline]
164pub fn fstat<Fd: AsFd>(fd: Fd) -> io::Result<Stat> {
165 backend::fs::syscalls::fstat(fd.as_fd())
166}
167
168/// `fstatfs(fd)`—Queries filesystem statistics for an open file or directory.
169///
170/// Compared to [`fstatvfs`], this function often provides more information,
171/// though it's less portable.
172///
173/// # References
174/// - [Linux]
175///
176/// [Linux]: https://man7.org/linux/man-pages/man2/fstatfs.2.html
177#[cfg(not(any(
178 solarish,
179 target_os = "espidf",
180 target_os = "haiku",
181 target_os = "netbsd",
182 target_os = "nto",
183 target_os = "redox",
184 target_os = "vita",
185 target_os = "wasi",
186)))]
187#[inline]
188pub fn fstatfs<Fd: AsFd>(fd: Fd) -> io::Result<StatFs> {
189 backend::fs::syscalls::fstatfs(fd.as_fd())
190}
191
192/// `fstatvfs(fd)`—Queries filesystem statistics for an open file or
193/// directory, POSIX version.
194///
195/// Compared to [`fstatfs`], this function often provides less information,
196/// but it is more portable. But even so, filesystems are very diverse and not
197/// all the fields are meaningful for every filesystem. And `f_fsid` doesn't
198/// seem to have a clear meaning anywhere.
199///
200/// # References
201/// - [POSIX]
202/// - [Linux]
203///
204/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fstatvfs.html
205/// [Linux]: https://man7.org/linux/man-pages/man2/fstatvfs.2.html
206#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
207#[inline]
208pub fn fstatvfs<Fd: AsFd>(fd: Fd) -> io::Result<StatVfs> {
209 backend::fs::syscalls::fstatvfs(fd.as_fd())
210}
211
212/// `futimens(fd, times)`—Sets timestamps for an open file or directory.
213///
214/// # References
215/// - [POSIX]
216/// - [Linux]
217///
218/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/futimens.html
219/// [Linux]: https://man7.org/linux/man-pages/man2/utimensat.2.html
220#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
221#[inline]
222pub fn futimens<Fd: AsFd>(fd: Fd, times: &Timestamps) -> io::Result<()> {
223 backend::fs::syscalls::futimens(fd.as_fd(), times)
224}
225
226/// `fallocate(fd, mode, offset, len)`—Adjusts file allocation.
227///
228/// This is a more general form of `posix_fallocate`, adding a `mode` argument
229/// which modifies the behavior. On platforms which only support
230/// `posix_fallocate` and not the more general form, no `FallocateFlags` values
231/// are defined so it will always be empty.
232///
233/// # References
234/// - [POSIX]
235/// - [Linux `fallocate`]
236/// - [Linux `posix_fallocate`]
237///
238/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_fallocate.html
239/// [Linux `fallocate`]: https://man7.org/linux/man-pages/man2/fallocate.2.html
240/// [Linux `posix_fallocate`]: https://man7.org/linux/man-pages/man3/posix_fallocate.3.html
241#[cfg(not(any(
242 netbsdlike,
243 target_os = "dragonfly",
244 target_os = "espidf",
245 target_os = "nto",
246 target_os = "redox",
247 target_os = "vita",
248)))] // not implemented in libc for netbsd yet
249#[inline]
250#[doc(alias = "posix_fallocate")]
251pub fn fallocate<Fd: AsFd>(fd: Fd, mode: FallocateFlags, offset: u64, len: u64) -> io::Result<()> {
252 backend::fs::syscalls::fallocate(fd.as_fd(), mode, offset, len)
253}
254
255/// `fcntl(fd, F_GETFL) & O_ACCMODE`
256///
257/// Returns a pair of booleans indicating whether the file descriptor is
258/// readable and/or writable, respectively. This is only reliable on files; for
259/// example, it doesn't reflect whether sockets have been shut down; for
260/// general I/O handle support, use [`io::is_read_write`].
261#[inline]
262pub fn is_file_read_write<Fd: AsFd>(fd: Fd) -> io::Result<(bool, bool)> {
263 _is_file_read_write(fd.as_fd())
264}
265
266pub(crate) fn _is_file_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> {
267 let mode = backend::fs::syscalls::fcntl_getfl(fd)?;
268
269 // Check for `O_PATH`.
270 #[cfg(any(linux_kernel, target_os = "emscripten", target_os = "fuchsia"))]
271 if mode.contains(OFlags::PATH) {
272 return Ok((false, false));
273 }
274
275 // Use `RWMODE` rather than `ACCMODE` as `ACCMODE` may include `O_PATH`.
276 // We handled `O_PATH` above.
277 match mode & OFlags::RWMODE {
278 OFlags::RDONLY => Ok((true, false)),
279 OFlags::RDWR => Ok((true, true)),
280 OFlags::WRONLY => Ok((false, true)),
281 _ => unreachable!(),
282 }
283}
284
285/// `fsync(fd)`—Ensures that file data and metadata is written to the
286/// underlying storage device.
287///
288/// On iOS and macOS this isn't sufficient to ensure that data has reached
289/// persistent storage; use [`fcntl_fullfsync`] to ensure that.
290///
291/// # References
292/// - [POSIX]
293/// - [Linux]
294///
295/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fsync.html
296/// [Linux]: https://man7.org/linux/man-pages/man2/fsync.2.html
297/// [`fcntl_fullfsync`]: https://docs.rs/rustix/*/x86_64-apple-darwin/rustix/fs/fn.fcntl_fullfsync.html
298#[inline]
299pub fn fsync<Fd: AsFd>(fd: Fd) -> io::Result<()> {
300 backend::fs::syscalls::fsync(fd.as_fd())
301}
302
303/// `fdatasync(fd)`—Ensures that file data is written to the underlying
304/// storage device.
305///
306/// # References
307/// - [POSIX]
308/// - [Linux]
309///
310/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fdatasync.html
311/// [Linux]: https://man7.org/linux/man-pages/man2/fdatasync.2.html
312#[cfg(not(any(
313 apple,
314 target_os = "dragonfly",
315 target_os = "espidf",
316 target_os = "haiku",
317 target_os = "redox",
318 target_os = "vita",
319)))]
320#[inline]
321pub fn fdatasync<Fd: AsFd>(fd: Fd) -> io::Result<()> {
322 backend::fs::syscalls::fdatasync(fd.as_fd())
323}
324
325/// `ftruncate(fd, length)`—Sets the length of a file.
326///
327/// # References
328/// - [POSIX]
329/// - [Linux]
330///
331/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/ftruncate.html
332/// [Linux]: https://man7.org/linux/man-pages/man2/ftruncate.2.html
333#[inline]
334pub fn ftruncate<Fd: AsFd>(fd: Fd, length: u64) -> io::Result<()> {
335 backend::fs::syscalls::ftruncate(fd.as_fd(), length)
336}
337
338/// `flock(fd, operation)`—Acquire or release an advisory lock on an open file.
339///
340/// # References
341/// - [Linux]
342///
343/// [Linux]: https://man7.org/linux/man-pages/man2/flock.2.html
344#[cfg(not(any(
345 target_os = "espidf",
346 target_os = "solaris",
347 target_os = "vita",
348 target_os = "wasi"
349)))]
350#[inline]
351pub fn flock<Fd: AsFd>(fd: Fd, operation: FlockOperation) -> io::Result<()> {
352 backend::fs::syscalls::flock(fd.as_fd(), operation)
353}
354
355/// `syncfs(fd)`—Flush cached filesystem data.
356///
357/// # References
358/// - [Linux]
359///
360/// [Linux]: https://man7.org/linux/man-pages/man2/syncfs.2.html
361#[cfg(linux_kernel)]
362#[inline]
363pub fn syncfs<Fd: AsFd>(fd: Fd) -> io::Result<()> {
364 backend::fs::syscalls::syncfs(fd.as_fd())
365}