twizzler_rt_abi/
fd.rs

1//! Runtime interface for file descriptors.
2
3use core::time::Duration;
4
5pub use crate::bindings::descriptor as RawFd;
6use crate::{
7    error::{ArgumentError, RawTwzError, TwzError},
8    Result,
9};
10
11bitflags::bitflags! {
12    /// Flags for file descriptors.
13    #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
14pub struct FdFlags : crate::bindings::fd_flags {
15    /// The file descriptor refers to a terminal.
16    const IS_TERMINAL = crate::bindings::FD_IS_TERMINAL;
17}
18}
19
20#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default)]
21#[repr(u32)]
22/// Possible Fd Kinds
23pub enum FdKind {
24    #[default]
25    Regular = crate::bindings::fd_kind_FdKind_Regular,
26    Directory = crate::bindings::fd_kind_FdKind_Directory,
27    SymLink = crate::bindings::fd_kind_FdKind_SymLink,
28    Other = u32::MAX,
29}
30
31impl From<u32> for FdKind {
32    fn from(value: u32) -> Self {
33        match value {
34            crate::bindings::fd_kind_FdKind_Regular => Self::Regular,
35            crate::bindings::fd_kind_FdKind_Directory => Self::Directory,
36            crate::bindings::fd_kind_FdKind_SymLink => Self::SymLink,
37            _ => Self::Other,
38        }
39    }
40}
41
42impl Into<u32> for FdKind {
43    fn into(self) -> u32 {
44        match self {
45            Self::Regular => crate::bindings::fd_kind_FdKind_Regular,
46            Self::Directory => crate::bindings::fd_kind_FdKind_Directory,
47            Self::SymLink => crate::bindings::fd_kind_FdKind_SymLink,
48            Self::Other => u32::MAX,
49        }
50    }
51}
52
53/// Information about an open file descriptor.
54#[derive(Copy, Clone, Debug, Default)]
55pub struct FdInfo {
56    /// Flags for this descriptor
57    pub flags: FdFlags,
58    /// Length of underlying object
59    pub size: u64,
60    /// Kind of file
61    pub kind: FdKind,
62    /// Object ID
63    pub id: twizzler_types::ObjID,
64    /// Created time
65    pub created: Duration,
66    /// Accessed time
67    pub accessed: Duration,
68    /// Modified time
69    pub modified: Duration,
70    /// Unix mode
71    pub unix_mode: u32,
72}
73
74impl From<crate::bindings::fd_info> for FdInfo {
75    fn from(value: crate::bindings::fd_info) -> Self {
76        Self {
77            flags: FdFlags::from_bits_truncate(value.flags),
78            size: value.len,
79            kind: FdKind::from(value.kind),
80            id: value.id,
81            created: value.created.into(),
82            accessed: value.accessed.into(),
83            modified: value.modified.into(),
84            unix_mode: value.unix_mode,
85        }
86    }
87}
88
89impl From<FdInfo> for crate::bindings::fd_info {
90    fn from(value: FdInfo) -> Self {
91        Self {
92            flags: value.flags.bits(),
93            len: value.size,
94            kind: value.kind.into(),
95            id: value.id,
96            created: value.created.into(),
97            accessed: value.accessed.into(),
98            modified: value.modified.into(),
99            unix_mode: value.unix_mode,
100        }
101    }
102}
103
104impl From<Result<RawFd>> for crate::bindings::open_result {
105    fn from(value: Result<RawFd>) -> Self {
106        match value {
107            Ok(fd) => Self {
108                fd,
109                err: RawTwzError::success().raw(),
110            },
111            Err(e) => Self {
112                fd: 0,
113                err: e.raw(),
114            },
115        }
116    }
117}
118
119impl From<crate::bindings::open_result> for Result<RawFd> {
120    fn from(value: crate::bindings::open_result) -> Self {
121        let raw = RawTwzError::new(value.err);
122        if raw.is_success() {
123            Ok(value.fd)
124        } else {
125            Err(raw.error())
126        }
127    }
128}
129
130/// Get information about an open file descriptor. If the fd is invalid or closed, returns None.
131pub fn twz_rt_fd_get_info(fd: RawFd) -> Result<FdInfo> {
132    let mut info = core::mem::MaybeUninit::uninit();
133    unsafe {
134        if crate::bindings::twz_rt_fd_get_info(fd, info.as_mut_ptr()) {
135            return Ok(info.assume_init().into());
136        }
137    }
138    Err(TwzError::Argument(ArgumentError::BadHandle))
139}
140
141pub use crate::bindings::name_entry as NameEntry;
142
143impl Default for NameEntry {
144    fn default() -> Self {
145        Self {
146            name: [0; Self::NAME_MAX_LEN],
147            name_len: 0,
148            linkname_len: 0,
149            info: FdInfo::default().into(),
150        }
151    }
152}
153
154impl NameEntry {
155    pub const NAME_MAX_LEN: usize = crate::bindings::NAME_ENTRY_LEN as usize;
156    pub fn new(iname: &[u8], info: crate::bindings::fd_info) -> Self {
157        let nl = iname.len().min(Self::NAME_MAX_LEN);
158        let mut name = [0; Self::NAME_MAX_LEN];
159        name[0..nl].copy_from_slice(&iname[0..nl]);
160        Self {
161            name,
162            info,
163            name_len: nl as u32,
164            linkname_len: 0,
165        }
166    }
167
168    pub fn new_symlink(iname: &[u8], ilinkname: &[u8], info: crate::bindings::fd_info) -> Self {
169        let nl = iname.len().min(Self::NAME_MAX_LEN);
170        let linknl = ilinkname.len().min(Self::NAME_MAX_LEN - nl);
171        let mut name = [0; Self::NAME_MAX_LEN];
172        name[0..nl].copy_from_slice(&iname[0..nl]);
173        name[nl..(nl + linknl)].copy_from_slice(&ilinkname[0..linknl]);
174        Self {
175            name,
176            info,
177            name_len: nl as u32,
178            linkname_len: linknl as u32,
179        }
180    }
181
182    pub fn name_bytes(&self) -> &[u8] {
183        &self.name[0..self.name_len as usize]
184    }
185
186    pub fn linkname_bytes(&self) -> &[u8] {
187        &self.name[self.name_len as usize..(self.name_len + self.linkname_len) as usize]
188    }
189}
190
191/// Enumerate sub-names for an fd (e.g. directory entries). Returns Some(n) on success, None if no
192/// names can be enumerated. Return of Some(n) indicates number of items read into the buffer, 0 if
193/// end of name list. Offset argument specifies number of entries to skip.
194pub fn twz_rt_fd_enumerate_names(
195    fd: RawFd,
196    entries: &mut [NameEntry],
197    off: usize,
198) -> Result<usize> {
199    unsafe {
200        crate::bindings::twz_rt_fd_enumerate_names(fd, entries.as_mut_ptr(), entries.len(), off)
201            .into()
202    }
203}
204
205/// Open a file descriptor by name, as a C-string.
206pub fn twz_rt_fd_copen(
207    name: &core::ffi::CStr,
208    create: crate::bindings::create_options,
209    flags: u32,
210) -> Result<RawFd> {
211    let info = crate::bindings::open_info {
212        name: name.as_ptr().cast(),
213        len: name.count_bytes(),
214        create,
215        flags,
216    };
217    unsafe { crate::bindings::twz_rt_fd_open(info).into() }
218}
219
220/// Open a file descriptor by name, as a Rust-string.
221pub fn twz_rt_fd_open(
222    name: &str,
223    create: crate::bindings::create_options,
224    flags: u32,
225) -> Result<RawFd> {
226    let info = crate::bindings::open_info {
227        name: name.as_ptr().cast(),
228        len: name.len(),
229        create,
230        flags,
231    };
232    unsafe { crate::bindings::twz_rt_fd_open(info).into() }
233}
234
235/// Remove a name
236pub fn twz_rt_fd_remove(name: &str) -> Result<()> {
237    unsafe {
238        RawTwzError::new(crate::bindings::twz_rt_fd_remove(
239            name.as_ptr().cast(),
240            name.len(),
241        ))
242        .result()
243    }
244}
245
246/// Make a new namespace
247pub fn twz_rt_fd_mkns(name: &str) -> Result<()> {
248    unsafe {
249        RawTwzError::new(crate::bindings::twz_rt_fd_mkns(
250            name.as_ptr().cast(),
251            name.len(),
252        ))
253        .result()
254    }
255}
256
257/// Make a new symlink
258pub fn twz_rt_fd_symlink(name: &str, target: &str) -> Result<()> {
259    unsafe {
260        RawTwzError::new(crate::bindings::twz_rt_fd_symlink(
261            name.as_ptr().cast(),
262            name.len(),
263            target.as_ptr().cast(),
264            target.len(),
265        ))
266        .result()
267    }
268}
269
270pub fn twz_rt_fd_readlink(name: &str, buf: &mut [u8]) -> Result<usize> {
271    let mut len: u64 = 0;
272    unsafe {
273        RawTwzError::new(crate::bindings::twz_rt_fd_readlink(
274            name.as_ptr().cast(),
275            name.len(),
276            buf.as_mut_ptr().cast(),
277            buf.len(),
278            &mut len,
279        ))
280        .result()?;
281    }
282    Ok(len as usize)
283}
284
285#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
286#[repr(u32)]
287pub enum OpenAnonKind {
288    Pipe = crate::bindings::open_anon_kind_AnonKind_Pipe,
289    SocketConnect = crate::bindings::open_anon_kind_AnonKind_SocketConnect,
290    SocketBind = crate::bindings::open_anon_kind_AnonKind_SocketBind,
291}
292
293impl TryFrom<u32> for OpenAnonKind {
294    type Error = ();
295
296    fn try_from(val: u32) -> core::result::Result<OpenAnonKind, Self::Error> {
297        match val {
298            crate::bindings::open_anon_kind_AnonKind_Pipe => Ok(Self::Pipe),
299            crate::bindings::open_anon_kind_AnonKind_SocketConnect => Ok(Self::SocketConnect),
300            crate::bindings::open_anon_kind_AnonKind_SocketBind => Ok(Self::SocketBind),
301            _ => Err(()),
302        }
303    }
304}
305
306impl From<OpenAnonKind> for u32 {
307    fn from(val: OpenAnonKind) -> u32 {
308        match val {
309            OpenAnonKind::Pipe => crate::bindings::open_anon_kind_AnonKind_Pipe,
310            OpenAnonKind::SocketBind => crate::bindings::open_anon_kind_AnonKind_SocketBind,
311            OpenAnonKind::SocketConnect => crate::bindings::open_anon_kind_AnonKind_SocketConnect,
312        }
313    }
314}
315
316#[derive(Clone, Copy)]
317#[repr(transparent)]
318pub struct SocketAddress(pub(crate) crate::bindings::socket_address);
319
320impl SocketAddress {
321    fn new_v4(octets: [u8; 4], port: u16) -> Self {
322        Self(crate::bindings::socket_address {
323            kind: crate::bindings::addr_kind_AddrKind_Ipv4,
324            addr_octets: crate::bindings::socket_address_addrs { v4: octets },
325            port,
326            flowinfo: 0,
327            scope_id: 0,
328        })
329    }
330
331    fn new_v6(octets: [u8; 16], port: u16, flowinfo: u32, scope_id: u32) -> Self {
332        Self(crate::bindings::socket_address {
333            kind: crate::bindings::addr_kind_AddrKind_Ipv6,
334            addr_octets: crate::bindings::socket_address_addrs { v6: octets },
335            port,
336            flowinfo,
337            scope_id,
338        })
339    }
340
341    fn v4_octets(&self) -> [u8; 4] {
342        assert!(self.is_v4());
343        unsafe { self.0.addr_octets.v4 }
344    }
345
346    fn v6_octets(&self) -> [u8; 16] {
347        assert!(!self.is_v4());
348        unsafe { self.0.addr_octets.v6 }
349    }
350
351    fn is_v4(&self) -> bool {
352        self.0.kind == crate::bindings::addr_kind_AddrKind_Ipv4
353    }
354}
355
356impl From<SocketAddress> for core::net::IpAddr {
357    fn from(value: SocketAddress) -> Self {
358        if value.is_v4() {
359            Self::V4(core::net::Ipv4Addr::from_octets(value.v4_octets()))
360        } else {
361            Self::V6(core::net::Ipv6Addr::from_octets(value.v6_octets()))
362        }
363    }
364}
365
366impl From<SocketAddress> for core::net::SocketAddr {
367    fn from(value: SocketAddress) -> Self {
368        if value.is_v4() {
369            Self::V4(core::net::SocketAddrV4::new(
370                core::net::Ipv4Addr::from_octets(value.v4_octets()),
371                value.0.port,
372            ))
373        } else {
374            Self::V6(core::net::SocketAddrV6::new(
375                core::net::Ipv6Addr::from_octets(value.v6_octets()),
376                value.0.port,
377                value.0.flowinfo,
378                value.0.scope_id,
379            ))
380        }
381    }
382}
383
384impl From<core::net::Ipv4Addr> for SocketAddress {
385    fn from(value: core::net::Ipv4Addr) -> Self {
386        Self::new_v4(value.octets(), 0)
387    }
388}
389
390impl From<core::net::Ipv6Addr> for SocketAddress {
391    fn from(value: core::net::Ipv6Addr) -> Self {
392        Self::new_v6(value.octets(), 0, 0, 0)
393    }
394}
395
396impl From<core::net::SocketAddrV4> for SocketAddress {
397    fn from(value: core::net::SocketAddrV4) -> Self {
398        Self::new_v4(value.ip().octets(), value.port())
399    }
400}
401
402impl From<core::net::SocketAddrV6> for SocketAddress {
403    fn from(value: core::net::SocketAddrV6) -> Self {
404        Self::new_v6(
405            value.ip().octets(),
406            value.port(),
407            value.flowinfo(),
408            value.scope_id(),
409        )
410    }
411}
412
413impl From<core::net::SocketAddr> for SocketAddress {
414    fn from(value: core::net::SocketAddr) -> Self {
415        match value {
416            core::net::SocketAddr::V4(v4) => v4.into(),
417            core::net::SocketAddr::V6(v6) => v6.into(),
418        }
419    }
420}
421
422impl From<core::net::IpAddr> for SocketAddress {
423    fn from(value: core::net::IpAddr) -> Self {
424        match value {
425            core::net::IpAddr::V4(v4) => v4.into(),
426            core::net::IpAddr::V6(v6) => v6.into(),
427        }
428    }
429}
430
431/// Open an anonymous file descriptor.
432pub fn twz_rt_fd_open_socket_bind(mut addr: SocketAddress, flags: u32) -> Result<RawFd> {
433    unsafe {
434        crate::bindings::twz_rt_fd_open_anon(
435            OpenAnonKind::SocketBind.into(),
436            flags,
437            ((&mut addr.0) as *mut crate::bindings::socket_address).cast(),
438            core::mem::size_of::<crate::bindings::socket_address>(),
439        )
440        .into()
441    }
442}
443
444/// Open an anonymous file descriptor.
445pub fn twz_rt_fd_open_socket_connect(mut addr: SocketAddress, flags: u32) -> Result<RawFd> {
446    unsafe {
447        crate::bindings::twz_rt_fd_open_anon(
448            OpenAnonKind::SocketConnect.into(),
449            flags,
450            ((&mut addr.0) as *mut crate::bindings::socket_address).cast(),
451            core::mem::size_of::<crate::bindings::socket_address>(),
452        )
453        .into()
454    }
455}
456
457/// Open an anonymous file descriptor.
458pub fn twz_rt_fd_open_pipe(flags: u32) -> Result<RawFd> {
459    unsafe {
460        crate::bindings::twz_rt_fd_open_anon(
461            OpenAnonKind::Pipe.into(),
462            flags,
463            core::ptr::null_mut(),
464            0,
465        )
466        .into()
467    }
468}
469
470/// Duplicate a file descriptor.
471pub fn twz_rt_fd_dup(fd: RawFd) -> Result<RawFd> {
472    let mut new_fd = core::mem::MaybeUninit::<RawFd>::uninit();
473    unsafe {
474        let e = crate::bindings::twz_rt_fd_cmd(
475            fd,
476            crate::bindings::FD_CMD_DUP,
477            core::ptr::null_mut(),
478            new_fd.as_mut_ptr().cast(),
479        );
480        let raw = RawTwzError::new(e);
481        if raw.is_success() {
482            Ok(new_fd.assume_init())
483        } else {
484            Err(raw.error())
485        }
486    }
487}
488
489/// Sync a file descriptor.
490pub fn twz_rt_fd_sync(fd: RawFd) {
491    unsafe {
492        crate::bindings::twz_rt_fd_cmd(
493            fd,
494            crate::bindings::FD_CMD_SYNC,
495            core::ptr::null_mut(),
496            core::ptr::null_mut(),
497        );
498    }
499}
500
501/// Truncate a file descriptor.
502pub fn twz_rt_fd_truncate(fd: RawFd, mut len: u64) -> Result<()> {
503    unsafe {
504        let e = crate::bindings::twz_rt_fd_cmd(
505            fd,
506            crate::bindings::FD_CMD_TRUNCATE,
507            (&mut len as *mut u64).cast(),
508            core::ptr::null_mut(),
509        );
510        let raw = RawTwzError::new(e);
511        if !raw.is_success() {
512            return Err(raw.error());
513        }
514    }
515    Ok(())
516}
517
518/// Close a file descriptor. If the fd is already closed, or invalid, this function has no effect.
519pub fn twz_rt_fd_close(fd: RawFd) {
520    unsafe { crate::bindings::twz_rt_fd_close(fd) }
521}