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