Skip to main content

relibc/header/fcntl/
mod.rs

1//! `fcntl.h` implementation.
2//!
3//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/fcntl.h.html>.
4
5use core::num::NonZeroU64;
6
7use crate::{
8    c_str::CStr,
9    error::ResultExt,
10    platform::{
11        Pal, Sys,
12        types::{c_char, c_int, c_short, c_ulonglong, mode_t, off_t, pid_t},
13    },
14};
15
16pub use self::sys::*;
17pub use crate::header::bits_open_flags::*;
18
19use super::errno::EINVAL;
20
21#[cfg(target_os = "linux")]
22#[path = "linux.rs"]
23pub mod sys;
24
25#[cfg(target_os = "redox")]
26#[path = "redox.rs"]
27pub mod sys;
28
29/// Duplicate file descriptor.
30pub const F_DUPFD: c_int = 0;
31/// Get file descriptor flags.
32pub const F_GETFD: c_int = 1;
33/// Set file descriptor flags.
34pub const F_SETFD: c_int = 2;
35/// Get file status flags and file access modes.
36pub const F_GETFL: c_int = 3;
37/// Set file status flags.
38pub const F_SETFL: c_int = 4;
39/// Get information about file locks.
40pub const F_GETLK: c_int = 5;
41/// Set a process-owned file lock.
42pub const F_SETLK: c_int = 6;
43/// Set a process-owned file lock; wait if blocked.
44pub const F_SETLKW: c_int = 7;
45/// Get information about file locks.
46pub const F_OFD_GETLK: c_int = 36;
47/// Set an OFD-owned file lock.
48pub const F_OFD_SETLK: c_int = 37;
49/// Set an OFD-owned file lock; wait if blocked.
50pub const F_OFD_SETLKW: c_int = 38;
51/// Duplicate file descriptor with the close-on-exec flag `FD_CLOEXEC` set.
52pub const F_DUPFD_CLOEXEC: c_int = 1030;
53
54// Used for `l_type` to describe the type of lock {
55/// Shared or read lock.
56pub const F_RDLCK: c_int = 0;
57/// Exclusive or write lock.
58pub const F_WRLCK: c_int = 1;
59/// Unlock.
60pub const F_UNLCK: c_int = 2;
61// }
62
63/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/creat.html>.
64#[unsafe(no_mangle)]
65pub unsafe extern "C" fn creat(path: *const c_char, mode: mode_t) -> c_int {
66    unsafe { open(path, O_WRONLY | O_CREAT | O_TRUNC, mode) }
67}
68
69/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/fcntl.h.html>.
70#[repr(C)]
71#[derive(Clone, Copy, Default)]
72pub struct flock {
73    /// Type of lock; `F_RDLCK`, `F_WRLCK`, `F_UNLCK`.
74    pub l_type: c_short,
75    /// Flag for starting offset.
76    pub l_whence: c_short,
77    /// Relative offset in bytes.
78    pub l_start: off_t,
79    /// Size; if `0` then until EOF.
80    pub l_len: off_t,
81    /// For a process-owned file lock, ignored on input or the process ID of
82    /// the owning process on output; for an OFD-owned file lock, zero on input
83    /// or `(pid_t) - 1` on output.
84    pub l_pid: pid_t,
85}
86
87/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fcntl.html>.
88///
89/// Performs the operation specified by `cmd` on open files pointed to by the
90/// file descriptor `fildes`.
91///
92/// The return value depends on the value of `cmd`:
93/// - `F_DUPFD`: A new file descriptor.
94/// - `F_DUPFD_CLOEXEC`: A new file descriptor.
95/// - `F_DUPFD_CLOFORK`: A new file descriptor.
96/// - `F_GETFD`: Value of flags. The return value shall not be negative.
97/// - `F_SETFD`: Value other than `-1`.
98/// - `F_GETFL`: Value of file status flags and access modes. The return value
99///   shall not be negative.
100/// - `F_SETFL`: Value other than `-1`.
101/// - `F_GETLK`: Value other than `-1`.
102/// - `F_SETLK`: Value other than `-1`.
103/// - `F_SETLKW`: Value other than `-1`.
104/// - `F_OFD_GETLK`: Value other than `-1`.
105/// - `F_OFD_SETLK`: Value other than `-1`.
106/// - `F_OFD_SETLKW`: Value other than `-1`.
107/// - `F_GETOWN`: Value of the socket owner process or process group; this
108///   shall not be `-1`.
109/// - `F_SETOWN`: Value other than `-1`.
110/// - `F_GETOWN_EX`: Value other than `-1`.
111/// - `F_SETOWN_EX`: Value other than `-1`.
112///
113/// Otherwise, `-1` shall be returned and errno set to indicate the error.
114#[unsafe(no_mangle)]
115pub unsafe extern "C" fn fcntl(fildes: c_int, cmd: c_int, mut __valist: ...) -> c_int {
116    // c_ulonglong
117    let arg = match cmd {
118        F_DUPFD | F_SETFD | F_SETFL | F_GETLK | F_SETLK | F_SETLKW | F_OFD_GETLK | F_OFD_SETLK
119        | F_OFD_SETLKW | F_DUPFD_CLOEXEC => unsafe { __valist.next_arg::<c_ulonglong>() },
120        _ => 0,
121    };
122
123    Sys::fcntl(fildes, cmd, arg).or_minus_one_errno()
124}
125
126/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/open.html>.
127///
128/// Establishes a connection between a file and a file descriptor.
129///
130/// Upon success, opens the file and returns a non-negative integer
131/// representing the file descriptor. Upon failure, returns `-1` and sets errno
132/// to indicate the error. If `-1` is returned, no files shall be created or
133/// modified.
134#[unsafe(no_mangle)]
135pub unsafe extern "C" fn open(path: *const c_char, oflag: c_int, mut __valist: ...) -> c_int {
136    let mode = if oflag & O_CREAT == O_CREAT
137    /* || oflag & O_TMPFILE == O_TMPFILE */
138    {
139        unsafe { __valist.next_arg::<mode_t>() }
140    } else {
141        0
142    };
143
144    let path = unsafe { CStr::from_ptr(path) };
145    Sys::openat(AT_FDCWD, path, oflag, mode).or_minus_one_errno()
146}
147
148/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/openat.html>.
149///
150/// Establishes a connection between a file and a file descriptor. Equivalent
151/// to `open()` except in the case where `path` specifies a relative path (the
152/// file to be opened is determined relative to the directory associated with
153/// the file descriptor `fd` instead of the current working directory).
154///
155/// Upon success, opens the file and returns a non-negative integer
156/// representing the file descriptor. Upon failure, returns `-1` and sets errno
157/// to indicate the error. If `-1` is returned, no files shall be created or
158/// modified.
159#[unsafe(no_mangle)]
160pub unsafe extern "C" fn openat(
161    fd: c_int,
162    path: *const c_char,
163    oflag: c_int,
164    mut __valist: ...
165) -> c_int {
166    let mode = if oflag & O_CREAT == O_CREAT
167    /* || oflag & O_TMPFILE == O_TMPFILE */
168    {
169        unsafe { __valist.next_arg::<mode_t>() }
170    } else {
171        0
172    };
173
174    let path = unsafe { CStr::from_ptr(path) };
175    Sys::openat(fd, path, oflag, mode).or_minus_one_errno()
176}
177
178/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_fallocate.html>.
179///
180/// Ensures that any required storage for regular file data starting at
181/// `offset` and continuing for `len` bytes is allocated on the file system
182/// storage media.
183///
184/// Upon success, returns `0`. Upon failure, returns error number.
185#[unsafe(no_mangle)]
186pub unsafe extern "C" fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int {
187    // Length can't be zero and offset must be positive.
188    let Ok(offset) = offset.try_into() else {
189        return EINVAL;
190    };
191    let Some(len) = len.try_into().ok().and_then(NonZeroU64::new) else {
192        return EINVAL;
193    };
194
195    Sys::posix_fallocate(fd, offset, len)
196        .err()
197        .map(|e| e.0)
198        .unwrap_or_default()
199}