Pre-release 0.0.9-r0: Started `NamedMemoryFile` refactor into `MemoryFile`.

Fortune for mapped-file's current commit: Blessing − 吉
master
Avril 3 weeks ago
parent 8fcd1929a4
commit ee28043069
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -2,7 +2,7 @@
name = "mapped-file"
description = "Construct a memory mapping over any file object"
keywords = ["unix", "mmap", "generic", "file", "fd"]
version = "0.0.8-r1"
version = "0.0.9-r0"
edition = "2021"
repository="https://github.com/notflan/mapped-file"
license="MIT"
@ -10,7 +10,7 @@ license="MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["default-cloexec"]
default = ["default-cloexec", "file"]
# Add support for file-descriptor operations other than simply mapping
# TODO: XXX: Incomplete, will be enabled by default when complete
@ -26,3 +26,4 @@ default-cloexec = []
lazy_static = "1.4.0"
libc = "0.2.132"
memchr = "2.5.0"
stackalloc = "1.2.1"

@ -2,6 +2,8 @@
//!
//! This can be useful for temporary buffers where a file descriptor is required.
//! Huge-pages can also be used for this memory.
#![allow(deprecated)]
use super::*;
use libc::{
c_uint,
@ -12,10 +14,14 @@ use libc::{
ftruncate,
};
use std::{
ffi::CStr,
ffi::{CStr, CString},
borrow::{
Borrow,
BorrowMut,
Cow,
},
path::{
Path, PathBuf,
},
ops,
};
@ -48,8 +54,69 @@ pub struct MemoryFile(ManagedFD);
/// A named, physical-memory backed file
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[deprecated(note = "Use `MemoryFile::named[_with_size]()` instead.")]
pub struct NamedMemoryFile(Box<CStr>, MemoryFile);
impl NamedMemoryFile
{
pub(crate) const PATH_PREFIX: &'static str = "/proc/self/fd/";
/// Get the name of the memfd which will be `/proc/self/fd/memfd:{}` (where `{}` is `.name()`.)
#[inline]
pub fn name(&self) -> &CStr
{
self.0.as_ref()
}
/// Get the absolute path (in `/proc/self/fd/`) of this memfd.
#[inline]
pub fn get_path(&self) -> PathBuf
{
use std::ffi::OsStr;
/// Name prefix within `PATH_PREFIX`.
const PREFIX: &[u8; 6] = b"memfd:";
// Alloc space for `PREFIX`+`self.0.len()` to create last element in path.
stackalloc::alloca_zeroed(self.0.count_bytes() + PREFIX.len(), move |name| {
// Write `memfd:` to `name[..6]`
name[..PREFIX.len()].copy_from_slice(&PREFIX[..]);
// Write name to `name+6`
name[PREFIX.len()..].copy_from_slice(self.0.to_bytes());
// for (&src, dest) in PREFIX.into_iter().chain(self.0.to_bytes().iter()).zip(&mut name[..]) {
// *dest = src;
// }
debug_assert_ne!(name.last().unwrap(), &0, "Invalid stack based path-builder string");
Path::new(Self::PATH_PREFIX).join(OsStr::from_bytes(&name[..]))
})
}
/// Consume into the internal `MemoryFile`.
#[inline]
pub fn into_inner(self) -> MemoryFile
{
self.1
}
}
impl AsRawFd for NamedMemoryFile
{
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.1.as_raw_fd()
}
}
impl IntoRawFd for NamedMemoryFile
{
#[inline]
fn into_raw_fd(self) -> RawFd {
self.1.into_raw_fd()
}
}
impl Borrow<MemoryFile> for NamedMemoryFile
{
#[inline]
@ -79,20 +146,43 @@ impl ops::Deref for NamedMemoryFile
}
}
#[cold]
fn last_os_error() -> io::Error
{
io::Error::last_os_error()
}
//impl `MemoryFile` (memfd_create() fd wrapper)
impl MemoryFile
{
/// Create a new, empty, memory file with no name and no flags.
pub fn new() -> io::Result<Self>
/// Create a new, empty, memory file with the specified raw C-string pointer name and the default set of flags.
/// # Safety
///
/// `name` must be a:
/// - Non-null, aligned, valid pointer to:
/// - A nul-terminated, non-wide C string.
/// - Which must **not** contain a `/`.
#[inline(always)]
pub(super) unsafe fn new_raw_named(name: *const std::ffi::c_char, flags: c_uint) -> io::Result<Self>
{
let managed = unsafe {
match memfd_create(UNNAMED.as_ptr(), DEFAULT_FLAGS) {
-1 => return Err(io::Error::last_os_error()),
match memfd_create(name, flags) {
-1 => return Err(last_os_error()),
fd => ManagedFD::take_unchecked(fd),
}
};
Ok(Self(managed))
}
/// Create a new, empty, memory file with no user-provided name and the default set of flags.
pub fn new() -> io::Result<Self>
{
// SAFETY: `UNNAMED` is a constant that fits the constraints required for `name`.
unsafe {
Self::new_raw_named(UNNAMED.as_ptr(), DEFAULT_FLAGS)
}
}
#[inline]
pub fn resize(&mut self, value: usize) -> io::Result<()>
{
@ -105,7 +195,7 @@ impl MemoryFile
pub fn with_hugetlb(hugetlb: MapHugeFlag) -> io::Result<Self>
{
unsafe { create_raw(UNNAMED, DEFAULT_FLAGS | (hugetlb.get_mask() as c_uint)) }
unsafe { create_raw(UNNAMED, DEFAULT_FLAGS | MFD_HUGETLB | (hugetlb.get_mask() as c_uint)) }
.map(ManagedFD::take)
.map(Self)
}
@ -124,6 +214,50 @@ impl MemoryFile
this.resize(size)?;
Ok(this)
}
/// Create a new, empty, memory file with the specified raw C-string pointer name and the default set of flags.
pub fn new_named(name: impl AsRef<str>) -> io::Result<Self>
{
Self::raw_with_str_name(name.as_ref(), DEFAULT_FLAGS)
}
#[inline(always)]
pub(crate) fn raw_with_str_name(name: &str, flags: c_uint) -> io::Result<Self>
{
stackalloc::alloca_zeroed(name.len()+1, move |cname| {
cname[..name.len()].copy_from_slice(name.as_bytes());
debug_assert_ne!(cname[name.len()], 0, "Copied name not nul-terminated for `memfd_create()` call.");
// SAFETY: We have initialised `cname[..]`, and we know the final byte will be
unsafe {
Self::new_raw_named(cname.as_ptr() as *const _, flags)
}
})
}
/// Create a new, empty, memory file with the specified raw C-string pointer name and the `MEMFD_HUGETLB` flag setup as provided as `hugetlb`.
pub fn new_named_with_hugetlb(name: impl AsRef<str>, hugetlb: MapHugeFlag) -> io::Result<Self>
{
Self::raw_with_str_name(name.as_ref(), DEFAULT_FLAGS | MFD_HUGETLB | (hugetlb.get_mask() as c_uint))
}
/// Create a new memory file with the specified raw C-string pointer name and the default set of flags.
/// Then resize it via `ftruncate()` to `size` bytes.
pub fn new_named_with_size(name: impl AsRef<str>, size: usize) -> io::Result<Self>
{
let mut this = Self::raw_with_str_name(name.as_ref(), DEFAULT_FLAGS)?;
this.resize(size)?;
Ok(this)
}
/// Create a new memory file with the specified raw C-string pointer name and the `MEMFD_HUGETLB` flag setup as provided as `hugetlb`.
/// Then resize it via `ftruncate()` to `size` bytes.
pub fn new_named_with_size_hugetlb(name: impl AsRef<str>, size: usize, hugetlb: MapHugeFlag) -> io::Result<Self>
{
let mut this = Self::raw_with_str_name(name.as_ref(), DEFAULT_FLAGS | MFD_HUGETLB | (hugetlb.get_mask() as c_uint))?;
this.resize(size)?;
Ok(this)
}
}
fn alloc_cstring(string: &str) -> std::ffi::CString
@ -170,7 +304,7 @@ impl NamedMemoryFile
pub fn with_hugetlb(name: impl AsRef<str>, hugetlb: MapHugeFlag) -> io::Result<Self>
{
let name: Box<CStr> = alloc_cstring(name.as_ref()).into();
let memfd = MemoryFile(unsafe { create_raw(&name, DEFAULT_FLAGS | (hugetlb.get_mask() as c_uint)) }
let memfd = MemoryFile(unsafe { create_raw(&name, DEFAULT_FLAGS | MFD_HUGETLB | (hugetlb.get_mask() as c_uint)) }
.map(ManagedFD::take)?);
Ok(Self(name, memfd))
}
@ -245,4 +379,6 @@ mod test {
assert_eq!(super::DEFAULT_FLAGS, cfg!(feature="default-cloexec").then(|| super::MFD_CLOEXEC).unwrap_or_default(), "Compile-time default creation flags are not in accordance with provided global crate configuration");
}
//TODO: Test if `NamedMemoryFile.get_path()` works properly.
}

Loading…
Cancel
Save