1 //! linux_raw syscalls supporting `rustix::fs`.
5 //! See the `rustix::backend` module documentation for details.
8 #![allow(clippy::undocumented_unsafe_blocks)]
11 use super::super::conv
::{
12 by_ref
, c_int
, c_uint
, dev_t
, oflags_for_open_how
, opt_mut
, pass_usize
, raw_fd
, ret
, ret_c_int
,
13 ret_c_uint
, ret_infallible
, ret_owned_fd
, ret_usize
, size_of
, slice_mut
, zero
,
15 #[cfg(target_pointer_width = "64")]
16 use super::super::conv
::{loff_t, loff_t_from_u64, ret_u64}
;
18 target_arch
= "aarch64",
19 target_arch
= "riscv64",
20 target_arch
= "mips64",
21 target_pointer_width
= "32",
24 use crate::fd
::{BorrowedFd, OwnedFd}
;
27 inotify
, Access
, Advice
, AtFlags
, FallocateFlags
, FileType
, FlockOperation
, MemfdFlags
, Mode
,
28 OFlags
, RenameFlags
, ResolveFlags
, SealFlags
, Stat
, StatFs
, StatVfs
, StatVfsMountFlags
,
29 StatxFlags
, Timestamps
,
31 use crate::io
::{self, SeekFrom}
;
32 use crate::process
::{Gid, Uid}
;
33 #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
34 use core
::convert
::TryInto
;
35 use core
::mem
::MaybeUninit
;
36 #[cfg(target_arch = "mips64")]
37 use linux_raw_sys
::general
::stat
as linux_stat64
;
38 use linux_raw_sys
::general
::{
39 __kernel_fsid_t
, __kernel_timespec
, open_how
, statx
, AT_EACCESS
, AT_FDCWD
, AT_REMOVEDIR
,
40 AT_SYMLINK_NOFOLLOW
, F_ADD_SEALS
, F_GETFL
, F_GETLEASE
, F_GETOWN
, F_GETPIPE_SZ
, F_GETSIG
,
41 F_GET_SEALS
, F_SETFL
, F_SETPIPE_SZ
, SEEK_CUR
, SEEK_DATA
, SEEK_END
, SEEK_HOLE
, SEEK_SET
,
44 #[cfg(target_pointer_width = "32")]
46 super::super::conv
::{hi, lo, slice_just_addr}
,
47 linux_raw_sys
::general
::stat64
as linux_stat64
,
48 linux_raw_sys
::general
::timespec
as __kernel_old_timespec
,
52 pub(crate) fn open(filename
: &CStr
, flags
: OFlags
, mode
: Mode
) -> io
::Result
<OwnedFd
> {
53 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
55 openat(crate::fs
::cwd().as_fd(), filename
, flags
, mode
)
58 target_pointer_width
= "32",
59 not(any(target_arch
= "aarch64", target_arch
= "riscv64")),
62 ret_owned_fd(syscall_readonly
!(__NR_open
, filename
, flags
, mode
))
65 target_pointer_width
= "64",
66 not(any(target_arch
= "aarch64", target_arch
= "riscv64")),
69 ret_owned_fd(syscall_readonly
!(__NR_open
, filename
, flags
, mode
))
75 dirfd
: BorrowedFd
<'_
>,
79 ) -> io
::Result
<OwnedFd
> {
80 #[cfg(target_pointer_width = "32")]
82 ret_owned_fd(syscall_readonly
!(__NR_openat
, dirfd
, filename
, flags
, mode
))
84 #[cfg(target_pointer_width = "64")]
86 ret_owned_fd(syscall_readonly
!(__NR_openat
, dirfd
, filename
, flags
, mode
))
91 pub(crate) fn openat2(
92 dirfd
: BorrowedFd
<'_
>,
96 resolve
: ResolveFlags
,
97 ) -> io
::Result
<OwnedFd
> {
98 #[cfg(target_pointer_width = "32")]
100 ret_owned_fd(syscall_readonly
!(
105 flags
: oflags_for_open_how(flags
),
106 mode
: u64::from(mode
.bits()),
107 resolve
: resolve
.bits(),
109 size_of
::<open_how
, _
>()
112 #[cfg(target_pointer_width = "64")]
114 ret_owned_fd(syscall_readonly
!(
119 flags
: oflags_for_open_how(flags
),
120 mode
: u64::from(mode
.bits()),
121 resolve
: resolve
.bits(),
123 size_of
::<open_how
, _
>()
129 pub(crate) fn chmod(filename
: &CStr
, mode
: Mode
) -> io
::Result
<()> {
131 ret(syscall_readonly
!(
141 pub(crate) fn chmodat(
142 dirfd
: BorrowedFd
<'_
>,
146 ) -> io
::Result
<()> {
147 if flags
== AtFlags
::SYMLINK_NOFOLLOW
{
148 return Err(io
::Errno
::OPNOTSUPP
);
150 if !flags
.is_empty() {
151 return Err(io
::Errno
::INVAL
);
153 unsafe { ret(syscall_readonly!(__NR_fchmodat, dirfd, filename, mode)) }
157 pub(crate) fn fchmod(fd
: BorrowedFd
<'_
>, mode
: Mode
) -> io
::Result
<()> {
158 unsafe { ret(syscall_readonly!(__NR_fchmod, fd, mode)) }
162 pub(crate) fn chownat(
163 dirfd
: BorrowedFd
<'_
>,
168 ) -> io
::Result
<()> {
170 let (ow
, gr
) = crate::process
::translate_fchown_args(owner
, group
);
171 ret(syscall_readonly
!(
183 pub(crate) fn fchown(fd
: BorrowedFd
<'_
>, owner
: Option
<Uid
>, group
: Option
<Gid
>) -> io
::Result
<()> {
185 let (ow
, gr
) = crate::process
::translate_fchown_args(owner
, group
);
186 ret(syscall_readonly
!(__NR_fchown
, fd
, c_uint(ow
), c_uint(gr
)))
191 pub(crate) fn mknodat(
192 dirfd
: BorrowedFd
<'_
>,
197 ) -> io
::Result
<()> {
198 #[cfg(target_pointer_width = "32")]
200 ret(syscall_readonly
!(
208 #[cfg(target_pointer_width = "64")]
210 ret(syscall_readonly
!(
221 pub(crate) fn seek(fd
: BorrowedFd
<'_
>, pos
: SeekFrom
) -> io
::Result
<u64> {
222 let (whence
, offset
) = match pos
{
223 SeekFrom
::Start(pos
) => {
225 // Silently cast; we'll get `EINVAL` if the value is negative.
226 (SEEK_SET
, pos
as i64)
228 SeekFrom
::End(offset
) => (SEEK_END
, offset
),
229 SeekFrom
::Current(offset
) => (SEEK_CUR
, offset
),
230 #[cfg(any(freebsdlike, target_os = "linux", target_os = "solaris"))]
231 SeekFrom
::Data(offset
) => (SEEK_DATA
, offset
),
232 #[cfg(any(freebsdlike, target_os = "linux", target_os = "solaris"))]
233 SeekFrom
::Hole(offset
) => (SEEK_HOLE
, offset
),
235 _seek(fd
, offset
, whence
)
239 pub(crate) fn _seek(fd
: BorrowedFd
<'_
>, offset
: i64, whence
: c
::c_uint
) -> io
::Result
<u64> {
240 #[cfg(target_pointer_width = "32")]
242 let mut result
= MaybeUninit
::<u64>::uninit();
246 // Don't use the hi/lo functions here because Linux's llseek
247 // takes its 64-bit argument differently from everything else.
248 pass_usize((offset
>> 32) as usize),
249 pass_usize(offset
as usize),
253 Ok(result
.assume_init())
255 #[cfg(target_pointer_width = "64")]
257 ret_u64(syscall_readonly
!(
267 pub(crate) fn tell(fd
: BorrowedFd
<'_
>) -> io
::Result
<u64> {
268 _seek(fd
, 0, SEEK_CUR
).map(|x
| x
as u64)
272 pub(crate) fn ftruncate(fd
: BorrowedFd
<'_
>, length
: u64) -> io
::Result
<()> {
273 // <https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/arch/arm64/kernel/sys32.c#L81-L83>
275 target_pointer_width
= "32",
276 any(target_arch
= "arm", target_arch
= "mips", target_arch
= "powerpc"),
279 ret(syscall_readonly
!(
288 target_pointer_width
= "32",
289 not(any(target_arch
= "arm", target_arch
= "mips", target_arch
= "powerpc")),
292 ret(syscall_readonly
!(
299 #[cfg(target_pointer_width = "64")]
301 ret(syscall_readonly
!(
304 loff_t_from_u64(length
)
310 pub(crate) fn fallocate(
312 mode
: FallocateFlags
,
315 ) -> io
::Result
<()> {
316 #[cfg(target_pointer_width = "32")]
318 ret(syscall_readonly
!(
328 #[cfg(target_pointer_width = "64")]
330 ret(syscall_readonly
!(
334 loff_t_from_u64(offset
),
341 pub(crate) fn fadvise(fd
: BorrowedFd
<'_
>, pos
: u64, len
: u64, advice
: Advice
) -> io
::Result
<()> {
342 // On ARM, the arguments are reordered so that the len and pos argument
343 // pairs are aligned. And ARM has a custom syscall code for this.
344 #[cfg(target_arch = "arm")]
346 ret(syscall_readonly
!(
347 __NR_arm_fadvise64_64
,
357 // On powerpc, the arguments are reordered as on ARM.
358 #[cfg(target_arch = "powerpc")]
360 ret(syscall_readonly
!(
370 // On mips, the arguments are not reordered, and padding is inserted
371 // instead to ensure alignment.
372 #[cfg(target_arch = "mips")]
374 ret(syscall_readonly
!(
386 target_pointer_width
= "32",
387 not(any(target_arch
= "arm", target_arch
= "mips", target_arch
= "powerpc")),
390 ret(syscall_readonly
!(
400 #[cfg(target_pointer_width = "64")]
402 ret(syscall_readonly
!(
405 loff_t_from_u64(pos
),
406 loff_t_from_u64(len
),
413 pub(crate) fn fsync(fd
: BorrowedFd
<'_
>) -> io
::Result
<()> {
414 unsafe { ret(syscall_readonly!(__NR_fsync, fd)) }
418 pub(crate) fn fdatasync(fd
: BorrowedFd
<'_
>) -> io
::Result
<()> {
419 unsafe { ret(syscall_readonly!(__NR_fdatasync, fd)) }
423 pub(crate) fn flock(fd
: BorrowedFd
<'_
>, operation
: FlockOperation
) -> io
::Result
<()> {
425 ret(syscall_readonly
!(
428 c_uint(operation
as c
::c_uint
)
434 pub(crate) fn syncfs(fd
: BorrowedFd
<'_
>) -> io
::Result
<()> {
435 unsafe { ret(syscall_readonly!(__NR_syncfs, fd)) }
439 pub(crate) fn sync() {
440 unsafe { ret_infallible(syscall_readonly!(__NR_sync)) }
444 pub(crate) fn fstat(fd
: BorrowedFd
<'_
>) -> io
::Result
<Stat
> {
445 #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
447 match statx(fd
, cstr
!(""), AtFlags
::EMPTY_PATH
, StatxFlags
::BASIC_STATS
) {
448 Ok(x
) => statx_to_stat(x
),
449 Err(io
::Errno
::NOSYS
) => fstat_old(fd
),
450 Err(err
) => Err(err
),
454 #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))]
456 let mut result
= MaybeUninit
::<Stat
>::uninit();
457 ret(syscall
!(__NR_fstat
, fd
, &mut result
))?
;
458 Ok(result
.assume_init())
462 #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
463 fn fstat_old(fd
: BorrowedFd
<'_
>) -> io
::Result
<Stat
> {
464 let mut result
= MaybeUninit
::<linux_stat64
>::uninit();
466 #[cfg(target_arch = "mips64")]
468 ret(syscall
!(__NR_fstat
, fd
, &mut result
))?
;
469 stat_to_stat(result
.assume_init())
472 #[cfg(target_pointer_width = "32")]
474 ret(syscall
!(__NR_fstat64
, fd
, &mut result
))?
;
475 stat_to_stat(result
.assume_init())
480 pub(crate) fn stat(filename
: &CStr
) -> io
::Result
<Stat
> {
481 #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
484 crate::fs
::cwd().as_fd(),
487 StatxFlags
::BASIC_STATS
,
489 Ok(x
) => statx_to_stat(x
),
490 Err(io
::Errno
::NOSYS
) => stat_old(filename
),
491 Err(err
) => Err(err
),
495 #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))]
497 let mut result
= MaybeUninit
::<Stat
>::uninit();
505 Ok(result
.assume_init())
509 #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
510 fn stat_old(filename
: &CStr
) -> io
::Result
<Stat
> {
511 let mut result
= MaybeUninit
::<linux_stat64
>::uninit();
513 #[cfg(target_arch = "mips64")]
522 stat_to_stat(result
.assume_init())
525 #[cfg(target_pointer_width = "32")]
534 stat_to_stat(result
.assume_init())
539 pub(crate) fn statat(dirfd
: BorrowedFd
<'_
>, filename
: &CStr
, flags
: AtFlags
) -> io
::Result
<Stat
> {
540 #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
542 match statx(dirfd
, filename
, flags
, StatxFlags
::BASIC_STATS
) {
543 Ok(x
) => statx_to_stat(x
),
544 Err(io
::Errno
::NOSYS
) => statat_old(dirfd
, filename
, flags
),
545 Err(err
) => Err(err
),
549 #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))]
551 let mut result
= MaybeUninit
::<Stat
>::uninit();
559 Ok(result
.assume_init())
563 #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
564 fn statat_old(dirfd
: BorrowedFd
<'_
>, filename
: &CStr
, flags
: AtFlags
) -> io
::Result
<Stat
> {
565 let mut result
= MaybeUninit
::<linux_stat64
>::uninit();
567 #[cfg(target_arch = "mips64")]
576 stat_to_stat(result
.assume_init())
579 #[cfg(target_pointer_width = "32")]
588 stat_to_stat(result
.assume_init())
593 pub(crate) fn lstat(filename
: &CStr
) -> io
::Result
<Stat
> {
594 #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
597 crate::fs
::cwd().as_fd(),
599 AtFlags
::SYMLINK_NOFOLLOW
,
600 StatxFlags
::BASIC_STATS
,
602 Ok(x
) => statx_to_stat(x
),
603 Err(io
::Errno
::NOSYS
) => lstat_old(filename
),
604 Err(err
) => Err(err
),
608 #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))]
610 let mut result
= MaybeUninit
::<Stat
>::uninit();
616 c_uint(AT_SYMLINK_NOFOLLOW
)
618 Ok(result
.assume_init())
622 #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
623 fn lstat_old(filename
: &CStr
) -> io
::Result
<Stat
> {
624 let mut result
= MaybeUninit
::<linux_stat64
>::uninit();
626 #[cfg(target_arch = "mips64")]
633 c_uint(AT_SYMLINK_NOFOLLOW
)
635 stat_to_stat(result
.assume_init())
638 #[cfg(target_pointer_width = "32")]
645 c_uint(AT_SYMLINK_NOFOLLOW
)
647 stat_to_stat(result
.assume_init())
651 /// Convert from a Linux `statx` value to rustix's `Stat`.
652 #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
653 fn statx_to_stat(x
: crate::fs
::Statx
) -> io
::Result
<Stat
> {
655 st_dev
: crate::fs
::makedev(x
.stx_dev_major
, x
.stx_dev_minor
),
656 st_mode
: x
.stx_mode
.into(),
657 st_nlink
: x
.stx_nlink
.into(),
658 st_uid
: x
.stx_uid
.into(),
659 st_gid
: x
.stx_gid
.into(),
660 st_rdev
: crate::fs
::makedev(x
.stx_rdev_major
, x
.stx_rdev_minor
),
661 st_size
: x
.stx_size
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
662 st_blksize
: x
.stx_blksize
.into(),
663 st_blocks
: x
.stx_blocks
.into(),
668 .map_err(|_
| io
::Errno
::OVERFLOW
)?
,
669 st_atime_nsec
: x
.stx_atime
.tv_nsec
.into(),
674 .map_err(|_
| io
::Errno
::OVERFLOW
)?
,
675 st_mtime_nsec
: x
.stx_mtime
.tv_nsec
.into(),
680 .map_err(|_
| io
::Errno
::OVERFLOW
)?
,
681 st_ctime_nsec
: x
.stx_ctime
.tv_nsec
.into(),
682 st_ino
: x
.stx_ino
.into(),
686 /// Convert from a Linux `stat64` value to rustix's `Stat`.
687 #[cfg(target_pointer_width = "32")]
688 fn stat_to_stat(s64
: linux_raw_sys
::general
::stat64
) -> io
::Result
<Stat
> {
690 st_dev
: s64
.st_dev
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
691 st_mode
: s64
.st_mode
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
692 st_nlink
: s64
.st_nlink
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
693 st_uid
: s64
.st_uid
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
694 st_gid
: s64
.st_gid
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
695 st_rdev
: s64
.st_rdev
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
696 st_size
: s64
.st_size
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
697 st_blksize
: s64
.st_blksize
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
698 st_blocks
: s64
.st_blocks
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
699 st_atime
: s64
.st_atime
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
703 .map_err(|_
| io
::Errno
::OVERFLOW
)?
,
704 st_mtime
: s64
.st_mtime
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
708 .map_err(|_
| io
::Errno
::OVERFLOW
)?
,
709 st_ctime
: s64
.st_ctime
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
713 .map_err(|_
| io
::Errno
::OVERFLOW
)?
,
714 st_ino
: s64
.st_ino
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
718 /// Convert from a Linux `stat` value to rustix's `Stat`.
719 #[cfg(target_arch = "mips64")]
720 fn stat_to_stat(s
: linux_raw_sys
::general
::stat
) -> io
::Result
<Stat
> {
722 st_dev
: s
.st_dev
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
723 st_mode
: s
.st_mode
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
724 st_nlink
: s
.st_nlink
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
725 st_uid
: s
.st_uid
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
726 st_gid
: s
.st_gid
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
727 st_rdev
: s
.st_rdev
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
728 st_size
: s
.st_size
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
729 st_blksize
: s
.st_blksize
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
730 st_blocks
: s
.st_blocks
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
731 st_atime
: s
.st_atime
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
735 .map_err(|_
| io
::Errno
::OVERFLOW
)?
,
736 st_mtime
: s
.st_mtime
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
740 .map_err(|_
| io
::Errno
::OVERFLOW
)?
,
741 st_ctime
: s
.st_ctime
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
745 .map_err(|_
| io
::Errno
::OVERFLOW
)?
,
746 st_ino
: s
.st_ino
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
752 dirfd
: BorrowedFd
<'_
>,
756 ) -> io
::Result
<statx
> {
757 // If a future Linux kernel adds more fields to `struct statx` and users
758 // passing flags unknown to rustix in `StatxFlags`, we could end up
759 // writing outside of the buffer. To prevent this possibility, we mask off
760 // any flags that we don't know about.
762 // This includes `STATX__RESERVED`, which has a value that we know, but
763 // which could take on arbitrary new meaning in the future. Linux currently
764 // rejects this flag with `EINVAL`, so we do the same.
766 // This doesn't rely on `STATX_ALL` because [it's deprecated] and already
767 // doesn't represent all the known flags.
769 // [it's deprecated]: https://patchwork.kernel.org/project/linux-fsdevel/patch/20200505095915.11275-7-mszeredi@redhat.com/
770 if (mask
.bits() & STATX__RESERVED
) == STATX__RESERVED
{
771 return Err(io
::Errno
::INVAL
);
773 let mask
= mask
& StatxFlags
::all();
776 let mut statx_buf
= MaybeUninit
::<statx
>::uninit();
785 Ok(statx_buf
.assume_init())
790 pub(crate) fn is_statx_available() -> bool
{
792 // Call `statx` with null pointers so that if it fails for any reason
793 // other than `EFAULT`, we know it's not supported.
803 Err(io
::Errno
::FAULT
)
809 pub(crate) fn fstatfs(fd
: BorrowedFd
<'_
>) -> io
::Result
<StatFs
> {
810 #[cfg(target_pointer_width = "32")]
812 let mut result
= MaybeUninit
::<StatFs
>::uninit();
816 size_of
::<StatFs
, _
>(),
819 Ok(result
.assume_init())
822 #[cfg(target_pointer_width = "64")]
824 let mut result
= MaybeUninit
::<StatFs
>::uninit();
825 ret(syscall
!(__NR_fstatfs
, fd
, &mut result
))?
;
826 Ok(result
.assume_init())
831 pub(crate) fn fstatvfs(fd
: BorrowedFd
<'_
>) -> io
::Result
<StatVfs
> {
832 // Linux doesn't have an `fstatvfs` syscall; we have to do `fstatfs` and
833 // translate the fields as best we can.
834 let statfs
= fstatfs(fd
)?
;
836 Ok(statfs_to_statvfs(statfs
))
840 pub(crate) fn statfs(filename
: &CStr
) -> io
::Result
<StatFs
> {
841 #[cfg(target_pointer_width = "32")]
843 let mut result
= MaybeUninit
::<StatFs
>::uninit();
847 size_of
::<StatFs
, _
>(),
850 Ok(result
.assume_init())
852 #[cfg(target_pointer_width = "64")]
854 let mut result
= MaybeUninit
::<StatFs
>::uninit();
855 ret(syscall
!(__NR_statfs
, filename
, &mut result
))?
;
856 Ok(result
.assume_init())
861 pub(crate) fn statvfs(filename
: &CStr
) -> io
::Result
<StatVfs
> {
862 // Linux doesn't have a `statvfs` syscall; we have to do `statfs` and
863 // translate the fields as best we can.
864 let statfs
= statfs(filename
)?
;
866 Ok(statfs_to_statvfs(statfs
))
869 fn statfs_to_statvfs(statfs
: StatFs
) -> StatVfs
{
870 let __kernel_fsid_t { val }
= statfs
.f_fsid
;
871 let [f_fsid_val0
, f_fsid_val1
]: [i32; 2] = val
;
874 f_bsize
: statfs
.f_bsize
as u64,
875 f_frsize
: if statfs
.f_frsize
!= 0 {
880 f_blocks
: statfs
.f_blocks
as u64,
881 f_bfree
: statfs
.f_bfree
as u64,
882 f_bavail
: statfs
.f_bavail
as u64,
883 f_files
: statfs
.f_files
as u64,
884 f_ffree
: statfs
.f_ffree
as u64,
885 f_favail
: statfs
.f_ffree
as u64,
886 f_fsid
: f_fsid_val0
as u32 as u64 | ((f_fsid_val1
as u32 as u64) << 32),
887 f_flag
: unsafe { StatVfsMountFlags::from_bits_unchecked(statfs.f_flags as u64) }
,
888 f_namemax
: statfs
.f_namelen
as u64,
893 pub(crate) fn readlink(path
: &CStr
, buf
: &mut [u8]) -> io
::Result
<usize> {
894 let (buf_addr_mut
, buf_len
) = slice_mut(buf
);
907 pub(crate) fn readlinkat(dirfd
: BorrowedFd
<'_
>, path
: &CStr
, buf
: &mut [u8]) -> io
::Result
<usize> {
908 let (buf_addr_mut
, buf_len
) = slice_mut(buf
);
921 pub(crate) fn fcntl_getfl(fd
: BorrowedFd
<'_
>) -> io
::Result
<OFlags
> {
922 #[cfg(target_pointer_width = "32")]
924 ret_c_uint(syscall_readonly
!(__NR_fcntl64
, fd
, c_uint(F_GETFL
)))
925 .map(OFlags
::from_bits_truncate
)
927 #[cfg(target_pointer_width = "64")]
929 ret_c_uint(syscall_readonly
!(__NR_fcntl
, fd
, c_uint(F_GETFL
)))
930 .map(OFlags
::from_bits_truncate
)
935 pub(crate) fn fcntl_setfl(fd
: BorrowedFd
<'_
>, flags
: OFlags
) -> io
::Result
<()> {
936 #[cfg(target_pointer_width = "32")]
938 ret(syscall_readonly
!(__NR_fcntl64
, fd
, c_uint(F_SETFL
), flags
))
940 #[cfg(target_pointer_width = "64")]
942 ret(syscall_readonly
!(__NR_fcntl
, fd
, c_uint(F_SETFL
), flags
))
947 pub(crate) fn fcntl_getlease(fd
: BorrowedFd
<'_
>) -> io
::Result
<c
::c_int
> {
948 #[cfg(target_pointer_width = "32")]
950 ret_c_int(syscall_readonly
!(__NR_fcntl64
, fd
, c_uint(F_GETLEASE
)))
952 #[cfg(target_pointer_width = "64")]
954 ret_c_int(syscall_readonly
!(__NR_fcntl
, fd
, c_uint(F_GETLEASE
)))
959 pub(crate) fn fcntl_getown(fd
: BorrowedFd
<'_
>) -> io
::Result
<c
::c_int
> {
960 #[cfg(target_pointer_width = "32")]
962 ret_c_int(syscall_readonly
!(__NR_fcntl64
, fd
, c_uint(F_GETOWN
)))
964 #[cfg(target_pointer_width = "64")]
966 ret_c_int(syscall_readonly
!(__NR_fcntl
, fd
, c_uint(F_GETOWN
)))
971 pub(crate) fn fcntl_getsig(fd
: BorrowedFd
<'_
>) -> io
::Result
<c
::c_int
> {
972 #[cfg(target_pointer_width = "32")]
974 ret_c_int(syscall_readonly
!(__NR_fcntl64
, fd
, c_uint(F_GETSIG
)))
976 #[cfg(target_pointer_width = "64")]
978 ret_c_int(syscall_readonly
!(__NR_fcntl
, fd
, c_uint(F_GETSIG
)))
983 pub(crate) fn fcntl_getpipe_sz(fd
: BorrowedFd
<'_
>) -> io
::Result
<usize> {
984 #[cfg(target_pointer_width = "32")]
986 ret_usize(syscall_readonly
!(__NR_fcntl64
, fd
, c_uint(F_GETPIPE_SZ
)))
988 #[cfg(target_pointer_width = "64")]
990 ret_usize(syscall_readonly
!(__NR_fcntl
, fd
, c_uint(F_GETPIPE_SZ
)))
995 pub(crate) fn fcntl_setpipe_sz(fd
: BorrowedFd
<'_
>, size
: c
::c_int
) -> io
::Result
<usize> {
996 #[cfg(target_pointer_width = "32")]
998 ret_usize(syscall_readonly
!(
1001 c_uint(F_SETPIPE_SZ
),
1005 #[cfg(target_pointer_width = "64")]
1007 ret_usize(syscall_readonly
!(
1010 c_uint(F_SETPIPE_SZ
),
1017 pub(crate) fn fcntl_get_seals(fd
: BorrowedFd
<'_
>) -> io
::Result
<SealFlags
> {
1018 #[cfg(target_pointer_width = "32")]
1020 ret_c_int(syscall_readonly
!(__NR_fcntl64
, fd
, c_uint(F_GET_SEALS
)))
1021 .map(|seals
| SealFlags
::from_bits_unchecked(seals
as u32))
1023 #[cfg(target_pointer_width = "64")]
1025 ret_c_int(syscall_readonly
!(__NR_fcntl
, fd
, c_uint(F_GET_SEALS
)))
1026 .map(|seals
| SealFlags
::from_bits_unchecked(seals
as u32))
1031 pub(crate) fn fcntl_add_seals(fd
: BorrowedFd
<'_
>, seals
: SealFlags
) -> io
::Result
<()> {
1032 #[cfg(target_pointer_width = "32")]
1034 ret(syscall_readonly
!(
1037 c_uint(F_ADD_SEALS
),
1041 #[cfg(target_pointer_width = "64")]
1043 ret(syscall_readonly
!(
1046 c_uint(F_ADD_SEALS
),
1053 pub(crate) fn fcntl_lock(fd
: BorrowedFd
<'_
>, operation
: FlockOperation
) -> io
::Result
<()> {
1054 #[cfg(target_pointer_width = "64")]
1055 use linux_raw_sys
::general
::{flock, F_SETLK, F_SETLKW}
;
1056 #[cfg(target_pointer_width = "32")]
1057 use linux_raw_sys
::general
::{flock64 as flock, F_SETLK64 as F_SETLK, F_SETLKW64 as F_SETLKW}
;
1058 use linux_raw_sys
::general
::{F_RDLCK, F_UNLCK, F_WRLCK}
;
1060 let (cmd
, l_type
) = match operation
{
1061 FlockOperation
::LockShared
=> (F_SETLKW
, F_RDLCK
),
1062 FlockOperation
::LockExclusive
=> (F_SETLKW
, F_WRLCK
),
1063 FlockOperation
::Unlock
=> (F_SETLKW
, F_UNLCK
),
1064 FlockOperation
::NonBlockingLockShared
=> (F_SETLK
, F_RDLCK
),
1065 FlockOperation
::NonBlockingLockExclusive
=> (F_SETLK
, F_WRLCK
),
1066 FlockOperation
::NonBlockingUnlock
=> (F_SETLK
, F_UNLCK
),
1071 l_type
: l_type
as _
,
1073 // When `l_len` is zero, this locks all the bytes from
1074 // `l_whence`/`l_start` to the end of the file, even as the
1075 // file grows dynamically.
1076 l_whence
: SEEK_SET
as _
,
1080 ..core
::mem
::zeroed()
1083 #[cfg(target_pointer_width = "32")]
1085 ret(syscall_readonly
!(
1092 #[cfg(target_pointer_width = "64")]
1094 ret(syscall_readonly
!(
1105 pub(crate) fn rename(oldname
: &CStr
, newname
: &CStr
) -> io
::Result
<()> {
1106 #[cfg(target_arch = "riscv64")]
1108 ret(syscall_readonly
!(
1117 #[cfg(not(target_arch = "riscv64"))]
1119 ret(syscall_readonly
!(
1130 pub(crate) fn renameat(
1131 old_dirfd
: BorrowedFd
<'_
>,
1133 new_dirfd
: BorrowedFd
<'_
>,
1135 ) -> io
::Result
<()> {
1136 #[cfg(target_arch = "riscv64")]
1138 ret(syscall_readonly
!(
1147 #[cfg(not(target_arch = "riscv64"))]
1149 ret(syscall_readonly
!(
1160 pub(crate) fn renameat2(
1161 old_dirfd
: BorrowedFd
<'_
>,
1163 new_dirfd
: BorrowedFd
<'_
>,
1166 ) -> io
::Result
<()> {
1168 ret(syscall_readonly
!(
1180 pub(crate) fn unlink(pathname
: &CStr
) -> io
::Result
<()> {
1182 ret(syscall_readonly
!(
1192 pub(crate) fn unlinkat(dirfd
: BorrowedFd
<'_
>, pathname
: &CStr
, flags
: AtFlags
) -> io
::Result
<()> {
1193 unsafe { ret(syscall_readonly!(__NR_unlinkat, dirfd, pathname, flags)) }
1197 pub(crate) fn rmdir(pathname
: &CStr
) -> io
::Result
<()> {
1199 ret(syscall_readonly
!(
1203 c_uint(AT_REMOVEDIR
)
1209 pub(crate) fn link(oldname
: &CStr
, newname
: &CStr
) -> io
::Result
<()> {
1211 ret(syscall_readonly
!(
1223 pub(crate) fn linkat(
1224 old_dirfd
: BorrowedFd
<'_
>,
1226 new_dirfd
: BorrowedFd
<'_
>,
1229 ) -> io
::Result
<()> {
1231 ret(syscall_readonly
!(
1243 pub(crate) fn symlink(oldname
: &CStr
, newname
: &CStr
) -> io
::Result
<()> {
1245 ret(syscall_readonly
!(
1255 pub(crate) fn symlinkat(oldname
: &CStr
, dirfd
: BorrowedFd
<'_
>, newname
: &CStr
) -> io
::Result
<()> {
1256 unsafe { ret(syscall_readonly!(__NR_symlinkat, oldname, dirfd, newname)) }
1260 pub(crate) fn mkdir(pathname
: &CStr
, mode
: Mode
) -> io
::Result
<()> {
1262 ret(syscall_readonly
!(
1272 pub(crate) fn mkdirat(dirfd
: BorrowedFd
<'_
>, pathname
: &CStr
, mode
: Mode
) -> io
::Result
<()> {
1273 unsafe { ret(syscall_readonly!(__NR_mkdirat, dirfd, pathname, mode)) }
1277 pub(crate) fn getdents(fd
: BorrowedFd
<'_
>, dirent
: &mut [u8]) -> io
::Result
<usize> {
1278 let (dirent_addr_mut
, dirent_len
) = slice_mut(dirent
);
1280 unsafe { ret_usize(syscall!(__NR_getdents64, fd, dirent_addr_mut, dirent_len)) }
1284 pub(crate) fn getdents_uninit(
1286 dirent
: &mut [MaybeUninit
<u8>],
1287 ) -> io
::Result
<usize> {
1288 let (dirent_addr_mut
, dirent_len
) = slice_mut(dirent
);
1290 unsafe { ret_usize(syscall!(__NR_getdents64, fd, dirent_addr_mut, dirent_len)) }
1294 pub(crate) fn utimensat(
1295 dirfd
: BorrowedFd
<'_
>,
1299 ) -> io
::Result
<()> {
1300 _utimensat(dirfd
, Some(pathname
), times
, flags
)
1305 dirfd
: BorrowedFd
<'_
>,
1306 pathname
: Option
<&CStr
>,
1309 ) -> io
::Result
<()> {
1310 // Assert that `Timestamps` has the expected layout.
1311 let _
= unsafe { core::mem::transmute::<Timestamps, [__kernel_timespec; 2]>(times.clone()) }
;
1313 #[cfg(target_pointer_width = "32")]
1315 match ret(syscall_readonly
!(
1316 __NR_utimensat_time64
,
1322 Err(io
::Errno
::NOSYS
) => _utimensat_old(dirfd
, pathname
, times
, flags
),
1323 otherwise
=> otherwise
,
1326 #[cfg(target_pointer_width = "64")]
1328 ret(syscall_readonly
!(
1338 #[cfg(target_pointer_width = "32")]
1339 unsafe fn _utimensat_old(
1340 dirfd
: BorrowedFd
<'_
>,
1341 pathname
: Option
<&CStr
>,
1344 ) -> io
::Result
<()> {
1345 // See the comments in `rustix_clock_gettime_via_syscall` about
1348 __kernel_old_timespec
{
1353 .map_err(|_
| io
::Errno
::OVERFLOW
)?
,
1358 .map_err(|_
| io
::Errno
::INVAL
)?
,
1360 __kernel_old_timespec
{
1365 .map_err(|_
| io
::Errno
::OVERFLOW
)?
,
1370 .map_err(|_
| io
::Errno
::INVAL
)?
,
1373 // The length of the array is fixed and not passed into the syscall.
1374 let old_times_addr
= slice_just_addr(&old_times
);
1375 ret(syscall_readonly
!(
1385 pub(crate) fn futimens(fd
: BorrowedFd
<'_
>, times
: &Timestamps
) -> io
::Result
<()> {
1386 _utimensat(fd
, None
, times
, AtFlags
::empty())
1389 pub(crate) fn accessat(
1390 dirfd
: BorrowedFd
<'_
>,
1394 ) -> io
::Result
<()> {
1395 // Linux's `faccessat` doesn't have a flags parameter. If we have
1396 // `AT_EACCESS` and we're not setuid or setgid, we can emulate it.
1398 || (flags
.bits() == AT_EACCESS
1399 && crate::process
::getuid() == crate::process
::geteuid()
1400 && crate::process
::getgid() == crate::process
::getegid())
1402 return unsafe { ret(syscall_readonly!(__NR_faccessat, dirfd, path, access)) }
;
1405 if flags
.bits() != AT_EACCESS
{
1406 return Err(io
::Errno
::INVAL
);
1409 // TODO: Use faccessat2 in newer Linux versions.
1410 Err(io
::Errno
::NOSYS
)
1414 pub(crate) fn copy_file_range(
1415 fd_in
: BorrowedFd
<'_
>,
1416 off_in
: Option
<&mut u64>,
1417 fd_out
: BorrowedFd
<'_
>,
1418 off_out
: Option
<&mut u64>,
1420 ) -> io
::Result
<usize> {
1423 __NR_copy_file_range
,
1435 pub(crate) fn memfd_create(name
: &CStr
, flags
: MemfdFlags
) -> io
::Result
<OwnedFd
> {
1436 unsafe { ret_owned_fd(syscall_readonly!(__NR_memfd_create, name, flags)) }
1440 pub(crate) fn sendfile(
1441 out_fd
: BorrowedFd
<'_
>,
1442 in_fd
: BorrowedFd
<'_
>,
1443 offset
: Option
<&mut u64>,
1445 ) -> io
::Result
<usize> {
1446 #[cfg(target_pointer_width = "32")]
1456 #[cfg(target_pointer_width = "64")]
1469 #[cfg(any(target_os = "android", target_os = "linux"))]
1470 pub(crate) fn mount(
1471 source
: Option
<&CStr
>,
1473 file_system_type
: Option
<&CStr
>,
1474 flags
: super::types
::MountFlagsArg
,
1475 data
: Option
<&CStr
>,
1476 ) -> io
::Result
<()> {
1478 ret(syscall_readonly
!(
1490 #[cfg(any(target_os = "android", target_os = "linux"))]
1491 pub(crate) fn unmount(target
: &CStr
, flags
: super::types
::UnmountFlags
) -> io
::Result
<()> {
1492 unsafe { ret(syscall_readonly!(__NR_umount2, target, flags)) }
1496 pub(crate) fn inotify_init1(flags
: inotify
::CreateFlags
) -> io
::Result
<OwnedFd
> {
1497 unsafe { ret_owned_fd(syscall_readonly!(__NR_inotify_init1, flags)) }
1501 pub(crate) fn inotify_add_watch(
1502 infd
: BorrowedFd
<'_
>,
1504 flags
: inotify
::WatchFlags
,
1505 ) -> io
::Result
<i32> {
1506 unsafe { ret_c_int(syscall_readonly!(__NR_inotify_add_watch, infd, path, flags)) }
1510 pub(crate) fn inotify_rm_watch(infd
: BorrowedFd
<'_
>, wfd
: i32) -> io
::Result
<()> {
1511 unsafe { ret(syscall_readonly!(__NR_inotify_rm_watch, infd, c_int(wfd))) }