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