android13/external/crosvm/base/src/descriptor.rs

131 lines
4.3 KiB
Rust

// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::{PollToken, RawDescriptor};
use serde::{Deserialize, Serialize};
use std::{
fs::File,
mem::{self, ManuallyDrop},
};
/// Wraps a RawDescriptor and safely closes it when self falls out of scope.
#[derive(Serialize, Deserialize, Debug, Eq)]
#[serde(transparent)]
pub struct SafeDescriptor {
#[serde(with = "super::with_raw_descriptor")]
pub(crate) descriptor: RawDescriptor,
}
/// Trait for forfeiting ownership of the current raw descriptor, and returning the raw descriptor
pub trait IntoRawDescriptor {
fn into_raw_descriptor(self) -> RawDescriptor;
}
/// Trait for returning the underlying raw descriptor, without giving up ownership of the
/// descriptor.
pub trait AsRawDescriptor {
fn as_raw_descriptor(&self) -> RawDescriptor;
}
/// A trait similar to `AsRawDescriptor` but supports an arbitrary number of descriptors.
pub trait AsRawDescriptors {
fn as_raw_descriptors(&self) -> Vec<RawDescriptor>;
}
pub trait FromRawDescriptor {
/// # Safety
/// Safe only if the caller ensures nothing has access to the descriptor after passing it to
/// `from_raw_descriptor`
unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self;
}
impl AsRawDescriptor for SafeDescriptor {
fn as_raw_descriptor(&self) -> RawDescriptor {
self.descriptor
}
}
impl<T> AsRawDescriptors for T
where
T: AsRawDescriptor,
{
fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
vec![self.as_raw_descriptor()]
}
}
impl IntoRawDescriptor for SafeDescriptor {
fn into_raw_descriptor(self) -> RawDescriptor {
let descriptor = self.descriptor;
mem::forget(self);
descriptor
}
}
impl FromRawDescriptor for SafeDescriptor {
unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
SafeDescriptor { descriptor }
}
}
impl TryFrom<&dyn AsRawDescriptor> for SafeDescriptor {
type Error = std::io::Error;
/// Clones the underlying descriptor (handle), internally creating a new descriptor.
///
/// WARNING: Windows does NOT support cloning/duplicating all types of handles. DO NOT use this
/// function on IO completion ports, sockets, or pseudo-handles (except those from
/// GetCurrentProcess or GetCurrentThread). See
/// https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle
/// for further details.
///
/// TODO(b/191800567): this API has sharp edges on Windows. We should evaluate making some
/// adjustments to smooth those edges.
fn try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error> {
// Safe because the underlying raw descriptor is guaranteed valid by rd's existence.
//
// Note that we are cloning the underlying raw descriptor since we have no guarantee of
// its existence after this function returns.
let rd_as_safe_desc = ManuallyDrop::new(unsafe {
SafeDescriptor::from_raw_descriptor(rd.as_raw_descriptor())
});
// We have to clone rd because we have no guarantee ownership was transferred (rd is
// borrowed).
rd_as_safe_desc
.try_clone()
.map_err(|e| Self::Error::from_raw_os_error(e.errno()))
}
}
impl From<File> for SafeDescriptor {
fn from(f: File) -> SafeDescriptor {
// Safe because we own the File at this point.
unsafe { SafeDescriptor::from_raw_descriptor(f.into_raw_descriptor()) }
}
}
/// For use cases where a simple wrapper around a RawDescriptor is needed.
/// This is a simply a wrapper and does not manage the lifetime of the descriptor.
/// Most usages should prefer SafeDescriptor or using a RawDescriptor directly
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Descriptor(pub RawDescriptor);
impl AsRawDescriptor for Descriptor {
fn as_raw_descriptor(&self) -> RawDescriptor {
self.0
}
}
/// Implement token for implementations that wish to use this struct as such
impl PollToken for Descriptor {
fn as_raw_token(&self) -> u64 {
self.0 as u64
}
fn from_raw_token(data: u64) -> Self {
Descriptor(data as RawDescriptor)
}
}