X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=filetree_ops.ml;h=dcea59df75b4ba0641eeb67b080785d5c3354c88;hb=f0a4c05b84a29abe171d0b82d5f6305606b3ce8d;hp=801f50a8cfe6b9d260a0ebfded6d4ebd12b8fbf1;hpb=f09bb82de01019f24411cac2916d9567b5e9a235;p=guestfs-browser.git diff --git a/filetree_ops.ml b/filetree_ops.ml index 801f50a..dcea59d 100644 --- a/filetree_ops.ml +++ b/filetree_ops.ml @@ -19,9 +19,16 @@ open Printf open Utils +open Slave_types + open Filetree_type open Filetree_markup +(* Temporary directory for shared use by any function in this file. + * It is cleaned up when the program exits. + *) +let tmpdir = tmpdir () + (* Get the basename of a file, using path conventions which are valid * for libguestfs. So [Filename.basename] won't necessarily work * because it will use host path conventions. @@ -35,6 +42,19 @@ let basename pathname = with Not_found -> pathname +(* Get the extension of a file using libguestfs path conventions, + * including the leading point (eg. ".txt"). Might return an empty + * string if there is no extension. + *) +let extension pathname = + let len = String.length pathname in + try + let i = String.rindex pathname '.' in + let r = String.sub pathname i (len-i) in + r + with + Not_found -> "" + (* Download a single file. *) let rec download_file ({ model = model } as t) path () = let row = model#get_iter path in @@ -78,9 +98,9 @@ let rec download_dir_tarball ({ model = model } as t) format path () = dlg#add_select_button_stock `SAVE `SAVE; let extension = match format with - | Slave.Tar -> ".tar" - | Slave.TGZ -> ".tar.gz" - | Slave.TXZ -> ".tar.xz" + | Tar -> ".tar" + | TGZ -> ".tar.gz" + | TXZ -> ".tar.xz" in dlg#set_current_name (basename pathname ^ extension); @@ -170,7 +190,7 @@ let rec disk_usage ({ model = model } as t) path () = and when_disk_usage ({ model = model } as t) path pathname kbytes = let row = model#get_iter path in - (* Find the Info "disk_usage" child node add above, and replace the + (* Find the Info "disk_usage" child node added above, and replace the * text in it with the final size. *) try @@ -193,8 +213,8 @@ let display_inspection_data ({ model = model } as t) path () = (* Should be an OS source, if not ignore. *) match src with - | Slave.Volume _ -> () - | Slave.OS os -> + | Volume _ -> () + | OS os -> (* See if this node already has an Info "inspection_data" child * node. If so they don't recreate it. *) @@ -208,20 +228,20 @@ let display_inspection_data ({ model = model } as t) path () = (* XXX UGHLEE *) let data = sprintf "Type: %s\nDistro: %s\nVersion: %d.%d\nArch.: %s\nPackaging: %s/%s\n%sMountpoints:\n%s" - os.Slave.insp_type os.Slave.insp_distro - os.Slave.insp_major_version os.Slave.insp_minor_version - os.Slave.insp_arch - os.Slave.insp_package_management os.Slave.insp_package_format - (match os.Slave.insp_windows_systemroot with + os.insp_type os.insp_distro + os.insp_major_version os.insp_minor_version + os.insp_arch + os.insp_package_management os.insp_package_format + (match os.insp_windows_systemroot with | None -> "" | Some path -> - sprintf "%%systemroot%%: %s\n" (markup_escape path)) + sprintf "Systemroot: %s\n" (markup_escape path)) (String.concat "\n" (List.map ( fun (mp, dev) -> sprintf "%s on %s" (markup_escape dev) (markup_escape mp)) - os.Slave.insp_mountpoints) + os.insp_mountpoints) ) in model#set ~row ~column:t.name_col data @@ -239,3 +259,152 @@ let copy_regvalue ({ model = model } as t) path () = cb#set_text v | _ -> () (* not a registry value row, ignore *) + +(* View a single file. *) +let rec view_file ({ model = model } as t) path opener () = + let row = model#get_iter path in + let src, pathname = get_pathname t row in + debug "view_file %s" pathname; + + (* Download the file into a temporary directory. *) + let ext = extension pathname in + let localfile = tmpdir // string_of_int (unique ()) ^ ext in + Slave.download_file src pathname localfile + (when_downloaded_file_for_view t path opener localfile) + +and when_downloaded_file_for_view ({ model = model } as t) path + opener localfile () = + let row = model#get_iter path in + set_visited t row; + + let cmd = + sprintf "%s %s" (Filename.quote opener) (Filename.quote localfile) in + Slave.run_command cmd Slave.no_callback + +(* Compute the checksum of a file. *) +let rec checksum_file ({ model = model } as t) path csumtype () = + let row = model#get_iter path in + let src, pathname = get_pathname t row in + debug "checksum_file %s" pathname; + + (* See if this node already has an Info "checksum" child + * node. If so they don't recreate it. + *) + let content = Info ("checksum:" ^ csumtype) in + if not (has_child_node_equals t row content) then ( + let row = model#insert ~parent:row 0 in + let hdata = + { state=IsLeaf; content=content; visited=false; hiveh=None } in + store_hdata t row hdata; + model#set ~row ~column:t.name_col + (sprintf "Calculating %s ..." csumtype); + + t.view#expand_row path; + + Slave.checksum_file src pathname csumtype + (when_checksum_file t path pathname csumtype) + ) + +and when_checksum_file ({ model = model } as t) path pathname csumtype checksum= + let row = model#get_iter path in + set_visited t row; + + (* Find the child node added above, and replace the text. *) + try + let content = Info ("checksum:" ^ csumtype) in + let row = find_child_node_by_content t row content in + let msg = sprintf "%s: %s" csumtype checksum in + model#set ~row ~column:t.name_col msg + with + Not_found -> () + +(* Compute the file information of a file. *) +let rec file_information ({ model = model } as t) path () = + let row = model#get_iter path in + let src, pathname = get_pathname t row in + debug "file_information %s" pathname; + + (* See if this node already has an Info "file_information" child + * node. If so they don't recreate it. + *) + let content = Info "file_information" in + if not (has_child_node_equals t row content) then ( + let row = model#insert ~parent:row 0 in + let hdata = + { state=IsLeaf; content=content; visited=false; hiveh=None } in + store_hdata t row hdata; + model#set ~row ~column:t.name_col "Calculating file information ..."; + + t.view#expand_row path; + + Slave.file_information src pathname (when_file_information t path pathname) + ) + +and when_file_information ({ model = model } as t) path pathname info = + let row = model#get_iter path in + set_visited t row; + + (* Find the child node added above, and replace the text. *) + try + let content = Info "file_information" in + let row = find_child_node_by_content t row content in + model#set ~row ~column:t.name_col (markup_escape info) + with + Not_found -> () + +(* Export a registry key/subkey tree as a reg file. This is pretty + * effortless with hivexregedit. + *) +let download_as_reg ({ model = model } as t) path hivexregedit () = + let row = model#get_iter path in + let hdata = get_hdata t row in + + (* Get path to the top of the registry tree. *) + let (_, rootkey, _, cachefile), nodes = get_registry_path t row in + let regpath = String.concat "\\" (List.rev nodes) in + debug "download_as_reg: %s %s %s" cachefile rootkey regpath; + + let do_dialog () = + (* Put up the dialog. *) + let title = "Download as .reg file" in + let dlg = GWindow.file_chooser_dialog + ~action:`SAVE ~title ~modal:true () in + dlg#add_button_stock `CANCEL `CANCEL; + dlg#add_select_button_stock `SAVE `SAVE; + let name = match nodes with [] -> rootkey | (name::_) -> name in + dlg#set_current_name (name ^ ".reg"); + + match dlg#run () with + | `DELETE_EVENT | `CANCEL -> + dlg#destroy () + | `SAVE -> + match dlg#filename with + | None -> () + | Some localfile -> + dlg#destroy (); + + (* Use hivexregedit to save it. *) + let cmd = + sprintf "%s --export --prefix %s %s %s > %s" + (Filename.quote hivexregedit) + (Filename.quote rootkey) (Filename.quote cachefile) + (Filename.quote regpath) (Filename.quote localfile) in + Slave.run_command cmd Slave.no_callback + in + + match hdata with + | { content=RegKey _ } -> + do_dialog () + + | { content=TopWinReg (src, _, remotefile, cachefile) } -> + (* There's a subtle problem here: If the top node has not been + * opened, the registry cachefile won't have been downloaded. If + * the top node has been opened, the registry might still be + * being downloaded as we are running here. Either way we can't + * trust the cachefile. Tell the slave thread to download the + * file if it's not downloaded already (since the slave thread + * runs in a serial loop, this is always race free). + *) + cache_registry_file t path src remotefile cachefile do_dialog + + | _ -> () (* not a registry key, ignore *)