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