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 | target_os = "dragonfly" , |
13 | target_os = "espidf" , |
14 | target_os = "nto" , |
15 | target_os = "redox" , |
16 | target_os = "vita" , |
17 | )))] |
18 | use 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 | )))] |
25 | use backend::fs::types::FlockOperation; |
26 | #[cfg (linux_kernel)] |
27 | use backend::fs::types::FsWord; |
28 | use 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 | )))] |
39 | use backend::fs::types::StatFs; |
40 | #[cfg (not(any(target_os = "haiku" , target_os = "redox" , target_os = "wasi" )))] |
41 | use backend::fs::types::StatVfs; |
42 | use 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)] |
52 | pub 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 | impl fmt::Debug for Timestamps { |
61 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
62 | f&mut DebugStruct<'_, '_>.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(name:"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)] |
77 | pub 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)] |
85 | pub 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" )] |
97 | pub 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" )] |
115 | pub 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 ] |
132 | pub 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 ] |
146 | pub 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 ] |
164 | pub 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 ] |
188 | pub 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 ] |
208 | pub 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 ] |
222 | pub 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" )] |
251 | pub 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 ] |
262 | pub fn is_file_read_write<Fd: AsFd>(fd: Fd) -> io::Result<(bool, bool)> { |
263 | _is_file_read_write(fd.as_fd()) |
264 | } |
265 | |
266 | pub(crate) fn _is_file_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { |
267 | let mode: OFlags = 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 ] |
299 | pub 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 ] |
321 | pub 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 ] |
334 | pub 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 ] |
351 | pub 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 ] |
363 | pub fn syncfs<Fd: AsFd>(fd: Fd) -> io::Result<()> { |
364 | backend::fs::syscalls::syncfs(fd.as_fd()) |
365 | } |
366 | |