+ method virtual blocksize : int63
+ method virtual map_block : int63 -> (device * int63) list
+ method virtual contiguous : Int63.t -> Int63.t
+
+ (* Block-based read. Inefficient so normally overridden in subclasses. *)
+ method read offset len =
+ if offset < ~^0 || len < ~^0 then
+ invalid_arg "device: read: negative offset or length";
+
+ let blocksize = self#blocksize in
+
+ (* Break the request into blocks.
+ * Find the first and last blocks of this request.
+ *)
+ let first_blk = offset /^ blocksize in
+ let offset_in_first_blk = offset -^ first_blk *^ blocksize in
+ let last_blk = (offset +^ len -^ ~^1) /^ blocksize in
+
+ (* Buffer for the result. *)
+ let buf = Buffer.create (Int63.to_int len) in
+
+ let not_mapped_error () = invalid_arg "device: read: block not mapped" in
+
+ (* Copy the first block (partial). *)
+ (match self#map_block first_blk with
+ | [] -> not_mapped_error ()
+ | (dev, base) :: _ ->
+ let len =
+ min len (blocksize -^ offset_in_first_blk) in
+ let str = dev#read (base +^ offset_in_first_blk) len in
+ Buffer.add_string buf str
+ );