1 use crate::errno::Errno;
2 use libc::{self, c_char, c_int, c_uint, size_t, ssize_t};
3 use std::ffi::OsString;
4 #[cfg(not(target_os = "redox"))]
5 use std::os::raw;
6 use std::os::unix::ffi::OsStringExt;
7 use std::os::unix::io::RawFd;
8 use crate::sys::stat::Mode;
9 use crate::{NixPath, Result};
10 
11 #[cfg(any(target_os = "android", target_os = "linux"))]
12 use std::ptr; // For splice and copy_file_range
13 #[cfg(any(target_os = "android", target_os = "linux"))]
14 use 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_os = "freebsd"
24 ))]
25 pub use self::posix_fadvise::*;
26 
27 #[cfg(not(target_os = "redox"))]
28 libc_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 
40 libc_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)]
open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd>166 pub 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"))]
openat<P: ?Sized + NixPath>( dirfd: RawFd, path: &P, oflag: OFlag, mode: Mode, ) -> Result<RawFd>177 pub 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"))]
renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( old_dirfd: Option<RawFd>, old_path: &P1, new_dirfd: Option<RawFd>, new_path: &P2, ) -> Result<()>190 pub 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 
wrap_readlink_result(mut v: Vec<u8>, len: ssize_t) -> Result<OsString>209 fn 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 
readlink_maybe_at<P: ?Sized + NixPath>( dirfd: Option<RawFd>, path: &P, v: &mut Vec<u8>, ) -> Result<libc::ssize_t>215 fn 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 
inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P) -> Result<OsString>240 fn 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 
readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString>282 pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> {
283     inner_readlink(None, path)
284 }
285 
286 #[cfg(not(target_os = "redox"))]
readlinkat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P) -> Result<OsString>287 pub 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"))]
at_rawfd(fd: Option<RawFd>) -> raw::c_int293 pub(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"))]
301 libc_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 
315 libc_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)]
325 pub 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)]
356 pub 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 }
364 pub use self::FcntlArg::*;
365 
366 // TODO: Figure out how to handle value fcntl returns
fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int>367 pub 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)]
405 pub enum FlockArg {
406     LockShared,
407     LockExclusive,
408     Unlock,
409     LockSharedNonblock,
410     LockExclusiveNonblock,
411     UnlockNonblock,
412 }
413 
414 #[cfg(not(target_os = "redox"))]
flock(fd: RawFd, arg: FlockArg) -> Result<()>415 pub 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"))]
433 libc_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"))]
copy_file_range( fd_in: RawFd, off_in: Option<&mut libc::loff_t>, fd_out: RawFd, off_out: Option<&mut libc::loff_t>, len: usize, ) -> Result<usize>470 pub 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"))]
splice( fd_in: RawFd, off_in: Option<&mut libc::loff_t>, fd_out: RawFd, off_out: Option<&mut libc::loff_t>, len: usize, flags: SpliceFFlags, ) -> Result<usize>499 pub 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"))]
tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Result<usize>519 pub 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"))]
vmsplice(fd: RawFd, iov: &[IoVec<&[u8]>], flags: SpliceFFlags) -> Result<usize>525 pub 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"))]
538 libc_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"))]
fallocate( fd: RawFd, mode: FallocateFlags, offset: libc::off_t, len: libc::off_t, ) -> Result<()>573 pub 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_os = "freebsd"
591 ))]
592 mod 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 
posix_fadvise( fd: RawFd, offset: libc::off_t, len: libc::off_t, advice: PosixFadviseAdvice, ) -> Result<libc::c_int>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 ))]
posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<()>629 pub 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 }
637