@ -13,8 +13,12 @@ use std::{
} ,
} ;
mod fd ;
pub mod fd ;
pub mod error ;
mod map ;
/// Flags passed to `memfd_create()` when used in this module
const MEMFD_CREATE_FLAGS : libc ::c_uint = libc ::MFD_CLOEXEC ;
#[ derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord) ]
#[ repr(transparent) ]
@ -24,21 +28,55 @@ impl RawFile
{
/// Get the raw fd for this raw file
#[ inline(always) ]
pub const fn fileno ( & self ) -> RawFd
pub const fn fileno ( & self ) -> & fd ::RawFileDescriptor
{
self . 0. get ( )
& self . 0 //.clone_const()
}
#[ inline(always) ]
pub fn into_fileno ( self ) -> fd ::RawFileDescriptor
{
// SAFETY: We know this is safe since we are just converting the released (valid) fd from `self`
unsafe {
fd ::RawFileDescriptor ::new_unchecked ( self . into_raw_fd ( ) )
}
}
#[ inline(always) ]
pub fn into_fileno ( self ) -> RawFd
pub unsafe fn from_fileno ( fd : fd ::RawFileDescriptor ) -> Self
{
self . into_raw_fd ( )
Self::from_raw_fd ( fd . get ( ) )
}
#[ inline(always) ]
pub unsafe fn from_fileno ( fd : RawFd ) -> Self
const fn take_ownership_of_unchecked ( fd : RawFd ) -> Self
{
Self ::from_raw_fd ( fd )
//! **Internal**: Non-`unsafe` and `const` version of `take_ownership_of_raw_unchecked()`
//! : assumes `fd` is `>= 0`
//!
//! For use in `memfile` functions where `fd` has already been checked for validation (since `unsafe fn`s aren't first-class :/)
unsafe {
Self ( fd ::RawFileDescriptor ::new_unchecked ( fd ) )
}
}
#[ inline ]
pub fn take_ownership_of ( fd : impl Into < fd ::RawFileDescriptor > ) -> Self
{
Self ( fd . into ( ) )
}
#[ inline ]
pub fn take_ownership_of_raw ( fd : impl Into < RawFd > ) -> Result < Self , RawFd >
{
let fd = fd . into ( ) ;
Ok ( Self ( fd . try_into ( ) . map_err ( | _ | fd ) ? ) )
}
#[ inline ]
pub unsafe fn take_ownership_of_raw_unchecked ( fd : impl Into < RawFd > ) -> Self
{
Self ( fd ::RawFileDescriptor ::new_unchecked ( fd . into ( ) ) )
}
/// Attempt to link this instance's fd to another container over an fd
@ -51,7 +89,7 @@ impl RawFile
where T : AsRawFd
{
if unsafe {
libc ::dup2 ( self . fileno ( ) , other . as_raw_fd ( ) )
libc ::dup2 ( self . 0. get ( ) , other . as_raw_fd ( ) )
} < 0 {
Err ( error ::DuplicateError ::new_dup2 ( self , other ) )
} else {
@ -91,12 +129,12 @@ impl RawFile
}
}
/// Consume into a managed file
/// Consume into a nother managed file type container
#[ inline(always) ]
pub fn into_file ( self ) -> fs ::File
pub fn into_file < T : FromRawFd > ( self ) -> T
{
unsafe {
fs::File ::from_raw_fd ( self . into_raw_fd ( ) )
T ::from_raw_fd ( self . into_raw_fd ( ) )
}
}
@ -106,14 +144,65 @@ impl RawFile
{
opt . borrow ( ) . open ( path ) . map ( Into ::into )
}
/// Open a new in-memory (W+R) file with an optional name and a fixed size.
pub fn open_mem ( name : Option < & str > , len : usize ) -> Result < Self , error ::MemfileError >
{
lazy_static ! {
static ref DEFAULT_NAME : String = format! ( concat! ( "<memfile@" , file! ( ) , "->" , "{}" , ":" , line! ( ) , "-" , column! ( ) , ">" ) , function ! ( ) ) ; //TODO: If it turns out memfd_create() requires an `&'static str`; remove the use of stackalloc, and have this variable be a nul-terminated CString instead.
}
use libc ::{
memfd_create ,
fallocate ,
} ;
use error ::MemfileCreationStep ::* ;
let rname = name . unwrap_or ( & DEFAULT_NAME ) ;
stackalloc ::alloca_zeroed ( rname . len ( ) + 1 , move | bname | { //XXX: Isn't the whole point of making `name` `&'static` that I don't know if `memfd_create()` requires static-lifetime name strings? TODO: Check this
macro_rules! attempt_call
{
( $errcon :literal , $expr :expr , $step :expr ) = > {
match unsafe {
$expr
} {
$errcon = > Err ( $step ) ,
x = > Ok ( x )
}
}
}
let bname = {
unsafe {
std ::ptr ::copy_nonoverlapping ( rname . as_ptr ( ) , bname . as_mut_ptr ( ) , rname . len ( ) ) ;
}
debug_assert_eq! ( bname [ rname . len ( ) ] , 0 , "Copied name string not null-terminated?" ) ;
bname . as_ptr ( )
} ;
let fd = attempt_call ! ( - 1 , memfd_create ( bname as * const _ , MEMFD_CREATE_FLAGS ) , Create ( name . map ( str ::to_owned ) , MEMFD_CREATE_FLAGS ) )
. map ( Self ::take_ownership_of_unchecked ) ? ; // Ensures `fd` is dropped if any subsequent calls fail
attempt_call ! ( - 1
, fallocate ( fd . 0. get ( ) , 0 , 0 , len . try_into ( )
. map_err ( | _ | Allocate ( fd . fileno ( ) . clone ( ) , len ) ) ? )
, Allocate ( fd . fileno ( ) . clone ( ) , len ) ) ? ;
Ok ( fd )
} )
}
}
impl io ::Write for RawFile
{
#[ inline ]
fn write ( & mut self , buf : & [ u8 ] ) -> io ::Result < usize > {
match unsafe {
libc ::write ( self . fileno ( ) , buf . as_ptr ( ) as * const _ , buf . len ( ) )
libc ::write ( self . 0. get ( ) , buf . as_ptr ( ) as * const _ , buf . len ( ) )
} {
- 1 = > Err ( io ::Error ::last_os_error ( ) ) ,
wr = > Ok ( wr as usize )
@ -129,7 +218,7 @@ impl io::Write for RawFile
fn write_vectored ( & mut self , bufs : & [ io ::IoSlice < ' _ > ] ) -> io ::Result < usize > {
// SAFETY: IoSlice is guaranteed to be ABI-compatible with `struct iovec`
match unsafe {
libc ::writev ( self . fileno ( ) , bufs . as_ptr ( ) as * const _ , bufs . len ( ) as i32 )
libc ::writev ( self . 0. get ( ) , bufs . as_ptr ( ) as * const _ , bufs . len ( ) as i32 )
} {
- 1 = > Err ( io ::Error ::last_os_error ( ) ) ,
wr = > Ok ( wr as usize )
@ -142,7 +231,7 @@ impl io::Read for RawFile
#[ inline ]
fn read ( & mut self , buf : & mut [ u8 ] ) -> io ::Result < usize > {
match unsafe {
libc ::read ( self . fileno ( ) , buf . as_mut_ptr ( ) as * mut _ , buf . len ( ) )
libc ::read ( self . 0. get ( ) , buf . as_mut_ptr ( ) as * mut _ , buf . len ( ) )
} {
- 1 = > Err ( io ::Error ::last_os_error ( ) ) ,
wr = > Ok ( wr as usize )
@ -153,7 +242,7 @@ impl io::Read for RawFile
fn read_vectored ( & mut self , bufs : & mut [ io ::IoSliceMut < ' _ > ] ) -> io ::Result < usize > {
// SAFETY: IoSlice is guaranteed to be ABI-compatible with `struct iovec`
match unsafe {
libc ::readv ( self . fileno ( ) , bufs . as_mut_ptr ( ) as * mut _ , bufs . len ( ) as i32 )
libc ::readv ( self . 0. get ( ) , bufs . as_mut_ptr ( ) as * mut _ , bufs . len ( ) as i32 )
} {
- 1 = > Err ( io ::Error ::last_os_error ( ) ) ,
wr = > Ok ( wr as usize )