X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;ds=sidebyside;f=lib%2Fdiskimage_mbr.ml;h=8e1c5c05c304cc7d546a3e6a76b0c792f026c7d0;hb=2e218847fac3e2e7b698ae6cc6fe1a6f3b462431;hp=07f9df8a999918bbf1faa07b28327e3aad121745;hpb=4cb1be48118971ebe749c4030f871aa25d26c520;p=virt-df.git diff --git a/lib/diskimage_mbr.ml b/lib/diskimage_mbr.ml index 07f9df8..8e1c5c0 100644 --- a/lib/diskimage_mbr.ml +++ b/lib/diskimage_mbr.ml @@ -24,16 +24,27 @@ open Printf open Unix open ExtList -open Diskimage_utils +open Diskimage_impl -let plugin_id = "mbr" +open Int63.Operators -let sector_size = 512 -let sector_size64 = 512L +let id = "mbr" + +let sector_size = ~^512 (* Maximum number of extended partitions possible. *) let max_extended_partitions = 100 +(* The private data attached to a partitions structure. *) +type private_t = mbr_part list (* list of partitions that we found *) +and mbr_part = { + mbr_part_start : int63; (* start of partition in bytes *) + mbr_part_size : int63; (* size of partition in bytes *) +} + +let attach_private_data, get_private_data = + private_data_functions (fun {parts_cb = {parts_cb_uq = u}} -> u) + (* Device representing a single partition. It just acts as an offset * into the underlying device. * @@ -47,8 +58,8 @@ let max_extended_partitions = 100 class partition_device partno start size dev = let devname = dev#name in let name = sprintf "%s%d" devname partno in - let start = start *^ sector_size64 in - let size = size *^ sector_size64 in + let start = start *^ sector_size in + let size = size *^ sector_size in object (self) inherit offset_device name start size sector_size dev end @@ -62,7 +73,7 @@ end let rec probe dev = (* Read the first sector. *) let bits = - try dev#read_bitstring 0L sector_size + try dev#read_bitstring ~^0 sector_size with exn -> raise Not_found in (* Does this match a likely-looking MBR? *) @@ -88,9 +99,15 @@ let rec probe dev = | part -> [] ) primaries in let extendeds = List.concat extendeds in - primaries @ extendeds *) - { parts_plugin_id = plugin_id; parts = primaries } + + let parts = primaries (* @ extendeds *) in + let privs = List.concat (List.map snd parts) in + let parts = List.map fst parts in + + let r = { parts_cb = callbacks (); parts_dev = dev; parts = parts } in + attach_private_data r privs; + r | { _ } -> raise Not_found (* not an MBR *) @@ -102,29 +119,40 @@ and parse_mbr_entry dev i bits = bitmatch bits with | { 0l : 32; 0l : 32; 0l : 32; 0l : 32 } -> { part_status = NullEntry; part_type = 0; - part_dev = null_device; part_content = `Unknown } + part_dev = null_device; part_content = `Unknown }, [] | { ((0|0x80) as bootable) : 8; first_chs : 24; part_type : 8; last_chs : 24; first_lba : 32 : unsigned, littleendian; part_size : 32 : unsigned, littleendian } -> + let bootable = if bootable = 0 then Nonbootable else Bootable in - make_mbr_entry bootable dev (i+1) part_type first_lba part_size + let first_lba = Int63.of_int32 first_lba in + let part_size = Int63.of_int32 part_size in + let partno = i+1 in + + if !debug then + eprintf "parse_mbr_entry: first_lba = %s part_size = %s\n%!" + (Int63.to_string first_lba) (Int63.to_string part_size); + + let part = { + part_status = bootable; + part_type = part_type; + part_dev = new partition_device partno first_lba part_size dev; + part_content = `Unknown; + } in + + (* Extra private data which we'll use to calculate free offsets. *) + let priv = { + mbr_part_start = first_lba *^ sector_size; + mbr_part_size = part_size *^ sector_size; + } in + + part, [priv] | { _ } -> { part_status = Malformed; part_type = 0; - part_dev = null_device; part_content = `Unknown } - -and make_mbr_entry part_status dev partno part_type first_lba part_size = - let first_lba = uint64_of_int32 first_lba in - let part_size = uint64_of_int32 part_size in - if !debug then - eprintf "make_mbr_entry: first_lba = %Lx part_size = %Lx\n%!" - first_lba part_size; - { part_status = part_status; - part_type = part_type; - part_dev = new partition_device partno first_lba part_size dev; - part_content = `Unknown } + part_dev = null_device; part_content = `Unknown }, [] (* This code worked previously, but now needs some love ... @@ -169,6 +197,7 @@ and probe_extended_partition max fd epart sect = else [] *) +(* (* Ugh, fake a UInt32 -> UInt64 conversion without sign extension, until * we get working UInt32/UInt64 modules in extlib. *) @@ -176,3 +205,41 @@ and uint64_of_int32 u32 = let i64 = Int64.of_int32 u32 in if u32 >= 0l then i64 else Int64.add i64 0x1_0000_0000_L +*) + +and offset_is_free parts offset = + let privs = get_private_data parts in + + (* The first partition is somehow privileged in that we assume + * everything before this is not free. Usually this is the first + * 63 sectors containing the MBR itself and sectors which should + * be blank but in reality contain all sorts of stupid hacks like + * alternate partitioning schemes. + *) + match privs with + | [] -> false + | { mbr_part_start = start; mbr_part_size = size } :: rest -> + if offset < start +^ size then + false + else ( + let rec loop = function + | [] -> true (* not in a partition, must be free *) + | { mbr_part_start = start; mbr_part_size = size } :: rest -> + if start <= offset && offset < start +^ size then + false + else + loop rest + in + loop rest + ) + +and callbacks = + let i = ref 0 in + fun () -> { + parts_cb_uq = (incr i; !i); + parts_cb_name = id; + parts_cb_offset_is_free = offset_is_free; + } + +(* Register the plugin. *) +let () = register_plugin ~partitioner:probe id