Skip to main content

relibc/header/sys_stat/
mod.rs

1//! `sys/stat.h` implementation.
2//!
3//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_stat.h.html>.
4
5use crate::{
6    c_str::CStr,
7    error::ResultExt,
8    header::{fcntl::AT_SYMLINK_NOFOLLOW, time::timespec},
9    out::Out,
10    platform::{
11        Pal, Sys,
12        types::{
13            blkcnt_t, blksize_t, c_char, c_int, c_long, dev_t, gid_t, ino_t, mode_t, nlink_t,
14            off_t, uid_t,
15        },
16    },
17};
18
19/// Type of file.
20pub const S_IFMT: mode_t = 0o0_170_000;
21
22/// Directory.
23pub const S_IFDIR: mode_t = 0o040_000;
24/// Character special.
25pub const S_IFCHR: mode_t = 0o020_000;
26/// Block special.
27pub const S_IFBLK: mode_t = 0o060_000;
28/// Regular.
29pub const S_IFREG: mode_t = 0o100_000;
30/// FIFO special.
31pub const S_IFIFO: mode_t = 0o010_000;
32/// Symbolic link.
33pub const S_IFLNK: mode_t = 0o120_000;
34/// Socket.
35pub const S_IFSOCK: mode_t = 0o140_000;
36
37/// Read, write, execute/search by owner.
38pub const S_IRWXU: mode_t = 0o0_700;
39/// Read permission, owner.
40pub const S_IRUSR: mode_t = 0o0_400;
41/// Write permission, owner.
42pub const S_IWUSR: mode_t = 0o0_200;
43/// Execute/search permission, owner.
44pub const S_IXUSR: mode_t = 0o0_100;
45
46// Defined for compatibility
47pub const S_IREAD: mode_t = S_IRUSR;
48pub const S_IWRITE: mode_t = S_IWUSR;
49pub const S_IEXEC: mode_t = S_IXUSR;
50
51/// Read, write, execute/search by group.
52pub const S_IRWXG: mode_t = 0o0_070;
53/// Read permission, group.
54pub const S_IRGRP: mode_t = 0o0_040;
55/// Write permission, group.
56pub const S_IWGRP: mode_t = 0o0_020;
57/// Execute/search permission, group.
58pub const S_IXGRP: mode_t = 0o0_010;
59
60/// Read, write, execute/search by others.
61pub const S_IRWXO: mode_t = 0o0_007;
62/// Read permission, others.
63pub const S_IROTH: mode_t = 0o0_004;
64/// Write permission, others.
65pub const S_IWOTH: mode_t = 0o0_002;
66/// Execute/search permission, others.
67pub const S_IXOTH: mode_t = 0o0_001;
68/// Set-user-ID on execution.
69pub const S_ISUID: mode_t = 0o4_000;
70/// Set-group-ID on execution.
71pub const S_ISGID: mode_t = 0o2_000;
72/// On directories, restricted deletion flag.
73pub const S_ISVTX: mode_t = 0o1_000;
74
75pub const UTIME_NOW: c_long = (1 << 30) - 1;
76pub const UTIME_OMIT: c_long = (1 << 30) - 2;
77
78/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_stat.h.html>.
79#[repr(C)]
80#[derive(Default)]
81pub struct stat {
82    /// Device ID of device containing file.
83    pub st_dev: dev_t,
84    /// File serial number.
85    pub st_ino: ino_t,
86    /// Number of hard links to the file.
87    pub st_nlink: nlink_t,
88    /// Mode of file.
89    pub st_mode: mode_t,
90    /// User ID of file.
91    pub st_uid: uid_t,
92    /// Group ID of file.
93    pub st_gid: gid_t,
94    /// Device ID (if file is character or block special).
95    pub st_rdev: dev_t,
96    /// For regular files, the file size in bytes.
97    /// For symbolic links, the length in bytes of the pathname contained
98    /// in the symbolic link.
99    /// For a shared or typed memory object, the length in bytes.
100    /// For other file types, the use of this field is unspecified.
101    pub st_size: off_t,
102    /// A file system-specific preferred I/O block size for this object.
103    /// In some file system types, this may vary from file to file.
104    pub st_blksize: blksize_t,
105    /// Number of blocks allocated for this object.
106    pub st_blocks: blkcnt_t,
107
108    /// Last data access timestamp.
109    pub st_atim: timespec,
110    /// Last data modification timestamp.
111    pub st_mtim: timespec,
112    /// Last file status change timestamp.
113    pub st_ctim: timespec,
114
115    // Compared to glibc, our struct is for some reason 24 bytes too small.
116    // Accessing atime works, so clearly the struct isn't incorrect...
117    // This works.
118    pub _pad: [c_char; 24],
119}
120
121/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/chmod.html>.
122#[unsafe(no_mangle)]
123pub unsafe extern "C" fn chmod(path: *const c_char, mode: mode_t) -> c_int {
124    let path = unsafe { CStr::from_ptr(path) };
125    Sys::chmod(path, mode).map(|()| 0).or_minus_one_errno()
126}
127
128/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fchmod.html>.
129#[unsafe(no_mangle)]
130pub extern "C" fn fchmod(fildes: c_int, mode: mode_t) -> c_int {
131    Sys::fchmod(fildes, mode).map(|()| 0).or_minus_one_errno()
132}
133
134/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fchmodat.html>.
135#[unsafe(no_mangle)]
136pub unsafe extern "C" fn fchmodat(
137    dirfd: c_int,
138    path: *const c_char,
139    mode: mode_t,
140    flags: c_int,
141) -> c_int {
142    let path = unsafe { CStr::from_nullable_ptr(path) };
143    Sys::fchmodat(dirfd, path, mode, flags)
144        .map(|()| 0)
145        .or_minus_one_errno()
146}
147
148/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fstat.html>.
149#[unsafe(no_mangle)]
150pub unsafe extern "C" fn fstat(fildes: c_int, buf: *mut stat) -> c_int {
151    let buf = unsafe { Out::nonnull(buf) };
152    Sys::fstat(fildes, buf).map(|()| 0).or_minus_one_errno()
153}
154
155/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fstatat.html>.
156#[unsafe(no_mangle)]
157pub unsafe extern "C" fn fstatat(
158    fildes: c_int,
159    path: *const c_char,
160    buf: *mut stat,
161    flags: c_int,
162) -> c_int {
163    let path = unsafe { CStr::from_nullable_ptr(path) };
164    let buf = unsafe { Out::nonnull(buf) };
165    Sys::fstatat(fildes, path, buf, flags)
166        .map(|()| 0)
167        .or_minus_one_errno()
168}
169
170#[unsafe(no_mangle)]
171pub unsafe extern "C" fn __fxstat(_ver: c_int, fildes: c_int, buf: *mut stat) -> c_int {
172    unsafe { fstat(fildes, buf) }
173}
174
175/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/futimens.html>.
176#[unsafe(no_mangle)]
177pub unsafe extern "C" fn futimens(fd: c_int, times: *const timespec) -> c_int {
178    unsafe { Sys::futimens(fd, times) }
179        .map(|()| 0)
180        .or_minus_one_errno()
181}
182
183/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/lstat.html>.
184#[unsafe(no_mangle)]
185pub unsafe extern "C" fn lstat(path: *const c_char, buf: *mut stat) -> c_int {
186    let path = unsafe { CStr::from_ptr(path) };
187    let buf = unsafe { Out::nonnull(buf) };
188    Sys::lstat(path, buf).map(|()| 0).or_minus_one_errno()
189}
190
191/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdirat.html>.
192#[unsafe(no_mangle)]
193pub unsafe extern "C" fn mkdirat(dirfd: c_int, path: *const c_char, mode: mode_t) -> c_int {
194    let path = unsafe { CStr::from_ptr(path) };
195    Sys::mkdirat(dirfd, path, mode)
196        .map(|()| 0)
197        .or_minus_one_errno()
198}
199
200/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdir.html>.
201#[unsafe(no_mangle)]
202pub unsafe extern "C" fn mkdir(path: *const c_char, mode: mode_t) -> c_int {
203    let path = unsafe { CStr::from_ptr(path) };
204    Sys::mkdir(path, mode).map(|()| 0).or_minus_one_errno()
205}
206
207/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkfifoat.html>.
208#[unsafe(no_mangle)]
209pub unsafe extern "C" fn mkfifoat(dirfd: c_int, path: *const c_char, mode: mode_t) -> c_int {
210    let path = unsafe { CStr::from_ptr(path) };
211    Sys::mkfifoat(dirfd, path, mode)
212        .map(|()| 0)
213        .or_minus_one_errno()
214}
215
216/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkfifo.html>.
217#[unsafe(no_mangle)]
218pub unsafe extern "C" fn mkfifo(path: *const c_char, mode: mode_t) -> c_int {
219    let path = unsafe { CStr::from_ptr(path) };
220    Sys::mkfifo(path, mode).map(|()| 0).or_minus_one_errno()
221}
222
223/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mknod.html>.
224#[unsafe(no_mangle)]
225pub unsafe extern "C" fn mknod(path: *const c_char, mode: mode_t, dev: dev_t) -> c_int {
226    let path = unsafe { CStr::from_ptr(path) };
227    Sys::mknod(path, mode, dev).map(|()| 0).or_minus_one_errno()
228}
229
230/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mknodat.html>.
231#[unsafe(no_mangle)]
232pub unsafe extern "C" fn mknodat(
233    dirfd: c_int,
234    path: *const c_char,
235    mode: mode_t,
236    dev: dev_t,
237) -> c_int {
238    let path = unsafe { CStr::from_ptr(path) };
239    Sys::mknodat(dirfd, path, mode, dev)
240        .map(|()| 0)
241        .or_minus_one_errno()
242}
243
244/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/stat.html>.
245#[unsafe(no_mangle)]
246pub unsafe extern "C" fn stat(file: *const c_char, buf: *mut stat) -> c_int {
247    let file = unsafe { CStr::from_ptr(file) };
248    let buf = unsafe { Out::nonnull(buf) };
249    Sys::stat(file, buf).map(|()| 0).or_minus_one_errno()
250}
251
252/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/umask.html>.
253#[unsafe(no_mangle)]
254pub extern "C" fn umask(mask: mode_t) -> mode_t {
255    Sys::umask(mask)
256}
257
258/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/utimensat.html>.
259#[unsafe(no_mangle)]
260pub unsafe extern "C" fn utimensat(
261    fd: c_int,
262    path: *const c_char,
263    times: *const timespec,
264    flag: c_int,
265) -> c_int {
266    let path = unsafe { CStr::from_ptr(path) };
267    match Sys::openat(fd, path, flag & AT_SYMLINK_NOFOLLOW, 0) {
268        Ok(fd) => unsafe {
269            let r = Sys::futimens(fd, times).map(|()| 0).or_minus_one_errno();
270            let _ = Sys::close(fd);
271            r
272        },
273        r => r.or_minus_one_errno(),
274    }
275}