blob: d107694b63c1665592df6a9cc9f7a92b764516d3 [file] [log] [blame]
use std::ffi::CString;
use std::ffi::OsStr;
use std::io;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::ptr;
use libc::{ssize_t, ERANGE};
// Need to use this one as libc only defines this on supported platforms. Given
// that we want to at least compile on unsupported platforms, we define this in
// our platform-specific modules.
use sys::ENOATTR;
#[allow(dead_code)]
pub fn name_to_c(name: &OsStr) -> io::Result<CString> {
match CString::new(name.as_bytes()) {
Ok(name) => Ok(name),
Err(_) => Err(io::Error::new(
io::ErrorKind::InvalidInput,
"name must not contain null bytes",
)),
}
}
pub fn path_to_c(path: &Path) -> io::Result<CString> {
match CString::new(path.as_os_str().as_bytes()) {
Ok(name) => Ok(name),
Err(_) => Err(io::Error::new(io::ErrorKind::NotFound, "file not found")),
}
}
pub fn extract_noattr(result: io::Result<Vec<u8>>) -> io::Result<Option<Vec<u8>>> {
result.map(Some).or_else(|e| match e.raw_os_error() {
Some(ENOATTR) => Ok(None),
_ => Err(e),
})
}
pub unsafe fn allocate_loop<F: FnMut(*mut u8, usize) -> ssize_t>(mut f: F) -> io::Result<Vec<u8>> {
let mut vec: Vec<u8> = Vec::new();
loop {
let ret = (f)(ptr::null_mut(), 0);
if ret < 0 {
return Err(io::Error::last_os_error());
} else if ret == 0 {
break;
}
vec.reserve_exact(ret as usize);
let ret = (f)(vec.as_mut_ptr(), vec.capacity());
if ret >= 0 {
vec.set_len(ret as usize);
break;
} else {
let error = io::Error::last_os_error();
if error.raw_os_error() == Some(ERANGE) {
continue;
}
return Err(error);
}
}
vec.shrink_to_fit();
Ok(vec)
}