Skip to main content

strat9_abi/
flag.rs

1//! ABI-level flags for syscalls and data structures.
2//!
3//! These are Strat9 OS native flags, NOT POSIX flags.
4//! POSIX shims (relibc, musl-compat) must translate from POSIX `O_*`
5//! to these flags using [`posix_oflags_to_strat9`].
6
7use bitflags::bitflags;
8
9// ── Open Flags ──────────────────────────────────────────────────────────────
10
11bitflags! {
12    /// File open flags for `SYS_OPEN` and `SYS_OPENAT`.
13    ///
14    /// These are **not** POSIX `O_*` values. Use [`posix_oflags_to_strat9`]
15    /// to convert from POSIX flags when implementing a compatibility layer.
16    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17    pub struct OpenFlags: u32 {
18        /// Open for reading.
19        const READ      = 1 << 0;
20        /// Open for writing.
21        const WRITE     = 1 << 1;
22        /// Create file if it does not exist (requires `WRITE` or `APPEND`).
23        const CREATE    = 1 << 2;
24        /// Truncate file to zero length on open.
25        const TRUNCATE  = 1 << 3;
26        /// Append all writes to the end of the file.
27        const APPEND    = 1 << 4;
28        /// Open as a directory (fails if path is not a directory).
29        const DIRECTORY = 1 << 5;
30        /// Fail if file already exists (only meaningful with `CREATE`).
31        const EXCL      = 1 << 6;
32        /// Non-blocking mode: return `EAGAIN` instead of blocking.
33        const NONBLOCK  = 1 << 7;
34        /// Do not follow symbolic links in the final path component.
35        const NOFOLLOW  = 1 << 8;
36        /// Do not allocate a controlling terminal.
37        const NOCTTY    = 1 << 9;
38        /// Synchronous writes: data + metadata flushed to disk before return.
39        const SYNC      = 1 << 10;
40
41        /// Open for reading only (alias for `READ`).
42        const RDONLY = Self::READ.bits();
43        /// Open for writing only (alias for `WRITE`).
44        const WRONLY = Self::WRITE.bits();
45        /// Open for reading and writing.
46        const RDWR   = Self::READ.bits() | Self::WRITE.bits();
47    }
48}
49
50// ── Memory Map Flags ────────────────────────────────────────────────────────
51
52bitflags! {
53    /// Memory mapping flags for `SYS_MMAP`.
54    ///
55    /// These are **not** POSIX `MAP_*` values. The kernel uses its own
56    /// bit layout for efficiency.
57    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
58    pub struct MapFlags: u32 {
59        /// Shared mapping: writes are visible to other processes mapping the same region.
60        const MAP_SHARED    = 0x01;
61        /// Private mapping: copy-on-write semantics.
62        const MAP_PRIVATE   = 0x02;
63        /// Fixed mapping: place at the exact address specified (may overwrite existing mappings).
64        const MAP_FIXED     = 0x10;
65        /// Anonymous mapping: not backed by a file (requires `MAP_PRIVATE`).
66        const MAP_ANONYMOUS = 0x0020;
67        /// Do not reserve swap space for this mapping.
68        const MAP_NORESERVE = 0x40;
69        /// Populate pages on demand (prefault all pages).
70        const MAP_POPULATE  = 0x8000;
71        /// Lock the mapping in memory (cannot be swapped out).
72        const MAP_LOCKED    = 0x2000;
73        /// Automatically expand the mapping downward (stack growth).
74        const MAP_GROWSDOWN = 0x0100;
75    }
76}
77
78// ── IPC Call Flags ──────────────────────────────────────────────────────────
79
80bitflags! {
81    /// Flags for IPC call operations (used with `SYS_IPC_CALL`).
82    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
83    pub struct CallFlags: u32 {
84        /// Read operation (receive data).
85        const READ    = 0x01;
86        /// Write operation (send data).
87        const WRITE   = 0x02;
88        /// Non-blocking: return immediately if no data available.
89        const NONBLOCK = 0x04;
90        /// Peek: read data without consuming it.
91        const PEEK    = 0x08;
92        /// Wait for data (blocking).
93        const WAIT    = 0x10;
94        /// Do not wait (return immediately).
95        const NOWAIT  = 0x20;
96    }
97}
98
99// ── Unlink Flags ────────────────────────────────────────────────────────────
100
101bitflags! {
102    /// Flags for `SYS_UNLINKAT`.
103    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
104    pub struct UnlinkFlags: u32 {
105        /// Remove a directory instead of a file.
106        const REMOVEDIR = 0o02000000;
107    }
108}
109
110// ── POSIX to Strat9 Translation ─────────────────────────────────────────────
111
112/// Translate POSIX `O_*` flags to Strat9 ABI `OpenFlags`.
113///
114/// This function is used by POSIX compatibility layers (relibc, musl-compat)
115/// to convert standard Linux/POSIX open flags to the Strat9 native format.
116///
117/// # Example
118///
119/// ```ignore
120/// let strat9_flags = posix_oflags_to_strat9(libc::O_RDONLY | libc::O_CREAT);
121/// assert!(strat9_flags.contains(OpenFlags::READ));
122/// assert!(strat9_flags.contains(OpenFlags::CREATE));
123/// ```
124pub fn posix_oflags_to_strat9(posix: u32) -> OpenFlags {
125    const O_ACCMODE: u32 = 0o3;
126    const O_RDONLY: u32 = 0o000000;
127    const O_WRONLY: u32 = 0o000001;
128    const O_RDWR: u32 = 0o000002;
129    const O_CREAT: u32 = 0o000100;
130    const O_EXCL: u32 = 0o000200;
131    const O_NOCTTY: u32 = 0o000400;
132    const O_TRUNC: u32 = 0o001000;
133    const O_APPEND: u32 = 0o002000;
134    const O_NONBLOCK: u32 = 0o004000;
135    const O_DIRECTORY: u32 = 0o0200000;
136    const O_NOFOLLOW: u32 = 0o0400000;
137    const O_SYNC: u32 = 0o04000000;
138
139    let access = posix & O_ACCMODE;
140    let mut out = OpenFlags::empty();
141
142    match access {
143        O_RDONLY => {
144            out |= OpenFlags::READ;
145        }
146        O_WRONLY => {
147            out |= OpenFlags::WRITE;
148        }
149        O_RDWR => {
150            out |= OpenFlags::READ | OpenFlags::WRITE;
151        }
152        _ => {}
153    }
154
155    if posix & O_CREAT != 0 {
156        out |= OpenFlags::CREATE;
157    }
158    if posix & O_TRUNC != 0 {
159        out |= OpenFlags::TRUNCATE;
160    }
161    if posix & O_APPEND != 0 {
162        out |= OpenFlags::APPEND;
163    }
164    if posix & O_DIRECTORY != 0 {
165        out |= OpenFlags::DIRECTORY;
166    }
167    if posix & O_EXCL != 0 {
168        out |= OpenFlags::EXCL;
169    }
170    if posix & O_NONBLOCK != 0 {
171        out |= OpenFlags::NONBLOCK;
172    }
173    if posix & O_NOFOLLOW != 0 {
174        out |= OpenFlags::NOFOLLOW;
175    }
176    if posix & O_NOCTTY != 0 {
177        out |= OpenFlags::NOCTTY;
178    }
179    if posix & O_SYNC != 0 {
180        out |= OpenFlags::SYNC;
181    }
182
183    out
184}