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