From 0fc0fb3ad375da219b5822339a01fc78e524720b Mon Sep 17 00:00:00 2001 From: Steven Murawski Date: Tue, 20 Sep 2016 11:00:44 -0500 Subject: [PATCH] move platform dependent calls to core wrap std::os::unix::ffi::OsStrExt and add a windows equal wrap std::os::unix::symlink and add a windows mock. There are windows symlink calls but they differ for file and directory. Signed-off-by: Steven Murawski --- components/core/src/os/ffi/mod.rs | 22 +++ components/core/src/os/ffi/windows.rs | 150 +++++++++++++++++++ components/core/src/os/filesystem/linux.rs | 2 + components/core/src/os/filesystem/mod.rs | 6 +- components/core/src/os/filesystem/windows.rs | 9 +- components/core/src/os/mod.rs | 1 + components/hab/src/command/pkg.rs | 7 +- components/hab/src/exec.rs | 2 +- 8 files changed, 190 insertions(+), 9 deletions(-) create mode 100644 components/core/src/os/ffi/mod.rs create mode 100644 components/core/src/os/ffi/windows.rs diff --git a/components/core/src/os/ffi/mod.rs b/components/core/src/os/ffi/mod.rs new file mode 100644 index 0000000000..f902fb6448 --- /dev/null +++ b/components/core/src/os/ffi/mod.rs @@ -0,0 +1,22 @@ +// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[cfg(windows)] +mod windows; + +#[cfg(windows)] +pub use self::windows::OsStrExt3 as OsStrExt; + +#[cfg(not(windows))] +pub use std::os::unix::ffi::OsStrExt; diff --git a/components/core/src/os/ffi/windows.rs b/components/core/src/os/ffi/windows.rs new file mode 100644 index 0000000000..8f4b190bc9 --- /dev/null +++ b/components/core/src/os/ffi/windows.rs @@ -0,0 +1,150 @@ +// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::ffi::OsStr; +const INVALID_UTF8: &'static str = "unexpected invalid UTF-8 code point"; + +pub trait OsStrExt3 { + fn from_bytes(b: &[u8]) -> &Self; + fn as_bytes(&self) -> &[u8]; +} + +pub trait OsStrExt2 { + fn starts_with(&self, s: &[u8]) -> bool; + fn split_at_byte(&self, b: u8) -> (&OsStr, &OsStr); + fn split_at(&self, i: usize) -> (&OsStr, &OsStr); + fn trim_left_matches(&self, b: u8) -> &OsStr; + fn len_(&self) -> usize; + fn contains_byte(&self, b: u8) -> bool; + fn is_empty_(&self) -> bool; + fn split(&self, b: u8) -> OsSplit; +} + +impl OsStrExt3 for OsStr { + fn from_bytes(b: &[u8]) -> &Self { + use ::std::mem; + unsafe { mem::transmute(b) } + } + fn as_bytes(&self) -> &[u8] { + self.to_str().map(|s| s.as_bytes()).expect(INVALID_UTF8) + } +} + +impl OsStrExt2 for OsStr { + fn starts_with(&self, s: &[u8]) -> bool { + self.as_bytes().starts_with(s) + } + + fn is_empty_(&self) -> bool { + self.as_bytes().is_empty() + } + + fn contains_byte(&self, byte: u8) -> bool { + for b in self.as_bytes() { + if b == &byte { + return true; + } + } + false + } + + fn split_at_byte(&self, byte: u8) -> (&OsStr, &OsStr) { + for (i, b) in self.as_bytes().iter().enumerate() { + if b == &byte { + return (&OsStr::from_bytes(&self.as_bytes()[..i]), + &OsStr::from_bytes(&self.as_bytes()[i + 1..])); + } + } + (&*self, &OsStr::from_bytes(&self.as_bytes()[self.len_()..self.len_()])) + } + + fn trim_left_matches(&self, byte: u8) -> &OsStr { + for (i, b) in self.as_bytes().iter().enumerate() { + if b != &byte { + return &OsStr::from_bytes(&self.as_bytes()[i..]); + } + } + &*self + } + + fn split_at(&self, i: usize) -> (&OsStr, &OsStr) { + (&OsStr::from_bytes(&self.as_bytes()[..i]), &OsStr::from_bytes(&self.as_bytes()[i..])) + } + + fn len_(&self) -> usize { + self.as_bytes().len() + } + + fn split(&self, b: u8) -> OsSplit { + OsSplit { + sep: b, + val: self.as_bytes(), + pos: 0, + } + } +} + +#[doc(hidden)] +#[derive(Clone, Debug)] +pub struct OsSplit<'a> { + sep: u8, + val: &'a [u8], + pos: usize, +} + +impl<'a> Iterator for OsSplit<'a> { + type Item = &'a OsStr; + + fn next(&mut self) -> Option<&'a OsStr> { + if self.pos == self.val.len() { + return None; + } + let start = self.pos; + for b in &self.val[start..] { + self.pos += 1; + if *b == self.sep { + return Some(&OsStr::from_bytes(&self.val[start..self.pos - 1])); + } + } + Some(&OsStr::from_bytes(&self.val[start..])) + } + fn size_hint(&self) -> (usize, Option) { + let mut count = 0; + for b in &self.val[self.pos..] { + if *b == self.sep { + count += 1; + } + } + if count > 0 { + return (count, Some(count)); + } + (0, None) + } +} + +impl<'a> DoubleEndedIterator for OsSplit<'a> { + fn next_back(&mut self) -> Option<&'a OsStr> { + if self.pos == 0 { + return None; + } + let start = self.pos; + for b in self.val[..self.pos].iter().rev() { + self.pos -= 1; + if *b == self.sep { + return Some(&OsStr::from_bytes(&self.val[self.pos + 1..start])); + } + } + Some(&OsStr::from_bytes(&self.val[..start])) + } +} diff --git a/components/core/src/os/filesystem/linux.rs b/components/core/src/os/filesystem/linux.rs index d5b333784f..3072fd43eb 100644 --- a/components/core/src/os/filesystem/linux.rs +++ b/components/core/src/os/filesystem/linux.rs @@ -14,6 +14,8 @@ use libc::{self, c_int, c_char, mode_t}; +pub use std::os::unix::fs::symlink; + pub fn chown(r_path: *const c_char, uid: u32, gid: u32) -> c_int { unsafe { libc::chown(r_path, uid, gid) } } diff --git a/components/core/src/os/filesystem/mod.rs b/components/core/src/os/filesystem/mod.rs index e4dadb39fb..f27363259c 100644 --- a/components/core/src/os/filesystem/mod.rs +++ b/components/core/src/os/filesystem/mod.rs @@ -16,10 +16,10 @@ mod windows; #[cfg(windows)] -pub use self::windows::{chown, chmod}; +pub use self::windows::{chown, chmod, symlink}; #[cfg(not(windows))] -pub mod linux; +mod linux; #[cfg(not(windows))] -pub use self::linux::{chown, chmod}; +pub use self::linux::{chown, chmod, symlink}; diff --git a/components/core/src/os/filesystem/windows.rs b/components/core/src/os/filesystem/windows.rs index 2b1ac059b7..84e04cff07 100644 --- a/components/core/src/os/filesystem/windows.rs +++ b/components/core/src/os/filesystem/windows.rs @@ -15,6 +15,7 @@ use libc::{c_int, c_char}; use std::ffi::CStr; use std::path::Path; +use std::io; pub fn chown(r_path: *const c_char, uid: u32, gid: u32) -> c_int { unimplemented!(); @@ -25,7 +26,11 @@ pub fn chmod(r_path: *const c_char, mode: u32) -> c_int { let path = CStr::from_ptr(r_path).to_str().unwrap(); match Path::new(path).exists() { false => 1, - true => 0 - } + true => 0, + } } } + +pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { + unimplemented!(); +} diff --git a/components/core/src/os/mod.rs b/components/core/src/os/mod.rs index 732973c27a..62d9ca4c51 100644 --- a/components/core/src/os/mod.rs +++ b/components/core/src/os/mod.rs @@ -15,3 +15,4 @@ pub mod users; pub mod filesystem; pub mod system; +pub mod ffi; diff --git a/components/hab/src/command/pkg.rs b/components/hab/src/command/pkg.rs index f844efbf0d..d32782dbe4 100644 --- a/components/hab/src/command/pkg.rs +++ b/components/hab/src/command/pkg.rs @@ -17,10 +17,11 @@ pub mod binlink { use std::fs; use std::path::Path; - use std::os::unix; + use common::ui::{Status, UI}; use hcore::package::{PackageIdent, PackageInstall}; + use hcore::os::filesystem; use error::{Error, Result}; use exec::find_command_in_pkg; @@ -54,10 +55,10 @@ pub mod binlink { Ok(path) => { if path != src { try!(fs::remove_file(&dst)); - try!(unix::fs::symlink(&src, &dst)); + try!(filesystem::symlink(&src, &dst)); } } - Err(_) => try!(unix::fs::symlink(&src, &dst)), + Err(_) => try!(filesystem::symlink(&src, &dst)), } try!(ui.end(format!("Binary {} from {} symlinked to {}", &binary, diff --git a/components/hab/src/exec.rs b/components/hab/src/exec.rs index 18d62607fd..fb724c5cde 100644 --- a/components/hab/src/exec.rs +++ b/components/hab/src/exec.rs @@ -16,7 +16,7 @@ extern crate libc; use std; use std::ffi::{CString, OsString}; -use std::os::unix::ffi::OsStrExt; +use hcore::os::ffi::OsStrExt; use std::path::{Path, PathBuf}; use std::ptr;