Skip to main content

zvariant/
fd.rs

1use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
2use std::os::fd::{self, AsFd, AsRawFd, BorrowedFd, RawFd};
3
4use crate::{Basic, Type};
5
6/// A file-descriptor type wrapper.
7///
8/// Since [`std::os::fd::BorrowedFd`] and [`std::os::fd::OwnedFd`] types
9/// do not implement  [`Serialize`] and [`Deserialize`]. So we provide a
10/// wrapper for both that implements these traits.
11///
12/// # D-Bus FD Encoding
13///
14/// In D-Bus, file descriptors are **not** encoded as their raw numeric values on the wire.
15/// Instead, the message body contains a `u32` **index** into an out-of-band array of file
16/// descriptors that is transferred alongside the message via `SCM_RIGHTS` on Unix sockets.
17///
18/// The [`Deserialize`] implementation on this type is designed for zvariant's D-Bus
19/// deserializer, which resolves that index through the message's FD list before calling the
20/// serde visitor. **Using this type with other deserializers (JSON, CBOR, etc.) is not
21/// supported** — you would receive a `BorrowedFd` pointing to whatever FD number happened to
22/// be in the payload, which is almost certainly not what you want.
23///
24/// [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html
25/// [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
26#[derive(Debug)]
27pub enum Fd<'f> {
28    Borrowed(BorrowedFd<'f>),
29    Owned(fd::OwnedFd),
30}
31
32impl Fd<'_> {
33    /// Try to create an owned version of `self`.
34    pub fn try_to_owned(&self) -> crate::Result<Fd<'static>> {
35        self.as_fd()
36            .try_clone_to_owned()
37            .map(Fd::Owned)
38            .map_err(Into::into)
39    }
40
41    /// Try to clone `self`.
42    pub fn try_clone(&self) -> crate::Result<Self> {
43        Ok(match self {
44            Self::Borrowed(fd) => Self::Borrowed(*fd),
45            Self::Owned(fd) => Self::Owned(fd.try_clone()?),
46        })
47    }
48}
49
50impl<'f> From<BorrowedFd<'f>> for Fd<'f> {
51    fn from(fd: BorrowedFd<'f>) -> Self {
52        Self::Borrowed(fd)
53    }
54}
55
56impl From<fd::OwnedFd> for Fd<'_> {
57    fn from(fd: fd::OwnedFd) -> Self {
58        Self::Owned(fd)
59    }
60}
61
62impl From<OwnedFd> for Fd<'_> {
63    fn from(owned: OwnedFd) -> Self {
64        owned.inner
65    }
66}
67
68impl TryFrom<Fd<'_>> for fd::OwnedFd {
69    type Error = crate::Error;
70
71    fn try_from(fd: Fd<'_>) -> crate::Result<Self> {
72        match fd {
73            Fd::Borrowed(fd) => fd.try_clone_to_owned().map_err(Into::into),
74            Fd::Owned(fd) => Ok(fd),
75        }
76    }
77}
78
79impl AsRawFd for Fd<'_> {
80    fn as_raw_fd(&self) -> RawFd {
81        self.as_fd().as_raw_fd()
82    }
83}
84
85impl AsFd for Fd<'_> {
86    fn as_fd(&self) -> BorrowedFd<'_> {
87        match self {
88            Self::Borrowed(fd) => fd.as_fd(),
89            Self::Owned(fd) => fd.as_fd(),
90        }
91    }
92}
93
94impl<'fd, T> From<&'fd T> for Fd<'fd>
95where
96    T: AsFd,
97{
98    fn from(t: &'fd T) -> Self {
99        Self::Borrowed(t.as_fd())
100    }
101}
102
103impl std::fmt::Display for Fd<'_> {
104    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105        self.as_raw_fd().fmt(f)
106    }
107}
108
109macro_rules! fd_impl {
110    ($i:ty) => {
111        impl Basic for $i {
112            const SIGNATURE_CHAR: char = 'h';
113            const SIGNATURE_STR: &'static str = "h";
114        }
115
116        impl Type for $i {
117            const SIGNATURE: &'static crate::Signature = &crate::Signature::Fd;
118        }
119    };
120}
121
122fd_impl!(Fd<'_>);
123
124impl Serialize for Fd<'_> {
125    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
126    where
127        S: Serializer,
128    {
129        serializer.serialize_i32(self.as_raw_fd())
130    }
131}
132
133impl<'de> Deserialize<'de> for Fd<'de> {
134    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
135    where
136        D: Deserializer<'de>,
137    {
138        let raw = i32::deserialize(deserializer)?;
139        debug_assert!(raw >= 0);
140        // SAFETY: The `'de` lifetimes will ensure the borrow won't outlive the raw FD.
141        let fd = unsafe { BorrowedFd::borrow_raw(raw) };
142
143        Ok(Fd::Borrowed(fd))
144    }
145}
146
147impl PartialEq for Fd<'_> {
148    fn eq(&self, other: &Self) -> bool {
149        self.as_raw_fd().eq(&other.as_raw_fd())
150    }
151}
152impl Eq for Fd<'_> {}
153
154impl PartialOrd for Fd<'_> {
155    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
156        Some(self.cmp(other))
157    }
158}
159
160impl Ord for Fd<'_> {
161    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
162        self.as_raw_fd().cmp(&other.as_raw_fd())
163    }
164}
165
166impl std::hash::Hash for Fd<'_> {
167    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
168        self.as_raw_fd().hash(state)
169    }
170}
171
172/// A file-descriptor type wrapper.
173///
174/// This is the same as [`Fd`] type, except it only keeps an owned file descriptor.
175#[derive(Debug, PartialEq, Eq, Hash)]
176pub struct OwnedFd {
177    inner: Fd<'static>,
178}
179
180fd_impl!(OwnedFd);
181
182impl Serialize for OwnedFd {
183    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
184    where
185        S: Serializer,
186    {
187        self.inner.serialize(serializer)
188    }
189}
190
191impl<'de> Deserialize<'de> for OwnedFd {
192    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
193    where
194        D: Deserializer<'de>,
195    {
196        let fd = Fd::deserialize(deserializer)?;
197        Ok(OwnedFd {
198            inner: fd
199                .as_fd()
200                .try_clone_to_owned()
201                .map(Fd::Owned)
202                .map_err(D::Error::custom)?,
203        })
204    }
205}
206
207impl AsFd for OwnedFd {
208    fn as_fd(&self) -> BorrowedFd<'_> {
209        self.inner.as_fd()
210    }
211}
212
213impl AsRawFd for OwnedFd {
214    fn as_raw_fd(&self) -> RawFd {
215        self.inner.as_raw_fd()
216    }
217}
218
219impl From<fd::OwnedFd> for OwnedFd {
220    fn from(value: fd::OwnedFd) -> Self {
221        Self {
222            inner: Fd::Owned(value),
223        }
224    }
225}
226
227impl From<OwnedFd> for fd::OwnedFd {
228    fn from(value: OwnedFd) -> fd::OwnedFd {
229        match value.inner {
230            Fd::Owned(fd) => fd,
231            Fd::Borrowed(_) => unreachable!(),
232        }
233    }
234}
235
236impl From<Fd<'static>> for OwnedFd {
237    fn from(value: Fd<'static>) -> Self {
238        Self { inner: value }
239    }
240}
241
242impl std::fmt::Display for OwnedFd {
243    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244        self.inner.fmt(f)
245    }
246}