(* 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.
*
| part -> []
) primaries in
let extendeds = List.concat extendeds in
- primaries @ extendeds
*)
- { parts_cb = callbacks; parts_dev = dev; 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 *)
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 = Int63.of_int32 first_lba in
- let part_size = Int63.of_int32 part_size in
- (*
- XXX Used to be:
- let first_lba = uint63_of_int32 first_lba in
- let part_size = uint63_of_int32 part_size in
- *)
- if !debug then
- eprintf "make_mbr_entry: first_lba = %s part_size = %s\n%!"
- (Int63.to_string first_lba) (Int63.to_string 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 ...
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.
- *)
-and offset_is_free _ _ = false
+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 = {
- parts_cb_name = id;
- parts_cb_offset_is_free = offset_is_free;
-}
+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