[Libguestfs] [PATCH 1/8] mllib: Move Windows Registry functions from v2v to common code.

Richard W.M. Jones rjones at redhat.com
Sat Feb 18 08:05:28 UTC 2017


Move the functions decode_utf16le, encode_utf16le, get_node,
with_hive_readonly and with_hive_write to common code in a new module
called Registry.

This also defines types for nodes and values, instead of using int64
directly.

Just code motion.
---
 mllib/Makefile.am      |  2 ++
 mllib/regedit.ml       | 32 ++------------------
 mllib/regedit.mli      |  8 +----
 mllib/registry.ml      | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++
 mllib/registry.mli     | 45 +++++++++++++++++++++++++++
 v2v/convert_windows.ml | 44 +++++++++++++--------------
 v2v/windows.ml         | 31 -------------------
 v2v/windows.mli        | 17 -----------
 v2v/windows_virtio.mli |  2 +-
 9 files changed, 156 insertions(+), 107 deletions(-)
 create mode 100644 mllib/registry.ml
 create mode 100644 mllib/registry.mli

diff --git a/mllib/Makefile.am b/mllib/Makefile.am
index aa5472a..ff687b6 100644
--- a/mllib/Makefile.am
+++ b/mllib/Makefile.am
@@ -43,6 +43,7 @@ SOURCES_MLI = \
 	planner.mli \
 	progress.mli \
 	regedit.mli \
+	registry.mli \
 	StatVFS.mli \
 	stringMap.mli \
 	URI.mli \
@@ -64,6 +65,7 @@ SOURCES_ML = \
 	visit.ml \
 	fnmatch.ml \
 	planner.ml \
+	registry.ml \
 	regedit.ml \
 	StatVFS.ml \
 	JSON.ml \
diff --git a/mllib/regedit.ml b/mllib/regedit.ml
index 1ec7d4b..a97699c 100644
--- a/mllib/regedit.ml
+++ b/mllib/regedit.ml
@@ -32,32 +32,6 @@ and regtype =
 | REG_DWORD of int32
 | REG_MULTI_SZ of string list
 
-(* Take a 7 bit ASCII string and encode it as UTF16LE. *)
-let encode_utf16le str =
-  let len = String.length str in
-  let copy = Bytes.make (len*2) '\000' in
-  for i = 0 to len-1 do
-    Bytes.unsafe_set copy (i*2) (String.unsafe_get str i)
-  done;
-  Bytes.to_string copy
-
-(* Take a UTF16LE string and decode it to UTF-8.  Actually this
- * fails if the string is not 7 bit ASCII.  XXX Use iconv here.
- *)
-let decode_utf16le str =
-  let len = String.length str in
-  if len mod 2 <> 0 then
-    error (f_"decode_utf16le: Windows string does not appear to be in UTF16-LE encoding.  This could be a bug in %s.") prog;
-  let copy = Bytes.create (len/2) in
-  for i = 0 to (len/2)-1 do
-    let cl = String.unsafe_get str (i*2) in
-    let ch = String.unsafe_get str ((i*2)+1) in
-    if ch != '\000' || Char.code cl >= 127 then
-      error (f_"decode_utf16le: Windows UTF16-LE string contains non-7-bit characters.  This is a bug in %s, please report it.") prog;
-    Bytes.unsafe_set copy i cl
-  done;
-  Bytes.to_string copy
-
 let rec import_key (g : Guestfs.guestfs) root (path, values) =
   (* Create the path starting at the root node. *)
   let node =
@@ -91,9 +65,9 @@ and import_value g node = function
    * bytes at the end of string fields.
    *)
   | key, REG_SZ s ->
-    g#hivex_node_set_value node key 1L (encode_utf16le s ^ "\000\000")
+    g#hivex_node_set_value node key 1L (Registry.encode_utf16le s ^ "\000\000")
   | key, REG_EXPAND_SZ s ->
-    g#hivex_node_set_value node key 2L (encode_utf16le s ^ "\000\000")
+    g#hivex_node_set_value node key 2L (Registry.encode_utf16le s ^ "\000\000")
   | key, REG_BINARY bin ->
     g#hivex_node_set_value node key 3L bin
   | key, REG_DWORD dw ->
@@ -102,7 +76,7 @@ and import_value g node = function
     (* http://blogs.msdn.com/oldnewthing/archive/2009/10/08/9904646.aspx *)
     List.iter (fun s -> assert (s <> "")) ss;
     let ss = ss @ [""] in
-    let ss = List.map (fun s -> encode_utf16le s ^ "\000\000") ss in
+    let ss = List.map (fun s -> Registry.encode_utf16le s ^ "\000\000") ss in
     let ss = String.concat "" ss in
     g#hivex_node_set_value node key 7L ss
 
diff --git a/mllib/regedit.mli b/mllib/regedit.mli
index a65f5d3..6a5e383 100644
--- a/mllib/regedit.mli
+++ b/mllib/regedit.mli
@@ -55,11 +55,5 @@ and regtype =
     UTF-16LE, and integers are automatically packed and
     byte-swapped. *)
 
-val reg_import : Guestfs.guestfs -> int64 -> regedits -> unit
+val reg_import : Guestfs.guestfs -> Registry.node -> regedits -> unit
 (** Import the edits in [regedits] into the currently opened hive. *)
-
-val encode_utf16le : string -> string
-(** Helper: Take a 7 bit ASCII string and encode it as UTF-16LE. *)
-
-val decode_utf16le : string -> string
-(** Helper: Take a UTF-16LE string and decode it to UTF-8. *)
diff --git a/mllib/registry.ml b/mllib/registry.ml
new file mode 100644
index 0000000..a5f195f
--- /dev/null
+++ b/mllib/registry.ml
@@ -0,0 +1,82 @@
+(* virt-v2v
+ * Copyright (C) 2009-2017 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Printf
+
+open Common_gettext.Gettext
+open Common_utils
+
+type node = int64
+type value = int64
+
+let with_hive_readonly (g : Guestfs.guestfs) hive_filename f =
+  let verbose = verbose () in
+  g#hivex_open ~write:false ~unsafe:true ~verbose (* ~debug:verbose *)
+               hive_filename;
+  protect ~f:(
+    fun () ->
+      let root = g#hivex_root () in
+      f root
+  ) ~finally:g#hivex_close
+
+let with_hive_write (g : Guestfs.guestfs) hive_filename f =
+  let verbose = verbose () in
+  g#hivex_open ~write:true ~verbose (* ~debug:verbose *) hive_filename;
+  protect ~f:(
+    fun () ->
+      let root = g#hivex_root () in
+      let ret = f root in
+      g#hivex_commit None;
+      ret
+  ) ~finally:g#hivex_close
+
+(* Find the given node in the current hive, relative to the starting
+ * point.  Returns [None] if the node is not found.
+ *)
+let rec get_node (g : Guestfs.guestfs) node = function
+  | [] -> Some node
+  | x :: xs ->
+     let node = g#hivex_node_get_child node x in
+     if node = 0L then None
+     else get_node g node xs
+
+(* Take a 7 bit ASCII string and encode it as UTF16LE. *)
+let encode_utf16le str =
+  let len = String.length str in
+  let copy = Bytes.make (len*2) '\000' in
+  for i = 0 to len-1 do
+    Bytes.unsafe_set copy (i*2) (String.unsafe_get str i)
+  done;
+  Bytes.to_string copy
+
+(* Take a UTF16LE string and decode it to UTF-8.  Actually this
+ * fails if the string is not 7 bit ASCII.  XXX Use iconv here.
+ *)
+let decode_utf16le str =
+  let len = String.length str in
+  if len mod 2 <> 0 then
+    error (f_"decode_utf16le: Windows string does not appear to be in UTF16-LE encoding.  This could be a bug in %s.") prog;
+  let copy = Bytes.create (len/2) in
+  for i = 0 to (len/2)-1 do
+    let cl = String.unsafe_get str (i*2) in
+    let ch = String.unsafe_get str ((i*2)+1) in
+    if ch != '\000' || Char.code cl >= 127 then
+      error (f_"decode_utf16le: Windows UTF16-LE string contains non-7-bit characters.  This is a bug in %s, please report it.") prog;
+    Bytes.unsafe_set copy i cl
+  done;
+  Bytes.to_string copy
diff --git a/mllib/registry.mli b/mllib/registry.mli
new file mode 100644
index 0000000..1c9790d
--- /dev/null
+++ b/mllib/registry.mli
@@ -0,0 +1,45 @@
+(* mllib
+ * Copyright (C) 2009-2017 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+(** Common Windows Registry types and functions. *)
+
+type node = int64
+type value = int64
+
+val with_hive_readonly : Guestfs.guestfs -> string -> (node -> 'a) -> 'a
+val with_hive_write : Guestfs.guestfs -> string -> (node -> 'a) -> 'a
+(** [with_hive_(readonly|write) g hive_filename f]
+    are wrappers that handle opening and closing the hive
+    named [hive_filename] around a function [f].
+
+    [with_hive_readonly] opens the hive for read-only (attempts
+    to write will throw an error).  [with_hive_write] opens the
+    hive for writes, and commits the changes at the end if there
+    were no errors. *)
+
+val get_node : Guestfs.guestfs -> node -> string list -> node option
+(** [get_node g root path] starts at the [root] node of the hive (it does
+    not need to be the actual hive root), and searches down the [path].
+    It returns [Some node] of the final node if found, or [None] if
+    not found. *)
+
+val encode_utf16le : string -> string
+(** Helper: Take a 7 bit ASCII string and encode it as UTF-16LE. *)
+
+val decode_utf16le : string -> string
+(** Helper: Take a UTF-16LE string and decode it to UTF-8. *)
diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml
index 424288d..a231219 100644
--- a/v2v/convert_windows.ml
+++ b/v2v/convert_windows.ml
@@ -87,13 +87,13 @@ let convert ~keep_serial_console (g : G.guestfs) inspect source rcaps =
 
   (* If the Windows guest appears to be using group policy. *)
   let has_group_policy =
-    Windows.with_hive_readonly g software_hive_filename
+    Registry.with_hive_readonly g software_hive_filename
       (fun root ->
        try
          let path = ["Microsoft"; "Windows"; "CurrentVersion";
                      "Group Policy"; "History"]  in
          let node =
-           match Windows.get_node g root path with
+           match Registry.get_node g root path with
            | None -> raise Not_found
            | Some node -> node in
          let children = g#hivex_node_children node in
@@ -130,13 +130,13 @@ let convert ~keep_serial_console (g : G.guestfs) inspect source rcaps =
   let xenpv_uninst =
     let xenpvreg = "Red Hat Paravirtualized Xen Drivers for Windows(R)" in
 
-    Windows.with_hive_readonly g software_hive_filename
+    Registry.with_hive_readonly g software_hive_filename
       (fun root ->
        try
          let path = ["Microsoft"; "Windows"; "CurrentVersion"; "Uninstall";
                      xenpvreg] in
          let node =
-           match Windows.get_node g root path with
+           match Registry.get_node g root path with
            | None -> raise Not_found
            | Some node -> node in
          let uninstkey = "UninstallString" in
@@ -147,7 +147,7 @@ let convert ~keep_serial_console (g : G.guestfs) inspect source rcaps =
            raise Not_found
          );
          let data = g#hivex_value_value valueh in
-         let data = Regedit.decode_utf16le data in
+         let data = Registry.decode_utf16le data in
 
          (* The uninstall program will be uninst.exe.  This is a wrapper
           * around _uninst.exe which prompts the user.  As we don't want
@@ -171,12 +171,12 @@ let convert ~keep_serial_console (g : G.guestfs) inspect source rcaps =
   let prltools_uninsts =
     let uninsts = ref [] in
 
-    Windows.with_hive_readonly g software_hive_filename
+    Registry.with_hive_readonly g software_hive_filename
       (fun root ->
        try
          let path = ["Microsoft"; "Windows"; "CurrentVersion"; "Uninstall"] in
          let node =
-           match Windows.get_node g root path with
+           match Registry.get_node g root path with
            | None -> raise Not_found
            | Some node -> node in
          let uninstnodes = g#hivex_node_children node in
@@ -286,7 +286,7 @@ reg delete \"%s\" /v %s /f" strkey name
           let key_path = ["Policies"; "Microsoft"; "Windows"; "DeviceInstall";
                           "Settings"] in
           let name = "SuppressNewHWUI" in
-          let value = Windows.with_hive_write g software_hive_filename (
+          let value = Registry.with_hive_write g software_hive_filename (
             fun root ->
               set_reg_val_dword_1 root key_path name
           ) in
@@ -296,7 +296,7 @@ reg delete \"%s\" /v %s /f" strkey name
         | 5, 2 ->
           let key_path = ["Services"; "PlugPlay"; "Parameters"] in
           let name = "SuppressUI" in
-          let value = Windows.with_hive_write g system_hive_filename (
+          let value = Registry.with_hive_write g system_hive_filename (
             fun root ->
               let current_cs = get_current_cs root in
               set_reg_val_dword_1 root (current_cs :: key_path) name
@@ -413,7 +413,7 @@ if errorlevel 3010 exit /b 0
 
   and disable_xenpv_win_drivers root current_cs =
     (* Disable xenpv-win service (RHBZ#809273). *)
-    let services = Windows.get_node g root [current_cs; "Services"] in
+    let services = Registry.get_node g root [current_cs; "Services"] in
 
     match services with
     | None -> ()
@@ -424,7 +424,7 @@ if errorlevel 3010 exit /b 0
 
   and disable_prl_drivers root current_cs =
     (* Prevent Parallels drivers from loading at boot. *)
-    let services = Windows.get_node g root [current_cs; "Services"] in
+    let services = Registry.get_node g root [current_cs; "Services"] in
     let prl_svcs = [ "prl_boot"; "prl_dd"; "prl_eth5"; "prl_fs"; "prl_memdev";
                      "prl_mouf"; "prl_pv32"; "prl_pv64"; "prl_scsi";
                      "prl_sound"; "prl_strg"; "prl_tg"; "prl_time";
@@ -446,7 +446,7 @@ if errorlevel 3010 exit /b 0
     (* perfrom the equivalent of DelReg from prl_strg.inf:
      * HKLM, System\CurrentControlSet\Control\Class\{4d36e967-e325-11ce-bfc1-08002be10318}, LowerFilters, 0x00018002, prl_strg
      *)
-    let strg_cls = Windows.get_node g root
+    let strg_cls = Registry.get_node g root
                         [current_cs; "Control"; "Class";
                          "{4d36e967-e325-11ce-bfc1-08002be10318}"] in
     match strg_cls with
@@ -456,12 +456,12 @@ if errorlevel 3010 exit /b 0
         let valueh = g#hivex_node_get_value strg_cls lfkey in
         if valueh <> 0L then (
           let data = g#hivex_value_value valueh in
-          let filters = String.nsplit "\000" (Regedit.decode_utf16le data) in
+          let filters = String.nsplit "\000" (Registry.decode_utf16le data) in
           let filters = List.filter (
             fun x -> x <> "prl_strg" && x <> ""
           ) filters in
           let filters = List.map (
-            fun x -> Regedit.encode_utf16le x ^ "\000\000"
+            fun x -> Registry.encode_utf16le x ^ "\000\000"
           ) (filters @ [""]) in
           let data = String.concat "" filters in
           g#hivex_node_set_value strg_cls lfkey 7_L data
@@ -472,7 +472,7 @@ if errorlevel 3010 exit /b 0
      * error (eg. the infamous 0x0000007B).  Turn off autoreboot.
      *)
     let crash_control =
-      Windows.get_node g root [current_cs; "Control"; "CrashControl"] in
+      Registry.get_node g root [current_cs; "Control"; "CrashControl"] in
     match crash_control with
     | None -> ()
     | Some crash_control ->
@@ -489,10 +489,10 @@ if errorlevel 3010 exit /b 0
      * path to this key.
      *)
     let node =
-      Windows.get_node g root ["Microsoft"; "Windows"; "CurrentVersion"] in
+      Registry.get_node g root ["Microsoft"; "Windows"; "CurrentVersion"] in
     match node with
     | Some node ->
-       let append = Regedit.encode_utf16le ";%SystemRoot%\\Drivers\\VirtIO" in
+       let append = Registry.encode_utf16le ";%SystemRoot%\\Drivers\\VirtIO" in
        let values = Array.to_list (g#hivex_node_values node) in
        let rec loop = function
          | [] -> () (* DevicePath not found -- ignore this case *)
@@ -594,19 +594,19 @@ if errorlevel 3010 exit /b 0
     let fix_win_uefi_bcd esp_path =
       try
         let bcd_path = "/EFI/Microsoft/Boot/BCD" in
-        Windows.with_hive_write g (esp_path ^ bcd_path) (
+        Registry.with_hive_write g (esp_path ^ bcd_path) (
           (* Remove the 'graphicsmodedisabled' key in BCD *)
           fun root ->
           let path = ["Objects"; "{9dea862c-5cdd-4e70-acc1-f32b344d4795}";
                       "Elements"; "23000003"] in
           let boot_mgr_default_link =
-            match Windows.get_node g root path with
+            match Registry.get_node g root path with
             | None -> raise Not_found
             | Some node -> node in
           let current_boot_entry = g#hivex_value_utf8 (
             g#hivex_node_get_value boot_mgr_default_link "Element") in
           let path = ["Objects"; current_boot_entry; "Elements"; "16000046"] in
-          match Windows.get_node g root path with
+          match Registry.get_node g root path with
           | None -> raise Not_found
           | Some graphics_mode_disabled ->
             g#hivex_node_delete_child graphics_mode_disabled
@@ -635,10 +635,10 @@ if errorlevel 3010 exit /b 0
 
   (* Open the system hive for writes and update it. *)
   let block_driver, net_driver, video_driver =
-    Windows.with_hive_write g system_hive_filename update_system_hive in
+    Registry.with_hive_write g system_hive_filename update_system_hive in
 
   (* Open the software hive for writes and update it. *)
-  Windows.with_hive_write g software_hive_filename update_software_hive;
+  Registry.with_hive_write g software_hive_filename update_software_hive;
 
   fix_ntfs_heads ();
 
diff --git a/v2v/windows.ml b/v2v/windows.ml
index 79a14aa..6c6ed01 100644
--- a/v2v/windows.ml
+++ b/v2v/windows.ml
@@ -46,34 +46,3 @@ and check_app { Guestfs.app2_name = name;
 
 and (=~) str rex =
   try ignore (Str.search_forward rex str 0); true with Not_found -> false
-
-let with_hive_readonly (g : Guestfs.guestfs) hive_filename f =
-  let verbose = verbose () in
-  g#hivex_open ~write:false ~unsafe:true ~verbose (* ~debug:verbose *)
-               hive_filename;
-  protect ~f:(
-    fun () ->
-      let root = g#hivex_root () in
-      f root
-  ) ~finally:g#hivex_close
-
-let with_hive_write (g : Guestfs.guestfs) hive_filename f =
-  let verbose = verbose () in
-  g#hivex_open ~write:true ~verbose (* ~debug:verbose *) hive_filename;
-  protect ~f:(
-    fun () ->
-      let root = g#hivex_root () in
-      let ret = f root in
-      g#hivex_commit None;
-      ret
-  ) ~finally:g#hivex_close
-
-(* Find the given node in the current hive, relative to the starting
- * point.  Returns [None] if the node is not found.
- *)
-let rec get_node (g : Guestfs.guestfs) node = function
-  | [] -> Some node
-  | x :: xs ->
-     let node = g#hivex_node_get_child node x in
-     if node = 0L then None
-     else get_node g node xs
diff --git a/v2v/windows.mli b/v2v/windows.mli
index 95c4471..619a786 100644
--- a/v2v/windows.mli
+++ b/v2v/windows.mli
@@ -21,20 +21,3 @@
 val detect_antivirus : Types.inspect -> bool
 (** Return [true] if anti-virus (AV) software was detected in
     this Windows guest. *)
-
-val with_hive_readonly : Guestfs.guestfs -> string -> (int64 -> 'a) -> 'a
-val with_hive_write : Guestfs.guestfs -> string -> (int64 -> 'a) -> 'a
-(** [with_hive_(readonly|write) g hive_filename f]
-    are wrappers that handle opening and closing the hive
-    named [hive_filename] around a function [f].
-
-    [with_hive_readonly] opens the hive for read-only (attempts
-    to write will throw an error).  [with_hive_write] opens the
-    hive for writes, and commits the changes at the end if there
-    were no errors. *)
-
-val get_node : Guestfs.guestfs -> int64 -> string list -> int64 option
-(** [get_node g root path] starts at the [root] node of the hive (it does
-    not need to be the actual hive root), and searches down the [path].
-    It returns [Some node] of the final node if found, or [None] if
-    not found. *)
diff --git a/v2v/windows_virtio.mli b/v2v/windows_virtio.mli
index e6f984c..1d25260 100644
--- a/v2v/windows_virtio.mli
+++ b/v2v/windows_virtio.mli
@@ -19,7 +19,7 @@
 (** Functions for installing Windows virtio drivers. *)
 
 val install_drivers
-    : Guestfs.guestfs -> Types.inspect -> string -> int64 -> string ->
+    : Guestfs.guestfs -> Types.inspect -> string -> Registry.node -> string ->
       Types.requested_guestcaps ->
       Types.guestcaps_block_type * Types.guestcaps_net_type * Types.guestcaps_video_type
 (** [install_drivers g inspect systemroot root current_cs rcaps]
-- 
2.10.2




More information about the Libguestfs mailing list