X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=filetree_type.ml;h=285677f6f415d3db388ce89d522fdfa7ed8a6e84;hb=refs%2Ftags%2F0.1.7;hp=9c80e97912d8a339d34f4a2a5dfd56989ffd5c44;hpb=73f1dc10b4279528818fe0fda33daf4c34488d21;p=guestfs-browser.git diff --git a/filetree_type.ml b/filetree_type.ml index 9c80e97..285677f 100644 --- a/filetree_type.ml +++ b/filetree_type.ml @@ -18,39 +18,43 @@ 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; - mutable status : (string -> unit) option; } -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 *) - | 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 = @@ -64,6 +68,23 @@ let get_hdata { model = model; hash = hash; index_col = index_col } row = try Hashtbl.find hash index with Not_found -> assert false +(* Iterate over children of node, looking for matching hdata. *) +let find_child_node_by_content ({ model = model } as t) row c = + let rec loop row = + if (get_hdata t row).content = c then + row + else if model#iter_next row then + loop row + else + raise Not_found + in + + if not (model#iter_has_child row) then + raise Not_found; + + let first_child = model#iter_children (Some row) in + loop first_child + (* Search up to the top of the tree so we know if this directory * comes from an OS or a volume, and the full path to here. * @@ -72,31 +93,96 @@ let get_hdata { model = model; hash = hash; index_col = index_col } row = * \_ 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), Some parent -> + | { state=IsLeaf; content=(Loading|ErrorMessage _|Info _) }, Some parent -> get_pathname t parent - | (IsLeaf, Loading), 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 - -(* Update the status bar. *) -let update_status { status = f } msg = - match f with - | None -> () (* user didn't give us a [status] function to call *) - | Some f -> f msg + | { 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