From 8ecbebaf01f96a781ded3e24235697c62bc515b4 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 1 Jan 1970 00:00:00 +0000 Subject: [PATCH] Use tables of callbacks for the functions. Implement 'offset_is_free'. --- diskzip/diskzip.ml | 53 +++++++++++++++++++++++++++++++++------ lib/diskimage.ml | 52 +++++++++++++++++++++++++++----------- lib/diskimage.mli | 9 +++++++ lib/diskimage_ext2.ml | 7 ++++++ lib/diskimage_ext2.mli | 2 +- lib/diskimage_linux_swap.ml | 10 ++++++++ lib/diskimage_linux_swap.mli | 2 +- lib/diskimage_linux_swsuspend.ml | 10 ++++++++ lib/diskimage_linux_swsuspend.mli | 2 +- lib/diskimage_lvm2.ml | 14 ++++++++++- lib/diskimage_lvm2.mli | 6 +---- lib/diskimage_mbr.ml | 10 ++++++++ lib/diskimage_mbr.mli | 2 +- lib/diskimage_utils.ml | 16 ++++++++++++ lib/diskimage_utils.mli | 18 +++++++++++++ 15 files changed, 182 insertions(+), 31 deletions(-) diff --git a/diskzip/diskzip.ml b/diskzip/diskzip.ml index 8acabc4..721335a 100644 --- a/diskzip/diskzip.ml +++ b/diskzip/diskzip.ml @@ -182,14 +182,53 @@ and go_compress extcompress images = let size = disk#size in (* Size in bytes. *) let nr_blocks = size /^ blocksize in (* Number of disk sectors. *) - (* Get the lookup function for this disk. *) - let lookup = Diskimage.get_owners_lookup machine ownership disk in + if !Diskimage.debug then + eprintf "Writing disk %s (%s sectors) ...\n%!" + disk#name (Int63.to_string nr_blocks); - (* Lookup each sector. *) - for blk = 0 to nr_blocks-1 do - ignore (lookup blk) - done - ) machine.Diskimage.m_disks; + (* Get the lookup function for this disk. *) + let lookup_offset = + Diskimage.get_owners_lookup machine ownership disk in + + (* Convenience function to look up a block and test freeness. *) + let block_is_free blk = + let offset = blk *^ blocksize in + Diskimage.offset_is_free (lookup_offset offset) + in + + (* Look up owners for each sector in turn. *) + let rec loop blk = + if blk < nr_blocks then ( + (* The current sector (blk) is either free or not free. Look + * for a stretch of sectors which are the same. + *) + let current_free = block_is_free blk in + let rec find_end blk = + if blk < nr_blocks then ( + if block_is_free blk = current_free then + find_end (Int63.succ blk) + else + blk + ) else + nr_blocks (* End of the disk image. *) + in + let end_blk = find_end (Int63.succ blk) in + + (* Current stretch is from blk .. end_blk-1. *) + if !Diskimage.debug then + eprintf " %s stretch %s to %s-1 (%s bytes)\n" + (if current_free then "free" else "used") + (Int63.to_string blk) (Int63.to_string end_blk) + (Int63.to_string ((end_blk-^blk) *^ blocksize)); + + + + + loop end_blk + ) + in + loop ~^0 + ) machine.Diskimage.m_disks diff --git a/lib/diskimage.ml b/lib/diskimage.ml index f2b5823..6c2ef01 100644 --- a/lib/diskimage.ml +++ b/lib/diskimage.ml @@ -34,21 +34,21 @@ let disk_block_size = ~^512 (* The plug-ins. *) let partition_types = [ Diskimage_mbr.plugin_id, - ("MBR", Diskimage_mbr.probe); + ("MBR", Diskimage_mbr.callbacks); ] let filesystem_types = [ Diskimage_ext2.plugin_id, - ("Linux ext2/3", Diskimage_ext2.probe); + ("Linux ext2/3", Diskimage_ext2.callbacks); Diskimage_linux_swap.plugin_id, - ("Linux swap", Diskimage_linux_swap.probe); + ("Linux swap", Diskimage_linux_swap.callbacks); Diskimage_linux_swsuspend.plugin_id, - ("Linux s/w suspend", Diskimage_linux_swsuspend.probe); + ("Linux s/w suspend", Diskimage_linux_swsuspend.callbacks); ] let lvm_types = [ Diskimage_lvm2.plugin_id, - ("Linux LVM2", Diskimage_lvm2.probe, Diskimage_lvm2.list); + ("Linux LVM2", Diskimage_lvm2.callbacks); ] let name_of_parts id = @@ -58,7 +58,7 @@ let name_of_filesystem id = let name, _ = List.assoc id filesystem_types in name let name_of_lvm id = - let name, _, _ = List.assoc id lvm_types in + let name, _ = List.assoc id lvm_types in name (* Probe a device for partitions. Returns [Some parts] or [None]. *) @@ -66,8 +66,8 @@ let probe_for_partitions dev = if !debug then eprintf "probing for partitions on %s ...\n%!" dev#name; let rec loop = function | [] -> None - | (parts_plugin_id, (_, probe_fn)) :: rest -> - try Some (probe_fn dev) + | (parts_plugin_id, (_, cb)) :: rest -> + try Some (cb.parts_cb_probe dev) with Not_found -> loop rest in let r = loop partition_types in @@ -80,13 +80,17 @@ let probe_for_partitions dev = ); r +let parts_offset_is_free ({ parts_plugin_id = parts_name } as parts) offset = + let _, cb = List.assoc parts_name partition_types in + cb.parts_cb_offset_is_free parts offset + (* Probe a device for a filesystem. Returns [Some fs] or [None]. *) let probe_for_filesystem dev = if !debug then eprintf "probing for a filesystem on %s ...\n%!" dev#name; let rec loop = function | [] -> None - | (fs_name, (_, probe_fn)) :: rest -> - try Some (probe_fn dev) + | (fs_name, (_, cb)) :: rest -> + try Some (cb.fs_cb_probe dev) with Not_found -> loop rest in let r = loop filesystem_types in @@ -99,13 +103,17 @@ let probe_for_filesystem dev = ); r +let fs_offset_is_free ({ fs_plugin_id = fs_name } as fs) offset = + let _, cb = List.assoc fs_name filesystem_types in + cb.fs_cb_offset_is_free fs offset + (* Probe a device for a PV. Returns [Some lvm_name] or [None]. *) let probe_for_pv dev = if !debug then eprintf "probing if %s is a PV ...\n%!" dev#name; let rec loop = function | [] -> None - | (lvm_name, (_, probe_fn, _)) :: rest -> - try Some (probe_fn lvm_name dev) + | (lvm_name, (_, cb)) :: rest -> + try Some (cb.lvm_cb_probe lvm_name dev) with Not_found -> loop rest in let r = loop lvm_types in @@ -118,8 +126,12 @@ let probe_for_pv dev = r let list_lvs lvm_name devs = - let _, _, list_lvs_fn = List.assoc lvm_name lvm_types in - list_lvs_fn devs + let _, cb = List.assoc lvm_name lvm_types in + cb.lvm_cb_list_lvs devs + +let lvm_offset_is_free ({ lvm_plugin_id = lvm_name } as pv) offset = + let _, cb = List.assoc lvm_name lvm_types in + cb.lvm_cb_offset_is_free pv offset (*----------------------------------------------------------------------*) (* Create machine description. *) @@ -700,3 +712,15 @@ let get_owners_lookup machine ownership (disk : block_device) = List.map ( fun (owner, owner_offset) -> (owner, offset -^ owner_offset) ) owners + +(* Find out if a disk offset is free. + * Current algorithm just checks that at least one owner says + * it is free. We could be smarter about this. + *) +let offset_is_free owners = + List.exists ( + function + | `Filesystem fs, offset -> fs_offset_is_free fs offset + | `Partitions parts, offset -> parts_offset_is_free parts offset + | `PhysicalVolume pv, offset -> lvm_offset_is_free pv offset + ) owners diff --git a/lib/diskimage.mli b/lib/diskimage.mli index 5d2a420..4eab561 100644 --- a/lib/diskimage.mli +++ b/lib/diskimage.mli @@ -333,6 +333,15 @@ val get_owners_lookup : machine -> ownership -> block_device -> creates a tree structure which allows ownership to be determined in just a few steps. *) +val offset_is_free : (owner * Int63.t) list -> bool + (** [offset_is_free owners] tests if the offset is free (unused). + + If an offset is free, then it may be discarded without + changing the semantics of the disk image. In normal cases + this extends to the end of the current block, but blocksize + will differ for each owner, so what this really means is + tricky in practice. *) + (** {2 Debugging} *) val debug : bool ref diff --git a/lib/diskimage_ext2.ml b/lib/diskimage_ext2.ml index 3f72ca4..ea020b5 100644 --- a/lib/diskimage_ext2.ml +++ b/lib/diskimage_ext2.ml @@ -150,3 +150,10 @@ let probe dev = | { _ } -> raise Not_found (* Not an EXT2/3 superblock. *) + +let offset_is_free _ _ = false + +let callbacks = { + fs_cb_probe = probe; + fs_cb_offset_is_free = offset_is_free; +} diff --git a/lib/diskimage_ext2.mli b/lib/diskimage_ext2.mli index df0c1fd..a5b8426 100644 --- a/lib/diskimage_ext2.mli +++ b/lib/diskimage_ext2.mli @@ -20,4 +20,4 @@ (**/**) val plugin_id : string -val probe : Diskimage_utils.device -> Diskimage_utils.filesystem +val callbacks : Diskimage_utils.fs_cb diff --git a/lib/diskimage_linux_swap.ml b/lib/diskimage_linux_swap.ml index b8c49e6..4933980 100644 --- a/lib/diskimage_linux_swap.ml +++ b/lib/diskimage_linux_swap.ml @@ -59,3 +59,13 @@ let probe dev = | { _ } -> raise Not_found (* Not Linux swapspace. *) + +(* Linux swap space is always 'free', apart from the superblock. + * Compare diskimage_linux_swsuspend.ml + *) +let offset_is_free _ offset = offset >= blocksize + +let callbacks = { + fs_cb_probe = probe; + fs_cb_offset_is_free = offset_is_free; +} diff --git a/lib/diskimage_linux_swap.mli b/lib/diskimage_linux_swap.mli index df0c1fd..a5b8426 100644 --- a/lib/diskimage_linux_swap.mli +++ b/lib/diskimage_linux_swap.mli @@ -20,4 +20,4 @@ (**/**) val plugin_id : string -val probe : Diskimage_utils.device -> Diskimage_utils.filesystem +val callbacks : Diskimage_utils.fs_cb diff --git a/lib/diskimage_linux_swsuspend.ml b/lib/diskimage_linux_swsuspend.ml index 5f29286..c1eeac8 100644 --- a/lib/diskimage_linux_swsuspend.ml +++ b/lib/diskimage_linux_swsuspend.ml @@ -59,3 +59,13 @@ let probe dev = | { _ } -> raise Not_found (* Not Linux software suspend. *) + +(* Linux software suspend image is never free. + * Compare diskimage_linux_swap.ml + *) +let offset_is_free _ _ = false + +let callbacks = { + fs_cb_probe = probe; + fs_cb_offset_is_free = offset_is_free; +} diff --git a/lib/diskimage_linux_swsuspend.mli b/lib/diskimage_linux_swsuspend.mli index df0c1fd..a5b8426 100644 --- a/lib/diskimage_linux_swsuspend.mli +++ b/lib/diskimage_linux_swsuspend.mli @@ -20,4 +20,4 @@ (**/**) val plugin_id : string -val probe : Diskimage_utils.device -> Diskimage_utils.filesystem +val callbacks : Diskimage_utils.fs_cb diff --git a/lib/diskimage_lvm2.ml b/lib/diskimage_lvm2.ml index 143f32b..632e879 100644 --- a/lib/diskimage_lvm2.ml +++ b/lib/diskimage_lvm2.ml @@ -181,7 +181,7 @@ and read_metadata dev offset len = * (as devices) and return them. Note that we don't try to detect * what is on these LVs - that will be done in the main code. *) -let rec list devs = +let rec list_lvs devs = (* Read the UUID and metadata (again) from each device to end up with * an assoc list of PVs, keyed on the UUID. *) @@ -447,3 +447,15 @@ let rec list devs = (* Return the list of LV devices. *) lvs + +(* XXX We don't currently have enough information in the PV + * structure to determine quickly which blocks are used. Need + * to store the parsed metadata in the structure ... + *) +let offset_is_free _ _ = false + +let callbacks = { + lvm_cb_probe = probe; + lvm_cb_list_lvs = list_lvs; + lvm_cb_offset_is_free = offset_is_free; +} diff --git a/lib/diskimage_lvm2.mli b/lib/diskimage_lvm2.mli index be84be6..1031b96 100644 --- a/lib/diskimage_lvm2.mli +++ b/lib/diskimage_lvm2.mli @@ -20,8 +20,4 @@ (**/**) val plugin_id : string - -val probe : - Diskimage_utils.lvm_plugin_id -> Diskimage_utils.device -> - Diskimage_utils.pv -val list : Diskimage_utils.device list -> Diskimage_utils.lv list +val callbacks : Diskimage_utils.lvm_cb diff --git a/lib/diskimage_mbr.ml b/lib/diskimage_mbr.ml index 34e4061..009ef72 100644 --- a/lib/diskimage_mbr.ml +++ b/lib/diskimage_mbr.ml @@ -184,3 +184,13 @@ and uint64_of_int32 u32 = if u32 >= 0l then i64 else Int64.add i64 0x1_0000_0000_L *) + +(* XXX We don't currently keep enough data in the parts structure + * to allow us to reconstruct missing partition table entries. + *) +let offset_is_free _ _ = false + +let callbacks = { + parts_cb_probe = probe; + parts_cb_offset_is_free = offset_is_free; +} diff --git a/lib/diskimage_mbr.mli b/lib/diskimage_mbr.mli index ebce91a..d64d3b7 100644 --- a/lib/diskimage_mbr.mli +++ b/lib/diskimage_mbr.mli @@ -20,4 +20,4 @@ (**/**) val plugin_id : string -val probe : Diskimage_utils.device -> Diskimage_utils.partitions +val callbacks : Diskimage_utils.parts_cb diff --git a/lib/diskimage_utils.ml b/lib/diskimage_utils.ml index 1a85f52..dc67e36 100644 --- a/lib/diskimage_utils.ml +++ b/lib/diskimage_utils.ml @@ -234,6 +234,22 @@ and parts_plugin_id = string and fs_plugin_id = string and lvm_plugin_id = string +type parts_cb = { + parts_cb_probe : device -> partitions; + parts_cb_offset_is_free : partitions -> Int63.t -> bool; +} + +type fs_cb = { + fs_cb_probe : device -> filesystem; + fs_cb_offset_is_free : filesystem -> Int63.t -> bool; +} + +type lvm_cb = { + lvm_cb_probe : lvm_plugin_id -> device -> pv; + lvm_cb_list_lvs : device list -> lv list; + lvm_cb_offset_is_free : pv -> Int63.t -> bool; +} + (* Convert a UUID (containing '-' chars) to canonical form. *) let canonical_uuid uuid = let uuid' = String.make 32 ' ' in diff --git a/lib/diskimage_utils.mli b/lib/diskimage_utils.mli index 9eccf64..07179d8 100644 --- a/lib/diskimage_utils.mli +++ b/lib/diskimage_utils.mli @@ -136,6 +136,24 @@ and parts_plugin_id = string and fs_plugin_id = string and lvm_plugin_id = string +(** {2 Table of callbacks from each type of plug-in} *) + +type parts_cb = { + parts_cb_probe : device -> partitions; + parts_cb_offset_is_free : partitions -> Int63.t -> bool; +} + +type fs_cb = { + fs_cb_probe : device -> filesystem; + fs_cb_offset_is_free : filesystem -> Int63.t -> bool; +} + +type lvm_cb = { + lvm_cb_probe : lvm_plugin_id -> device -> pv; + lvm_cb_list_lvs : device list -> lv list; + lvm_cb_offset_is_free : pv -> Int63.t -> bool; +} + (** {2 Internal functions used by the plug-ins} *) val canonical_uuid : string -> string -- 1.8.3.1