/hg/icedtea-web: Os trait implemented for windows

jvanek at icedtea.classpath.org jvanek at icedtea.classpath.org
Wed Feb 13 18:14:51 UTC 2019


changeset 0ec171908528 in /hg/icedtea-web
details: http://icedtea.classpath.org/hg/icedtea-web?cmd=changeset;node=0ec171908528
author: Jiri Vanek <jvanek at redhat.com>
date: Wed Feb 13 19:14:35 2019 +0100

	Os trait implemented for windows

	* rust-launcher/src/dirs_paths_helper.rs: added (get_os) os dependent factory method to provide os impl with debug off. (check_config_files_paths_global) split to os independent (check_config_files_paths) and rest linux only
	* rust-launcher/src/jars_helper.rs:  (get_bootclasspath) fixed issue with hardcoded cp delimiter in xbootclasspath
	* rust-launcher/src/main.rs:  added (get_os) os dependent factory method to provide os impl with debug parameter
	* rust-launcher/src/os_access.rs: implemented os trait for windows
	* rust-launcher/src/utils.rs: better recognition of rop_dir and parent dir in (try_jre_exists_on_path)


diffstat:

 ChangeLog                              |   10 +
 rust-launcher/src/dirs_paths_helper.rs |   28 +-
 rust-launcher/src/jars_helper.rs       |    3 +-
 rust-launcher/src/main.rs              |   14 +-
 rust-launcher/src/os_access.rs         |  421 +++++++++++++++++++++++++++++++++
 rust-launcher/src/utils.rs             |    4 +-
 6 files changed, 468 insertions(+), 12 deletions(-)

diffs (truncated from 584 to 500 lines):

diff -r cb75d5ae33e0 -r 0ec171908528 ChangeLog
--- a/ChangeLog	Wed Feb 13 18:05:44 2019 +0100
+++ b/ChangeLog	Wed Feb 13 19:14:35 2019 +0100
@@ -1,3 +1,13 @@
+2019-02-13  Alex Kashchenko <akashche at redhat.com>
+
+	Os trait implemented for windows
+	* rust-launcher/src/dirs_paths_helper.rs: added (get_os) os dependent factory method to provide os impl with debug off.
+	(check_config_files_paths_global) split to os independent (check_config_files_paths) and rest linux only
+	* rust-launcher/src/jars_helper.rs:  (get_bootclasspath) fixed issue with hardcoded cp delimiter in xbootclasspath
+	* rust-launcher/src/main.rs:  added (get_os) os dependent factory method to provide os impl with debug parameter
+	* rust-launcher/src/os_access.rs: implemented os trait for windows
+	* rust-launcher/src/utils.rs: better recognition of rop_dir and parent dir in (try_jre_exists_on_path)
+
 2019-02-13  Jiri Vanek <jvanek at redhat.com>
 
 	Propagating unimplemented DownloadService2. Added tests for it
diff -r cb75d5ae33e0 -r 0ec171908528 rust-launcher/src/dirs_paths_helper.rs
--- a/rust-launcher/src/dirs_paths_helper.rs	Wed Feb 13 18:05:44 2019 +0100
+++ b/rust-launcher/src/dirs_paths_helper.rs	Wed Feb 13 19:14:35 2019 +0100
@@ -84,18 +84,34 @@
     use os_access;
     use utils::tests_utils as tu;
 
+    #[cfg(not(windows))]
+    fn get_os() -> os_access::Linux {
+        os_access::Linux::new(false)
+    }
+
+    #[cfg(windows)]
+    fn get_os() -> os_access::Windows {
+        os_access::Windows::new(false)
+    }
+
+
+    #[test]
+    fn check_config_files_paths() {
+        let os = get_os();
+        let p3 = super::get_itw_config_file(&os);
+        assert_ne!(None, p3);
+        println!("{}", p3.clone().expect("unwrap failed").display());
+        assert_eq!(true, p3.clone().expect("unwrap failed").display().to_string().contains("icedtea-web"));
+        assert_eq!(true, p3.clone().expect("unwrap failed").display().to_string().ends_with("deployment.properties"));
+    }
+
     #[test]
     #[cfg(not(windows))]
-    fn check_config_files_paths() {
+    fn check_config_files_paths_global() {
         let os = os_access::Linux::new(false);
-        let p3 = super::get_itw_config_file(&os);
         let p6 = super::get_itw_global_config_file(&os);
-        assert_ne!(None, p3);
         assert_ne!(None, p6);
-        println!("{}", p3.clone().expect("unwrap failed").display());
         println!("{}", p6.clone().expect("unwrap failed").display());
-        assert_eq!(true, p3.clone().expect("unwrap failed").display().to_string().contains("icedtea-web"));
-        assert_eq!(true, p3.clone().expect("unwrap failed").display().to_string().ends_with("deployment.properties"));
         assert_eq!(true, p6.clone().expect("unwrap failed").display().to_string().ends_with("deployment.properties"));
     }
 
diff -r cb75d5ae33e0 -r 0ec171908528 rust-launcher/src/jars_helper.rs
--- a/rust-launcher/src/jars_helper.rs	Wed Feb 13 18:05:44 2019 +0100
+++ b/rust-launcher/src/jars_helper.rs	Wed Feb 13 19:14:35 2019 +0100
@@ -158,8 +158,7 @@
 }
 
 pub fn get_bootclasspath(jre_path: &std::path::PathBuf, os: &os_access::Os) -> String {
-    let mut result = String::from("-Xbootclasspath/a");
-    result.push(os.get_classpath_separator());
+    let mut result = String::from("-Xbootclasspath/a:");
     result.push_str(&compose_class_path(get_bootcp_members(jre_path, os), os));
     result
 }
diff -r cb75d5ae33e0 -r 0ec171908528 rust-launcher/src/main.rs
--- a/rust-launcher/src/main.rs	Wed Feb 13 18:05:44 2019 +0100
+++ b/rust-launcher/src/main.rs	Wed Feb 13 19:14:35 2019 +0100
@@ -12,13 +12,23 @@
 use os_access::Os;
 use std::env;
 
+#[cfg(not(windows))]
+fn get_os(debug: bool) -> os_access::Linux {
+    os_access::Linux::new(debug)
+}
+
+#[cfg(windows)]
+fn get_os(debug: bool) -> os_access::Windows {
+    os_access::Windows::new(debug)
+}
+
 fn is_debug_on() -> bool {
     match is_debug_on_testable(env::args().collect::<Vec<_>>()) {
         Some(val) => {
             return val;
         }
         _none => {
-            let os = os_access::Linux::new(false);
+            let os = get_os(false);
             return property_from_files_resolver::try_main_verbose_from_properties(&os);
         }
     }
@@ -63,7 +73,7 @@
 }
 
 fn main() {
-    let os = os_access::Linux::new(is_debug_on());
+    let os = get_os(is_debug_on());
     os.log(&dirs_paths_helper::path_to_string(&dirs_paths_helper::current_program()));
     let mut info1 = String::new();
     write!(&mut info1, "itw-rust-debug: trying jdk over properties ({})", property_from_file::JRE_PROPERTY_NAME).expect("unwrap failed");
diff -r cb75d5ae33e0 -r 0ec171908528 rust-launcher/src/os_access.rs
--- a/rust-launcher/src/os_access.rs	Wed Feb 13 18:05:44 2019 +0100
+++ b/rust-launcher/src/os_access.rs	Wed Feb 13 19:14:35 2019 +0100
@@ -3,6 +3,8 @@
 use std::env;
 use std::fmt::Write;
 
+
+
 pub trait Os {
     // logging "api" can change
     fn log(&self, s: &str);
@@ -25,16 +27,19 @@
     fn get_exec_suffixes(&self) -> &'static [&'static str];
 }
 
+#[cfg(not(windows))]
 pub struct Linux {
     verbose: bool,
 }
 
+#[cfg(not(windows))]
 impl Linux {
     pub fn new(debug: bool) -> Linux {
         Linux { verbose: debug }
     }
 }
 
+#[cfg(not(windows))]
 impl Os for Linux {
     fn log(&self, s: &str) {
         if self.verbose {
@@ -127,3 +132,419 @@
         &[""]
     }
 }
+
+
+#[cfg(windows)]
+pub struct Windows {
+    verbose: bool,
+}
+
+#[cfg(windows)]
+impl Windows {
+    pub fn new(debug: bool) -> Windows {
+        Windows { verbose: debug }
+    }
+
+}
+
+#[cfg(windows)]
+impl Os for Windows {
+    fn log(&self, s: &str) {
+        if self.verbose {
+            println!("{}", s);
+        }
+    }
+
+    fn info(&self, s: &str) {
+        println!("{}", s);
+    }
+
+    fn get_registry_jdk(&self) -> Option<std::path::PathBuf> {
+        std::panic::catch_unwind(|| {
+            let path = win::jdk_registry_path();
+            Some(std::path::PathBuf::from(path))
+        }).unwrap_or_else(|_e| {
+            // show_error_message(errloc_msg(&e));
+            None
+        })
+    }
+
+    fn get_system_config_javadir(&self) -> Option<std::path::PathBuf> {
+        None
+    }
+
+    fn get_user_config_dir(&self) -> Option<std::path::PathBuf> {
+        match self.get_home() {
+            Some(mut p) => {
+                p.push(".config");
+                p.push(dirs_paths_helper::ICEDTEA_WEB);
+                Some(p)
+            }
+            None => None
+        }
+    }
+
+    fn get_legacy_system_config_javadir(&self) -> Option<std::path::PathBuf> {
+        None
+    }
+
+    fn get_legacy_user_config_dir(&self) -> Option<std::path::PathBuf> {
+        None
+    }
+
+    fn spawn_java_process(&self, jre_dir: &std::path::PathBuf, args: &Vec<String>) -> std::process::Child {
+        let mut bin_java = jre_dir.clone();
+        bin_java.push("bin");
+        bin_java.push("java");
+        let mut cmd = std::process::Command::new(&bin_java);
+        for ar in args.into_iter() {
+            cmd.arg(ar);
+        }
+        cmd.stdin(std::process::Stdio::inherit());
+        cmd.stdout(std::process::Stdio::inherit());
+        cmd.stderr(std::process::Stdio::inherit());
+        let mut info = String::new();
+        write!(&mut info, "itw-rust-debug: command {}", format!("{:?}", cmd)).expect("unwrap failed");
+        self.log(&info);
+        let res = cmd.spawn();
+        match res {
+            Ok(child) => child,
+            Err(_) => panic!("Error spawning JVM process, \
+                 java executable: [{}], arguments: [{:?}]", bin_java.into_os_string().to_str().expect("path should unwrap"), args)
+        }
+    }
+
+    fn get_home(&self) -> Option<std::path::PathBuf> {
+        match env::var("USERPROFILE") {
+            Ok(war) => {
+                let home_var_path = std::path::PathBuf::from(war);
+                if dirs_paths_helper::is_dir(&home_var_path) {
+                    return Some(home_var_path);
+                }
+            }
+            Err(_) => {}
+        }
+        None
+    }
+
+    fn get_classpath_separator(&self) -> char {
+         ';'
+    }
+
+    //on linux, java is known to be compiled witout any suffix, on windows, it should be .exe
+    fn get_exec_suffixes(&self) -> &'static [&'static str] {
+        &[".exe"]
+    }
+}
+
+
+#[cfg(windows)]
+#[allow(non_snake_case)]
+#[allow(non_camel_case_types)]
+mod win {
+    // https://crates.io/crates/scopeguard
+    macro_rules! defer {
+        ($e:expr) => {
+            let _deferred = ScopeGuard::new((), |_| $e);
+        }
+    }
+
+    pub struct ScopeGuard<T, F> where F: FnMut(&mut T) {
+        __dropfn: F,
+        __value: T
+    }
+
+    impl<T, F> ScopeGuard<T, F> where F: FnMut(&mut T) {
+        pub fn new(v: T, dropfn: F) -> ScopeGuard<T, F> {
+            ScopeGuard {
+                __value: v,
+                __dropfn: dropfn
+            }
+        }
+    }
+
+    impl<T, F> Drop for ScopeGuard<T, F> where F: FnMut(&mut T) {
+        fn drop(&mut self) {
+            (self.__dropfn)(&mut self.__value)
+        }
+    }
+
+    // https://crates.io/crates/errloc_macros
+    macro_rules! errloc {
+        () => {
+            concat!(file!(), ':', line!())
+        }
+    }
+
+    fn errloc_msg<'a>(e: &'a Box<std::any::Any + Send + 'static>) -> &'a str {
+        match e.downcast_ref::<&str>() {
+            Some(st) => st,
+            None => {
+                match e.downcast_ref::<String>() {
+                    Some(stw) => stw.as_str(),
+                    None => "()",
+                }
+            },
+        }
+    }
+
+    // implementation
+
+    use std;
+    use std::os::raw::*;
+    use std::ptr::{null, null_mut};
+
+    // constants
+    const CP_UTF8: c_ulong = 65001;
+    const FORMAT_MESSAGE_ALLOCATE_BUFFER: c_ulong = 0x00000100;
+    const FORMAT_MESSAGE_FROM_SYSTEM: c_ulong = 0x00001000;
+    const FORMAT_MESSAGE_IGNORE_INSERTS: c_ulong = 0x00000200;
+    const LANG_NEUTRAL: c_ushort = 0x00;
+    const SUBLANG_DEFAULT: c_ushort = 0x01;
+    const ERROR_SUCCESS: c_ulong = 0;
+    const READ_CONTROL: c_ulong = 0x00020000;
+    const STANDARD_RIGHTS_READ: c_ulong = READ_CONTROL;
+    const KEY_QUERY_VALUE: c_ulong = 0x0001;
+    const KEY_ENUMERATE_SUB_KEYS: c_ulong = 0x0008;
+    const KEY_NOTIFY: c_ulong = 0x0010;
+    const SYNCHRONIZE: c_ulong = 0x00100000;
+    const REG_SZ: c_ulong = 1;
+    const KEY_READ: c_ulong = (
+        STANDARD_RIGHTS_READ |
+            KEY_QUERY_VALUE |
+            KEY_ENUMERATE_SUB_KEYS |
+            KEY_NOTIFY
+    ) & (!SYNCHRONIZE);
+    const HKEY_LOCAL_MACHINE: *mut c_void = 0x80000002 as *mut c_void;
+
+    // function declarations
+
+    extern "system" {
+        fn MultiByteToWideChar(
+            CodePage: c_uint,
+            dwFlags: c_ulong,
+            lpMultiByteStr: *const c_char,
+            cbMultiByte: c_int,
+            lpWideCharStr: *mut c_ushort,
+            cchWideChar: c_int
+        ) -> c_int;
+
+        fn WideCharToMultiByte(
+            CodePage: c_uint,
+            dwFlags: c_ulong,
+            lpWideCharStr: *const c_ushort,
+            cchWideChar: c_int,
+            lpMultiByteStr: *mut c_char,
+            cbMultiByte: c_int,
+            lpDefaultChar: *const c_char,
+            lpUsedDefaultChar: *mut c_int
+        ) -> c_int;
+
+        fn GetLastError() -> c_ulong;
+
+        fn FormatMessageW(
+            dwFlags: c_ulong,
+            lpSource: *const c_void,
+            dwMessageId: c_ulong,
+            dwLanguageId: c_ulong,
+            lpBuffer: *mut c_ushort,
+            nSize: c_ulong,
+            Arguments: *mut *mut c_char
+        ) -> c_ulong;
+
+        fn LocalFree(
+            hMem: *mut c_void
+        ) -> *mut c_void;
+
+        fn RegOpenKeyExW(
+            hKey: *mut c_void,
+            lpSubKey: *const c_ushort,
+            ulOptions: c_ulong,
+            samDesired: c_ulong,
+            phkResult: *mut *mut c_void
+        ) -> c_long;
+
+        fn RegCloseKey(
+            hKey: *mut c_void
+        ) -> c_long;
+
+        fn RegQueryValueExW(
+            hKey: *mut c_void,
+            lpValueName: *const c_ushort,
+            lpReserved: *mut c_ulong,
+            lpType: *mut c_ulong,
+            lpData: *mut c_uchar,
+            lpcbData: *mut c_ulong
+        ) -> c_long;
+    }
+
+    // windows-specific utilities
+
+    fn MAKELANGID(p: c_ushort, s: c_ushort) -> c_ushort {
+        (s << 10 | p)
+    }
+
+    fn widen(st: &str) -> Vec<u16> {
+        unsafe {
+            let size_needed = MultiByteToWideChar(
+                CP_UTF8,
+                0,
+                st.as_ptr() as *mut i8,
+                st.len() as c_int,
+                null_mut::<u16>(),
+                0);
+            if 0 == size_needed {
+                panic!(format!("Error on string widen calculation, \
+                string: [{}], error: [{}]", st, errcode_to_string(GetLastError())));
+            }
+            let mut res: Vec<u16> = Vec::new();
+            res.resize((size_needed + 1) as usize, 0);
+            let chars_copied = MultiByteToWideChar(
+                CP_UTF8,
+                0,
+                st.as_ptr() as *mut i8,
+                st.len() as c_int,
+                res.as_mut_ptr(),
+                size_needed);
+            if chars_copied != size_needed {
+                panic!(format!("Error on string widen execution, \
+                string: [{}], error: [{}]", st, errcode_to_string(GetLastError())));
+            }
+            res.resize(size_needed as usize, 0);
+            res
+        }
+    }
+
+    fn narrow(wst: &[u16]) -> String {
+        unsafe {
+            let size_needed = WideCharToMultiByte(
+                CP_UTF8,
+                0,
+                wst.as_ptr(),
+                wst.len() as c_int,
+                null_mut::<i8>(),
+                0,
+                null::<c_char>(),
+                null_mut::<c_int>());
+            if 0 == size_needed {
+                panic!(format!("Error on string narrow calculation, \
+                string length: [{}], error code: [{}]", wst.len(), GetLastError()));
+            }
+            let mut vec: Vec<u8> = Vec::new();
+            vec.resize(size_needed as usize, 0);
+            let bytes_copied = WideCharToMultiByte(
+                CP_UTF8,
+                0,
+                wst.as_ptr(),
+                wst.len() as c_int,
+                vec.as_mut_ptr() as *mut i8,
+                size_needed,
+                null::<c_char>(),
+                null_mut::<c_int>());
+            if bytes_copied != size_needed {
+                panic!(format!("Error on string narrow execution, \
+                string length: [{}], error code: [{}]", vec.len(), GetLastError()));
+            }
+            String::from_utf8(vec).expect(errloc!())
+        }
+    }
+
+    fn errcode_to_string(code: c_ulong) -> String {
+        if 0 == code {
+            return String::new();
+        }
+        unsafe {
+            let mut buf: *mut u16 = null_mut::<u16>();
+            let size = FormatMessageW(
+                FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                    FORMAT_MESSAGE_FROM_SYSTEM |
+                    FORMAT_MESSAGE_IGNORE_INSERTS,
+                null::<c_void>(),
+                code,
+                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) as c_ulong,
+                std::mem::transmute::<*mut *mut u16, *mut u16>(&mut buf),
+                0,
+                null_mut::<*mut c_char>());
+            if 0 == size {
+                return format!("Cannot format code: [{}] \
+                 into message, error code: [{}]", code, GetLastError());
+            }
+            defer!({
+                LocalFree(buf as *mut c_void);
+            });
+            if size <= 2 {
+                return format!("code: [{}], message: []", code);
+            }
+            std::panic::catch_unwind(|| {
+                let slice = std::slice::from_raw_parts(buf, (size - 2) as usize);
+                let msg = narrow(slice);
+                format!("code: [{}], message: [{}]", code, msg)
+            }).unwrap_or_else(|e| {
+                format!("Cannot format code: [{}] \
+                 into message, narrow error: [{}]", code, errloc_msg(&e))
+            })
+        }
+    }


More information about the distro-pkg-dev mailing list