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