upstream: https://github.com/mirage/ocaml-mbr
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(mbr,gpt): migrate MBR and GPT binary codecs to Wire.Codec

Replace hand-written get/set helpers and explicit offset constants with
type-safe Wire.Codec definitions for MBR partition entries (16 bytes),
GPT partition entries (128 bytes), and GPT headers (92 bytes). Add Wire
roundtrip tests for all three structures.

+76 -40
+1 -1
lib/dune
··· 1 1 (library 2 2 (public_name mbr) 3 3 (name mbr) 4 - (libraries bytesrw) 4 + (libraries bytesrw wire) 5 5 (modules mbr))
+37 -37
lib/mbr.ml
··· 161 161 else Error "partition parameters do not fit in int32" 162 162 163 163 let sizeof = 16 164 - let status_offset = 0 165 - let first_absolute_sector_chs_offset = 1 166 - let ty_offset = 4 167 - let last_absolute_sector_chs_offset = 5 168 - let first_absolute_sector_lba_offset = 8 169 - let sectors_offset = 12 164 + 165 + let codec = 166 + let open Wire.Codec in 167 + let decode_chs s = 168 + let heads = Char.code s.[0] in 169 + let y = Char.code s.[1] in 170 + let z = Char.code s.[2] in 171 + { Geometry.cylinders = (y lsl 2) lor z; heads; sectors = y land 0x3F } 172 + in 173 + record "MbrPartition" (fun status first_chs ty last_chs lba sectors -> 174 + { 175 + active = status = 0x80; 176 + first_absolute_sector_chs = decode_chs first_chs; 177 + ty; 178 + last_absolute_sector_chs = decode_chs last_chs; 179 + first_absolute_sector_lba = Int32.of_int (Wire.UInt32.to_int lba); 180 + sectors = Int32.of_int (Wire.UInt32.to_int sectors); 181 + }) 182 + |+ field "status" Wire.uint8 (fun t -> if t.active then 0x80 else 0) 183 + |+ field "first_chs" 184 + (Wire.byte_array ~size:(Wire.int 3)) 185 + (fun _ -> "\000\000\000") 186 + |+ field "type" Wire.uint8 (fun t -> t.ty) 187 + |+ field "last_chs" 188 + (Wire.byte_array ~size:(Wire.int 3)) 189 + (fun _ -> "\000\000\000") 190 + |+ field "lba_start" Wire.uint32 (fun t -> 191 + Wire.UInt32.of_int (Int32.to_int t.first_absolute_sector_lba)) 192 + |+ field "sectors" Wire.uint32 (fun t -> 193 + Wire.UInt32.of_int (Int32.to_int t.sectors)) 194 + |> seal 195 + 196 + let struct_ = Wire.Codec.to_struct codec 170 197 171 198 let unmarshal buf off = 172 199 let* () = ··· 177 204 sizeof) 178 205 else Ok () 179 206 in 180 - let ty = get_u8 buf (off + ty_offset) in 181 - if ty == 0x00 then 207 + let p = Wire.Codec.decode codec buf off in 208 + if p.ty = 0x00 then 182 209 if bytes_all_zero buf off sizeof then Ok None 183 210 else Error "Non-zero empty partition type" 184 - else 185 - let active = get_u8 buf (off + status_offset) = 0x80 in 186 - let* first_absolute_sector_chs = 187 - Geometry.unmarshal buf (off + first_absolute_sector_chs_offset) 188 - in 189 - let* last_absolute_sector_chs = 190 - Geometry.unmarshal buf (off + last_absolute_sector_chs_offset) 191 - in 192 - let first_absolute_sector_lba = 193 - get_u32_le buf (off + first_absolute_sector_lba_offset) 194 - in 195 - let sectors = get_u32_le buf (off + sectors_offset) in 196 - Ok 197 - (Some 198 - { 199 - active; 200 - first_absolute_sector_chs; 201 - ty; 202 - last_absolute_sector_chs; 203 - first_absolute_sector_lba; 204 - sectors; 205 - }) 211 + else Ok (Some p) 206 212 207 - let marshal (buf : bytes) off t = 208 - set_u8 buf (off + status_offset) (if t.active then 0x80 else 0); 209 - set_u8 buf (off + ty_offset) t.ty; 210 - set_u32_le buf 211 - (off + first_absolute_sector_lba_offset) 212 - t.first_absolute_sector_lba; 213 - set_u32_le buf (off + sectors_offset) t.sectors 213 + let marshal (buf : bytes) off t = Wire.Codec.encode codec t buf off 214 214 end 215 215 216 216 type t = {
+6
lib/mbr.mli
··· 68 68 [make ?active ~partition_type (Int64.to_int32 sector_start) 69 69 (Int64.to_int32 size_sectors)] when both [sector_start] and 70 70 [size_sectors] fit in int32. Otherwise [Error _]. *) 71 + 72 + val codec : t Wire.Codec.t 73 + (** Wire codec for a 16-byte MBR partition entry. *) 74 + 75 + val struct_ : Wire.struct_ 76 + (** Wire struct definition for a partition entry. *) 71 77 end 72 78 73 79 type t = private {
+1 -1
test/dune
··· 1 1 (test 2 2 (name test_mbr) 3 - (libraries mbr alcotest fmt)) 3 + (libraries mbr wire alcotest fmt))
+31 -1
test/test_mbr.ml
··· 118 118 ("make sorts partitions", `Quick, test_make_sorted); 119 119 ] 120 120 121 + let test_partition_wire_size () = 122 + Alcotest.(check int) 123 + "partition wire_size" 16 124 + (Wire.Codec.wire_size Mbr.Partition.codec) 125 + 126 + let test_partition_wire_roundtrip () = 127 + let p = 128 + get_ok 129 + (Mbr.Partition.make ~active:true ~partition_type:0x83 130 + Mbr.default_partition_start 204800l) 131 + in 132 + let buf = Bytes.create 16 in 133 + Wire.Codec.encode Mbr.Partition.codec p buf 0; 134 + let p' = Wire.Codec.decode Mbr.Partition.codec buf 0 in 135 + Alcotest.(check bool) "active" p.active p'.active; 136 + Alcotest.(check int) "ty" p.ty p'.ty; 137 + Alcotest.(check int32) 138 + "lba_start" p.first_absolute_sector_lba p'.first_absolute_sector_lba; 139 + Alcotest.(check int32) "sectors" p.sectors p'.sectors 140 + 141 + let suite_wire = 142 + [ 143 + ("Partition.codec wire_size = 16", `Quick, test_partition_wire_size); 144 + ("Partition wire roundtrip", `Quick, test_partition_wire_roundtrip); 145 + ] 146 + 121 147 let () = 122 148 Alcotest.run "Mbr" 123 - [ ("Mbr.Partition.make", suite_partition_make); ("Mbr.make", suite_make) ] 149 + [ 150 + ("Mbr.Partition.make", suite_partition_make); 151 + ("Mbr.make", suite_make); 152 + ("Wire", suite_wire); 153 + ]