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};
25#[cfg(any(
26 target_arch = "aarch64",
27 target_arch = "riscv64",
28 target_arch = "mips64",
29 target_arch = "mips64r6",
30 target_pointer_width = "32",
31))]
32use crate::fd::AsFd;
33use crate::fd::{BorrowedFd, OwnedFd};
34use crate::ffi::CStr;
35#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
36use crate::fs::CWD;
37use crate::fs::{
38 inotify, Access, Advice, AtFlags, FallocateFlags, FileType, FlockOperation, Fsid, Gid,
39 MemfdFlags, Mode, OFlags, RenameFlags, ResolveFlags, SealFlags, SeekFrom, Stat, StatFs,
40 StatVfs, StatVfsMountFlags, Statx, StatxFlags, Timestamps, Uid, XattrFlags,
41};
42use crate::io;
43use core::mem::MaybeUninit;
44use core::num::NonZeroU64;
45#[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
46use linux_raw_sys::general::stat as linux_stat64;
47use linux_raw_sys::general::{
48 open_how, AT_EACCESS, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_NOFOLLOW, F_ADD_SEALS, F_GETFL,
49 F_GET_SEALS, F_SETFL, SEEK_CUR, SEEK_DATA, SEEK_END, SEEK_HOLE, SEEK_SET, STATX__RESERVED,
50};
51#[cfg(target_pointer_width = "32")]
52use {
53 crate::backend::conv::{hi, lo, slice_just_addr},
54 linux_raw_sys::general::stat64 as linux_stat64,
55 linux_raw_sys::general::timespec as __kernel_old_timespec,
56};
57
58#[inline]
59pub(crate) fn open(path: &CStr, flags: OFlags, mode: Mode) -> io::Result<OwnedFd> {
60 let flags = flags | OFlags::LARGEFILE;
62
63 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
64 {
65 openat(CWD.as_fd(), path, flags, mode)
66 }
67 #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
68 unsafe {
69 ret_owned_fd(syscall_readonly!(__NR_open, path, flags, mode))
70 }
71}
72
73#[inline]
74pub(crate) fn openat(
75 dirfd: BorrowedFd<'_>,
76 path: &CStr,
77 flags: OFlags,
78 mode: Mode,
79) -> io::Result<OwnedFd> {
80 let flags = flags | OFlags::LARGEFILE;
82
83 unsafe { ret_owned_fd(syscall_readonly!(__NR_openat, dirfd, path, flags, mode)) }
84}
85
86#[inline]
87pub(crate) fn openat2(
88 dirfd: BorrowedFd<'_>,
89 path: &CStr,
90 mut flags: OFlags,
91 mode: Mode,
92 resolve: ResolveFlags,
93) -> io::Result<OwnedFd> {
94 if !flags.contains(OFlags::PATH) {
97 flags |= OFlags::from_bits_retain(c::O_LARGEFILE);
98 }
99
100 unsafe {
101 ret_owned_fd(syscall_readonly!(
102 __NR_openat2,
103 dirfd,
104 path,
105 by_ref(&open_how {
106 flags: oflags_for_open_how(flags),
107 mode: u64::from(mode.bits()),
108 resolve: resolve.bits(),
109 }),
110 size_of::<open_how, _>()
111 ))
112 }
113}
114
115#[inline]
116pub(crate) fn chmod(path: &CStr, mode: Mode) -> io::Result<()> {
117 unsafe {
118 ret(syscall_readonly!(
119 __NR_fchmodat,
120 raw_fd(AT_FDCWD),
121 path,
122 mode
123 ))
124 }
125}
126
127#[inline]
128pub(crate) fn chmodat(
129 dirfd: BorrowedFd<'_>,
130 path: &CStr,
131 mode: Mode,
132 flags: AtFlags,
133) -> io::Result<()> {
134 if flags == AtFlags::SYMLINK_NOFOLLOW {
135 return Err(io::Errno::OPNOTSUPP);
136 }
137 if !flags.is_empty() {
138 return Err(io::Errno::INVAL);
139 }
140 unsafe { ret(syscall_readonly!(__NR_fchmodat, dirfd, path, mode)) }
141}
142
143#[inline]
144pub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> {
145 unsafe { ret(syscall_readonly!(__NR_fchmod, fd, mode)) }
146}
147
148#[inline]
149pub(crate) fn chownat(
150 dirfd: BorrowedFd<'_>,
151 path: &CStr,
152 owner: Option<Uid>,
153 group: Option<Gid>,
154 flags: AtFlags,
155) -> io::Result<()> {
156 unsafe {
157 let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
158 ret(syscall_readonly!(
159 __NR_fchownat,
160 dirfd,
161 path,
162 c_uint(ow),
163 c_uint(gr),
164 flags
165 ))
166 }
167}
168
169#[inline]
170pub(crate) fn chown(path: &CStr, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> {
171 #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
173 unsafe {
174 let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
175 ret(syscall_readonly!(__NR_chown, path, c_uint(ow), c_uint(gr)))
176 }
177
178 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
180 unsafe {
181 let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
182 ret(syscall_readonly!(
183 __NR_fchownat,
184 raw_fd(AT_FDCWD),
185 path,
186 c_uint(ow),
187 c_uint(gr),
188 zero()
189 ))
190 }
191}
192
193#[inline]
194pub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> {
195 unsafe {
196 let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
197 ret(syscall_readonly!(__NR_fchown, fd, c_uint(ow), c_uint(gr)))
198 }
199}
200
201#[inline]
202pub(crate) fn mknodat(
203 dirfd: BorrowedFd<'_>,
204 path: &CStr,
205 file_type: FileType,
206 mode: Mode,
207 dev: u64,
208) -> io::Result<()> {
209 #[cfg(target_pointer_width = "32")]
210 unsafe {
211 ret(syscall_readonly!(
212 __NR_mknodat,
213 dirfd,
214 path,
215 (mode, file_type),
216 dev_t(dev)?
217 ))
218 }
219 #[cfg(target_pointer_width = "64")]
220 unsafe {
221 ret(syscall_readonly!(
222 __NR_mknodat,
223 dirfd,
224 path,
225 (mode, file_type),
226 dev_t(dev)
227 ))
228 }
229}
230
231#[inline]
232pub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result<u64> {
233 let (whence, offset) = match pos {
234 SeekFrom::Start(pos) => {
235 let pos: u64 = pos;
236 (SEEK_SET, pos as i64)
238 }
239 SeekFrom::End(offset) => (SEEK_END, offset),
240 SeekFrom::Current(offset) => (SEEK_CUR, offset),
241 SeekFrom::Data(pos) => {
242 let pos: u64 = pos;
243 (SEEK_DATA, pos as i64)
245 }
246 SeekFrom::Hole(pos) => {
247 let pos: u64 = pos;
248 (SEEK_HOLE, pos as i64)
250 }
251 };
252 _seek(fd, offset, whence)
253}
254
255#[inline]
256pub(crate) fn _seek(fd: BorrowedFd<'_>, offset: i64, whence: c::c_uint) -> io::Result<u64> {
257 #[cfg(target_pointer_width = "32")]
258 unsafe {
259 let mut result = MaybeUninit::<u64>::uninit();
260 ret(syscall!(
261 __NR__llseek,
262 fd,
263 pass_usize((offset >> 32) as usize),
266 pass_usize(offset as usize),
267 &mut result,
268 c_uint(whence)
269 ))?;
270 Ok(result.assume_init())
271 }
272 #[cfg(target_pointer_width = "64")]
273 unsafe {
274 ret_u64(syscall_readonly!(
275 __NR_lseek,
276 fd,
277 loff_t(offset),
278 c_uint(whence)
279 ))
280 }
281}
282
283#[inline]
284pub(crate) fn tell(fd: BorrowedFd<'_>) -> io::Result<u64> {
285 _seek(fd, 0, SEEK_CUR).map(|x| x as u64)
286}
287
288#[inline]
289pub(crate) fn ftruncate(fd: BorrowedFd<'_>, length: u64) -> io::Result<()> {
290 #[cfg(all(
292 target_pointer_width = "32",
293 any(
294 target_arch = "arm",
295 target_arch = "mips",
296 target_arch = "mips32r6",
297 target_arch = "powerpc"
298 ),
299 ))]
300 unsafe {
301 ret(syscall_readonly!(
302 __NR_ftruncate64,
303 fd,
304 zero(),
305 hi(length),
306 lo(length)
307 ))
308 }
309 #[cfg(all(
310 target_pointer_width = "32",
311 not(any(
312 target_arch = "arm",
313 target_arch = "mips",
314 target_arch = "mips32r6",
315 target_arch = "powerpc"
316 )),
317 ))]
318 unsafe {
319 ret(syscall_readonly!(
320 __NR_ftruncate64,
321 fd,
322 hi(length),
323 lo(length)
324 ))
325 }
326 #[cfg(target_pointer_width = "64")]
327 unsafe {
328 ret(syscall_readonly!(
329 __NR_ftruncate,
330 fd,
331 loff_t_from_u64(length)
332 ))
333 }
334}
335
336#[inline]
337pub(crate) fn fallocate(
338 fd: BorrowedFd<'_>,
339 mode: FallocateFlags,
340 offset: u64,
341 len: u64,
342) -> io::Result<()> {
343 #[cfg(target_pointer_width = "32")]
344 unsafe {
345 ret(syscall_readonly!(
346 __NR_fallocate,
347 fd,
348 mode,
349 hi(offset),
350 lo(offset),
351 hi(len),
352 lo(len)
353 ))
354 }
355 #[cfg(target_pointer_width = "64")]
356 unsafe {
357 ret(syscall_readonly!(
358 __NR_fallocate,
359 fd,
360 mode,
361 loff_t_from_u64(offset),
362 loff_t_from_u64(len)
363 ))
364 }
365}
366
367#[inline]
368pub(crate) fn fadvise(
369 fd: BorrowedFd<'_>,
370 pos: u64,
371 len: Option<NonZeroU64>,
372 advice: Advice,
373) -> io::Result<()> {
374 let len = match len {
375 None => 0,
376 Some(len) => len.get(),
377 };
378
379 #[cfg(target_arch = "arm")]
382 unsafe {
383 ret(syscall_readonly!(
384 __NR_arm_fadvise64_64,
385 fd,
386 advice,
387 hi(pos),
388 lo(pos),
389 hi(len),
390 lo(len)
391 ))
392 }
393
394 #[cfg(target_arch = "powerpc")]
396 unsafe {
397 ret(syscall_readonly!(
398 __NR_fadvise64_64,
399 fd,
400 advice,
401 hi(pos),
402 lo(pos),
403 hi(len),
404 lo(len)
405 ))
406 }
407
408 #[cfg(any(target_arch = "mips", target_arch = "mips32r6"))]
411 unsafe {
412 ret(syscall_readonly!(
413 __NR_fadvise64,
414 fd,
415 zero(),
416 hi(pos),
417 lo(pos),
418 hi(len),
419 lo(len),
420 advice
421 ))
422 }
423
424 #[cfg(all(
427 target_pointer_width = "32",
428 not(any(
429 target_arch = "arm",
430 target_arch = "mips",
431 target_arch = "mips32r6",
432 target_arch = "powerpc"
433 )),
434 ))]
435 unsafe {
436 ret(syscall_readonly!(
437 __NR_fadvise64_64,
438 fd,
439 hi(pos),
440 lo(pos),
441 hi(len),
442 lo(len),
443 advice
444 ))
445 }
446
447 #[cfg(target_pointer_width = "64")]
449 unsafe {
450 ret(syscall_readonly!(
451 __NR_fadvise64,
452 fd,
453 loff_t_from_u64(pos),
454 loff_t_from_u64(len),
455 advice
456 ))
457 }
458}
459
460#[inline]
461pub(crate) fn fsync(fd: BorrowedFd<'_>) -> io::Result<()> {
462 unsafe { ret(syscall_readonly!(__NR_fsync, fd)) }
463}
464
465#[inline]
466pub(crate) fn fdatasync(fd: BorrowedFd<'_>) -> io::Result<()> {
467 unsafe { ret(syscall_readonly!(__NR_fdatasync, fd)) }
468}
469
470#[inline]
471pub(crate) fn flock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> {
472 unsafe {
473 ret(syscall_readonly!(
474 __NR_flock,
475 fd,
476 c_uint(operation as c::c_uint)
477 ))
478 }
479}
480
481#[inline]
482pub(crate) fn syncfs(fd: BorrowedFd<'_>) -> io::Result<()> {
483 unsafe { ret(syscall_readonly!(__NR_syncfs, fd)) }
484}
485
486#[inline]
487pub(crate) fn sync() {
488 unsafe { ret_infallible(syscall_readonly!(__NR_sync)) }
489}
490
491#[inline]
492pub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> {
493 #[cfg(any(
500 target_pointer_width = "32",
501 target_arch = "mips64",
502 target_arch = "mips64r6"
503 ))]
504 {
505 match crate::fs::statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) {
506 Ok(x) => statx_to_stat(x),
507 Err(io::Errno::NOSYS) => fstat_old(fd),
508 Err(err) => Err(err),
509 }
510 }
511
512 #[cfg(all(
513 target_pointer_width = "64",
514 not(target_arch = "mips64"),
515 not(target_arch = "mips64r6")
516 ))]
517 unsafe {
518 let mut result = MaybeUninit::<Stat>::uninit();
519 ret(syscall!(__NR_fstat, fd, &mut result))?;
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.as_fd(),
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.as_fd(),
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.as_fd(), 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#[test]
1669fn test_sizes() {
1670 assert_eq_size!(linux_raw_sys::general::__kernel_loff_t, u64);
1671 assert_eq_align!(linux_raw_sys::general::__kernel_loff_t, u64);
1672
1673 assert_eq_size!([linux_raw_sys::general::__kernel_timespec; 2], Timestamps);
1675 assert_eq_align!([linux_raw_sys::general::__kernel_timespec; 2], Timestamps);
1676}
1677
1678#[cfg(any(
1682 target_pointer_width = "32",
1683 target_arch = "mips64",
1684 target_arch = "mips64r6"
1685))]
1686mod to_signed {
1687 pub(super) trait ToSigned {
1688 type Signed;
1689 fn to_signed(self) -> Self::Signed;
1690 }
1691 impl ToSigned for u32 {
1692 type Signed = i32;
1693
1694 fn to_signed(self) -> Self::Signed {
1695 self as _
1696 }
1697 }
1698 impl ToSigned for i32 {
1699 type Signed = i32;
1700
1701 fn to_signed(self) -> Self::Signed {
1702 self
1703 }
1704 }
1705 impl ToSigned for u64 {
1706 type Signed = i64;
1707
1708 fn to_signed(self) -> Self::Signed {
1709 self as _
1710 }
1711 }
1712 impl ToSigned for i64 {
1713 type Signed = i64;
1714
1715 fn to_signed(self) -> Self::Signed {
1716 self
1717 }
1718 }
1719}
1720#[cfg(any(
1721 target_pointer_width = "32",
1722 target_arch = "mips64",
1723 target_arch = "mips64r6"
1724))]
1725use to_signed::*;