mllib: Move Windows Registry functions from v2v to common code.

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.
This commit is contained in:
Richard W.M. Jones
2017-02-17 19:58:50 +00:00
parent 2643c4d5f4
commit ca5e7233df
9 changed files with 156 additions and 107 deletions

View File

@@ -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 \

View File

@@ -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

View File

@@ -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. *)

82
mllib/registry.ml Normal file
View File

@@ -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

45
mllib/registry.mli Normal file
View File

@@ -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. *)

View File

@@ -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 ();

View File

@@ -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

View File

@@ -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. *)

View File

@@ -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]