blob: 1581d3a702d792e1c2ed687c6e439ad8185c36cc [file] [log] [blame]
Andrew Walbran12f61402020-10-14 11:10:53 +01001use crate::errno::Errno;
2use libc::{self, c_char, c_int, c_uint, size_t, ssize_t};
3use std::ffi::OsString;
4#[cfg(not(target_os = "redox"))]
5use std::os::raw;
6use std::os::unix::ffi::OsStringExt;
7use std::os::unix::io::RawFd;
8use crate::sys::stat::Mode;
9use crate::{NixPath, Result};
10
11#[cfg(any(target_os = "android", target_os = "linux"))]
12use std::ptr; // For splice and copy_file_range
13#[cfg(any(target_os = "android", target_os = "linux"))]
14use crate::sys::uio::IoVec; // For vmsplice
15
16#[cfg(any(
17 target_os = "linux",
18 target_os = "android",
19 target_os = "emscripten",
20 target_os = "fuchsia",
21 any(target_os = "wasi", target_env = "wasi"),
22 target_env = "uclibc",
23 target_env = "freebsd"
24))]
25pub use self::posix_fadvise::*;
26
27#[cfg(not(target_os = "redox"))]
28libc_bitflags! {
29 pub struct AtFlags: c_int {
30 AT_REMOVEDIR;
31 AT_SYMLINK_FOLLOW;
32 AT_SYMLINK_NOFOLLOW;
33 #[cfg(any(target_os = "android", target_os = "linux"))]
34 AT_NO_AUTOMOUNT;
35 #[cfg(any(target_os = "android", target_os = "linux"))]
36 AT_EMPTY_PATH;
37 }
38}
39
40libc_bitflags!(
41 /// Configuration options for opened files.
42 pub struct OFlag: c_int {
43 /// Mask for the access mode of the file.
44 O_ACCMODE;
45 /// Use alternate I/O semantics.
46 #[cfg(target_os = "netbsd")]
47 O_ALT_IO;
48 /// Open the file in append-only mode.
49 O_APPEND;
50 /// Generate a signal when input or output becomes possible.
51 O_ASYNC;
52 /// Closes the file descriptor once an `execve` call is made.
53 ///
54 /// Also sets the file offset to the beginning of the file.
55 O_CLOEXEC;
56 /// Create the file if it does not exist.
57 O_CREAT;
58 /// Try to minimize cache effects of the I/O for this file.
59 #[cfg(any(target_os = "android",
60 target_os = "dragonfly",
61 target_os = "freebsd",
62 target_os = "linux",
63 target_os = "netbsd"))]
64 O_DIRECT;
65 /// If the specified path isn't a directory, fail.
66 O_DIRECTORY;
67 /// Implicitly follow each `write()` with an `fdatasync()`.
68 #[cfg(any(target_os = "android",
69 target_os = "ios",
70 target_os = "linux",
71 target_os = "macos",
72 target_os = "netbsd",
73 target_os = "openbsd"))]
74 O_DSYNC;
75 /// Error out if a file was not created.
76 O_EXCL;
77 /// Open for execute only.
78 #[cfg(target_os = "freebsd")]
79 O_EXEC;
80 /// Open with an exclusive file lock.
81 #[cfg(any(target_os = "dragonfly",
82 target_os = "freebsd",
83 target_os = "ios",
84 target_os = "macos",
85 target_os = "netbsd",
86 target_os = "openbsd",
87 target_os = "redox"))]
88 O_EXLOCK;
89 /// Same as `O_SYNC`.
90 #[cfg(any(target_os = "dragonfly",
91 target_os = "freebsd",
92 target_os = "ios",
93 all(target_os = "linux", not(target_env = "musl")),
94 target_os = "macos",
95 target_os = "netbsd",
96 target_os = "openbsd",
97 target_os = "redox"))]
98 O_FSYNC;
99 /// Allow files whose sizes can't be represented in an `off_t` to be opened.
100 #[cfg(any(target_os = "android", target_os = "linux"))]
101 O_LARGEFILE;
102 /// Do not update the file last access time during `read(2)`s.
103 #[cfg(any(target_os = "android", target_os = "linux"))]
104 O_NOATIME;
105 /// Don't attach the device as the process' controlling terminal.
106 #[cfg(not(target_os = "redox"))]
107 O_NOCTTY;
108 /// Same as `O_NONBLOCK`.
109 #[cfg(not(target_os = "redox"))]
110 O_NDELAY;
111 /// `open()` will fail if the given path is a symbolic link.
112 O_NOFOLLOW;
113 /// When possible, open the file in nonblocking mode.
114 O_NONBLOCK;
115 /// Don't deliver `SIGPIPE`.
116 #[cfg(target_os = "netbsd")]
117 O_NOSIGPIPE;
118 /// Obtain a file descriptor for low-level access.
119 ///
120 /// The file itself is not opened and other file operations will fail.
121 #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
122 O_PATH;
123 /// Only allow reading.
124 ///
125 /// This should not be combined with `O_WRONLY` or `O_RDWR`.
126 O_RDONLY;
127 /// Allow both reading and writing.
128 ///
129 /// This should not be combined with `O_WRONLY` or `O_RDONLY`.
130 O_RDWR;
131 /// Similar to `O_DSYNC` but applies to `read`s instead.
132 #[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
133 O_RSYNC;
134 /// Skip search permission checks.
135 #[cfg(target_os = "netbsd")]
136 O_SEARCH;
137 /// Open with a shared file lock.
138 #[cfg(any(target_os = "dragonfly",
139 target_os = "freebsd",
140 target_os = "ios",
141 target_os = "macos",
142 target_os = "netbsd",
143 target_os = "openbsd",
144 target_os = "redox"))]
145 O_SHLOCK;
146 /// Implicitly follow each `write()` with an `fsync()`.
147 #[cfg(not(target_os = "redox"))]
148 O_SYNC;
149 /// Create an unnamed temporary file.
150 #[cfg(any(target_os = "android", target_os = "linux"))]
151 O_TMPFILE;
152 /// Truncate an existing regular file to 0 length if it allows writing.
153 O_TRUNC;
154 /// Restore default TTY attributes.
155 #[cfg(target_os = "freebsd")]
156 O_TTY_INIT;
157 /// Only allow writing.
158 ///
159 /// This should not be combined with `O_RDONLY` or `O_RDWR`.
160 O_WRONLY;
161 }
162);
163
164// The conversion is not identical on all operating systems.
165#[allow(clippy::identity_conversion)]
166pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
167 let fd = path.with_nix_path(|cstr| {
168 unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
169 })?;
170
171 Errno::result(fd)
172}
173
174// The conversion is not identical on all operating systems.
175#[allow(clippy::identity_conversion)]
176#[cfg(not(target_os = "redox"))]
177pub fn openat<P: ?Sized + NixPath>(
178 dirfd: RawFd,
179 path: &P,
180 oflag: OFlag,
181 mode: Mode,
182) -> Result<RawFd> {
183 let fd = path.with_nix_path(|cstr| {
184 unsafe { libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
185 })?;
186 Errno::result(fd)
187}
188
189#[cfg(not(target_os = "redox"))]
190pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
191 old_dirfd: Option<RawFd>,
192 old_path: &P1,
193 new_dirfd: Option<RawFd>,
194 new_path: &P2,
195) -> Result<()> {
196 let res = old_path.with_nix_path(|old_cstr| {
197 new_path.with_nix_path(|new_cstr| unsafe {
198 libc::renameat(
199 at_rawfd(old_dirfd),
200 old_cstr.as_ptr(),
201 at_rawfd(new_dirfd),
202 new_cstr.as_ptr(),
203 )
204 })
205 })??;
206 Errno::result(res).map(drop)
207}
208
209fn wrap_readlink_result(mut v: Vec<u8>, len: ssize_t) -> Result<OsString> {
210 unsafe { v.set_len(len as usize) }
211 v.shrink_to_fit();
212 Ok(OsString::from_vec(v.to_vec()))
213}
214
215fn readlink_maybe_at<P: ?Sized + NixPath>(
216 dirfd: Option<RawFd>,
217 path: &P,
218 v: &mut Vec<u8>,
219) -> Result<libc::ssize_t> {
220 path.with_nix_path(|cstr| unsafe {
221 match dirfd {
222 #[cfg(target_os = "redox")]
223 Some(_) => unreachable!(),
224 #[cfg(not(target_os = "redox"))]
225 Some(dirfd) => libc::readlinkat(
226 dirfd,
227 cstr.as_ptr(),
228 v.as_mut_ptr() as *mut c_char,
229 v.capacity() as size_t,
230 ),
231 None => libc::readlink(
232 cstr.as_ptr(),
233 v.as_mut_ptr() as *mut c_char,
234 v.capacity() as size_t,
235 ),
236 }
237 })
238}
239
240fn inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P) -> Result<OsString> {
241 let mut v = Vec::with_capacity(libc::PATH_MAX as usize);
242 // simple case: result is strictly less than `PATH_MAX`
243 let res = readlink_maybe_at(dirfd, path, &mut v)?;
244 let len = Errno::result(res)?;
245 debug_assert!(len >= 0);
246 if (len as usize) < v.capacity() {
247 return wrap_readlink_result(v, res);
248 }
249 // Uh oh, the result is too long...
250 // Let's try to ask lstat how many bytes to allocate.
251 let reported_size = super::sys::stat::lstat(path)
252 .and_then(|x| Ok(x.st_size))
253 .unwrap_or(0);
254 let mut try_size = if reported_size > 0 {
255 // Note: even if `lstat`'s apparently valid answer turns out to be
256 // wrong, we will still read the full symlink no matter what.
257 reported_size as usize + 1
258 } else {
259 // If lstat doesn't cooperate, or reports an error, be a little less
260 // precise.
261 (libc::PATH_MAX as usize).max(128) << 1
262 };
263 loop {
264 v.reserve_exact(try_size);
265 let res = readlink_maybe_at(dirfd, path, &mut v)?;
266 let len = Errno::result(res)?;
267 debug_assert!(len >= 0);
268 if (len as usize) < v.capacity() {
269 break wrap_readlink_result(v, res);
270 } else {
271 // Ugh! Still not big enough!
272 match try_size.checked_shl(1) {
273 Some(next_size) => try_size = next_size,
274 // It's absurd that this would happen, but handle it sanely
275 // anyway.
276 None => break Err(super::Error::Sys(Errno::ENAMETOOLONG)),
277 }
278 }
279 }
280}
281
282pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> {
283 inner_readlink(None, path)
284}
285
286#[cfg(not(target_os = "redox"))]
287pub fn readlinkat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P) -> Result<OsString> {
288 inner_readlink(Some(dirfd), path)
289}
290
291/// Computes the raw fd consumed by a function of the form `*at`.
292#[cfg(not(target_os = "redox"))]
293pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int {
294 match fd {
295 None => libc::AT_FDCWD,
296 Some(fd) => fd,
297 }
298}
299
300#[cfg(any(target_os = "android", target_os = "linux"))]
301libc_bitflags!(
302 /// Additional flags for file sealing, which allows for limiting operations on a file.
303 pub struct SealFlag: c_int {
304 /// Prevents further calls to `fcntl()` with `F_ADD_SEALS`.
305 F_SEAL_SEAL;
306 /// The file cannot be reduced in size.
307 F_SEAL_SHRINK;
308 /// The size of the file cannot be increased.
309 F_SEAL_GROW;
310 /// The file contents cannot be modified.
311 F_SEAL_WRITE;
312 }
313);
314
315libc_bitflags!(
316 /// Additional configuration flags for `fcntl`'s `F_SETFD`.
317 pub struct FdFlag: c_int {
318 /// The file descriptor will automatically be closed during a successful `execve(2)`.
319 FD_CLOEXEC;
320 }
321);
322
323#[cfg(not(target_os = "redox"))]
324#[derive(Debug, Eq, Hash, PartialEq)]
325pub enum FcntlArg<'a> {
326 F_DUPFD(RawFd),
327 F_DUPFD_CLOEXEC(RawFd),
328 F_GETFD,
329 F_SETFD(FdFlag), // FD_FLAGS
330 F_GETFL,
331 F_SETFL(OFlag), // O_NONBLOCK
332 F_SETLK(&'a libc::flock),
333 F_SETLKW(&'a libc::flock),
334 F_GETLK(&'a mut libc::flock),
335 #[cfg(any(target_os = "linux", target_os = "android"))]
336 F_OFD_SETLK(&'a libc::flock),
337 #[cfg(any(target_os = "linux", target_os = "android"))]
338 F_OFD_SETLKW(&'a libc::flock),
339 #[cfg(any(target_os = "linux", target_os = "android"))]
340 F_OFD_GETLK(&'a mut libc::flock),
341 #[cfg(any(target_os = "android", target_os = "linux"))]
342 F_ADD_SEALS(SealFlag),
343 #[cfg(any(target_os = "android", target_os = "linux"))]
344 F_GET_SEALS,
345 #[cfg(any(target_os = "macos", target_os = "ios"))]
346 F_FULLFSYNC,
347 #[cfg(any(target_os = "linux", target_os = "android"))]
348 F_GETPIPE_SZ,
349 #[cfg(any(target_os = "linux", target_os = "android"))]
350 F_SETPIPE_SZ(c_int),
351 // TODO: Rest of flags
352}
353
354#[cfg(target_os = "redox")]
355#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
356pub enum FcntlArg {
357 F_DUPFD(RawFd),
358 F_DUPFD_CLOEXEC(RawFd),
359 F_GETFD,
360 F_SETFD(FdFlag), // FD_FLAGS
361 F_GETFL,
362 F_SETFL(OFlag), // O_NONBLOCK
363}
364pub use self::FcntlArg::*;
365
366// TODO: Figure out how to handle value fcntl returns
367pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
368 let res = unsafe {
369 match arg {
370 F_DUPFD(rawfd) => libc::fcntl(fd, libc::F_DUPFD, rawfd),
371 F_DUPFD_CLOEXEC(rawfd) => libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, rawfd),
372 F_GETFD => libc::fcntl(fd, libc::F_GETFD),
373 F_SETFD(flag) => libc::fcntl(fd, libc::F_SETFD, flag.bits()),
374 F_GETFL => libc::fcntl(fd, libc::F_GETFL),
375 F_SETFL(flag) => libc::fcntl(fd, libc::F_SETFL, flag.bits()),
376 #[cfg(not(target_os = "redox"))]
377 F_SETLK(flock) => libc::fcntl(fd, libc::F_SETLK, flock),
378 #[cfg(not(target_os = "redox"))]
379 F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock),
380 #[cfg(not(target_os = "redox"))]
381 F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock),
382 #[cfg(any(target_os = "android", target_os = "linux"))]
383 F_OFD_SETLK(flock) => libc::fcntl(fd, libc::F_OFD_SETLK, flock),
384 #[cfg(any(target_os = "android", target_os = "linux"))]
385 F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock),
386 #[cfg(any(target_os = "android", target_os = "linux"))]
387 F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock),
388 #[cfg(any(target_os = "android", target_os = "linux"))]
389 F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()),
390 #[cfg(any(target_os = "android", target_os = "linux"))]
391 F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS),
392 #[cfg(any(target_os = "macos", target_os = "ios"))]
393 F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC),
394 #[cfg(any(target_os = "linux", target_os = "android"))]
395 F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ),
396 #[cfg(any(target_os = "linux", target_os = "android"))]
397 F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size),
398 }
399 };
400
401 Errno::result(res)
402}
403
404#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
405pub enum FlockArg {
406 LockShared,
407 LockExclusive,
408 Unlock,
409 LockSharedNonblock,
410 LockExclusiveNonblock,
411 UnlockNonblock,
412}
413
414#[cfg(not(target_os = "redox"))]
415pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> {
416 use self::FlockArg::*;
417
418 let res = unsafe {
419 match arg {
420 LockShared => libc::flock(fd, libc::LOCK_SH),
421 LockExclusive => libc::flock(fd, libc::LOCK_EX),
422 Unlock => libc::flock(fd, libc::LOCK_UN),
423 LockSharedNonblock => libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB),
424 LockExclusiveNonblock => libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB),
425 UnlockNonblock => libc::flock(fd, libc::LOCK_UN | libc::LOCK_NB),
426 }
427 };
428
429 Errno::result(res).map(drop)
430}
431
432#[cfg(any(target_os = "android", target_os = "linux"))]
433libc_bitflags! {
434 /// Additional flags to `splice` and friends.
435 pub struct SpliceFFlags: c_uint {
436 /// Request that pages be moved instead of copied.
437 ///
438 /// Not applicable to `vmsplice`.
439 SPLICE_F_MOVE;
440 /// Do not block on I/O.
441 SPLICE_F_NONBLOCK;
442 /// Hint that more data will be coming in a subsequent splice.
443 ///
444 /// Not applicable to `vmsplice`.
445 SPLICE_F_MORE;
446 /// Gift the user pages to the kernel.
447 ///
448 /// Not applicable to `splice`.
449 SPLICE_F_GIFT;
450 }
451}
452
453/// Copy a range of data from one file to another
454///
455/// The `copy_file_range` system call performs an in-kernel copy between
456/// file descriptors `fd_in` and `fd_out` without the additional cost of
457/// transferring data from the kernel to user space and then back into the
458/// kernel. It copies up to `len` bytes of data from file descriptor `fd_in` to
459/// file descriptor `fd_out`, overwriting any data that exists within the
460/// requested range of the target file.
461///
462/// If the `off_in` and/or `off_out` arguments are used, the values
463/// will be mutated to reflect the new position within the file after
464/// copying. If they are not used, the relevant filedescriptors will be seeked
465/// to the new position.
466///
467/// On successful completion the number of bytes actually copied will be
468/// returned.
469#[cfg(any(target_os = "android", target_os = "linux"))]
470pub fn copy_file_range(
471 fd_in: RawFd,
472 off_in: Option<&mut libc::loff_t>,
473 fd_out: RawFd,
474 off_out: Option<&mut libc::loff_t>,
475 len: usize,
476) -> Result<usize> {
477 let off_in = off_in
478 .map(|offset| offset as *mut libc::loff_t)
479 .unwrap_or(ptr::null_mut());
480 let off_out = off_out
481 .map(|offset| offset as *mut libc::loff_t)
482 .unwrap_or(ptr::null_mut());
483
484 let ret = unsafe {
485 libc::syscall(
486 libc::SYS_copy_file_range,
487 fd_in,
488 off_in,
489 fd_out,
490 off_out,
491 len,
492 0,
493 )
494 };
495 Errno::result(ret).map(|r| r as usize)
496}
497
498#[cfg(any(target_os = "linux", target_os = "android"))]
499pub fn splice(
500 fd_in: RawFd,
501 off_in: Option<&mut libc::loff_t>,
502 fd_out: RawFd,
503 off_out: Option<&mut libc::loff_t>,
504 len: usize,
505 flags: SpliceFFlags,
506) -> Result<usize> {
507 let off_in = off_in
508 .map(|offset| offset as *mut libc::loff_t)
509 .unwrap_or(ptr::null_mut());
510 let off_out = off_out
511 .map(|offset| offset as *mut libc::loff_t)
512 .unwrap_or(ptr::null_mut());
513
514 let ret = unsafe { libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) };
515 Errno::result(ret).map(|r| r as usize)
516}
517
518#[cfg(any(target_os = "linux", target_os = "android"))]
519pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Result<usize> {
520 let ret = unsafe { libc::tee(fd_in, fd_out, len, flags.bits()) };
521 Errno::result(ret).map(|r| r as usize)
522}
523
524#[cfg(any(target_os = "linux", target_os = "android"))]
525pub fn vmsplice(fd: RawFd, iov: &[IoVec<&[u8]>], flags: SpliceFFlags) -> Result<usize> {
526 let ret = unsafe {
527 libc::vmsplice(
528 fd,
529 iov.as_ptr() as *const libc::iovec,
530 iov.len(),
531 flags.bits(),
532 )
533 };
534 Errno::result(ret).map(|r| r as usize)
535}
536
537#[cfg(any(target_os = "linux"))]
538libc_bitflags!(
539 /// Mode argument flags for fallocate determining operation performed on a given range.
540 pub struct FallocateFlags: c_int {
541 /// File size is not changed.
542 ///
543 /// offset + len can be greater than file size.
544 FALLOC_FL_KEEP_SIZE;
545 /// Deallocates space by creating a hole.
546 ///
547 /// Must be ORed with FALLOC_FL_KEEP_SIZE. Byte range starts at offset and continues for len bytes.
548 FALLOC_FL_PUNCH_HOLE;
549 /// Removes byte range from a file without leaving a hole.
550 ///
551 /// Byte range to collapse starts at offset and continues for len bytes.
552 FALLOC_FL_COLLAPSE_RANGE;
553 /// Zeroes space in specified byte range.
554 ///
555 /// Byte range starts at offset and continues for len bytes.
556 FALLOC_FL_ZERO_RANGE;
557 /// Increases file space by inserting a hole within the file size.
558 ///
559 /// Does not overwrite existing data. Hole starts at offset and continues for len bytes.
560 FALLOC_FL_INSERT_RANGE;
561 /// Shared file data extants are made private to the file.
562 ///
563 /// Gaurantees that a subsequent write will not fail due to lack of space.
564 FALLOC_FL_UNSHARE_RANGE;
565 }
566);
567
568/// Manipulates file space.
569///
570/// Allows the caller to directly manipulate the allocated disk space for the
571/// file referred to by fd.
572#[cfg(any(target_os = "linux"))]
573pub fn fallocate(
574 fd: RawFd,
575 mode: FallocateFlags,
576 offset: libc::off_t,
577 len: libc::off_t,
578) -> Result<()> {
579 let res = unsafe { libc::fallocate(fd, mode.bits(), offset, len) };
580 Errno::result(res).map(drop)
581}
582
583#[cfg(any(
584 target_os = "linux",
585 target_os = "android",
586 target_os = "emscripten",
587 target_os = "fuchsia",
588 any(target_os = "wasi", target_env = "wasi"),
589 target_env = "uclibc",
590 target_env = "freebsd"
591))]
592mod posix_fadvise {
593 use crate::errno::Errno;
594 use libc;
595 use std::os::unix::io::RawFd;
596 use crate::Result;
597
598 libc_enum! {
599 #[repr(i32)]
600 pub enum PosixFadviseAdvice {
601 POSIX_FADV_NORMAL,
602 POSIX_FADV_SEQUENTIAL,
603 POSIX_FADV_RANDOM,
604 POSIX_FADV_NOREUSE,
605 POSIX_FADV_WILLNEED,
606 POSIX_FADV_DONTNEED,
607 }
608 }
609
610 pub fn posix_fadvise(
611 fd: RawFd,
612 offset: libc::off_t,
613 len: libc::off_t,
614 advice: PosixFadviseAdvice,
615 ) -> Result<libc::c_int> {
616 let res = unsafe { libc::posix_fadvise(fd, offset, len, advice as libc::c_int) };
617 Errno::result(res)
618 }
619}
620
621#[cfg(any(
622 target_os = "linux",
623 target_os = "android",
624 target_os = "emscripten",
625 target_os = "fuchsia",
626 any(target_os = "wasi", target_env = "wasi"),
627 target_os = "freebsd"
628))]
629pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<()> {
630 let res = unsafe { libc::posix_fallocate(fd, offset, len) };
631 match Errno::result(res) {
632 Err(err) => Err(err),
633 Ok(0) => Ok(()),
634 Ok(errno) => Err(crate::Error::Sys(Errno::from_i32(errno))),
635 }
636}