aranya_libc/sys/
unix.rs

1#![cfg(all(target_family = "unix", not(target_os = "vxworks")))]
2
3use core::ffi::{c_int, c_uint};
4
5pub use libc::{
6    LOCK_EX, LOCK_NB, O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, O_RDWR, S_IRGRP, S_IRUSR,
7    S_IWGRP, S_IWUSR, mode_t,
8};
9
10use crate::{
11    AsAtRoot, AsFd, BorrowedFd, OwnedFd,
12    errno::{Errno, errno},
13    path::Path,
14};
15
16/// A raw file descriptor.
17pub type RawFd = c_int;
18
19/// A raw directory stream.
20pub type RawDir = *mut libc::DIR;
21
22/// A raw directory entry.
23pub type DirEntry = *mut libc::dirent;
24
25/// The `fd` argument to `openat(2)`, etc.
26pub type AtRoot<'a> = BorrowedFd<'a>;
27
28impl<T: AsFd> AsAtRoot for T {
29    fn as_root(&self) -> AtRoot<'_> {
30        self.as_fd()
31    }
32}
33
34/// See `open(2)`.
35pub fn open(path: &Path, oflag: c_int, mode: mode_t) -> Result<RawFd, Errno> {
36    let fd = path.with_cstr(&|path| {
37        // SAFETY: FFI call, no invariants.
38        unsafe { libc::open(path, oflag, c_uint::from(mode)) }
39    });
40    if fd < 0 { Err(errno()) } else { Ok(fd) }
41}
42
43/// See `open(2)`.
44pub fn openat(fd: BorrowedFd<'_>, path: &Path, oflag: c_int, mode: mode_t) -> Result<RawFd, Errno> {
45    let fd = path.with_cstr(&|path| {
46        // SAFETY: FFI call, no invariants.
47        unsafe { libc::openat(fd.fd, path, oflag, c_uint::from(mode)) }
48    });
49    if fd < 0 { Err(errno()) } else { Ok(fd) }
50}
51
52/// See `close(2)`.
53pub fn close(fd: RawFd) -> Result<(), Errno> {
54    // SAFETY: FFI call, no invariants.
55    let ret = unsafe { libc::close(fd) };
56    if ret < 0 { Err(errno()) } else { Ok(()) }
57}
58
59/// See `flock(2)`.
60pub fn flock(fd: BorrowedFd<'_>, op: c_int) -> Result<(), Errno> {
61    // SAFETY: FFI call, no invariants.
62    let ret = unsafe { libc::flock(fd.fd, op) };
63    if ret < 0 { Err(errno()) } else { Ok(()) }
64}
65
66/// See `fsync(2)`.
67pub fn fsync(fd: BorrowedFd<'_>) -> Result<(), Errno> {
68    // SAFETY: FFI call, no invariants.
69    let ret = unsafe { libc::fsync(fd.fd) };
70    if ret < 0 { Err(errno()) } else { Ok(()) }
71}
72
73/// See `unlinkat(2)`.
74pub fn unlinkat(fd: BorrowedFd<'_>, path: &Path, flags: c_int) -> Result<(), Errno> {
75    // SAFETY: FFI call, no invariants.
76    let ret = path.with_cstr(&|path| {
77        // SAFETY: FFI call, no invariants.
78        unsafe { libc::unlinkat(fd.fd, path, flags) }
79    });
80    if ret < 0 { Err(errno()) } else { Ok(()) }
81}
82
83/// See `dup(2)`.
84pub fn dup(old_fd: BorrowedFd<'_>) -> Result<RawFd, Errno> {
85    // SAFETY: FFI call, no invariants.
86    let ret = unsafe { libc::dup(old_fd.fd) };
87    if ret < 0 { Err(errno()) } else { Ok(ret) }
88}
89
90/// See `fdopendir(2)`.
91pub fn fdopendir(fd: OwnedFd) -> Result<RawDir, Errno> {
92    // SAFETY: FFI call, no invariants.
93    let dir = unsafe { libc::fdopendir(fd.fd) };
94    if dir.is_null() {
95        Err(errno())
96    } else {
97        // SAFETY: This is now tied up in the DIR and will be freed once the
98        // OwnedDir gets dropped and we call closedir.
99        core::mem::forget(fd);
100        Ok(dir)
101    }
102}
103
104/// See `readdir(3p)`.
105pub fn readdir(dir: RawDir) -> Result<Option<DirEntry>, Errno> {
106    // `To distinguish between an end-of-directory condition or an
107    // error, you must set errno to zero before calling readdir.`
108    crate::errno::clear_errno();
109
110    // SAFETY: FFI call, no invariants.
111    let ret = unsafe { libc::readdir(dir) };
112
113    // If this is NULL, either we're at the end or an error occurred.
114    if ret.is_null() {
115        let errno = errno();
116        if errno.code() == 0 {
117            Ok(None)
118        } else {
119            Err(errno)
120        }
121    } else {
122        Ok(Some(ret))
123    }
124}
125
126/// See `rewinddir(3p)`.
127pub fn rewinddir(dir: RawDir) {
128    // SAFETY: FFI call, no invariants.
129    unsafe { libc::rewinddir(dir) };
130}
131
132/// See `closedir(3p)`.
133pub fn closedir(dir: RawDir) -> Result<(), Errno> {
134    // SAFETY: FFI call, no invariants.
135    let ret = unsafe { libc::closedir(dir) };
136    if ret < 0 { Err(errno()) } else { Ok(()) }
137}