extern crate winapi;
use self::winapi::shared::ntdef::{NULL};
use self::winapi::shared::minwindef::{FALSE};
use self::winapi::um::winbase::*;
use self::winapi::um::winnt::*;
use self::winapi::um::handleapi::*;
use self::winapi::um::memoryapi::*;
use self::winapi::um::errhandlingapi::*;
use self::winapi::um::synchapi::{
CreateMutexA,
WaitForSingleObject,
ReleaseMutex,
};
use super::{std,
SharedMem,
LockType,
LockNone,
SharedMemLockImpl,
};
use std::path::PathBuf;
use std::mem::size_of;
use std::ffi::CString;
use std::ptr::{null_mut};
use std::os::raw::c_void;
use std::slice;
type Result<T> = std::result::Result<T, Box<std::error::Error>>;
struct SharedData {
lock_ind: u8,
mapping_size: usize,
}
pub struct MemMetadata<'a> {
map_handle: HANDLE,
shared_data: *mut SharedData,
pub lock_data: *mut c_void,
pub lock_data_is_handle: bool,
pub data: *mut c_void,
pub lock_impl : &'a SharedMemLockImpl,
}
impl<'a> Drop for MemMetadata<'a> {
fn drop(&mut self) {
if self.lock_data_is_handle {
unsafe { CloseHandle(self.lock_data as *mut _); }
}
if self.shared_data as *mut _ == NULL {
unsafe { UnmapViewOfFile(self.shared_data as *mut _); }
}
if self.map_handle as *mut _ != NULL {
unsafe { CloseHandle(self.map_handle); }
}
}
}
pub fn open(mut new_file: SharedMem) -> Result<SharedMem> {
let is_raw: bool = !new_file.link_path.is_some();
let mapping_path = match new_file.real_path {
Some(ref path) => path.clone(),
None => {
panic!("Tried to open SharedMem with no real_path");
},
};
let map_handle = unsafe {
OpenFileMappingA(
FILE_MAP_READ| FILE_MAP_WRITE,
FALSE,
CString::new(mapping_path.clone())?.as_ptr()
)
};
if map_handle as *mut _ == NULL {
return Err(From::from(format!("CreateFileMappingA failed with {}", unsafe{GetLastError()})));
}
new_file.real_path = Some(mapping_path.clone());
let map_addr = unsafe {
MapViewOfFile(
map_handle,
FILE_MAP_READ| FILE_MAP_WRITE,
0,
0,
0
)
};
if map_addr == NULL {
unsafe { CloseHandle(map_handle); }
return Err(From::from(format!("MapViewOfFile failed with {}", unsafe{GetLastError()})));
}
let full_size = unsafe {
let mut mem_ba: MEMORY_BASIC_INFORMATION = MEMORY_BASIC_INFORMATION {
BaseAddress: null_mut(),
AllocationBase: null_mut(),
AllocationProtect: 0,
RegionSize: 0,
State: 0,
Protect: 0,
Type: 0,
};
let ret_val = VirtualQuery(
map_addr as *const _,
&mut mem_ba as *mut _,
size_of::<MEMORY_BASIC_INFORMATION>()
);
if ret_val == 0 {
UnmapViewOfFile(map_addr);
CloseHandle(map_handle);
return Err(From::from(format!("VirtualQuery failed with {}", GetLastError())));
}
mem_ba.RegionSize
};
if is_raw {
new_file.size = full_size;
new_file.meta = Some(MemMetadata {
map_handle: map_handle,
shared_data: map_addr as *mut SharedData,
lock_data: null_mut(),
lock_data_is_handle: false,
data: map_addr as *mut c_void,
lock_impl: &LockNone{},
});
return Ok(new_file);
}
let shared_data: &SharedData = unsafe {&(*(map_addr as *mut SharedData))};
let lock_info = supported_locktype_from_ind(shared_data.lock_ind as usize);
let lock_type: LockType = lock_info.0;
let shared_data_sz = (size_of::<SharedData>() + 3) & !(0x03 as usize);
let lock_data_sz = lock_info.1;
let mut meta: MemMetadata = MemMetadata {
map_handle: map_handle,
shared_data: map_addr as *mut SharedData,
lock_data: (map_addr as usize + shared_data_sz) as *mut _,
lock_data_is_handle: false,
data: (map_addr as usize + shared_data_sz + lock_data_sz) as *mut c_void,
lock_impl: &LockNone{},
};
match lock_type {
LockType::None => {},
LockType::Mutex => {
let mut mutex_name: String = String::with_capacity(Mutex::size_of());
for char_byte in unsafe {slice::from_raw_parts((meta.lock_data) as *const u8, Mutex::size_of())} {
if *char_byte == 0x00 { break }
mutex_name.push(*char_byte as char);
}
meta.lock_data = unsafe {OpenMutexA(
SYNCHRONIZE, FALSE, CString::new(mutex_name)?.as_ptr()) as *mut _};
if meta.lock_data as *mut winapi::ctypes::c_void == NULL {
return Err(From::from(format!("OpenMutexA failed with {}", unsafe{GetLastError()})));
}
meta.lock_data_is_handle = true;
meta.lock_impl = &Mutex{};
},
LockType::RwLock => {
}
};
if full_size > shared_data.mapping_size {
new_file.size = shared_data.mapping_size;
} else {
new_file.size = full_size - shared_data_sz - lock_data_sz;
}
new_file.meta = Some(meta);
Ok(new_file)
}
pub fn create(mut new_file: SharedMem, lock_type: LockType) -> Result<SharedMem> {
let is_raw: bool;
let real_path: String = match new_file.real_path {
Some(ref path) => {
is_raw = true;
path.clone()
},
None => {
is_raw = false;
if let Some(ref file_path) = new_file.link_path {
if !file_path.is_file() {
return Err(From::from("os_impl::create() on a link but not link file exists..."));
}
let abs_disk_path: PathBuf = file_path.canonicalize()?;
let chars = abs_disk_path.to_string_lossy();
let mut unique_name: String = String::with_capacity(chars.len());
let mut chars = chars.chars();
chars.next();
for c in chars {
match c {
'\\' | '.' => unique_name.push('_'),
'?' | ':' => {},
v => unique_name.push(v),
};
}
String::from(unique_name.trim_matches('_'))
} else {
panic!("Trying to create SharedMem without any name");
}
}
};
let locktype_info = supported_locktype_info(&lock_type);
let mut shared_data_sz: usize = 0;
let mut lock_ind: u8 = 0;
let mut lock_data_sz: usize = 0;
if !is_raw {
shared_data_sz = (size_of::<SharedData>() + 3) & !(0x03 as usize);
lock_ind = locktype_info.0 as u8;
lock_data_sz = locktype_info.1;
}
let actual_size: usize = new_file.size + lock_data_sz + shared_data_sz;
let map_handle = unsafe {
let high_size: u32 = (actual_size as u64 & 0xFFFFFFFF00000000 as u64) as u32;
let low_size: u32 = (actual_size as u64 & 0xFFFFFFFF as u64) as u32;
CreateFileMappingA(
INVALID_HANDLE_VALUE,
null_mut(),
PAGE_READWRITE,
high_size,
low_size,
CString::new(real_path.clone())?.as_ptr())
};
if map_handle == NULL {
return Err(From::from(format!("CreateFileMappingA failed with {}", unsafe{GetLastError()})));
}
new_file.real_path = Some(real_path.clone());
let map_addr = unsafe {
MapViewOfFile(
map_handle,
FILE_MAP_READ| FILE_MAP_WRITE,
0,
0,
0
)
};
if map_addr == NULL {
unsafe { CloseHandle(map_handle); }
return Err(From::from(format!("MapViewOfFile failed with {}", unsafe{GetLastError()})));
}
if is_raw {
new_file.meta = Some(MemMetadata {
map_handle: map_handle,
shared_data: map_addr as *mut SharedData,
lock_data: null_mut(),
lock_data_is_handle: false,
data: map_addr as *mut c_void,
lock_impl: &LockNone{},
});
return Ok(new_file);
}
let mut meta: MemMetadata = MemMetadata {
map_handle: map_handle,
shared_data: map_addr as *mut SharedData,
data: (map_addr as usize + shared_data_sz + lock_data_sz) as *mut c_void,
lock_data: (map_addr as usize + shared_data_sz) as *mut _,
lock_data_is_handle: false,
lock_impl: &LockNone{},
};
let shared_data: &mut SharedData = unsafe {
&mut (*meta.shared_data)
};
shared_data.mapping_size = new_file.size;
shared_data.lock_ind = lock_ind;
match lock_type {
LockType::None => {},
LockType::Mutex => {
let mutex_path: String = String::from("test_mutex");
let lock_data_as_slice: &mut [u8] = unsafe {
slice::from_raw_parts_mut((meta.lock_data) as *mut u8, Mutex::size_of())
};
lock_data_as_slice[0..mutex_path.as_bytes().len()].copy_from_slice(mutex_path.as_bytes());
meta.lock_data = unsafe {CreateMutexA(
null_mut(), FALSE, CString::new(mutex_path)?.as_ptr()) as *mut _};
if meta.lock_data as *mut winapi::ctypes::c_void == NULL {
return Err(From::from(format!("CreateMutexA failed with {}", unsafe{GetLastError()})));
}
meta.lock_data_is_handle = true;
meta.lock_impl = &Mutex{};
},
LockType::RwLock => {
}
};
new_file.meta = Some(meta);
Ok(new_file)
}
fn supported_locktype_info(lock_type: &LockType) -> (usize, usize) {
match lock_type {
&LockType::None => (0, LockNone::size_of()),
&LockType::Mutex => (1, Mutex::size_of()),
_ => unimplemented!("Windows does not support this lock type..."),
}
}
fn supported_locktype_from_ind(index: usize) -> (LockType, usize) {
match index {
0 => (LockType::None, LockNone::size_of()),
1 => (LockType::Mutex, Mutex::size_of()),
_ => unimplemented!("Windows does not support this locktype index..."),
}
}
pub struct Mutex {}
impl Mutex {
pub fn acquire_lock(&self, handle: *mut winapi::ctypes::c_void) -> Result<()> {
let wait_res = unsafe {WaitForSingleObject(
handle,
INFINITE)};
if wait_res == WAIT_OBJECT_0 {
Ok(())
} else {
Err(From::from("Failed to acquire Mutex !"))
}
}
pub fn release_lock(&self, handle: *mut winapi::ctypes::c_void) {
unsafe {ReleaseMutex(handle)};
}
}
impl SharedMemLockImpl for Mutex {
fn size_of() -> usize {
255
}
fn rlock(&self, lock_data: *mut c_void) -> Result<()> {
self.acquire_lock(lock_data as *mut winapi::ctypes::c_void)
}
fn wlock(&self, lock_data: *mut c_void) -> Result<()> {
self.acquire_lock(lock_data as *mut winapi::ctypes::c_void)
}
fn runlock(&self, lock_data: *mut c_void) -> () {
self.release_lock(lock_data as *mut winapi::ctypes::c_void);
}
fn wunlock(&self, lock_data: *mut c_void) -> () {
self.release_lock(lock_data as *mut winapi::ctypes::c_void);
}
}