1#![allow(unsafe_code)]
7#![allow(clippy::undocumented_unsafe_blocks)]
8
9use crate::backend::c;
10use crate::backend::conv::fs::oflags_for_open_how;
11#[cfg(any(
12 not(feature = "linux_4_11"),
13 target_arch = "aarch64",
14 target_arch = "riscv64",
15 target_arch = "mips",
16 target_arch = "mips32r6",
17 all(
18 target_pointer_width = "32",
19 any(target_arch = "arm", target_arch = "powerpc"),
20 )
21))]
22use crate::backend::conv::zero;
23use crate::backend::conv::{
24 by_ref, c_int, c_uint, dev_t, opt_mut, pass_usize, raw_fd, ret, ret_c_int, ret_c_uint,
25 ret_infallible, ret_owned_fd, ret_usize, size_of, slice, slice_mut,
26};
27#[cfg(target_pointer_width = "64")]
28use crate::backend::conv::{loff_t, loff_t_from_u64, ret_u64};
29use crate::fd::{BorrowedFd, OwnedFd};
30use crate::ffi::CStr;
31#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
32use crate::fs::CWD;
33use crate::fs::{
34 inotify, Access, Advice, AtFlags, FallocateFlags, FileType, FlockOperation, Fsid, Gid,
35 MemfdFlags, Mode, OFlags, RenameFlags, ResolveFlags, SealFlags, SeekFrom, Stat, StatFs,
36 StatVfs, StatVfsMountFlags, Statx, StatxFlags, Timestamps, Uid, XattrFlags,
37};
38use crate::io;
39use core::mem::MaybeUninit;
40use core::num::NonZeroU64;
41#[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
42use linux_raw_sys::general::stat as linux_stat64;
43use linux_raw_sys::general::{
44 open_how, AT_EACCESS, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_NOFOLLOW, F_ADD_SEALS, F_GETFL,
45 F_GET_SEALS, F_SETFL, SEEK_CUR, SEEK_DATA, SEEK_END, SEEK_HOLE, SEEK_SET, STATX__RESERVED,
46};
47#[cfg(target_pointer_width = "32")]
48use {
49 crate::backend::conv::{hi, lo, slice_just_addr},
50 linux_raw_sys::general::stat64 as linux_stat64,
51 linux_raw_sys::general::timespec as __kernel_old_timespec,
52};
53
54#[inline]
55pub(crate) fn open(path: &CStr, flags: OFlags, mode: Mode) -> io::Result<OwnedFd> {
56 let flags = flags | OFlags::LARGEFILE;
58
59 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
60 {
61 openat(CWD, path, flags, mode)
62 }
63 #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
64 unsafe {
65 ret_owned_fd(syscall_readonly!(__NR_open, path, flags, mode))
66 }
67}
68
69#[inline]
70pub(crate) fn openat(
71 dirfd: BorrowedFd<'_>,
72 path: &CStr,
73 flags: OFlags,
74 mode: Mode,
75) -> io::Result<OwnedFd> {
76 let flags = flags | OFlags::LARGEFILE;
78
79 unsafe { ret_owned_fd(syscall_readonly!(__NR_openat, dirfd, path, flags, mode)) }
80}
81
82#[inline]
83pub(crate) fn openat2(
84 dirfd: BorrowedFd<'_>,
85 path: &CStr,
86 mut flags: OFlags,
87 mode: Mode,
88 resolve: ResolveFlags,
89) -> io::Result<OwnedFd> {
90 if !flags.contains(OFlags::PATH) {
93 flags |= OFlags::from_bits_retain(c::O_LARGEFILE);
94 }
95
96 unsafe {
97 ret_owned_fd(syscall_readonly!(
98 __NR_openat2,
99 dirfd,
100 path,
101 by_ref(&open_how {
102 flags: oflags_for_open_how(flags),
103 mode: u64::from(mode.bits()),
104 resolve: resolve.bits(),
105 }),
106 size_of::<open_how, _>()
107 ))
108 }
109}
110
111#[inline]
112pub(crate) fn chmod(path: &CStr, mode: Mode) -> io::Result<()> {
113 unsafe {
114 ret(syscall_readonly!(
115 __NR_fchmodat,
116 raw_fd(AT_FDCWD),
117 path,
118 mode
119 ))
120 }
121}
122
123#[inline]
124pub(crate) fn chmodat(
125 dirfd: BorrowedFd<'_>,
126 path: &CStr,
127 mode: Mode,
128 flags: AtFlags,
129) -> io::Result<()> {
130 if flags == AtFlags::SYMLINK_NOFOLLOW {
131 return Err(io::Errno::OPNOTSUPP);
132 }
133 if !flags.is_empty() {
134 return Err(io::Errno::INVAL);
135 }
136 unsafe { ret(syscall_readonly!(__NR_fchmodat, dirfd, path, mode)) }
137}
138
139#[inline]
140pub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> {
141 unsafe { ret(syscall_readonly!(__NR_fchmod, fd, mode)) }
142}
143
144#[inline]
145pub(crate) fn chownat(
146 dirfd: BorrowedFd<'_>,
147 path: &CStr,
148 owner: Option<Uid>,
149 group: Option<Gid>,
150 flags: AtFlags,
151) -> io::Result<()> {
152 unsafe {
153 let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
154 ret(syscall_readonly!(
155 __NR_fchownat,
156 dirfd,
157 path,
158 c_uint(ow),
159 c_uint(gr),
160 flags
161 ))
162 }
163}
164
165#[inline]
166pub(crate) fn chown(path: &CStr, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> {
167 #[cfg(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86"))]
168 unsafe {
169 let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
170 ret(syscall_readonly!(
171 __NR_chown32,
172 path,
173 c_uint(ow),
174 c_uint(gr)
175 ))
176 }
177
178 #[cfg(not(any(
180 target_arch = "aarch64",
181 target_arch = "arm",
182 target_arch = "riscv64",
183 target_arch = "sparc",
184 target_arch = "x86"
185 )))]
186 unsafe {
187 let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
188 ret(syscall_readonly!(__NR_chown, path, c_uint(ow), c_uint(gr)))
189 }
190
191 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
193 unsafe {
194 let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
195 ret(syscall_readonly!(
196 __NR_fchownat,
197 raw_fd(AT_FDCWD),
198 path,
199 c_uint(ow),
200 c_uint(gr),
201 zero()
202 ))
203 }
204}
205
206#[inline]
207pub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> {
208 #[cfg(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86"))]
209 unsafe {
210 let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
211 ret(syscall_readonly!(__NR_fchown32, fd, c_uint(ow), c_uint(gr)))
212 }
213 #[cfg(not(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86")))]
214 unsafe {
215 let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
216 ret(syscall_readonly!(__NR_fchown, fd, c_uint(ow), c_uint(gr)))
217 }
218}
219
220#[inline]
221pub(crate) fn mknodat(
222 dirfd: BorrowedFd<'_>,
223 path: &CStr,
224 file_type: FileType,
225 mode: Mode,
226 dev: u64,
227) -> io::Result<()> {
228 #[cfg(target_pointer_width = "32")]
229 unsafe {
230 ret(syscall_readonly!(
231 __NR_mknodat,
232 dirfd,
233 path,
234 (mode, file_type),
235 dev_t(dev)?
236 ))
237 }
238 #[cfg(target_pointer_width = "64")]
239 unsafe {
240 ret(syscall_readonly!(
241 __NR_mknodat,
242 dirfd,
243 path,
244 (mode, file_type),
245 dev_t(dev)
246 ))
247 }
248}
249
250#[inline]
251pub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result<u64> {
252 let (whence, offset) = match pos {
253 SeekFrom::Start(pos) => {
254 let pos: u64 = pos;
255 (SEEK_SET, pos as i64)
257 }
258 SeekFrom::End(offset) => (SEEK_END, offset),
259 SeekFrom::Current(offset) => (SEEK_CUR, offset),
260 SeekFrom::Data(pos) => {
261 let pos: u64 = pos;
262 (SEEK_DATA, pos as i64)
264 }
265 SeekFrom::Hole(pos) => {
266 let pos: u64 = pos;
267 (SEEK_HOLE, pos as i64)
269 }
270 };
271 _seek(fd, offset, whence)
272}
273
274#[inline]
275pub(crate) fn _seek(fd: BorrowedFd<'_>, offset: i64, whence: c::c_uint) -> io::Result<u64> {
276 #[cfg(target_pointer_width = "32")]
277 unsafe {
278 let mut result = MaybeUninit::<u64>::uninit();
279 ret(syscall!(
280 __NR__llseek,
281 fd,
282 pass_usize((offset >> 32) as usize),
285 pass_usize(offset as usize),
286 &mut result,
287 c_uint(whence)
288 ))?;
289 Ok(result.assume_init())
290 }
291 #[cfg(target_pointer_width = "64")]
292 unsafe {
293 ret_u64(syscall_readonly!(
294 __NR_lseek,
295 fd,
296 loff_t(offset),
297 c_uint(whence)
298 ))
299 }
300}
301
302#[inline]
303pub(crate) fn tell(fd: BorrowedFd<'_>) -> io::Result<u64> {
304 _seek(fd, 0, SEEK_CUR).map(|x| x as u64)
305}
306
307#[inline]
308pub(crate) fn ftruncate(fd: BorrowedFd<'_>, length: u64) -> io::Result<()> {
309 #[cfg(all(
311 target_pointer_width = "32",
312 any(
313 target_arch = "arm",
314 target_arch = "mips",
315 target_arch = "mips32r6",
316 target_arch = "powerpc"
317 ),
318 ))]
319 unsafe {
320 ret(syscall_readonly!(
321 __NR_ftruncate64,
322 fd,
323 zero(),
324 hi(length),
325 lo(length)
326 ))
327 }
328 #[cfg(all(
329 target_pointer_width = "32",
330 not(any(
331 target_arch = "arm",
332 target_arch = "mips",
333 target_arch = "mips32r6",
334 target_arch = "powerpc"
335 )),
336 ))]
337 unsafe {
338 ret(syscall_readonly!(
339 __NR_ftruncate64,
340 fd,
341 hi(length),
342 lo(length)
343 ))
344 }
345 #[cfg(target_pointer_width = "64")]
346 unsafe {
347 ret(syscall_readonly!(
348 __NR_ftruncate,
349 fd,
350 loff_t_from_u64(length)
351 ))
352 }
353}
354
355#[inline]
356pub(crate) fn fallocate(
357 fd: BorrowedFd<'_>,
358 mode: FallocateFlags,
359 offset: u64,
360 len: u64,
361) -> io::Result<()> {
362 #[cfg(target_pointer_width = "32")]
363 unsafe {
364 ret(syscall_readonly!(
365 __NR_fallocate,
366 fd,
367 mode,
368 hi(offset),
369 lo(offset),
370 hi(len),
371 lo(len)
372 ))
373 }
374 #[cfg(target_pointer_width = "64")]
375 unsafe {
376 ret(syscall_readonly!(
377 __NR_fallocate,
378 fd,
379 mode,
380 loff_t_from_u64(offset),
381 loff_t_from_u64(len)
382 ))
383 }
384}
385
386#[inline]
387pub(crate) fn fadvise(
388 fd: BorrowedFd<'_>,
389 pos: u64,
390 len: Option<NonZeroU64>,
391 advice: Advice,
392) -> io::Result<()> {
393 let len = match len {
394 None => 0,
395 Some(len) => len.get(),
396 };
397
398 #[cfg(target_arch = "arm")]
401 unsafe {
402 ret(syscall_readonly!(
403 __NR_arm_fadvise64_64,
404 fd,
405 advice,
406 hi(pos),
407 lo(pos),
408 hi(len),
409 lo(len)
410 ))
411 }
412
413 #[cfg(target_arch = "powerpc")]
415 unsafe {
416 ret(syscall_readonly!(
417 __NR_fadvise64_64,
418 fd,
419 advice,
420 hi(pos),
421 lo(pos),
422 hi(len),
423 lo(len)
424 ))
425 }
426
427 #[cfg(any(target_arch = "mips", target_arch = "mips32r6"))]
430 unsafe {
431 ret(syscall_readonly!(
432 __NR_fadvise64,
433 fd,
434 zero(),
435 hi(pos),
436 lo(pos),
437 hi(len),
438 lo(len),
439 advice
440 ))
441 }
442
443 #[cfg(all(
446 target_pointer_width = "32",
447 not(any(
448 target_arch = "arm",
449 target_arch = "mips",
450 target_arch = "mips32r6",
451 target_arch = "powerpc"
452 )),
453 ))]
454 unsafe {
455 ret(syscall_readonly!(
456 __NR_fadvise64_64,
457 fd,
458 hi(pos),
459 lo(pos),
460 hi(len),
461 lo(len),
462 advice
463 ))
464 }
465
466 #[cfg(target_pointer_width = "64")]
468 unsafe {
469 ret(syscall_readonly!(
470 __NR_fadvise64,
471 fd,
472 loff_t_from_u64(pos),
473 loff_t_from_u64(len),
474 advice
475 ))
476 }
477}
478
479#[inline]
480pub(crate) fn fsync(fd: BorrowedFd<'_>) -> io::Result<()> {
481 unsafe { ret(syscall_readonly!(__NR_fsync, fd)) }
482}
483
484#[inline]
485pub(crate) fn fdatasync(fd: BorrowedFd<'_>) -> io::Result<()> {
486 unsafe { ret(syscall_readonly!(__NR_fdatasync, fd)) }
487}
488
489#[inline]
490pub(crate) fn flock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> {
491 unsafe {
492 ret(syscall_readonly!(
493 __NR_flock,
494 fd,
495 c_uint(operation as c::c_uint)
496 ))
497 }
498}
499
500#[inline]
501pub(crate) fn syncfs(fd: BorrowedFd<'_>) -> io::Result<()> {
502 unsafe { ret(syscall_readonly!(__NR_syncfs, fd)) }
503}
504
505#[inline]
506pub(crate) fn sync() {
507 unsafe { ret_infallible(syscall_readonly!(__NR_sync)) }
508}
509
510#[inline]
511pub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> {
512 #[cfg(any(
519 target_pointer_width = "32",
520 target_arch = "mips64",
521 target_arch = "mips64r6"
522 ))]
523 {
524 match crate::fs::statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) {
525 Ok(x) => statx_to_stat(x),
526 Err(io::Errno::NOSYS) => fstat_old(fd),
527 Err(err) => Err(err),
528 }
529 }
530
531 #[cfg(all(
532 target_pointer_width = "64",
533 not(target_arch = "mips64"),
534 not(target_arch = "mips64r6")
535 ))]
536 unsafe {
537 let mut result = MaybeUninit::<Stat>::uninit();
538 ret(syscall!(__NR_fstat, fd, &mut result))?;
539
540 #[cfg(sanitize_memory)]
541 crate::msan::unpoison_maybe_uninit(&result);
542
543 Ok(result.assume_init())
544 }
545}
546
547#[cfg(any(
548 target_pointer_width = "32",
549 target_arch = "mips64",
550 target_arch = "mips64r6",
551))]
552fn fstat_old(fd: BorrowedFd<'_>) -> io::Result<Stat> {
553 let mut result = MaybeUninit::<linux_stat64>::uninit();
554
555 #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
556 unsafe {
557 ret(syscall!(__NR_fstat, fd, &mut result))?;
558 stat_to_stat(result.assume_init())
559 }
560
561 #[cfg(target_pointer_width = "32")]
562 unsafe {
563 ret(syscall!(__NR_fstat64, fd, &mut result))?;
564 stat_to_stat(result.assume_init())
565 }
566}
567
568#[inline]
569pub(crate) fn stat(path: &CStr) -> io::Result<Stat> {
570 #[cfg(any(
572 target_pointer_width = "32",
573 target_arch = "mips64",
574 target_arch = "mips64r6"
575 ))]
576 {
577 match crate::fs::statx(
578 crate::fs::CWD,
579 path,
580 AtFlags::empty(),
581 StatxFlags::BASIC_STATS,
582 ) {
583 Ok(x) => statx_to_stat(x),
584 Err(io::Errno::NOSYS) => stat_old(path),
585 Err(err) => Err(err),
586 }
587 }
588
589 #[cfg(all(
590 target_pointer_width = "64",
591 not(target_arch = "mips64"),
592 not(target_arch = "mips64r6"),
593 ))]
594 unsafe {
595 let mut result = MaybeUninit::<Stat>::uninit();
596 ret(syscall!(
597 __NR_newfstatat,
598 raw_fd(AT_FDCWD),
599 path,
600 &mut result,
601 c_uint(0)
602 ))?;
603 Ok(result.assume_init())
604 }
605}
606
607#[cfg(any(
608 target_pointer_width = "32",
609 target_arch = "mips64",
610 target_arch = "mips64r6"
611))]
612fn stat_old(path: &CStr) -> io::Result<Stat> {
613 let mut result = MaybeUninit::<linux_stat64>::uninit();
614
615 #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
616 unsafe {
617 ret(syscall!(
618 __NR_newfstatat,
619 raw_fd(AT_FDCWD),
620 path,
621 &mut result,
622 c_uint(0)
623 ))?;
624 stat_to_stat(result.assume_init())
625 }
626
627 #[cfg(target_pointer_width = "32")]
628 unsafe {
629 ret(syscall!(
630 __NR_fstatat64,
631 raw_fd(AT_FDCWD),
632 path,
633 &mut result,
634 c_uint(0)
635 ))?;
636 stat_to_stat(result.assume_init())
637 }
638}
639
640#[inline]
641pub(crate) fn statat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> {
642 #[cfg(any(
644 target_pointer_width = "32",
645 target_arch = "mips64",
646 target_arch = "mips64r6"
647 ))]
648 {
649 match crate::fs::statx(dirfd, path, flags, StatxFlags::BASIC_STATS) {
650 Ok(x) => statx_to_stat(x),
651 Err(io::Errno::NOSYS) => statat_old(dirfd, path, flags),
652 Err(err) => Err(err),
653 }
654 }
655
656 #[cfg(all(
657 target_pointer_width = "64",
658 not(target_arch = "mips64"),
659 not(target_arch = "mips64r6"),
660 ))]
661 unsafe {
662 let mut result = MaybeUninit::<Stat>::uninit();
663 ret(syscall!(__NR_newfstatat, dirfd, path, &mut result, flags))?;
664 Ok(result.assume_init())
665 }
666}
667
668#[cfg(any(
669 target_pointer_width = "32",
670 target_arch = "mips64",
671 target_arch = "mips64r6"
672))]
673fn statat_old(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> {
674 let mut result = MaybeUninit::<linux_stat64>::uninit();
675
676 #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
677 unsafe {
678 ret(syscall!(__NR_newfstatat, dirfd, path, &mut result, flags))?;
679 stat_to_stat(result.assume_init())
680 }
681
682 #[cfg(target_pointer_width = "32")]
683 unsafe {
684 ret(syscall!(__NR_fstatat64, dirfd, path, &mut result, flags))?;
685 stat_to_stat(result.assume_init())
686 }
687}
688
689#[inline]
690pub(crate) fn lstat(path: &CStr) -> io::Result<Stat> {
691 #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
693 {
694 match crate::fs::statx(
695 crate::fs::CWD,
696 path,
697 AtFlags::SYMLINK_NOFOLLOW,
698 StatxFlags::BASIC_STATS,
699 ) {
700 Ok(x) => statx_to_stat(x),
701 Err(io::Errno::NOSYS) => lstat_old(path),
702 Err(err) => Err(err),
703 }
704 }
705
706 #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))]
707 unsafe {
708 let mut result = MaybeUninit::<Stat>::uninit();
709 ret(syscall!(
710 __NR_newfstatat,
711 raw_fd(AT_FDCWD),
712 path,
713 &mut result,
714 c_uint(AT_SYMLINK_NOFOLLOW)
715 ))?;
716 Ok(result.assume_init())
717 }
718}
719
720#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
721fn lstat_old(path: &CStr) -> io::Result<Stat> {
722 let mut result = MaybeUninit::<linux_stat64>::uninit();
723
724 #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
725 unsafe {
726 ret(syscall!(
727 __NR_newfstatat,
728 raw_fd(AT_FDCWD),
729 path,
730 &mut result,
731 c_uint(AT_SYMLINK_NOFOLLOW)
732 ))?;
733 stat_to_stat(result.assume_init())
734 }
735
736 #[cfg(target_pointer_width = "32")]
737 unsafe {
738 ret(syscall!(
739 __NR_fstatat64,
740 raw_fd(AT_FDCWD),
741 path,
742 &mut result,
743 c_uint(AT_SYMLINK_NOFOLLOW)
744 ))?;
745 stat_to_stat(result.assume_init())
746 }
747}
748
749#[cfg(any(
751 target_pointer_width = "32",
752 target_arch = "mips64",
753 target_arch = "mips64r6"
754))]
755fn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> {
756 Ok(Stat {
757 st_dev: crate::fs::makedev(x.stx_dev_major, x.stx_dev_minor),
758 st_mode: x.stx_mode.into(),
759 st_nlink: x.stx_nlink.into(),
760 st_uid: x.stx_uid.into(),
761 st_gid: x.stx_gid.into(),
762 st_rdev: crate::fs::makedev(x.stx_rdev_major, x.stx_rdev_minor),
763 st_size: x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?,
764 st_blksize: x.stx_blksize.into(),
765 st_blocks: x.stx_blocks.into(),
766 st_atime: i64::from(x.stx_atime.tv_sec),
767 st_atime_nsec: x.stx_atime.tv_nsec.into(),
768 st_mtime: i64::from(x.stx_mtime.tv_sec),
769 st_mtime_nsec: x.stx_mtime.tv_nsec.into(),
770 st_ctime: i64::from(x.stx_ctime.tv_sec),
771 st_ctime_nsec: x.stx_ctime.tv_nsec.into(),
772 st_ino: x.stx_ino.into(),
773 })
774}
775
776#[cfg(target_pointer_width = "32")]
778fn stat_to_stat(s64: linux_raw_sys::general::stat64) -> io::Result<Stat> {
779 Ok(Stat {
780 st_dev: s64.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?,
781 st_mode: s64.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?,
782 st_nlink: s64.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?,
783 st_uid: s64.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?,
784 st_gid: s64.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?,
785 st_rdev: s64.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?,
786 st_size: s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?,
787 st_blksize: s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?,
788 st_blocks: s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?,
789 st_atime: i64::from(s64.st_atime.to_signed()),
790 st_atime_nsec: s64
791 .st_atime_nsec
792 .try_into()
793 .map_err(|_| io::Errno::OVERFLOW)?,
794 st_mtime: i64::from(s64.st_mtime.to_signed()),
795 st_mtime_nsec: s64
796 .st_mtime_nsec
797 .try_into()
798 .map_err(|_| io::Errno::OVERFLOW)?,
799 st_ctime: i64::from(s64.st_ctime.to_signed()),
800 st_ctime_nsec: s64
801 .st_ctime_nsec
802 .try_into()
803 .map_err(|_| io::Errno::OVERFLOW)?,
804 st_ino: s64.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?,
805 })
806}
807
808#[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
810fn stat_to_stat(s: linux_raw_sys::general::stat) -> io::Result<Stat> {
811 Ok(Stat {
812 st_dev: s.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?,
813 st_mode: s.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?,
814 st_nlink: s.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?,
815 st_uid: s.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?,
816 st_gid: s.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?,
817 st_rdev: s.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?,
818 st_size: s.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?,
819 st_blksize: s.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?,
820 st_blocks: s.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?,
821 st_atime: i64::from(s.st_atime.to_signed()),
822 st_atime_nsec: s
823 .st_atime_nsec
824 .try_into()
825 .map_err(|_| io::Errno::OVERFLOW)?,
826 st_mtime: i64::from(s.st_mtime.to_signed()),
827 st_mtime_nsec: s
828 .st_mtime_nsec
829 .try_into()
830 .map_err(|_| io::Errno::OVERFLOW)?,
831 st_ctime: i64::from(s.st_ctime.to_signed()),
832 st_ctime_nsec: s
833 .st_ctime_nsec
834 .try_into()
835 .map_err(|_| io::Errno::OVERFLOW)?,
836 st_ino: s.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?,
837 })
838}
839
840#[inline]
841pub(crate) fn statx(
842 dirfd: BorrowedFd<'_>,
843 path: &CStr,
844 flags: AtFlags,
845 mask: StatxFlags,
846) -> io::Result<Statx> {
847 if (mask.bits() & STATX__RESERVED) == STATX__RESERVED {
861 return Err(io::Errno::INVAL);
862 }
863 let mask = mask & StatxFlags::all();
864
865 unsafe {
866 let mut statx_buf = MaybeUninit::<Statx>::uninit();
867 ret(syscall!(
868 __NR_statx,
869 dirfd,
870 path,
871 flags,
872 mask,
873 &mut statx_buf
874 ))?;
875 Ok(statx_buf.assume_init())
876 }
877}
878
879#[cfg(not(feature = "linux_4_11"))]
880#[inline]
881pub(crate) fn is_statx_available() -> bool {
882 unsafe {
883 matches!(
887 ret(syscall_readonly!(
888 __NR_statx,
889 raw_fd(AT_FDCWD),
890 zero(),
891 zero(),
892 zero(),
893 zero()
894 )),
895 Err(io::Errno::FAULT)
896 )
897 }
898}
899
900#[inline]
901pub(crate) fn fstatfs(fd: BorrowedFd<'_>) -> io::Result<StatFs> {
902 #[cfg(target_pointer_width = "32")]
903 unsafe {
904 let mut result = MaybeUninit::<StatFs>::uninit();
905 ret(syscall!(
906 __NR_fstatfs64,
907 fd,
908 size_of::<StatFs, _>(),
909 &mut result
910 ))?;
911 Ok(result.assume_init())
912 }
913
914 #[cfg(target_pointer_width = "64")]
915 unsafe {
916 let mut result = MaybeUninit::<StatFs>::uninit();
917 ret(syscall!(__NR_fstatfs, fd, &mut result))?;
918 Ok(result.assume_init())
919 }
920}
921
922#[inline]
923pub(crate) fn fstatvfs(fd: BorrowedFd<'_>) -> io::Result<StatVfs> {
924 let statfs = fstatfs(fd)?;
927
928 Ok(statfs_to_statvfs(statfs))
929}
930
931#[inline]
932pub(crate) fn statfs(path: &CStr) -> io::Result<StatFs> {
933 #[cfg(target_pointer_width = "32")]
934 unsafe {
935 let mut result = MaybeUninit::<StatFs>::uninit();
936 ret(syscall!(
937 __NR_statfs64,
938 path,
939 size_of::<StatFs, _>(),
940 &mut result
941 ))?;
942 Ok(result.assume_init())
943 }
944 #[cfg(target_pointer_width = "64")]
945 unsafe {
946 let mut result = MaybeUninit::<StatFs>::uninit();
947 ret(syscall!(__NR_statfs, path, &mut result))?;
948 Ok(result.assume_init())
949 }
950}
951
952#[inline]
953pub(crate) fn statvfs(path: &CStr) -> io::Result<StatVfs> {
954 let statfs = statfs(path)?;
957
958 Ok(statfs_to_statvfs(statfs))
959}
960
961fn statfs_to_statvfs(statfs: StatFs) -> StatVfs {
962 let Fsid { val } = Fsid {
963 val: statfs.f_fsid.val,
964 };
965 let [f_fsid_val0, f_fsid_val1]: [i32; 2] = val;
966
967 StatVfs {
968 f_bsize: statfs.f_bsize as u64,
969 f_frsize: if statfs.f_frsize != 0 {
970 statfs.f_frsize
971 } else {
972 statfs.f_bsize
973 } as u64,
974 f_blocks: statfs.f_blocks as u64,
975 f_bfree: statfs.f_bfree as u64,
976 f_bavail: statfs.f_bavail as u64,
977 f_files: statfs.f_files as u64,
978 f_ffree: statfs.f_ffree as u64,
979 f_favail: statfs.f_ffree as u64,
980 f_fsid: u64::from(f_fsid_val0 as u32) | (u64::from(f_fsid_val1 as u32) << 32),
981 f_flag: StatVfsMountFlags::from_bits_retain(statfs.f_flags as u64),
982 f_namemax: statfs.f_namelen as u64,
983 }
984}
985
986#[cfg(feature = "alloc")]
987#[inline]
988pub(crate) fn readlink(path: &CStr, buf: &mut [u8]) -> io::Result<usize> {
989 let (buf_addr_mut, buf_len) = slice_mut(buf);
990 unsafe {
991 ret_usize(syscall!(
992 __NR_readlinkat,
993 raw_fd(AT_FDCWD),
994 path,
995 buf_addr_mut,
996 buf_len
997 ))
998 }
999}
1000
1001#[inline]
1002pub(crate) unsafe fn readlinkat(
1003 dirfd: BorrowedFd<'_>,
1004 path: &CStr,
1005 buf: (*mut u8, usize),
1006) -> io::Result<usize> {
1007 ret_usize(syscall!(
1008 __NR_readlinkat,
1009 dirfd,
1010 path,
1011 buf.0,
1012 pass_usize(buf.1)
1013 ))
1014}
1015
1016#[inline]
1017pub(crate) fn fcntl_getfl(fd: BorrowedFd<'_>) -> io::Result<OFlags> {
1018 #[cfg(target_pointer_width = "32")]
1019 unsafe {
1020 ret_c_uint(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETFL)))
1021 .map(OFlags::from_bits_retain)
1022 }
1023 #[cfg(target_pointer_width = "64")]
1024 unsafe {
1025 ret_c_uint(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETFL))).map(OFlags::from_bits_retain)
1026 }
1027}
1028
1029#[inline]
1030pub(crate) fn fcntl_setfl(fd: BorrowedFd<'_>, flags: OFlags) -> io::Result<()> {
1031 let flags = flags | OFlags::from_bits_retain(c::O_LARGEFILE);
1033
1034 #[cfg(target_pointer_width = "32")]
1035 unsafe {
1036 ret(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_SETFL), flags))
1037 }
1038 #[cfg(target_pointer_width = "64")]
1039 unsafe {
1040 ret(syscall_readonly!(__NR_fcntl, fd, c_uint(F_SETFL), flags))
1041 }
1042}
1043
1044#[inline]
1045pub(crate) fn fcntl_get_seals(fd: BorrowedFd<'_>) -> io::Result<SealFlags> {
1046 #[cfg(target_pointer_width = "32")]
1047 unsafe {
1048 ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GET_SEALS)))
1049 .map(|seals| SealFlags::from_bits_retain(seals as u32))
1050 }
1051 #[cfg(target_pointer_width = "64")]
1052 unsafe {
1053 ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GET_SEALS)))
1054 .map(|seals| SealFlags::from_bits_retain(seals as u32))
1055 }
1056}
1057
1058#[inline]
1059pub(crate) fn fcntl_add_seals(fd: BorrowedFd<'_>, seals: SealFlags) -> io::Result<()> {
1060 #[cfg(target_pointer_width = "32")]
1061 unsafe {
1062 ret(syscall_readonly!(
1063 __NR_fcntl64,
1064 fd,
1065 c_uint(F_ADD_SEALS),
1066 seals
1067 ))
1068 }
1069 #[cfg(target_pointer_width = "64")]
1070 unsafe {
1071 ret(syscall_readonly!(
1072 __NR_fcntl,
1073 fd,
1074 c_uint(F_ADD_SEALS),
1075 seals
1076 ))
1077 }
1078}
1079
1080#[inline]
1081pub(crate) fn fcntl_lock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> {
1082 #[cfg(target_pointer_width = "64")]
1083 use linux_raw_sys::general::{flock, F_SETLK, F_SETLKW};
1084 #[cfg(target_pointer_width = "32")]
1085 use linux_raw_sys::general::{flock64 as flock, F_SETLK64 as F_SETLK, F_SETLKW64 as F_SETLKW};
1086 use linux_raw_sys::general::{F_RDLCK, F_UNLCK, F_WRLCK};
1087
1088 let (cmd, l_type) = match operation {
1089 FlockOperation::LockShared => (F_SETLKW, F_RDLCK),
1090 FlockOperation::LockExclusive => (F_SETLKW, F_WRLCK),
1091 FlockOperation::Unlock => (F_SETLKW, F_UNLCK),
1092 FlockOperation::NonBlockingLockShared => (F_SETLK, F_RDLCK),
1093 FlockOperation::NonBlockingLockExclusive => (F_SETLK, F_WRLCK),
1094 FlockOperation::NonBlockingUnlock => (F_SETLK, F_UNLCK),
1095 };
1096
1097 let lock = flock {
1098 l_type: l_type as _,
1099
1100 l_whence: SEEK_SET as _,
1104 l_start: 0,
1105 l_len: 0,
1106
1107 l_pid: 0,
1109 };
1110
1111 #[cfg(target_pointer_width = "32")]
1112 unsafe {
1113 ret(syscall_readonly!(
1114 __NR_fcntl64,
1115 fd,
1116 c_uint(cmd),
1117 by_ref(&lock)
1118 ))
1119 }
1120 #[cfg(target_pointer_width = "64")]
1121 unsafe {
1122 ret(syscall_readonly!(
1123 __NR_fcntl,
1124 fd,
1125 c_uint(cmd),
1126 by_ref(&lock)
1127 ))
1128 }
1129}
1130
1131#[inline]
1132pub(crate) fn rename(old_path: &CStr, new_path: &CStr) -> io::Result<()> {
1133 #[cfg(target_arch = "riscv64")]
1134 unsafe {
1135 ret(syscall_readonly!(
1136 __NR_renameat2,
1137 raw_fd(AT_FDCWD),
1138 old_path,
1139 raw_fd(AT_FDCWD),
1140 new_path,
1141 c_uint(0)
1142 ))
1143 }
1144 #[cfg(not(target_arch = "riscv64"))]
1145 unsafe {
1146 ret(syscall_readonly!(
1147 __NR_renameat,
1148 raw_fd(AT_FDCWD),
1149 old_path,
1150 raw_fd(AT_FDCWD),
1151 new_path
1152 ))
1153 }
1154}
1155
1156#[inline]
1157pub(crate) fn renameat(
1158 old_dirfd: BorrowedFd<'_>,
1159 old_path: &CStr,
1160 new_dirfd: BorrowedFd<'_>,
1161 new_path: &CStr,
1162) -> io::Result<()> {
1163 #[cfg(target_arch = "riscv64")]
1164 unsafe {
1165 ret(syscall_readonly!(
1166 __NR_renameat2,
1167 old_dirfd,
1168 old_path,
1169 new_dirfd,
1170 new_path,
1171 c_uint(0)
1172 ))
1173 }
1174 #[cfg(not(target_arch = "riscv64"))]
1175 unsafe {
1176 ret(syscall_readonly!(
1177 __NR_renameat,
1178 old_dirfd,
1179 old_path,
1180 new_dirfd,
1181 new_path
1182 ))
1183 }
1184}
1185
1186#[inline]
1187pub(crate) fn renameat2(
1188 old_dirfd: BorrowedFd<'_>,
1189 old_path: &CStr,
1190 new_dirfd: BorrowedFd<'_>,
1191 new_path: &CStr,
1192 flags: RenameFlags,
1193) -> io::Result<()> {
1194 unsafe {
1195 ret(syscall_readonly!(
1196 __NR_renameat2,
1197 old_dirfd,
1198 old_path,
1199 new_dirfd,
1200 new_path,
1201 flags
1202 ))
1203 }
1204}
1205
1206#[inline]
1207pub(crate) fn unlink(path: &CStr) -> io::Result<()> {
1208 unsafe {
1209 ret(syscall_readonly!(
1210 __NR_unlinkat,
1211 raw_fd(AT_FDCWD),
1212 path,
1213 c_uint(0)
1214 ))
1215 }
1216}
1217
1218#[inline]
1219pub(crate) fn unlinkat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<()> {
1220 unsafe { ret(syscall_readonly!(__NR_unlinkat, dirfd, path, flags)) }
1221}
1222
1223#[inline]
1224pub(crate) fn rmdir(path: &CStr) -> io::Result<()> {
1225 unsafe {
1226 ret(syscall_readonly!(
1227 __NR_unlinkat,
1228 raw_fd(AT_FDCWD),
1229 path,
1230 c_uint(AT_REMOVEDIR)
1231 ))
1232 }
1233}
1234
1235#[inline]
1236pub(crate) fn link(old_path: &CStr, new_path: &CStr) -> io::Result<()> {
1237 unsafe {
1238 ret(syscall_readonly!(
1239 __NR_linkat,
1240 raw_fd(AT_FDCWD),
1241 old_path,
1242 raw_fd(AT_FDCWD),
1243 new_path,
1244 c_uint(0)
1245 ))
1246 }
1247}
1248
1249#[inline]
1250pub(crate) fn linkat(
1251 old_dirfd: BorrowedFd<'_>,
1252 old_path: &CStr,
1253 new_dirfd: BorrowedFd<'_>,
1254 new_path: &CStr,
1255 flags: AtFlags,
1256) -> io::Result<()> {
1257 unsafe {
1258 ret(syscall_readonly!(
1259 __NR_linkat,
1260 old_dirfd,
1261 old_path,
1262 new_dirfd,
1263 new_path,
1264 flags
1265 ))
1266 }
1267}
1268
1269#[inline]
1270pub(crate) fn symlink(old_path: &CStr, new_path: &CStr) -> io::Result<()> {
1271 unsafe {
1272 ret(syscall_readonly!(
1273 __NR_symlinkat,
1274 old_path,
1275 raw_fd(AT_FDCWD),
1276 new_path
1277 ))
1278 }
1279}
1280
1281#[inline]
1282pub(crate) fn symlinkat(old_path: &CStr, dirfd: BorrowedFd<'_>, new_path: &CStr) -> io::Result<()> {
1283 unsafe { ret(syscall_readonly!(__NR_symlinkat, old_path, dirfd, new_path)) }
1284}
1285
1286#[inline]
1287pub(crate) fn mkdir(path: &CStr, mode: Mode) -> io::Result<()> {
1288 unsafe {
1289 ret(syscall_readonly!(
1290 __NR_mkdirat,
1291 raw_fd(AT_FDCWD),
1292 path,
1293 mode
1294 ))
1295 }
1296}
1297
1298#[inline]
1299pub(crate) fn mkdirat(dirfd: BorrowedFd<'_>, path: &CStr, mode: Mode) -> io::Result<()> {
1300 unsafe { ret(syscall_readonly!(__NR_mkdirat, dirfd, path, mode)) }
1301}
1302
1303#[cfg(feature = "alloc")]
1304#[inline]
1305pub(crate) fn getdents(fd: BorrowedFd<'_>, dirent: &mut [u8]) -> io::Result<usize> {
1306 let (dirent_addr_mut, dirent_len) = slice_mut(dirent);
1307
1308 unsafe { ret_usize(syscall!(__NR_getdents64, fd, dirent_addr_mut, dirent_len)) }
1309}
1310
1311#[inline]
1312pub(crate) fn getdents_uninit(
1313 fd: BorrowedFd<'_>,
1314 dirent: &mut [MaybeUninit<u8>],
1315) -> io::Result<usize> {
1316 let (dirent_addr_mut, dirent_len) = slice_mut(dirent);
1317
1318 unsafe { ret_usize(syscall!(__NR_getdents64, fd, dirent_addr_mut, dirent_len)) }
1319}
1320
1321#[inline]
1322pub(crate) fn utimensat(
1323 dirfd: BorrowedFd<'_>,
1324 path: &CStr,
1325 times: &Timestamps,
1326 flags: AtFlags,
1327) -> io::Result<()> {
1328 _utimensat(dirfd, Some(path), times, flags)
1329}
1330
1331#[inline]
1332fn _utimensat(
1333 dirfd: BorrowedFd<'_>,
1334 path: Option<&CStr>,
1335 times: &Timestamps,
1336 flags: AtFlags,
1337) -> io::Result<()> {
1338 #[cfg(target_pointer_width = "32")]
1341 unsafe {
1342 match ret(syscall_readonly!(
1343 __NR_utimensat_time64,
1344 dirfd,
1345 path,
1346 by_ref(times),
1347 flags
1348 )) {
1349 Err(io::Errno::NOSYS) => _utimensat_old(dirfd, path, times, flags),
1350 otherwise => otherwise,
1351 }
1352 }
1353 #[cfg(target_pointer_width = "64")]
1354 unsafe {
1355 ret(syscall_readonly!(
1356 __NR_utimensat,
1357 dirfd,
1358 path,
1359 by_ref(times),
1360 flags
1361 ))
1362 }
1363}
1364
1365#[cfg(target_pointer_width = "32")]
1366unsafe fn _utimensat_old(
1367 dirfd: BorrowedFd<'_>,
1368 path: Option<&CStr>,
1369 times: &Timestamps,
1370 flags: AtFlags,
1371) -> io::Result<()> {
1372 let old_times = [
1374 __kernel_old_timespec {
1375 tv_sec: times
1376 .last_access
1377 .tv_sec
1378 .try_into()
1379 .map_err(|_| io::Errno::OVERFLOW)?,
1380 tv_nsec: times
1381 .last_access
1382 .tv_nsec
1383 .try_into()
1384 .map_err(|_| io::Errno::INVAL)?,
1385 },
1386 __kernel_old_timespec {
1387 tv_sec: times
1388 .last_modification
1389 .tv_sec
1390 .try_into()
1391 .map_err(|_| io::Errno::OVERFLOW)?,
1392 tv_nsec: times
1393 .last_modification
1394 .tv_nsec
1395 .try_into()
1396 .map_err(|_| io::Errno::INVAL)?,
1397 },
1398 ];
1399 let old_times_addr = slice_just_addr(&old_times);
1401 ret(syscall_readonly!(
1402 __NR_utimensat,
1403 dirfd,
1404 path,
1405 old_times_addr,
1406 flags
1407 ))
1408}
1409
1410#[inline]
1411pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> {
1412 _utimensat(fd, None, times, AtFlags::empty())
1413}
1414
1415#[inline]
1416pub(crate) fn access(path: &CStr, access: Access) -> io::Result<()> {
1417 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
1418 {
1419 accessat_noflags(CWD, path, access)
1420 }
1421
1422 #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
1423 unsafe {
1424 ret(syscall_readonly!(__NR_access, path, access))
1425 }
1426}
1427
1428pub(crate) fn accessat(
1429 dirfd: BorrowedFd<'_>,
1430 path: &CStr,
1431 access: Access,
1432 flags: AtFlags,
1433) -> io::Result<()> {
1434 if !flags
1435 .difference(AtFlags::EACCESS | AtFlags::SYMLINK_NOFOLLOW)
1436 .is_empty()
1437 {
1438 return Err(io::Errno::INVAL);
1439 }
1440
1441 #[cfg(not(target_os = "android"))]
1446 if !flags.is_empty() {
1447 unsafe {
1448 match ret(syscall_readonly!(
1449 __NR_faccessat2,
1450 dirfd,
1451 path,
1452 access,
1453 flags
1454 )) {
1455 Ok(()) => return Ok(()),
1456 Err(io::Errno::NOSYS) => {}
1457 Err(other) => return Err(other),
1458 }
1459 }
1460 }
1461
1462 if flags.is_empty()
1465 || (flags.bits() == AT_EACCESS
1466 && crate::backend::ugid::syscalls::getuid()
1467 == crate::backend::ugid::syscalls::geteuid()
1468 && crate::backend::ugid::syscalls::getgid()
1469 == crate::backend::ugid::syscalls::getegid())
1470 {
1471 return accessat_noflags(dirfd, path, access);
1472 }
1473
1474 Err(io::Errno::NOSYS)
1475}
1476
1477#[inline]
1478fn accessat_noflags(dirfd: BorrowedFd<'_>, path: &CStr, access: Access) -> io::Result<()> {
1479 unsafe { ret(syscall_readonly!(__NR_faccessat, dirfd, path, access)) }
1480}
1481
1482#[inline]
1483pub(crate) fn copy_file_range(
1484 fd_in: BorrowedFd<'_>,
1485 off_in: Option<&mut u64>,
1486 fd_out: BorrowedFd<'_>,
1487 off_out: Option<&mut u64>,
1488 len: usize,
1489) -> io::Result<usize> {
1490 unsafe {
1491 ret_usize(syscall!(
1492 __NR_copy_file_range,
1493 fd_in,
1494 opt_mut(off_in),
1495 fd_out,
1496 opt_mut(off_out),
1497 pass_usize(len),
1498 c_uint(0)
1499 ))
1500 }
1501}
1502
1503#[inline]
1504pub(crate) fn memfd_create(name: &CStr, flags: MemfdFlags) -> io::Result<OwnedFd> {
1505 unsafe { ret_owned_fd(syscall_readonly!(__NR_memfd_create, name, flags)) }
1506}
1507
1508#[inline]
1509pub(crate) fn sendfile(
1510 out_fd: BorrowedFd<'_>,
1511 in_fd: BorrowedFd<'_>,
1512 offset: Option<&mut u64>,
1513 count: usize,
1514) -> io::Result<usize> {
1515 #[cfg(target_pointer_width = "32")]
1516 unsafe {
1517 ret_usize(syscall!(
1518 __NR_sendfile64,
1519 out_fd,
1520 in_fd,
1521 opt_mut(offset),
1522 pass_usize(count)
1523 ))
1524 }
1525 #[cfg(target_pointer_width = "64")]
1526 unsafe {
1527 ret_usize(syscall!(
1528 __NR_sendfile,
1529 out_fd,
1530 in_fd,
1531 opt_mut(offset),
1532 pass_usize(count)
1533 ))
1534 }
1535}
1536
1537#[inline]
1538pub(crate) fn inotify_init1(flags: inotify::CreateFlags) -> io::Result<OwnedFd> {
1539 unsafe { ret_owned_fd(syscall_readonly!(__NR_inotify_init1, flags)) }
1540}
1541
1542#[inline]
1543pub(crate) fn inotify_add_watch(
1544 infd: BorrowedFd<'_>,
1545 path: &CStr,
1546 flags: inotify::WatchFlags,
1547) -> io::Result<i32> {
1548 unsafe { ret_c_int(syscall_readonly!(__NR_inotify_add_watch, infd, path, flags)) }
1549}
1550
1551#[inline]
1552pub(crate) fn inotify_rm_watch(infd: BorrowedFd<'_>, wfd: i32) -> io::Result<()> {
1553 unsafe { ret(syscall_readonly!(__NR_inotify_rm_watch, infd, c_int(wfd))) }
1554}
1555
1556#[inline]
1557pub(crate) unsafe fn getxattr(
1558 path: &CStr,
1559 name: &CStr,
1560 value: (*mut u8, usize),
1561) -> io::Result<usize> {
1562 ret_usize(syscall!(
1563 __NR_getxattr,
1564 path,
1565 name,
1566 value.0,
1567 pass_usize(value.1)
1568 ))
1569}
1570
1571#[inline]
1572pub(crate) unsafe fn lgetxattr(
1573 path: &CStr,
1574 name: &CStr,
1575 value: (*mut u8, usize),
1576) -> io::Result<usize> {
1577 ret_usize(syscall!(
1578 __NR_lgetxattr,
1579 path,
1580 name,
1581 value.0,
1582 pass_usize(value.1)
1583 ))
1584}
1585
1586#[inline]
1587pub(crate) unsafe fn fgetxattr(
1588 fd: BorrowedFd<'_>,
1589 name: &CStr,
1590 value: (*mut u8, usize),
1591) -> io::Result<usize> {
1592 ret_usize(syscall!(
1593 __NR_fgetxattr,
1594 fd,
1595 name,
1596 value.0,
1597 pass_usize(value.1)
1598 ))
1599}
1600
1601#[inline]
1602pub(crate) fn setxattr(
1603 path: &CStr,
1604 name: &CStr,
1605 value: &[u8],
1606 flags: XattrFlags,
1607) -> io::Result<()> {
1608 let (value_addr, value_len) = slice(value);
1609 unsafe {
1610 ret(syscall_readonly!(
1611 __NR_setxattr,
1612 path,
1613 name,
1614 value_addr,
1615 value_len,
1616 flags
1617 ))
1618 }
1619}
1620
1621#[inline]
1622pub(crate) fn lsetxattr(
1623 path: &CStr,
1624 name: &CStr,
1625 value: &[u8],
1626 flags: XattrFlags,
1627) -> io::Result<()> {
1628 let (value_addr, value_len) = slice(value);
1629 unsafe {
1630 ret(syscall_readonly!(
1631 __NR_lsetxattr,
1632 path,
1633 name,
1634 value_addr,
1635 value_len,
1636 flags
1637 ))
1638 }
1639}
1640
1641#[inline]
1642pub(crate) fn fsetxattr(
1643 fd: BorrowedFd<'_>,
1644 name: &CStr,
1645 value: &[u8],
1646 flags: XattrFlags,
1647) -> io::Result<()> {
1648 let (value_addr, value_len) = slice(value);
1649 unsafe {
1650 ret(syscall_readonly!(
1651 __NR_fsetxattr,
1652 fd,
1653 name,
1654 value_addr,
1655 value_len,
1656 flags
1657 ))
1658 }
1659}
1660
1661#[inline]
1662pub(crate) unsafe fn listxattr(path: &CStr, list: (*mut u8, usize)) -> io::Result<usize> {
1663 ret_usize(syscall!(__NR_listxattr, path, list.0, pass_usize(list.1)))
1664}
1665
1666#[inline]
1667pub(crate) unsafe fn llistxattr(path: &CStr, list: (*mut u8, usize)) -> io::Result<usize> {
1668 ret_usize(syscall!(__NR_llistxattr, path, list.0, pass_usize(list.1)))
1669}
1670
1671#[inline]
1672pub(crate) unsafe fn flistxattr(fd: BorrowedFd<'_>, list: (*mut u8, usize)) -> io::Result<usize> {
1673 ret_usize(syscall!(__NR_flistxattr, fd, list.0, pass_usize(list.1)))
1674}
1675
1676#[inline]
1677pub(crate) fn removexattr(path: &CStr, name: &CStr) -> io::Result<()> {
1678 unsafe { ret(syscall_readonly!(__NR_removexattr, path, name)) }
1679}
1680
1681#[inline]
1682pub(crate) fn lremovexattr(path: &CStr, name: &CStr) -> io::Result<()> {
1683 unsafe { ret(syscall_readonly!(__NR_lremovexattr, path, name)) }
1684}
1685
1686#[inline]
1687pub(crate) fn fremovexattr(fd: BorrowedFd<'_>, name: &CStr) -> io::Result<()> {
1688 unsafe { ret(syscall_readonly!(__NR_fremovexattr, fd, name)) }
1689}
1690
1691#[cfg(any(
1695 target_pointer_width = "32",
1696 target_arch = "mips64",
1697 target_arch = "mips64r6"
1698))]
1699mod to_signed {
1700 pub(super) trait ToSigned {
1701 type Signed;
1702 fn to_signed(self) -> Self::Signed;
1703 }
1704 impl ToSigned for u32 {
1705 type Signed = i32;
1706
1707 fn to_signed(self) -> Self::Signed {
1708 self as _
1709 }
1710 }
1711 impl ToSigned for i32 {
1712 type Signed = i32;
1713
1714 fn to_signed(self) -> Self::Signed {
1715 self
1716 }
1717 }
1718 impl ToSigned for u64 {
1719 type Signed = i64;
1720
1721 fn to_signed(self) -> Self::Signed {
1722 self as _
1723 }
1724 }
1725 impl ToSigned for i64 {
1726 type Signed = i64;
1727
1728 fn to_signed(self) -> Self::Signed {
1729 self
1730 }
1731 }
1732}
1733#[cfg(any(
1734 target_pointer_width = "32",
1735 target_arch = "mips64",
1736 target_arch = "mips64r6"
1737))]
1738use to_signed::*;
1739
1740#[cfg(test)]
1741mod tests {
1742 use super::*;
1743
1744 #[test]
1745 fn test_sizes() {
1746 static_assertions::assert_eq_size!(linux_raw_sys::general::__kernel_loff_t, u64);
1747 static_assertions::assert_eq_align!(linux_raw_sys::general::__kernel_loff_t, u64);
1748
1749 static_assertions::assert_eq_size!(
1751 [linux_raw_sys::general::__kernel_timespec; 2],
1752 Timestamps
1753 );
1754 static_assertions::assert_eq_align!(
1755 [linux_raw_sys::general::__kernel_timespec; 2],
1756 Timestamps
1757 );
1758 }
1759}