Add drive mappings and Windows current control set to inspection data.
[guestfs-browser.git] / filetree_type.ml
index 9f2bc64..285677f 100644 (file)
 
 open Utils
 
+open Slave_types
+
+(* See struct/field description in .mli file. *)
 type t = {
   view : GTree.view;
   model : GTree.tree_store;
-  hash : (int, hdata) Hashtbl.t;    (* hash from index_col -> hdata *)
+  hash : (int, hdata) Hashtbl.t;
   index_col : int GTree.column;
   mode_col : string GTree.column;
   name_col : string GTree.column;
-  size_col : int64 GTree.column;
+  size_col : string GTree.column;
   date_col : string GTree.column;
-  link_col : string GTree.column;
 }
 
-and hdata = state_t * content_t
+and hdata = {
+  mutable state : state_t;
+  content : content_t;
+  mutable visited : bool;
+  mutable hiveh : Hivex.t option;
+}
 
-(* The type of the hidden column used to implement on-demand loading.
- * All rows are classified as either nodes or leafs (eg. a "node" might
- * be a directory, or a top-level operating system, or anything else
- * which the user could open and look inside).
- *)
 and state_t =
-  | IsLeaf           (* there are no children *)
-  | NodeNotStarted   (* user has not tried to open this *)
-  | NodeLoading      (* user tried to open it, still loading *)
-  | IsNode           (* we've loaded the children of this directory *)
+  | IsLeaf
+  | NodeNotStarted
+  | NodeLoading
+  | IsNode
 
-(* The actual content of a row. *)
 and content_t =
-  | Loading                          (* special "loading ..." node *)
-  | ErrorMessage of string           (* error message node *)
-  | Info of string                   (* information node (eg. disk usage) *)
-  | Top of Slave.source              (* top level OS or volume node *)
-  | Directory of Slave.direntry      (* a directory *)
-  | File of Slave.direntry           (* a file inc. special files *)
+  | Loading
+  | ErrorMessage of string
+  | Info of string
+  | Top of source
+  | TopWinReg of source * string * string * string
+  | Directory of direntry
+  | File of direntry
+  | RegKey of Hivex.node
+  | RegValue of Hivex.value
 
 (* Store hdata into a row. *)
 let store_hdata {model = model; hash = hash; index_col = index_col} row hdata =
@@ -65,9 +69,9 @@ let get_hdata { model = model; hash = hash; index_col = index_col } row =
   with Not_found -> assert false
 
 (* Iterate over children of node, looking for matching hdata. *)
-let find_child_node_by_hdata ({ model = model } as t) row hdata =
+let find_child_node_by_content ({ model = model } as t) row c =
   let rec loop row =
-    if hdata = get_hdata t row then
+    if (get_hdata t row).content = c then
       row
     else if model#iter_next row then
       loop row
@@ -89,26 +93,96 @@ let find_child_node_by_hdata ({ model = model } as t) row hdata =
  *       \_ Directory
  *            \_ Directory
  *                 \_ Loading    <--- you are here
+ *
+ * Note this function cannot be called on registry keys.  See
+ * {!get_registry_path} for that.
  *)
 let rec get_pathname ({ model = model } as t) row =
   let hdata = get_hdata t row in
   let parent = model#iter_parent row in
 
   match hdata, parent with
-  | (IsLeaf, (Loading|ErrorMessage _|Info _)), Some parent ->
+  | { state=IsLeaf; content=(Loading|ErrorMessage _|Info _) }, Some parent ->
       get_pathname t parent
-  | (IsLeaf, (Loading|ErrorMessage _|Info _)), None ->
+  | { state=IsLeaf; content=(Loading|ErrorMessage _|Info _) }, None ->
       assert false
-  | (_, Directory { Slave.dent_name = name }), Some parent
-  | (_, File { Slave.dent_name = name }), Some parent ->
+  | { content=Directory { dent_name = name }}, Some parent
+  | { content=File { dent_name = name }}, Some parent ->
       let src, parent_name = get_pathname t parent in
       let path =
         if parent_name = "/" then "/" ^ name
         else parent_name ^ "/" ^ name in
       src, path
-  | (_, Top src), _ -> src, "/"
-  | (_, Directory _), None -> assert false
-  | (_, File _), None -> assert false
-  | (_, Loading), _ -> assert false
-  | (_, ErrorMessage _), _ -> assert false
-  | (_, Info _), _ -> assert false
+  | { content=Top src }, _ -> src, "/"
+  | { content=Directory _ }, None -> assert false
+  | { content=File _ }, None -> assert false
+  | { content=Loading }, _ -> assert false
+  | { content=ErrorMessage _ }, _ -> assert false
+  | { content=Info _ }, _ -> assert false
+  | { content=TopWinReg _ }, _ -> assert false
+  | { content=RegKey _ }, _ -> assert false
+  | { content=RegValue _ }, _ -> assert false
+
+(* Search up to the top of the tree from a registry key.
+ *
+ * The path up the tree will always look something like:
+ *     TopWinReg
+ *       \_ RegKey
+ *            \_ RegKey          <--- you are here
+ *                 \_ Loading    <--- or here
+ *
+ * Note this function cannot be called on ordinary paths.  Use
+ * {!get_pathname} for that.
+ *)
+let rec get_registry_path ({ model = model } as t) row =
+  let hdata = get_hdata t row in
+  let parent = model#iter_parent row in
+
+  match hdata, parent with
+  | { state=IsLeaf; content=(Loading|ErrorMessage _|Info _) }, Some parent ->
+      get_registry_path t parent
+  | { state=IsLeaf; content=(Loading|ErrorMessage _|Info _) }, None ->
+      assert false
+  | { content=RegKey node; hiveh = Some h }, Some parent ->
+      let top, path = get_registry_path t parent in
+      let path = Hivex.node_name h node :: path in
+      top, path
+  | { content=TopWinReg (a,b,c,d) }, None -> (a,b,c,d), []
+  | { content=TopWinReg _ }, _ -> assert false
+  | { content=RegKey _}, _ -> assert false
+  | { content=Top _ }, _ -> assert false
+  | { content=Directory _ }, _ -> assert false
+  | { content=File _ }, _ -> assert false
+  | { content=Loading }, _ -> assert false
+  | { content=ErrorMessage _ }, _ -> assert false
+  | { content=Info _ }, _ -> assert false
+  | { content=RegValue _ }, _ -> assert false
+
+let rec cache_registry_file ?fail t path src remotefile cachefile cb =
+  Slave.download_file_if_not_exist ?fail src remotefile cachefile
+    (when_cached_registry ?fail t path cb)
+
+and when_cached_registry ?fail ({ model = model } as t) path cb () =
+  debug "when_cached_registry";
+  let row = model#get_iter path in
+  let hdata = get_hdata t row in
+
+  match hdata with
+  | { hiveh=Some _; content=TopWinReg _ } ->
+      (* Hive handle already opened. *)
+      cb ()
+
+  | { hiveh=None; content=TopWinReg (src, rootkey, remotefile, cachefile) } ->
+      (* Hive handle not opened, open it and save it in the handle. *)
+      (try
+         let flags = if verbose () then [ Hivex.OPEN_VERBOSE ] else [] in
+         let h = Hivex.open_file cachefile flags in
+         hdata.hiveh <- Some h;
+         cb ()
+       with
+         Hivex.Error _ as exn ->
+           match fail with
+           | Some fail -> fail exn
+           | None -> raise exn
+      )
+  | _ -> assert false