1 | use std::ffi::CString; |
2 | use std::ffi::OsStr; |
3 | use std::io; |
4 | use std::os::unix::ffi::OsStrExt; |
5 | use std::path::Path; |
6 | use std::ptr; |
7 | |
8 | use libc::{ssize_t, ERANGE}; |
9 | |
10 | // Need to use this one as libc only defines this on supported platforms. Given |
11 | // that we want to at least compile on unsupported platforms, we define this in |
12 | // our platform-specific modules. |
13 | use sys::ENOATTR; |
14 | |
15 | #[allow (dead_code)] |
16 | pub fn name_to_c(name: &OsStr) -> io::Result<CString> { |
17 | match CString::new(name.as_bytes()) { |
18 | Ok(name: CString) => Ok(name), |
19 | Err(_) => Err(io::Error::new( |
20 | kind:io::ErrorKind::InvalidInput, |
21 | error:"name must not contain null bytes" , |
22 | )), |
23 | } |
24 | } |
25 | |
26 | pub fn path_to_c(path: &Path) -> io::Result<CString> { |
27 | match CString::new(path.as_os_str().as_bytes()) { |
28 | Ok(name: CString) => Ok(name), |
29 | Err(_) => Err(io::Error::new(kind:io::ErrorKind::NotFound, error:"file not found" )), |
30 | } |
31 | } |
32 | |
33 | pub fn extract_noattr(result: io::Result<Vec<u8>>) -> io::Result<Option<Vec<u8>>> { |
34 | result.map(Some).or_else(|e: Error| match e.raw_os_error() { |
35 | Some(ENOATTR) => Ok(None), |
36 | _ => Err(e), |
37 | }) |
38 | } |
39 | |
40 | pub unsafe fn allocate_loop<F: FnMut(*mut u8, usize) -> ssize_t>(mut f: F) -> io::Result<Vec<u8>> { |
41 | let mut vec: Vec<u8> = Vec::new(); |
42 | loop { |
43 | let ret = (f)(ptr::null_mut(), 0); |
44 | if ret < 0 { |
45 | return Err(io::Error::last_os_error()); |
46 | } else if ret == 0 { |
47 | break; |
48 | } |
49 | vec.reserve_exact(ret as usize); |
50 | |
51 | let ret = (f)(vec.as_mut_ptr(), vec.capacity()); |
52 | if ret >= 0 { |
53 | vec.set_len(ret as usize); |
54 | break; |
55 | } else { |
56 | let error = io::Error::last_os_error(); |
57 | if error.raw_os_error() == Some(ERANGE) { |
58 | continue; |
59 | } |
60 | return Err(error); |
61 | } |
62 | } |
63 | vec.shrink_to_fit(); |
64 | Ok(vec) |
65 | } |
66 | |