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 { 78 /// # Safety 79 /// Safe only if the caller ensures nothing has access to the descriptor after passing it to 80 /// `from_raw_descriptor` from_raw_descriptor(descriptor: RawDescriptor) -> Self81 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self { 82 SafeDescriptor { descriptor } 83 } 84 } 85 86 impl TryFrom<&dyn AsRawDescriptor> for SafeDescriptor { 87 type Error = std::io::Error; 88 89 /// Clones the underlying descriptor (handle), internally creating a new descriptor. 90 /// 91 /// WARNING: Windows does NOT support cloning/duplicating all types of handles. DO NOT use this 92 /// function on IO completion ports, sockets, or pseudo-handles (except those from 93 /// GetCurrentProcess or GetCurrentThread). See 94 /// <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle> 95 /// for further details. 96 /// 97 /// TODO(b/191800567): this API has sharp edges on Windows. We should evaluate making some 98 /// adjustments to smooth those edges. try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error>99 fn try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error> { 100 // SAFETY: 101 // Safe because the underlying raw descriptor is guaranteed valid by rd's existence. 102 // 103 // Note that we are cloning the underlying raw descriptor since we have no guarantee of 104 // its existence after this function returns. 105 let rd_as_safe_desc = ManuallyDrop::new(unsafe { 106 SafeDescriptor::from_raw_descriptor(rd.as_raw_descriptor()) 107 }); 108 109 // We have to clone rd because we have no guarantee ownership was transferred (rd is 110 // borrowed). 111 rd_as_safe_desc 112 .try_clone() 113 .map_err(|_| Self::Error::last_os_error()) 114 } 115 } 116 117 impl From<File> for SafeDescriptor { from(f: File) -> SafeDescriptor118 fn from(f: File) -> SafeDescriptor { 119 // SAFETY: 120 // Safe because we own the File at this point. 121 unsafe { SafeDescriptor::from_raw_descriptor(f.into_raw_descriptor()) } 122 } 123 } 124 125 /// For use cases where a simple wrapper around a [`RawDescriptor`] is needed, in order to e.g. 126 /// implement [`trait@AsRawDescriptor`]. 127 /// 128 /// This is a simply a wrapper and does not manage the lifetime of the descriptor. As such it is the 129 /// responsibility of the user to ensure that the wrapped descriptor will not be closed for as long 130 /// as the `Descriptor` is alive. 131 /// 132 /// Most use-cases should prefer [`SafeDescriptor`] or implementing and using 133 /// [`trait@AsRawDescriptor`] on the type providing the descriptor. Using this wrapper usually means 134 /// something can be improved in your code. 135 /// 136 /// Valid uses of this struct include: 137 /// * You only have a valid [`RawDescriptor`] and need to pass something that implements 138 /// [`trait@AsRawDescriptor`] to a function, 139 /// * You need to serialize a [`RawDescriptor`], 140 /// * You need [`trait@Send`] or [`trait@Sync`] for your descriptor and properly handle the case 141 /// where your descriptor gets closed. 142 /// 143 /// Note that with the exception of the last use-case (which requires proper error checking against 144 /// the descriptor being closed), the `Descriptor` instance would be very short-lived. 145 #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 146 #[repr(transparent)] 147 pub struct Descriptor(pub RawDescriptor); 148 impl AsRawDescriptor for Descriptor { as_raw_descriptor(&self) -> RawDescriptor149 fn as_raw_descriptor(&self) -> RawDescriptor { 150 self.0 151 } 152 } 153