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