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