X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=filetree_type.ml;h=285677f6f415d3db388ce89d522fdfa7ed8a6e84;hb=refs%2Ftags%2F0.1.7;hp=4b70b769ba0154862a6849c4deb6f58a33ca4943;hpb=02614e74adee2a5d499bd557a6adde99a3c56e73;p=guestfs-browser.git diff --git a/filetree_type.ml b/filetree_type.ml index 4b70b76..285677f 100644 --- a/filetree_type.ml +++ b/filetree_type.ml @@ -17,7 +17,8 @@ *) open Utils -open Printf + +open Slave_types (* See struct/field description in .mli file. *) type t = { @@ -35,6 +36,7 @@ and hdata = { mutable state : state_t; content : content_t; mutable visited : bool; + mutable hiveh : Hivex.t option; } and state_t = @@ -47,9 +49,12 @@ and content_t = | Loading | ErrorMessage of string | Info of string - | Top of Slave.source - | Directory of Slave.direntry - | File of Slave.direntry + | 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 = @@ -88,6 +93,9 @@ let find_child_node_by_content ({ model = model } as t) row c = * \_ 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 @@ -98,100 +106,83 @@ let rec get_pathname ({ model = model } as t) row = get_pathname t parent | { state=IsLeaf; content=(Loading|ErrorMessage _|Info _) }, None -> assert false - | { content=Directory { Slave.dent_name = name }}, Some parent - | { content=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 | { content=Top src }, _ -> src, "/" - | { content=Directory _}, None -> assert false - | { content=File _}, None -> assert false + | { content=Directory _ }, None -> assert false + | { content=File _ }, None -> assert false | { content=Loading }, _ -> assert false - | { content=ErrorMessage _}, _ -> assert false - | { content=Info _}, _ -> assert false - -(* Base colours. XXX Should be configurable somewhere. *) -let file_color = 0x20, 0x20, 0xff (* regular file *) -let dir_color = 0x80, 0x80, 0x20 (* directory *) -let symlink_color = file_color (* symlink *) -let suid_color = 0x20, 0x20, 0x80 (* setuid bit set on regular file *) -let suid_bgcolor = 0xff, 0xc0, 0xc0 -let sgid_color = suid_color (* setgid bit set on regular file *) -let sgid_bgcolor = suid_bgcolor -let block_color = 0x00, 0x60, 0x60 (* block device *) -let char_color = block_color (* char device *) -let fifo_color = 0x60, 0x00, 0x60 (* fifo *) -let socket_color = fifo_color (* socket *) -let other_color = file_color (* anything not one of the above *) - -(* Mark up a filename for the name_col column. - * - * XXX This shouldn't be in Filetree_type module, but we have to have - * it here because set_visited is here. - * - * See also - * http://library.gnome.org/devel/pango/stable/PangoMarkupFormat.html - *) -let rec markup_of_name ?(visited = false) direntry = - let name = direntry.Slave.dent_name in - let mode = direntry.Slave.dent_stat.Guestfs.mode in - if is_directory mode then ( (* directory *) - let fg = if not visited then normal dir_color else darken dir_color in - sprintf "%s" - fg (markup_escape name) - ) - else if is_symlink mode then ( (* symlink *) - let link = direntry.Slave.dent_link in - let fg = - if not visited then normal symlink_color else darken symlink_color in - sprintf "%s %s %s" - fg (markup_escape name) utf8_rarrow fg (markup_escape link) - ) - else ( (* not directory, not symlink *) - let fg, bg = - if is_regular_file mode then ( - if is_suid mode then suid_color, Some suid_bgcolor - else if is_sgid mode then sgid_color, Some sgid_bgcolor - else file_color, None - ) - else if is_block mode then block_color, None - else if is_char mode then char_color, None - else if is_fifo mode then fifo_color, None - else if is_socket mode then socket_color, None - else other_color, None in - let fg = if not visited then normal fg else darken fg in - let bg = - match bg with - | Some bg -> sprintf " bgcolor=\"%s\"" (normal bg) - | None -> "" in - sprintf "%s" - fg bg (markup_escape name) - ) - -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 - let b = if b < 0 then 0 else if b > 255 then 255 else b in - sprintf "#%02x%02x%02x" r g b - -and darken (r, g, b) = - normal (r * 4 / 10, g * 4 / 10, b * 4 / 10) - -(* This is a bit of a hack. Ideally just setting 'visited' would - * darken the colour when the cell was re-rendered. However that would - * mean we couldn't store other stuff in the name column. Therefore, - * repopulate the name column. + | { 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 set_visited ({ model = model; name_col = name_col } as t) row = +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 - if hdata.visited = false then ( - hdata.visited <- true; - match hdata.content with - | Directory direntry | File direntry -> - debug "set_visited %s" direntry.Slave.dent_name; - model#set ~row ~column:name_col - (markup_of_name ~visited:true direntry) - | Loading | ErrorMessage _ | Info _ | Top _ -> () - ) + + 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