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    nk, 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    Pty = crate::bindings::fd_kind_FdKind_Pty,
29    Socket = crate::bindings::fd_kind_FdKind_Socket,
30    Pipe = crate::bindings::fd_kind_FdKind_Pipe,
31    Compartment = crate::bindings::fd_kind_FdKind_Compartment,
32    Other = u32::MAX,
33}
34
35impl From<u32> for FdKind {
36    fn from(value: u32) -> Self {
37        match value {
38            crate::bindings::fd_kind_FdKind_Regular => Self::Regular,
39            crate::bindings::fd_kind_FdKind_Directory => Self::Directory,
40            crate::bindings::fd_kind_FdKind_SymLink => Self::SymLink,
41            crate::bindings::fd_kind_FdKind_Pty => Self::Pty,
42            crate::bindings::fd_kind_FdKind_Socket => Self::Socket,
43            crate::bindings::fd_kind_FdKind_Pipe => Self::Pipe,
44            crate::bindings::fd_kind_FdKind_Compartment => Self::Compartment,
45            _ => Self::Other,
46        }
47    }
48}
49
50impl Into<u32> for FdKind {
51    fn into(self) -> u32 {
52        match self {
53            Self::Regular => crate::bindings::fd_kind_FdKind_Regular,
54            Self::Directory => crate::bindings::fd_kind_FdKind_Directory,
55            Self::SymLink => crate::bindings::fd_kind_FdKind_SymLink,
56            Self::Pty => crate::bindings::fd_kind_FdKind_Pty,
57            Self::Socket => crate::bindings::fd_kind_FdKind_Socket,
58            Self::Pipe => crate::bindings::fd_kind_FdKind_Pipe,
59            Self::Compartment => crate::bindings::fd_kind_FdKind_Compartment,
60            Self::Other => u32::MAX,
61        }
62    }
63}
64
65/// Information about an open file descriptor.
66#[derive(Copy, Clone, Debug, Default)]
67pub struct FdInfo {
68    /// Flags for this descriptor
69    pub flags: FdFlags,
70    /// Length of underlying object
71    pub size: u64,
72    /// Kind of file
73    pub kind: FdKind,
74    /// Object ID
75    pub id: twizzler_types::ObjID,
76    /// Created time
77    pub created: Duration,
78    /// Accessed time
79    pub accessed: Duration,
80    /// Modified time
81    pub modified: Duration,
82    /// Unix mode
83    pub unix_mode: u32,
84}
85
86impl From<crate::bindings::fd_info> for FdInfo {
87    fn from(value: crate::bindings::fd_info) -> Self {
88        Self {
89            flags: FdFlags::from_bits_truncate(value.flags),
90            size: value.len,
91            kind: FdKind::from(value.kind),
92            id: value.id,
93            created: value.created.into(),
94            accessed: value.accessed.into(),
95            modified: value.modified.into(),
96            unix_mode: value.unix_mode,
97        }
98    }
99}
100
101impl From<FdInfo> for crate::bindings::fd_info {
102    fn from(value: FdInfo) -> Self {
103        Self {
104            flags: value.flags.bits(),
105            len: value.size,
106            kind: value.kind.into(),
107            id: value.id,
108            created: value.created.into(),
109            accessed: value.accessed.into(),
110            modified: value.modified.into(),
111            unix_mode: value.unix_mode,
112        }
113    }
114}
115
116impl From<Result<RawFd>> for crate::bindings::open_result {
117    fn from(value: Result<RawFd>) -> Self {
118        match value {
119            Ok(fd) => Self {
120                fd,
121                err: RawTwzError::success().raw(),
122            },
123            Err(e) => Self {
124                fd: 0,
125                err: e.raw(),
126            },
127        }
128    }
129}
130
131impl From<crate::bindings::open_result> for Result<RawFd> {
132    fn from(value: crate::bindings::open_result) -> Self {
133        let raw = RawTwzError::new(value.err);
134        if raw.is_success() {
135            Ok(value.fd)
136        } else {
137            Err(raw.error())
138        }
139    }
140}
141
142/// Get information about an open file descriptor. If the fd is invalid or closed, returns None.
143pub fn twz_rt_fd_get_info(fd: RawFd) -> Result<FdInfo> {
144    let mut info = core::mem::MaybeUninit::uninit();
145    unsafe {
146        if nk!(crate::bindings::twz_rt_fd_get_info(fd, info.as_mut_ptr())) {
147            return Ok(info.assume_init().into());
148        }
149    }
150    Err(TwzError::Argument(ArgumentError::BadHandle))
151}
152
153pub use crate::bindings::name_entry as NameEntry;
154
155impl NameEntry {
156    pub const NAME_MAX_LEN: usize = crate::bindings::NAME_ENTRY_LEN as usize;
157    pub fn new(iname: &[u8], info: crate::bindings::fd_info) -> Self {
158        let nl = iname.len().min(Self::NAME_MAX_LEN);
159        let mut name = [0; Self::NAME_MAX_LEN];
160        name[0..nl].copy_from_slice(&iname[0..nl]);
161        Self {
162            name,
163            info,
164            name_len: nl as u32,
165            linkname_len: 0,
166        }
167    }
168
169    pub fn new_symlink(iname: &[u8], ilinkname: &[u8], info: crate::bindings::fd_info) -> Self {
170        let nl = iname.len().min(Self::NAME_MAX_LEN);
171        let linknl = ilinkname.len().min(Self::NAME_MAX_LEN - nl);
172        let mut name = [0; Self::NAME_MAX_LEN];
173        name[0..nl].copy_from_slice(&iname[0..nl]);
174        name[nl..(nl + linknl)].copy_from_slice(&ilinkname[0..linknl]);
175        Self {
176            name,
177            info,
178            name_len: nl as u32,
179            linkname_len: linknl as u32,
180        }
181    }
182
183    pub fn name_bytes(&self) -> &[u8] {
184        &self.name[0..self.name_len as usize]
185    }
186
187    pub fn linkname_bytes(&self) -> &[u8] {
188        &self.name[self.name_len as usize..(self.name_len + self.linkname_len) as usize]
189    }
190}
191
192/// Enumerate sub-names for an fd (e.g. directory entries). Returns Some(n) on success, None if no
193/// names can be enumerated. Return of Some(n) indicates number of items read into the buffer, 0 if
194/// end of name list. Offset argument specifies number of entries to skip.
195pub fn twz_rt_fd_enumerate_names(
196    fd: RawFd,
197    entries: &mut [NameEntry],
198    off: usize,
199) -> Result<usize> {
200    unsafe {
201        nk!(crate::bindings::twz_rt_fd_enumerate_names(
202            fd,
203            entries.as_mut_ptr(),
204            entries.len(),
205            off
206        )
207        .into())
208    }
209}
210
211use crate::bindings::{
212    binding_info, descriptor, object_bind_info, objid, prot_kind, socket_address, socket_bind_info,
213};
214impl binding_info {
215    pub fn new_object_binding(fd: descriptor, kind: OpenKind, flags: u32, id: objid) -> Self {
216        let mut this = Self {
217            kind: kind.into(),
218            flags,
219            fd,
220            bind_data: [0; _],
221            bind_len: size_of::<object_bind_info>() as u32,
222        };
223        let bind_info = object_bind_info { id };
224        let bind_info_bytes = &bind_info as *const _ as *const u8;
225        let slice =
226            unsafe { core::slice::from_raw_parts(bind_info_bytes, size_of::<object_bind_info>()) };
227        this.bind_data[0..(this.bind_len as usize)].copy_from_slice(slice);
228        this
229    }
230
231    pub fn new_socket_binding(
232        fd: descriptor,
233        kind: OpenKind,
234        flags: u32,
235        addr: socket_address,
236        prot: prot_kind,
237    ) -> Self {
238        let mut this = Self {
239            kind: kind.into(),
240            flags,
241            fd,
242            bind_data: [0; _],
243            bind_len: size_of::<socket_bind_info>() as u32,
244        };
245        let bind_info = socket_bind_info { addr, prot };
246        let bind_info_bytes = &bind_info as *const _ as *const u8;
247        let slice =
248            unsafe { core::slice::from_raw_parts(bind_info_bytes, size_of::<socket_bind_info>()) };
249        this.bind_data[0..(this.bind_len as usize)].copy_from_slice(slice);
250        this
251    }
252
253    pub fn new_fd_binding(fd: descriptor, kind: OpenKind, flags: u32, bind_fd: descriptor) -> Self {
254        let mut this = Self {
255            kind: kind.into(),
256            flags,
257            fd,
258            bind_data: [0; _],
259            bind_len: size_of::<descriptor>() as u32,
260        };
261        let bind_info_bytes = &bind_fd as *const _ as *const u8;
262        let slice =
263            unsafe { core::slice::from_raw_parts(bind_info_bytes, size_of::<descriptor>()) };
264        this.bind_data[0..(this.bind_len as usize)].copy_from_slice(slice);
265        this
266    }
267}
268
269pub fn twz_rt_fd_read_binds(binds: &mut [binding_info]) -> usize {
270    unsafe {
271        nk!(crate::bindings::twz_rt_fd_read_binds(
272            binds.as_mut_ptr(),
273            binds.len()
274        ))
275    }
276}
277
278/// Open a file descriptor by name, as a C-string.
279pub fn twz_rt_fd_copen(
280    name: &core::ffi::CStr,
281    create: crate::bindings::create_options,
282    flags: u32,
283) -> Result<RawFd> {
284    let name_len = name.count_bytes().min(crate::bindings::NAME_DATA_MAX);
285    let mut info = crate::bindings::open_info {
286        len: name_len,
287        create,
288        flags,
289        name: [0; _],
290    };
291    info.name[0..name_len].copy_from_slice(&name.to_bytes()[0..name_len]);
292    unsafe {
293        nk!(crate::bindings::twz_rt_fd_open(
294            crate::bindings::open_kind_OpenKind_Path,
295            flags,
296            (&mut info as *mut crate::bindings::open_info).cast(),
297            size_of_val(&info),
298        )
299        .into())
300    }
301}
302
303/// Open a file descriptor by name, as a Rust-string.
304pub fn twz_rt_fd_open(
305    name: &str,
306    create: crate::bindings::create_options,
307    flags: u32,
308) -> Result<RawFd> {
309    let name_len = name.as_bytes().len().min(crate::bindings::NAME_DATA_MAX);
310    let mut info = crate::bindings::open_info {
311        len: name_len,
312        create,
313        flags,
314        name: [0; _],
315    };
316    info.name[0..name_len].copy_from_slice(&name.as_bytes()[0..name_len]);
317    unsafe {
318        nk!(crate::bindings::twz_rt_fd_open(
319            crate::bindings::open_kind_OpenKind_Path,
320            flags,
321            (&mut info as *mut crate::bindings::open_info).cast(),
322            size_of_val(&info),
323        )
324        .into())
325    }
326}
327
328/// Remove a name
329pub fn twz_rt_fd_remove(name: &str) -> Result<()> {
330    unsafe {
331        RawTwzError::new(nk!(crate::bindings::twz_rt_fd_remove(
332            name.as_ptr().cast(),
333            name.len(),
334        )))
335        .result()
336    }
337}
338
339/// Make a new namespace
340pub fn twz_rt_fd_mkns(name: &str) -> Result<()> {
341    unsafe {
342        RawTwzError::new(nk!(crate::bindings::twz_rt_fd_mkns(
343            name.as_ptr().cast(),
344            name.len(),
345        )))
346        .result()
347    }
348}
349
350/// Make a new symlink
351pub fn twz_rt_fd_symlink(name: &str, target: &str) -> Result<()> {
352    unsafe {
353        RawTwzError::new(nk!(crate::bindings::twz_rt_fd_symlink(
354            name.as_ptr().cast(),
355            name.len(),
356            target.as_ptr().cast(),
357            target.len(),
358        )))
359        .result()
360    }
361}
362
363/// Rename a name in the namespace.
364pub fn twz_rt_fd_rename(old_name: &str, new_name: &str) -> Result<()> {
365    unsafe {
366        RawTwzError::new(nk!(crate::bindings::twz_rt_fd_rename(
367            old_name.as_ptr().cast(),
368            old_name.len(),
369            new_name.as_ptr().cast(),
370            new_name.len(),
371        )))
372        .result()
373    }
374}
375
376pub fn twz_rt_fd_readlink(name: &str, buf: &mut [u8]) -> Result<usize> {
377    let mut len: u64 = 0;
378    unsafe {
379        RawTwzError::new(nk!(crate::bindings::twz_rt_fd_readlink(
380            name.as_ptr().cast(),
381            name.len(),
382            buf.as_mut_ptr().cast(),
383            buf.len(),
384            &mut len,
385        )))
386        .result()?;
387    }
388    Ok(len as usize)
389}
390
391#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
392#[repr(u32)]
393pub enum OpenKind {
394    Object = crate::bindings::open_kind_OpenKind_Object,
395    Path = crate::bindings::open_kind_OpenKind_Path,
396    Pipe = crate::bindings::open_kind_OpenKind_Pipe,
397    SocketConnect = crate::bindings::open_kind_OpenKind_SocketConnect,
398    SocketBind = crate::bindings::open_kind_OpenKind_SocketBind,
399    SocketAccept = crate::bindings::open_kind_OpenKind_SocketAccept,
400    PtyServer = crate::bindings::open_kind_OpenKind_PtyServer,
401    PtyClient = crate::bindings::open_kind_OpenKind_PtyClient,
402    Compartment = crate::bindings::open_kind_OpenKind_Compartment,
403    KernelConsole = crate::bindings::open_kind_OpenKind_KernelConsole,
404}
405
406impl TryFrom<u32> for OpenKind {
407    type Error = ();
408
409    fn try_from(val: u32) -> core::result::Result<OpenKind, Self::Error> {
410        match val {
411            crate::bindings::open_kind_OpenKind_Pipe => Ok(Self::Pipe),
412            crate::bindings::open_kind_OpenKind_SocketConnect => Ok(Self::SocketConnect),
413            crate::bindings::open_kind_OpenKind_SocketBind => Ok(Self::SocketBind),
414            crate::bindings::open_kind_OpenKind_SocketAccept => Ok(Self::SocketAccept),
415            crate::bindings::open_kind_OpenKind_PtyServer => Ok(Self::PtyServer),
416            crate::bindings::open_kind_OpenKind_PtyClient => Ok(Self::PtyClient),
417            crate::bindings::open_kind_OpenKind_Path => Ok(Self::Path),
418            crate::bindings::open_kind_OpenKind_Object => Ok(Self::Object),
419            crate::bindings::open_kind_OpenKind_Compartment => Ok(Self::Compartment),
420            crate::bindings::open_kind_OpenKind_KernelConsole => Ok(Self::KernelConsole),
421
422            _ => Err(()),
423        }
424    }
425}
426
427impl From<OpenKind> for u32 {
428    fn from(val: OpenKind) -> u32 {
429        match val {
430            OpenKind::Pipe => crate::bindings::open_kind_OpenKind_Pipe,
431            OpenKind::Path => crate::bindings::open_kind_OpenKind_Path,
432            OpenKind::Object => crate::bindings::open_kind_OpenKind_Object,
433            OpenKind::SocketConnect => crate::bindings::open_kind_OpenKind_SocketConnect,
434            OpenKind::SocketBind => crate::bindings::open_kind_OpenKind_SocketBind,
435            OpenKind::SocketAccept => crate::bindings::open_kind_OpenKind_SocketAccept,
436            OpenKind::PtyServer => crate::bindings::open_kind_OpenKind_PtyServer,
437            OpenKind::PtyClient => crate::bindings::open_kind_OpenKind_PtyClient,
438            OpenKind::Compartment => crate::bindings::open_kind_OpenKind_Compartment,
439            OpenKind::KernelConsole => crate::bindings::open_kind_OpenKind_KernelConsole,
440        }
441    }
442}
443
444#[derive(Clone, Copy, Default)]
445#[repr(transparent)]
446pub struct SocketAddress(pub crate::bindings::socket_address);
447
448#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
449#[repr(u32)]
450pub enum ProtKind {
451    Stream = crate::bindings::prot_kind_ProtKind_Stream,
452    Datagram = crate::bindings::prot_kind_ProtKind_Datagram,
453}
454
455impl SocketAddress {
456    fn new_v4(octets: [u8; 4], port: u16) -> Self {
457        Self(crate::bindings::socket_address {
458            kind: crate::bindings::addr_kind_AddrKind_Ipv4,
459            addr_octets: crate::bindings::socket_address_addrs { v4: octets },
460            port,
461            flowinfo: 0,
462            scope_id: 0,
463        })
464    }
465
466    fn new_v6(octets: [u8; 16], port: u16, flowinfo: u32, scope_id: u32) -> Self {
467        Self(crate::bindings::socket_address {
468            kind: crate::bindings::addr_kind_AddrKind_Ipv6,
469            addr_octets: crate::bindings::socket_address_addrs { v6: octets },
470            port,
471            flowinfo,
472            scope_id,
473        })
474    }
475
476    fn v4_octets(&self) -> [u8; 4] {
477        assert!(self.is_v4());
478        unsafe { self.0.addr_octets.v4 }
479    }
480
481    fn v6_octets(&self) -> [u8; 16] {
482        assert!(!self.is_v4());
483        unsafe { self.0.addr_octets.v6 }
484    }
485
486    fn is_v4(&self) -> bool {
487        self.0.kind == crate::bindings::addr_kind_AddrKind_Ipv4
488    }
489}
490
491impl From<SocketAddress> for core::net::IpAddr {
492    fn from(value: SocketAddress) -> Self {
493        if value.is_v4() {
494            Self::V4(core::net::Ipv4Addr::from_octets(value.v4_octets()))
495        } else {
496            Self::V6(core::net::Ipv6Addr::from_octets(value.v6_octets()))
497        }
498    }
499}
500
501impl From<SocketAddress> for core::net::SocketAddr {
502    fn from(value: SocketAddress) -> Self {
503        if value.is_v4() {
504            Self::V4(core::net::SocketAddrV4::new(
505                core::net::Ipv4Addr::from_octets(value.v4_octets()),
506                value.0.port,
507            ))
508        } else {
509            Self::V6(core::net::SocketAddrV6::new(
510                core::net::Ipv6Addr::from_octets(value.v6_octets()),
511                value.0.port,
512                value.0.flowinfo,
513                value.0.scope_id,
514            ))
515        }
516    }
517}
518
519impl From<core::net::Ipv4Addr> for SocketAddress {
520    fn from(value: core::net::Ipv4Addr) -> Self {
521        Self::new_v4(value.octets(), 0)
522    }
523}
524
525impl From<core::net::Ipv6Addr> for SocketAddress {
526    fn from(value: core::net::Ipv6Addr) -> Self {
527        Self::new_v6(value.octets(), 0, 0, 0)
528    }
529}
530
531impl From<core::net::SocketAddrV4> for SocketAddress {
532    fn from(value: core::net::SocketAddrV4) -> Self {
533        Self::new_v4(value.ip().octets(), value.port())
534    }
535}
536
537impl From<core::net::SocketAddrV6> for SocketAddress {
538    fn from(value: core::net::SocketAddrV6) -> Self {
539        Self::new_v6(
540            value.ip().octets(),
541            value.port(),
542            value.flowinfo(),
543            value.scope_id(),
544        )
545    }
546}
547
548impl From<core::net::SocketAddr> for SocketAddress {
549    fn from(value: core::net::SocketAddr) -> Self {
550        match value {
551            core::net::SocketAddr::V4(v4) => v4.into(),
552            core::net::SocketAddr::V6(v6) => v6.into(),
553        }
554    }
555}
556
557impl From<core::net::IpAddr> for SocketAddress {
558    fn from(value: core::net::IpAddr) -> Self {
559        match value {
560            core::net::IpAddr::V4(v4) => v4.into(),
561            core::net::IpAddr::V6(v6) => v6.into(),
562        }
563    }
564}
565
566/// Open an anonymous file descriptor.
567pub fn twz_rt_fd_open_socket_bind(
568    addr: SocketAddress,
569    flags: u32,
570    prot: ProtKind,
571) -> Result<RawFd> {
572    let mut binding = crate::bindings::socket_bind_info {
573        addr: addr.0,
574        prot: prot as u32,
575    };
576    unsafe {
577        nk!(crate::bindings::twz_rt_fd_open(
578            OpenKind::SocketBind.into(),
579            flags,
580            ((&mut binding) as *mut crate::bindings::socket_bind_info).cast(),
581            core::mem::size_of::<crate::bindings::socket_bind_info>(),
582        ))
583        .into()
584    }
585}
586
587/// Open an anonymous file descriptor.
588pub fn twz_rt_fd_open_socket(flags: u32, _prot: ProtKind) -> Result<RawFd> {
589    unsafe {
590        nk!(crate::bindings::twz_rt_fd_open(
591            OpenKind::SocketBind.into(),
592            flags,
593            core::ptr::null_mut(),
594            0,
595        ))
596        .into()
597    }
598}
599
600/// Open an anonymous file descriptor.
601pub fn twz_rt_fd_socket_rebind(
602    fd: RawFd,
603    addr: SocketAddress,
604    flags: u32,
605    prot: ProtKind,
606) -> Result<()> {
607    let mut binding = crate::bindings::socket_bind_info {
608        addr: addr.0,
609        prot: prot as u32,
610    };
611    unsafe {
612        RawTwzError::new(nk!(crate::bindings::twz_rt_fd_reopen(
613            fd,
614            OpenKind::SocketBind.into(),
615            flags,
616            ((&mut binding) as *mut crate::bindings::socket_bind_info).cast(),
617            core::mem::size_of::<crate::bindings::socket_bind_info>(),
618        )))
619        .result()
620    }
621}
622
623// Accept a connection on a bound socket file descriptor, creating a new file descriptor.
624pub fn twz_rt_fd_open_socket_accept(mut fd: RawFd, flags: u32) -> Result<RawFd> {
625    unsafe {
626        nk!(crate::bindings::twz_rt_fd_open(
627            OpenKind::SocketAccept.into(),
628            flags,
629            ((&mut fd) as *mut RawFd).cast(),
630            core::mem::size_of::<RawFd>(),
631        ))
632        .into()
633    }
634}
635
636/// Open an anonymous file descriptor.
637pub fn twz_rt_fd_open_socket_connect(
638    addr: SocketAddress,
639    flags: u32,
640    prot: ProtKind,
641) -> Result<RawFd> {
642    let mut binding = crate::bindings::socket_bind_info {
643        addr: addr.0,
644        prot: prot as u32,
645    };
646    unsafe {
647        nk!(crate::bindings::twz_rt_fd_open(
648            OpenKind::SocketConnect.into(),
649            flags,
650            ((&mut binding) as *mut crate::bindings::socket_bind_info).cast(),
651            core::mem::size_of::<crate::bindings::socket_bind_info>(),
652        ))
653        .into()
654    }
655}
656
657/// Open an anonymous file descriptor.
658pub fn twz_rt_fd_socket_reconnect(
659    fd: RawFd,
660    addr: SocketAddress,
661    flags: u32,
662    prot: ProtKind,
663) -> Result<()> {
664    let mut binding = crate::bindings::socket_bind_info {
665        addr: addr.0,
666        prot: prot as u32,
667    };
668    unsafe {
669        RawTwzError::new(nk!(crate::bindings::twz_rt_fd_reopen(
670            fd,
671            OpenKind::SocketConnect.into(),
672            flags,
673            ((&mut binding) as *mut crate::bindings::socket_bind_info).cast(),
674            core::mem::size_of::<crate::bindings::socket_bind_info>(),
675        )))
676        .result()
677    }
678}
679
680/// Open an PTY.
681pub fn twz_rt_fd_open_pty_server(id: twizzler_types::ObjID, flags: u32) -> Result<RawFd> {
682    let mut binding = crate::bindings::object_bind_info { id };
683    unsafe {
684        nk!(crate::bindings::twz_rt_fd_open(
685            OpenKind::PtyServer.into(),
686            flags,
687            ((&mut binding) as *mut crate::bindings::object_bind_info).cast(),
688            core::mem::size_of::<crate::bindings::object_bind_info>(),
689        ))
690        .into()
691    }
692}
693
694/// Open an PTY.
695pub fn twz_rt_fd_open_pty_client(id: twizzler_types::ObjID, flags: u32) -> Result<RawFd> {
696    let mut binding = crate::bindings::object_bind_info { id };
697    unsafe {
698        nk!(crate::bindings::twz_rt_fd_open(
699            OpenKind::PtyClient.into(),
700            flags,
701            ((&mut binding) as *mut crate::bindings::object_bind_info).cast(),
702            core::mem::size_of::<crate::bindings::object_bind_info>(),
703        ))
704        .into()
705    }
706}
707
708/// Open an anonymous file descriptor.
709pub fn twz_rt_fd_open_compartment(id: crate::bindings::objid, flags: u32) -> Result<RawFd> {
710    let mut binding = crate::bindings::object_bind_info { id };
711    unsafe {
712        nk!(crate::bindings::twz_rt_fd_open(
713            OpenKind::Compartment.into(),
714            flags,
715            ((&mut binding) as *mut crate::bindings::object_bind_info).cast(),
716            core::mem::size_of::<crate::bindings::object_bind_info>(),
717        ))
718        .into()
719    }
720}
721
722/// Open an anonymous file descriptor.
723pub fn twz_rt_fd_open_pipe(id: Option<crate::bindings::objid>, flags: u32) -> Result<RawFd> {
724    let mut binding = crate::bindings::object_bind_info {
725        id: id.unwrap_or(0),
726    };
727    unsafe {
728        nk!(crate::bindings::twz_rt_fd_open(
729            OpenKind::Pipe.into(),
730            flags,
731            ((&mut binding) as *mut crate::bindings::object_bind_info).cast(),
732            core::mem::size_of::<crate::bindings::object_bind_info>(),
733        ))
734        .into()
735    }
736}
737
738/// Duplicate a file descriptor.
739pub fn twz_rt_fd_dup(fd: RawFd) -> Result<RawFd> {
740    let mut new_fd = core::mem::MaybeUninit::<RawFd>::uninit();
741    unsafe {
742        let e = nk!(crate::bindings::twz_rt_fd_cmd(
743            fd,
744            crate::bindings::FD_CMD_DUP,
745            core::ptr::null_mut(),
746            new_fd.as_mut_ptr().cast(),
747        ));
748        let raw = RawTwzError::new(e);
749        if raw.is_success() {
750            Ok(new_fd.assume_init())
751        } else {
752            Err(raw.error())
753        }
754    }
755}
756
757/// Sync a file descriptor.
758pub fn twz_rt_fd_sync(fd: RawFd) {
759    unsafe {
760        nk!(crate::bindings::twz_rt_fd_cmd(
761            fd,
762            crate::bindings::FD_CMD_SYNC,
763            core::ptr::null_mut(),
764            core::ptr::null_mut(),
765        ));
766    }
767}
768
769/// Truncate a file descriptor.
770pub fn twz_rt_fd_truncate(fd: RawFd, mut len: u64) -> Result<()> {
771    unsafe {
772        let e = nk!(crate::bindings::twz_rt_fd_cmd(
773            fd,
774            crate::bindings::FD_CMD_TRUNCATE,
775            (&mut len as *mut u64).cast(),
776            core::ptr::null_mut(),
777        ));
778        let raw = RawTwzError::new(e);
779        if !raw.is_success() {
780            return Err(raw.error());
781        }
782    }
783    Ok(())
784}
785
786pub fn twz_rt_fd_shutdown(fd: RawFd, read: bool, write: bool) -> Result<()> {
787    let mut bits: u32 = 0;
788    if read {
789        bits |= 1;
790    }
791    if write {
792        bits |= 2;
793    }
794    unsafe {
795        let e = nk!(crate::bindings::twz_rt_fd_cmd(
796            fd,
797            crate::bindings::FD_CMD_SHUTDOWN,
798            (&mut bits as *mut u32).cast(),
799            core::ptr::null_mut(),
800        ));
801        let raw = RawTwzError::new(e);
802        if !raw.is_success() {
803            return Err(raw.error());
804        }
805    }
806    Ok(())
807}
808
809/// Close a file descriptor. If the fd is already closed, or invalid, this function has no effect.
810pub fn twz_rt_fd_close(fd: RawFd) {
811    unsafe { nk!(crate::bindings::twz_rt_fd_close(fd)) }
812}
813
814#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
815#[repr(u32)]
816pub enum NameRoot {
817    Root = crate::bindings::name_root_NameRoot_Root,
818    Home = crate::bindings::name_root_NameRoot_Home,
819    Current = crate::bindings::name_root_NameRoot_Current,
820    Temp = crate::bindings::name_root_NameRoot_Temp,
821    Exe = crate::bindings::name_root_NameRoot_Exe,
822}
823
824impl From<u32> for NameRoot {
825    fn from(value: u32) -> Self {
826        match value {
827            crate::bindings::name_root_NameRoot_Root => NameRoot::Root,
828            crate::bindings::name_root_NameRoot_Home => NameRoot::Home,
829            crate::bindings::name_root_NameRoot_Current => NameRoot::Current,
830            crate::bindings::name_root_NameRoot_Temp => NameRoot::Temp,
831            crate::bindings::name_root_NameRoot_Exe => NameRoot::Exe,
832            _ => panic!("invalid NameRoot value"),
833        }
834    }
835}
836
837pub fn twz_rt_get_nameroot(root: NameRoot, buf: &mut [u8]) -> Result<usize> {
838    unsafe {
839        nk!(
840            crate::bindings::twz_rt_get_nameroot(root as u32, buf.as_mut_ptr().cast(), buf.len())
841                .into()
842        )
843    }
844}
845
846pub fn twz_rt_set_nameroot(root: NameRoot, buf: &[u8]) -> Result<()> {
847    let res = unsafe {
848        nk!(crate::bindings::twz_rt_set_nameroot(
849            root as u32,
850            buf.as_ptr().cast(),
851            buf.len()
852        ))
853    };
854    let r = RawTwzError::new(res);
855    if r.is_success() {
856        Ok(())
857    } else {
858        Err(r.error())
859    }
860}
861
862#[derive(Default, Copy, Clone)]
863#[repr(u32)]
864pub enum NameResolver {
865    #[default]
866    Default = crate::bindings::name_resolver_NameResolver_Default,
867    Socket = crate::bindings::name_resolver_NameResolver_Socket,
868}
869
870impl From<u32> for NameResolver {
871    fn from(value: u32) -> Self {
872        match value {
873            crate::bindings::name_resolver_NameResolver_Default => NameResolver::Default,
874            crate::bindings::name_resolver_NameResolver_Socket => NameResolver::Socket,
875            _ => panic!("invalid NameResolver value"),
876        }
877    }
878}
879
880pub fn twz_rt_resolve_name(
881    resolver: NameResolver,
882    name: impl AsRef<str>,
883) -> Result<crate::object::ObjID> {
884    let name = name.as_ref().as_bytes();
885    let res = unsafe {
886        nk!(crate::bindings::twz_rt_resolve_name(
887            resolver as u32,
888            name.as_ptr().cast(),
889            name.len()
890        ))
891    };
892    let r = RawTwzError::new(res.err);
893    if r.is_success() {
894        Ok(res.val.into())
895    } else {
896        Err(r.error())
897    }
898}
899
900pub fn twz_rt_canon_name(
901    resolver: NameResolver,
902    name: impl AsRef<str>,
903    out_name: &mut [u8],
904) -> Result<usize> {
905    let name = name.as_ref().as_bytes();
906    let mut out_len = out_name.len();
907    let res = unsafe {
908        nk!(crate::bindings::twz_rt_canon_name(
909            resolver as u32,
910            name.as_ptr().cast(),
911            name.len(),
912            out_name.as_mut_ptr().cast(),
913            &mut out_len,
914        ))
915    };
916    let r = RawTwzError::new(res);
917    if r.is_success() {
918        Ok(out_len)
919    } else {
920        Err(r.error())
921    }
922}
923
924pub fn twz_rt_socket_names(
925    name: impl AsRef<str>,
926    out_addrs: &mut [SocketAddress],
927) -> Result<usize> {
928    let name = name.as_ref().as_bytes();
929    let mut out_len = out_addrs.len() * size_of::<SocketAddress>();
930    let res = unsafe {
931        nk!(crate::bindings::twz_rt_canon_name(
932            NameResolver::Socket as u32,
933            name.as_ptr().cast(),
934            name.len(),
935            out_addrs.as_mut_ptr().cast(),
936            &mut out_len,
937        ))
938    };
939    let r = RawTwzError::new(res);
940    if r.is_success() {
941        Ok(out_len / size_of::<SocketAddress>())
942    } else {
943        Err(r.error())
944    }
945}