Skip to main content

gio/
unix_fd_list.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3#[cfg(unix)]
4use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
5use std::{mem, ptr};
6
7use glib::{prelude::*, translate::*};
8#[cfg(all(not(unix), docsrs))]
9use socket::{AsFd, AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
10
11use crate::{UnixFDList, ffi};
12
13impl UnixFDList {
14    /// Creates a new [`UnixFDList`][crate::UnixFDList] containing the file descriptors given
15    /// in @fds. The file descriptors become the property of the new list and may no
16    /// longer be used by the caller. The array itself is owned by the caller.
17    ///
18    /// Each file descriptor in the array should be set to close-on-exec.
19    ///
20    /// If @n_fds is -1 then @fds must be terminated with -1.
21    /// ## `fds`
22    /// the initial list of file descriptors
23    ///
24    /// # Returns
25    ///
26    /// a new [`UnixFDList`][crate::UnixFDList]
27    #[doc(alias = "g_unix_fd_list_new_from_array")]
28    pub fn from_array(fds: impl IntoIterator<Item = impl IntoRawFd>) -> UnixFDList {
29        let fds = fds.into_iter().map(|t| t.into_raw_fd()).collect::<Vec<_>>();
30        unsafe {
31            from_glib_full(ffi::g_unix_fd_list_new_from_array(
32                fds.to_glib_none().0,
33                fds.len() as i32,
34            ))
35        }
36    }
37}
38
39pub trait UnixFDListExtManual: IsA<UnixFDList> + Sized {
40    /// Adds a file descriptor to @self.
41    ///
42    /// The file descriptor is duplicated using `dup()`. You keep your copy
43    /// of the descriptor and the copy contained in @self will be closed
44    /// when @self is finalized.
45    ///
46    /// A possible cause of failure is exceeding the per-process or
47    /// system-wide file descriptor limit.
48    ///
49    /// The index of the file descriptor in the list is returned.  If you use
50    /// this index with [`UnixFDListExtManual::get()`][crate::prelude::UnixFDListExtManual::get()] then you will receive back a
51    /// duplicated copy of the same file descriptor.
52    /// ## `fd`
53    /// a valid open file descriptor
54    ///
55    /// # Returns
56    ///
57    /// the index of the appended fd in case of success, else `-1`
58    ///          (and @error is set)
59    #[doc(alias = "g_unix_fd_list_append")]
60    fn append(&self, fd: impl AsFd) -> Result<i32, glib::Error> {
61        unsafe {
62            let mut error = ptr::null_mut();
63            let ret = ffi::g_unix_fd_list_append(
64                self.as_ref().to_glib_none().0,
65                fd.as_fd().as_raw_fd(),
66                &mut error,
67            );
68            if error.is_null() {
69                Ok(ret)
70            } else {
71                Err(from_glib_full(error))
72            }
73        }
74    }
75
76    /// Gets a file descriptor out of @self.
77    ///
78    /// @index_ specifies the index of the file descriptor to get.  It is a
79    /// programmer error for @index_ to be out of range. Either use
80    /// [`UnixFDListExtManual::lookup()`][crate::prelude::UnixFDListExtManual::lookup()] to do a checked lookup, or check the index
81    /// against the list length using [`UnixFDListExt::length()`][crate::prelude::UnixFDListExt::length()].
82    ///
83    /// The file descriptor is duplicated using `dup()` and set as
84    /// close-on-exec before being returned.  You must call `close()` on it
85    /// when you are done.
86    ///
87    /// A possible cause of failure is exceeding the per-process or
88    /// system-wide file descriptor limit.
89    /// ## `index_`
90    /// the index into the list
91    ///
92    /// # Returns
93    ///
94    /// the file descriptor, or `-1` in case of error
95    #[doc(alias = "g_unix_fd_list_get")]
96    fn get(&self, index_: i32) -> Result<OwnedFd, glib::Error> {
97        unsafe {
98            let mut error = ptr::null_mut();
99            let raw_fd =
100                ffi::g_unix_fd_list_get(self.as_ref().to_glib_none().0, index_, &mut error);
101            if error.is_null() {
102                let fd = OwnedFd::from_raw_fd(raw_fd);
103                Ok(fd)
104            } else {
105                Err(from_glib_full(error))
106            }
107        }
108    }
109
110    /// Returns the array of file descriptors that is contained in this
111    /// object.
112    ///
113    /// After this call, the descriptors remain the property of @self.  The
114    /// caller must not close them and must not free the array.  The array is
115    /// valid only until @self is changed in any way.
116    ///
117    /// If @length is non-`NULL` then it is set to the number of file
118    /// descriptors in the returned array. The returned array is also
119    /// terminated with `-1`.
120    ///
121    /// This function never returns `NULL`. In case there are no file
122    /// descriptors contained in @self, an empty array is returned.
123    ///
124    /// # Returns
125    ///
126    /// an array of file
127    ///     descriptors
128    #[doc(alias = "g_unix_fd_list_peek_fds")]
129    fn peek_fds(&self) -> Vec<RawFd> {
130        unsafe {
131            let mut length = mem::MaybeUninit::uninit();
132
133            FromGlibContainer::from_glib_none_num(
134                ffi::g_unix_fd_list_peek_fds(self.as_ref().to_glib_none().0, length.as_mut_ptr()),
135                length.assume_init() as usize,
136            )
137        }
138    }
139
140    /// Returns the array of file descriptors that is contained in this
141    /// object.
142    ///
143    /// After this call, the descriptors are no longer contained in
144    /// @self. Further calls will return an empty list (unless more
145    /// descriptors have been added).
146    ///
147    /// The return result of this function must be freed with `g_free()`.
148    /// The caller is also responsible for closing all of the file
149    /// descriptors.  The file descriptors in the array are set to
150    /// close-on-exec.
151    ///
152    /// If @length is non-`NULL` then it is set to the number of file
153    /// descriptors in the returned array. The returned array is also
154    /// terminated with `-1`.
155    ///
156    /// This function never returns `NULL`. In case there are no file
157    /// descriptors contained in @self, an empty array is returned.
158    ///
159    /// # Returns
160    ///
161    /// an array of file
162    ///     descriptors
163    #[doc(alias = "g_unix_fd_list_steal_fds")]
164    fn steal_fds(&self) -> Vec<RawFd> {
165        unsafe {
166            let mut length = mem::MaybeUninit::uninit();
167
168            FromGlibContainer::from_glib_full_num(
169                ffi::g_unix_fd_list_steal_fds(self.as_ref().to_glib_none().0, length.as_mut_ptr()),
170                length.assume_init() as usize,
171            )
172        }
173    }
174
175    /// Adds a file descriptor to @self.
176    ///
177    /// After this call, @fd belongs to the @self and may no longer be closed by the
178    /// caller.
179    ///
180    /// The file descriptor @fd should be set to close-on-exec.
181    ///
182    /// The index of the file descriptor in the list is returned. If you use this
183    /// index with [`UnixFDListExtManual::get()`][crate::prelude::UnixFDListExtManual::get()] then you will receive back a
184    /// duplicated copy of the same file descriptor.
185    /// ## `fd`
186    /// a valid open file descriptor
187    ///
188    /// # Returns
189    ///
190    /// the index of the appended @fd
191    #[cfg(feature = "v2_90")]
192    #[cfg_attr(docsrs, doc(cfg(feature = "v2_90")))]
193    #[doc(alias = "g_unix_fd_list_append_take")]
194    fn append_take(&self, fd: impl IntoRawFd) -> usize {
195        unsafe { ffi::g_unix_fd_list_append_take(self.as_ref().to_glib_none().0, fd.into_raw_fd()) }
196    }
197
198    /// Looks up a file descriptor in @self at position @index_.
199    ///
200    /// @index_ specifies the index of the file descriptor to get. If no file
201    /// descriptor exists at this index, `-1` is returned.
202    ///
203    /// After this call, the descriptor remains the property of @self. The caller
204    /// must not close it. The descriptor is valid only until @self is changed in any
205    /// way.
206    /// ## `index_`
207    /// the file descriptor index
208    ///
209    /// # Returns
210    ///
211    /// the file descriptor, or `-1` if not found
212    #[cfg(feature = "v2_90")]
213    #[cfg_attr(docsrs, doc(cfg(feature = "v2_90")))]
214    #[doc(alias = "g_unix_fd_list_lookup")]
215    fn lookup(&self, index_: usize) -> RawFd {
216        unsafe { ffi::g_unix_fd_list_lookup(self.as_ref().to_glib_none().0, index_) }
217    }
218
219    /// Gets a file descriptor out of @self.
220    ///
221    /// @index_ specifies the index of the file descriptor to get. It is a programmer
222    /// error for @index_ to be out of range; see [`UnixFDListExt::length()`][crate::prelude::UnixFDListExt::length()].
223    ///
224    /// This will always return a valid (non-negative) file descriptor.
225    ///
226    /// After this call, the descriptor remains the property of @self. The caller
227    /// must not close it. The descriptor is valid only until @self is changed in any
228    /// way.
229    /// ## `index_`
230    /// the index into the list
231    ///
232    /// # Returns
233    ///
234    /// the file descriptor
235    #[cfg(feature = "v2_90")]
236    #[cfg_attr(docsrs, doc(cfg(feature = "v2_90")))]
237    #[doc(alias = "g_unix_fd_list_peek")]
238    fn peek(&self, index_: usize) -> RawFd {
239        unsafe { ffi::g_unix_fd_list_peek(self.as_ref().to_glib_none().0, index_) }
240    }
241}
242
243impl<O: IsA<UnixFDList>> UnixFDListExtManual for O {}