Version 0.1.3. 0.1.3
authorRichard W.M. Jones <rjones@redhat.com>
Fri, 17 Dec 2010 14:24:22 +0000 (14:24 +0000)
committerRichard W.M. Jones <rjones@redhat.com>
Fri, 17 Dec 2010 19:03:43 +0000 (19:03 +0000)
configure.ac
filetree.ml
filetree_markup.ml
filetree_ops.ml
filetree_ops.mli
guestfs-browser.spec.in
slave.ml
utils.ml
utils.mli

index 05a7dcf..67272ef 100644 (file)
@@ -15,7 +15,7 @@ dnl You should have received a copy of the GNU General Public License along
 dnl with this program; if not, write to the Free Software Foundation, Inc.,
 dnl 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-AC_INIT([guestfs-browser],[0.1.2])
+AC_INIT([guestfs-browser],[0.1.3])
 AM_INIT_AUTOMAKE([foreign])
 AC_CONFIG_MACRO_DIR([m4])
 
index a007d97..2bf0b3d 100644 (file)
@@ -155,9 +155,9 @@ and button_press ({ model = model; view = view } as t) ev =
     (* Based on number of selected rows and what is selected, construct
      * the context menu.
      *)
-    if paths <> [] then (
-      let menu = make_context_menu t paths in
-      menu#popup ~button ~time
+    (match make_context_menu t paths with
+     | Some menu -> menu#popup ~button ~time
+     | None -> ()
     );
 
     (* Return true so no other handler will run. *)
@@ -170,9 +170,6 @@ and make_context_menu t paths =
   let menu = GMenu.menu () in
   let factory = new GMenu.factory menu in
 
-  let item = factory#add_item "Open" in
-  item#misc#set_sensitive false;
-
   let rec add_file_items path =
     let item = factory#add_item "File information" in
     item#misc#set_sensitive false;
@@ -202,46 +199,70 @@ and make_context_menu t paths =
     let item = factory#add_item "Download list of filenames ..." in
     ignore (item#connect#activate ~callback:(download_dir_find0 t path));
 
-  and add_os_items path =
+  and add_top_os_items path =
     let item = factory#add_item "Operating system information" in
     ignore (item#connect#activate ~callback:(display_inspection_data t path));
     ignore (factory#add_separator ());
-    add_volume_items path
+    add_top_volume_items path
 
-  and add_volume_items path =
+  and add_top_volume_items path =
     let item = factory#add_item "Filesystem used & free" in
     item#misc#set_sensitive false;
     let item = factory#add_item "Block device information" in
     item#misc#set_sensitive false;
     ignore (factory#add_separator ());
     add_directory_items path
+
+  and add_topwinreg_items path =
+    let item = factory#add_item "Download hive file ..." in
+    item#misc#set_sensitive false;
+    ignore (factory#add_separator ());
+    add_regkey_items path
+
+  and add_regkey_items path =
+    let item = factory#add_item "Download as .reg file ..." in
+    item#misc#set_sensitive false
+
+  and add_regvalue_items path =
+    let item = factory#add_item "Copy value to clipboard" in
+    ignore (item#connect#activate ~callback:(copy_regvalue t path));
+
   in
 
-  (match paths with
-   (* single selection *)
-   | [path, { content=Top (Slave.OS os)} ] ->  (* top level operating system *)
-       add_os_items path
+  let has_menu =
+    match paths with
+    | [] -> false
 
-   | [path, { content=Top (Slave.Volume dev) }] -> (* top level volume *)
-       add_volume_items path
+    (* single selection *)
+    | [path, { content=Top (Slave.OS os)} ] ->  (* top level operating system *)
+        add_top_os_items path; true
 
-   | [path, { content=Directory direntry }] ->     (* directory *)
-       add_directory_items path
+    | [path, { content=Top (Slave.Volume dev) }] -> (* top level volume *)
+        add_top_volume_items path; true
 
-   | [path, { content=File direntry }] ->          (* file *)
-       add_file_items path
+    | [path, { content=Directory _ }] -> (* directory *)
+        add_directory_items path; true
 
-   | [_, { content=Loading }]
-   | [_, { content=ErrorMessage _ }] -> ()
+    | [path, { content=File _ }] ->      (* file *)
+        add_file_items path; true
 
-   | _ ->
-       (* At the moment multiple selection is disabled.  When/if we
-        * enable it we should do something intelligent here. XXX
-        *)
-       ()
-  );
+    | [path, { content=TopWinReg _ }] -> (* top level registry node *)
+        add_topwinreg_items path; true
+
+    | [path, { content=RegKey _ }] ->    (* registry node *)
+        add_regkey_items path; true
+
+    | [path, { content=RegValue _ }] ->  (* registry key/value pair *)
+        add_regvalue_items path; true
 
-  menu
+    | [_, { content=(Loading|ErrorMessage _|Info _) }] -> false
+
+    | _::_::_ ->
+        (* At the moment multiple selection is disabled.  When/if we
+         * enable it we should do something intelligent here. XXX
+         *)
+        false in
+  if has_menu then Some menu else None
 
 let clear { model = model; hash = hash } =
   model#clear ();
@@ -435,6 +456,12 @@ and when_read_directory ({ model = model } as t) path entries =
 
   let row = model#get_iter path in
 
+  (* Sort the entries by lexicographic ordering. *)
+  let cmp { Slave.dent_name = n1 } { Slave.dent_name = n2 } =
+    UTF8.compare n1 n2
+  in
+  let entries = List.sort ~cmp entries in
+
   (* Add the entries. *)
   List.iter (
     fun direntry ->
@@ -543,7 +570,7 @@ and expand_hive_node ({ model = model } as t) row node =
    * to the tree.
    *)
   let values = Hivex.node_values h node in
-  let cmp v1 v2 = compare (Hivex.value_key h v1) (Hivex.value_key h v2) in
+  let cmp v1 v2 = UTF8.compare (Hivex.value_key h v1) (Hivex.value_key h v2) in
   Array.sort cmp values;
   Array.iter (
     fun value ->
@@ -555,7 +582,7 @@ and expand_hive_node ({ model = model } as t) row node =
   ) values;
 
   let children = Hivex.node_children h node in
-  let cmp n1 n2 = compare (Hivex.node_name h n1) (Hivex.node_name h n2) in
+  let cmp n1 n2 = UTF8.compare (Hivex.node_name h n1) (Hivex.node_name h n2) in
   Array.sort cmp children;
   Array.iter (
     fun node ->
index beb41b2..a890cca 100644 (file)
@@ -90,7 +90,6 @@ and markup_of_regkey ?(visited = false) h node =
 
 (* Mark up a registry value. *)
 and markup_of_regvalue ?(visited = false) h value =
-  debug "markup_of_regvalue";
   let k = Hivex.value_key h value in
   let k = if k = "" then "@" else k in
   let t, v = Hivex.value_value h value in
@@ -98,56 +97,13 @@ and markup_of_regvalue ?(visited = false) h value =
   (* Ignore long values. *)
   let len = String.length v in
   let v =
-    if len >= 256 then
-      sprintf "&lt;%d bytes not printed&gt;" len
-    else (
-      (* Deal as best we can with printing the value. *)
-      match t with
-      | Hivex.REG_NONE -> if v = "" then "" else markup_hex_data v
-      | Hivex.REG_SZ -> markup_windows_string v
-      | Hivex.REG_EXPAND_SZ -> markup_windows_string v
-      | Hivex.REG_BINARY -> markup_hex_data v
-      | Hivex.REG_DWORD ->
-          (bitmatch Bitstring.bitstring_of_string v with
-           | { i : 32 : littleendian } -> sprintf "%08lx" i
-           | { _ } -> markup_hex_data v)
-      | Hivex.REG_DWORD_BIG_ENDIAN ->
-          (bitmatch Bitstring.bitstring_of_string v with
-           | { i : 32 : bigendian } -> sprintf "%08lx" i
-           | { _ } -> markup_hex_data v)
-      | Hivex.REG_LINK -> markup_hex_data v
-      | Hivex.REG_MULTI_SZ -> (* XXX could do better with this *)
-          markup_hex_data v
-      | Hivex.REG_RESOURCE_LIST -> markup_hex_data v
-      | Hivex.REG_FULL_RESOURCE_DESCRIPTOR -> markup_hex_data v
-      | Hivex.REG_RESOURCE_REQUIREMENTS_LIST -> markup_hex_data v
-      | Hivex.REG_QWORD ->
-          (bitmatch Bitstring.bitstring_of_string v with
-           | { i : 64 : littleendian } -> sprintf "%016Lx" i
-           | { _ } -> markup_hex_data v)
-      | Hivex.REG_UNKNOWN i32 -> markup_hex_data v
-    ) in
+    if len >= 512 then sprintf "&lt;%d bytes not printed&gt;" len
+    else markup_escape (printable_hivex_value ~split_long_lines:true t v) in
 
   let fg = if not visited then normal file_color else darken file_color in
   sprintf "<span fgcolor=\"%s\">%s</span>=<span fgcolor=\"%s\">%s</span>"
     fg (markup_escape k) fg v
 
-(* Mark up registry value as hex data. *)
-and markup_hex_data v =
-  let vs = String.explode v in
-  let vs = List.mapi (
-    fun i c ->
-      sprintf "%s%02x" (if i mod 16 = 0 then "\n" else "") (int_of_char c)
-  ) vs in
-  String.concat "," vs
-
-(* Best guess the format of the string and convert to UTF-8. *)
-and markup_windows_string v =
-  try markup_escape (windows_string_to_utf8 v)
-  with CharEncoding.Malformed_code | CharEncoding.Out_of_range ->
-    (* Fallback to displaying the string as hex. *)
-    markup_hex_data v
-
 and normal (r, g, b) =
   let r = if r < 0 then 0 else if r > 255 then 255 else r in
   let g = if g < 0 then 0 else if g > 255 then 255 else g in
index 5946a81..801f50a 100644 (file)
@@ -226,3 +226,16 @@ let display_inspection_data ({ model = model } as t) path () =
 
         model#set ~row ~column:t.name_col data
       )
+
+(* Copy registry key value to clipboard. *)
+let copy_regvalue ({ model = model } as t) path () =
+  let row = model#get_iter path in
+  let hdata = get_hdata t row in
+  match hdata with
+  | { content=RegValue value; hiveh = Some h } ->
+      let t, v = Hivex.value_value h value in
+      let v = printable_hivex_value t v in
+      let cb = GData.clipboard Gdk.Atom.clipboard in
+      cb#set_text v
+
+  | _ -> () (* not a registry value row, ignore *)
index 9191ad4..a30b390 100644 (file)
@@ -28,6 +28,8 @@
 
 (**/**)
 
+val copy_regvalue : Filetree_type.t -> Gtk.tree_path -> unit -> unit
+
 val disk_usage : Filetree_type.t -> Gtk.tree_path -> unit -> unit
 
 val display_inspection_data : Filetree_type.t -> Gtk.tree_path -> unit -> unit
index 889ea95..05dc733 100644 (file)
@@ -16,6 +16,7 @@ BuildRequires:  libguestfs-devel >= 1.7.24
 BuildRequires:  libvirt-devel
 BuildRequires:  ocaml
 BuildRequires:  ocaml-bitstring-devel
+BuildRequires:  ocaml-camlp4-devel
 BuildRequires:  ocaml-camomile-devel, ocaml-camomile-data
 BuildRequires:  ocaml-extlib-devel
 BuildRequires:  ocaml-findlib-devel
index 8cf8199..01105ef 100644 (file)
--- a/slave.ml
+++ b/slave.ml
@@ -292,7 +292,7 @@ and execute_command = function
             dom_name = D.get_name d;
             dom_state = (D.get_info d).D.state }
       ) doms in
-      let cmp { dom_name = n1 } { dom_name = n2 } = compare n1 n2 in
+      let cmp { dom_name = n1 } { dom_name = n2 } = UTF8.compare n1 n2 in
       let doms = List.sort ~cmp doms in
 
       status "Connected to %s" printable_name;
index f9cf35d..95c1289 100644 (file)
--- a/utils.ml
+++ b/utils.ml
@@ -17,6 +17,7 @@
  *)
 
 open ExtString
+open ExtList
 open CamomileLibrary
 open Default.Camomile
 
@@ -176,3 +177,44 @@ let windows_string_to_utf8 str =
     String.sub str 0 (UTF8.last str)
   else
     str
+
+(* Best effort convert hive value to printable string. *)
+let rec printable_hivex_value ?split_long_lines t v =
+  let hex = reg_hex_of_string ?split_long_lines in
+  match t with
+  | Hivex.REG_NONE -> if v = "" then "" else hex v
+  | Hivex.REG_SZ ->
+      (try windows_string_to_utf8 v with _ -> hex v)
+  | Hivex.REG_EXPAND_SZ ->
+      (try windows_string_to_utf8 v with _ -> hex v)
+  | Hivex.REG_BINARY -> hex v
+  | Hivex.REG_DWORD ->
+      (bitmatch Bitstring.bitstring_of_string v with
+       | { i : 32 : littleendian } -> sprintf "%08lx" i
+       | { _ } -> hex v)
+  | Hivex.REG_DWORD_BIG_ENDIAN ->
+      (bitmatch Bitstring.bitstring_of_string v with
+       | { i : 32 : bigendian } -> sprintf "%08lx" i
+       | { _ } -> hex v)
+  | Hivex.REG_LINK -> hex v
+  | Hivex.REG_MULTI_SZ -> (* XXX should be better for this one *)
+      hex v
+  | Hivex.REG_RESOURCE_LIST -> hex v
+  | Hivex.REG_FULL_RESOURCE_DESCRIPTOR -> hex v
+  | Hivex.REG_RESOURCE_REQUIREMENTS_LIST -> hex v
+  | Hivex.REG_QWORD ->
+      (bitmatch Bitstring.bitstring_of_string v with
+       | { i : 64 : littleendian } -> sprintf "%016Lx" i
+       | { _ } -> hex v)
+  | Hivex.REG_UNKNOWN i32 -> hex v
+
+(* Convert binary data to a hex string.  This includes line breaks. *)
+and reg_hex_of_string ?(split_long_lines=false) v =
+  let vs = String.explode v in
+  let vs = List.mapi (
+    fun i c ->
+      sprintf "%s%02x"
+        (if split_long_lines && i mod 16 = 0 then "\n" else "")
+        (int_of_char c)
+  ) vs in
+  String.concat "," vs
index 92e2bb6..7a15144 100644 (file)
--- a/utils.mli
+++ b/utils.mli
@@ -121,3 +121,7 @@ val windows_string_to_utf8 : string -> string
 
       This may fail in multiple ways, raising a Camomile exception
       which you probably need to catch. *)
+
+val printable_hivex_value : ?split_long_lines:bool -> Hivex.hive_type -> string -> string
+  (** [printable_hivex_value t v] converts raw registry value
+      [v] of type [t] to a printable string. *)