1 | //! Functions which operate on file descriptors. |
2 | |
3 | #[cfg (not(target_os = "wasi" ))] |
4 | use crate::fs::Mode; |
5 | use crate::fs::{OFlags, Timespec}; |
6 | use crate::io::SeekFrom; |
7 | #[cfg (not(target_os = "wasi" ))] |
8 | use crate::process::{Gid, Uid}; |
9 | use crate::{backend, io}; |
10 | use backend::fd::{AsFd, BorrowedFd}; |
11 | |
12 | #[cfg (not(target_os = "wasi" ))] |
13 | pub 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 | )))] |
22 | pub use backend::fs::types::FallocateFlags; |
23 | |
24 | pub 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 | )))] |
33 | pub use backend::fs::types::StatFs; |
34 | |
35 | #[cfg (not(any(target_os = "haiku" , target_os = "redox" , target_os = "wasi" )))] |
36 | pub use backend::fs::types::{StatVfs, StatVfsMountFlags}; |
37 | |
38 | #[cfg (linux_kernel)] |
39 | pub 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)] |
49 | pub 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)] |
63 | pub 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)] |
71 | pub 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" )] |
83 | pub 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" )] |
101 | pub 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 ] |
118 | pub 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 ] |
132 | pub 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 ] |
150 | pub 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 ] |
171 | pub 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 ] |
191 | pub 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 ] |
204 | pub 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" )] |
232 | pub 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 ] |
243 | pub fn is_file_read_write<Fd: AsFd>(fd: Fd) -> io::Result<(bool, bool)> { |
244 | _is_file_read_write(fd.as_fd()) |
245 | } |
246 | |
247 | pub(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 ] |
280 | pub 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 ] |
300 | pub 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 ] |
313 | pub 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 ] |
325 | pub 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 ] |
337 | pub fn syncfs<Fd: AsFd>(fd: Fd) -> io::Result<()> { |
338 | backend::fs::syscalls::syncfs(fd.as_fd()) |
339 | } |
340 | |