• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::fs::File;
6 use std::mem;
7 use std::mem::ManuallyDrop;
8 
9 use crate::rutabaga_os::RawDescriptor;
10 
11 /// Wraps a RawDescriptor and safely closes it when self falls out of scope.
12 pub struct SafeDescriptor {
13     pub(crate) descriptor: RawDescriptor,
14 }
15 
16 /// Trait for forfeiting ownership of the current raw descriptor, and returning the raw descriptor
17 pub trait IntoRawDescriptor {
into_raw_descriptor(self) -> RawDescriptor18     fn into_raw_descriptor(self) -> RawDescriptor;
19 }
20 
21 /// Trait for returning the underlying raw descriptor, without giving up ownership of the
22 /// descriptor.
23 pub trait AsRawDescriptor {
24     /// Returns the underlying raw descriptor.
25     ///
26     /// Since the descriptor is still owned by the provider, callers should not assume that it will
27     /// remain open for longer than the immediate call of this method. In particular, it is a
28     /// dangerous practice to store the result of this method for future use: instead, it should be
29     /// used to e.g. obtain a raw descriptor that is immediately passed to a system call.
30     ///
31     /// If you need to use the descriptor for a longer time (and particularly if you cannot reliably
32     /// track the lifetime of the providing object), you should probably consider using
33     /// [`SafeDescriptor`] (possibly along with [`trait@IntoRawDescriptor`]) to get full ownership
34     /// over a descriptor pointing to the same resource.
as_raw_descriptor(&self) -> RawDescriptor35     fn as_raw_descriptor(&self) -> RawDescriptor;
36 }
37 
38 /// A trait similar to `AsRawDescriptor` but supports an arbitrary number of descriptors.
39 pub trait AsRawDescriptors {
40     /// Returns the underlying raw descriptors.
41     ///
42     /// Please refer to the documentation of [`AsRawDescriptor::as_raw_descriptor`] for limitations
43     /// and recommended use.
as_raw_descriptors(&self) -> Vec<RawDescriptor>44     fn as_raw_descriptors(&self) -> Vec<RawDescriptor>;
45 }
46 
47 pub trait FromRawDescriptor {
48     /// # Safety
49     /// Safe only if the caller ensures nothing has access to the descriptor after passing it to
50     /// `from_raw_descriptor`
from_raw_descriptor(descriptor: RawDescriptor) -> Self51     unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self;
52 }
53 
54 impl AsRawDescriptor for SafeDescriptor {
as_raw_descriptor(&self) -> RawDescriptor55     fn as_raw_descriptor(&self) -> RawDescriptor {
56         self.descriptor
57     }
58 }
59 
60 impl<T> AsRawDescriptors for T
61 where
62     T: AsRawDescriptor,
63 {
as_raw_descriptors(&self) -> Vec<RawDescriptor>64     fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
65         vec![self.as_raw_descriptor()]
66     }
67 }
68 
69 impl IntoRawDescriptor for SafeDescriptor {
into_raw_descriptor(self) -> RawDescriptor70     fn into_raw_descriptor(self) -> RawDescriptor {
71         let descriptor = self.descriptor;
72         mem::forget(self);
73         descriptor
74     }
75 }
76 
77 impl FromRawDescriptor for SafeDescriptor {
from_raw_descriptor(descriptor: RawDescriptor) -> Self78     unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
79         SafeDescriptor { descriptor }
80     }
81 }
82 
83 impl TryFrom<&dyn AsRawDescriptor> for SafeDescriptor {
84     type Error = std::io::Error;
85 
86     /// Clones the underlying descriptor (handle), internally creating a new descriptor.
87     ///
88     /// WARNING: Windows does NOT support cloning/duplicating all types of handles. DO NOT use this
89     /// function on IO completion ports, sockets, or pseudo-handles (except those from
90     /// GetCurrentProcess or GetCurrentThread). See
91     /// <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle>
92     /// for further details.
93     ///
94     /// TODO(b/191800567): this API has sharp edges on Windows. We should evaluate making some
95     /// adjustments to smooth those edges.
try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error>96     fn try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error> {
97         // Safe because the underlying raw descriptor is guaranteed valid by rd's existence.
98         //
99         // Note that we are cloning the underlying raw descriptor since we have no guarantee of
100         // its existence after this function returns.
101         let rd_as_safe_desc = ManuallyDrop::new(unsafe {
102             SafeDescriptor::from_raw_descriptor(rd.as_raw_descriptor())
103         });
104 
105         // We have to clone rd because we have no guarantee ownership was transferred (rd is
106         // borrowed).
107         rd_as_safe_desc
108             .try_clone()
109             .map_err(|_| Self::Error::last_os_error())
110     }
111 }
112 
113 impl From<File> for SafeDescriptor {
from(f: File) -> SafeDescriptor114     fn from(f: File) -> SafeDescriptor {
115         // Safe because we own the File at this point.
116         unsafe { SafeDescriptor::from_raw_descriptor(f.into_raw_descriptor()) }
117     }
118 }
119 
120 /// For use cases where a simple wrapper around a [`RawDescriptor`] is needed, in order to e.g.
121 /// implement [`trait@AsRawDescriptor`].
122 ///
123 /// This is a simply a wrapper and does not manage the lifetime of the descriptor. As such it is the
124 /// responsibility of the user to ensure that the wrapped descriptor will not be closed for as long
125 /// as the `Descriptor` is alive.
126 ///
127 /// Most use-cases should prefer [`SafeDescriptor`] or implementing and using
128 /// [`trait@AsRawDescriptor`] on the type providing the descriptor. Using this wrapper usually means
129 /// something can be improved in your code.
130 ///
131 /// Valid uses of this struct include:
132 /// * You only have a valid [`RawDescriptor`] and need to pass something that implements
133 ///   [`trait@AsRawDescriptor`] to a function,
134 /// * You need to serialize a [`RawDescriptor`],
135 /// * You need [`trait@Send`] or [`trait@Sync`] for your descriptor and properly handle the case
136 ///   where your descriptor gets closed.
137 ///
138 /// Note that with the exception of the last use-case (which requires proper error checking against
139 /// the descriptor being closed), the `Descriptor` instance would be very short-lived.
140 #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
141 #[repr(transparent)]
142 pub struct Descriptor(pub RawDescriptor);
143 impl AsRawDescriptor for Descriptor {
as_raw_descriptor(&self) -> RawDescriptor144     fn as_raw_descriptor(&self) -> RawDescriptor {
145         self.0
146     }
147 }
148