// Copyright 2020 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 std::mem; use std::ops::Drop; use std::os::unix::io::{AsRawFd, RawFd}; use crate::{errno_result, Result}; pub type RawDescriptor = RawFd; /// 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; } 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; } /// Wraps a RawDescriptor and safely closes it when self falls out of scope. #[derive(Debug, PartialEq)] pub struct SafeDescriptor { descriptor: RawDescriptor, } impl Drop for SafeDescriptor { fn drop(&mut self) { let _ = unsafe { libc::close(self.descriptor) }; } } impl AsRawDescriptor for SafeDescriptor { fn as_raw_descriptor(&self) -> RawDescriptor { self.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 AsRawFd for SafeDescriptor { fn as_raw_fd(&self) -> RawFd { self.as_raw_descriptor() } } impl SafeDescriptor { /// Clones this descriptor, internally creating a new descriptor. The new SafeDescriptor will /// share the same underlying count within the kernel. pub fn try_clone(&self) -> Result { // Safe because self.as_raw_descriptor() returns a valid value let copy_fd = unsafe { libc::dup(self.as_raw_descriptor()) }; if copy_fd < 0 { return errno_result(); } // Safe becuase we just successfully duplicated and this object will uniquely // own the raw descriptor. Ok(unsafe { SafeDescriptor::from_raw_descriptor(copy_fd) }) } } /// 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 } }