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