object
method virtual name : string
(** Return some printable name for the device. *)
- method virtual size : int64
+
+ method virtual size : Int63.t
(** Return the size of the device in bytes.
Note: For some types of devices, the device may have
"holes", alignment requirements, etc. so this method doesn't
imply that every byte from [0..size-1] is readable. *)
- method read : int64 -> int -> string
+ method read : Int63.t -> Int63.t -> string
(** [read offset len] reads len bytes starting at offset.
Note: A default implementation is provided for [read],
- but it is fairly inefficient because it uses {!mapblock} to
+ but it is fairly inefficient because it uses {!map_block} to
map each block in the request. *)
- method read_bitstring : int64 -> int -> Bitmatch.bitstring
+ method read_bitstring : Int63.t -> Int63.t -> Bitmatch.bitstring
(** [read_bitstring] is the same as [read] but returns
a pa_bitmatch-style bitstring. *)
- method virtual blocksize : int
+
+ method virtual blocksize : Int63.t
(** [blocksize] returns the natural block size of the device. *)
- method virtual mapblock : int64 -> (device * int64) list
- (** [mapblock] describes how a block in this device is
+ method virtual map_block : Int63.t -> (device * Int63.t) list
+ (** [map_block] describes how a block in this device is
mapped down to any underlying device(s).
Returns [[]] (empty list) if there is no underlying
Normally the returned list has length 1, but in cases
such as mirroring you can have the same block mapped
to several underlying devices. *)
+
+ method virtual contiguous : Int63.t -> Int63.t
+ (** [contiguous offset] returns the number of contiguous
+ {i bytes} starting at byte [offset] on this device,
+ before (eg.) end of device or some discontinuity in
+ the mapping table occurs.
+
+ This method and {!map_block} allow callers to determine how
+ high level blocks map to low level disk images efficiently
+ (complex striping and interleaving patterns can make the
+ process much less efficient however). *)
end
(**
A virtual (or physical!) device, encapsulating any translation
that has to be done to access the device. eg. For partitions
there is a simple offset, but for LVM you may need complicated
table lookups.
-
+
Note this very rare use of OOP in OCaml!
*)
-class block_device : string -> int ->
+class block_device : string -> Int63.t ->
object
method name : string
- method size : int64
- method read : int64 -> int -> string
- method read_bitstring : int64 -> int -> Bitmatch.bitstring
- method blocksize : int
- method mapblock : int64 -> (device * int64) list
+ method size : Int63.t
+ method read : Int63.t -> Int63.t -> string
+ method read_bitstring : Int63.t -> Int63.t -> Bitmatch.bitstring
+ method blocksize : Int63.t
+ method map_block : Int63.t -> (device * Int63.t) list
+ method contiguous : Int63.t -> Int63.t
method close : unit -> unit
(** Close the device, freeing up the file descriptor. *)
end
where [filename] is the path to the file or device and
[blocksize] is the blocksize of the device. *)
-class offset_device : string -> int64 -> int64 -> int -> device ->
+class offset_device : string -> Int63.t -> Int63.t -> Int63.t -> device ->
object
method name : string
- method size : int64
- method read : int64 -> int -> string
- method read_bitstring : int64 -> int -> Bitmatch.bitstring
- method blocksize : int
- method mapblock : int64 -> (device * int64) list
+ method size : Int63.t
+ method read : Int63.t -> Int63.t -> string
+ method read_bitstring : Int63.t -> Int63.t -> Bitmatch.bitstring
+ method blocksize : Int63.t
+ method map_block : Int63.t -> (device * Int63.t) list
+ method contiguous : Int63.t -> Int63.t
end
(** A concrete device which maps a linear part of an underlying device.
Useful for things like partitions.
*)
+class blocksize_overlay : Int63.t -> device ->
+ object
+ method name : string
+ method size : Int63.t
+ method read : Int63.t -> Int63.t -> string
+ method read_bitstring : Int63.t -> Int63.t -> Bitmatch.bitstring
+ method blocksize : Int63.t
+ method contiguous : Int63.t -> Int63.t
+ method map_block : Int63.t -> (device * Int63.t) list
+ end
+ (** Change the blocksize of an existing device. *)
+
val null_device : device
(** The null device. Any attempt to read generates an error. *)
]
and partitions = {
- parts_plugin_id : parts_plugin_id; (** Partitioning scheme. *)
+ parts_cb : partitioner_callbacks; (** Partitioning scheme. *)
+ parts_dev : device; (** Partitions (whole) device. *)
parts : partition list; (** Partitions. *)
}
and partition = {
]
and filesystem = {
+ fs_cb : filesystem_callbacks; (** Filesystem type. *)
fs_dev : device; (** Device containing the filesystem. *)
- fs_plugin_id : fs_plugin_id; (** Filesystem type. *)
- fs_block_size : int64; (** Block size (bytes). *)
- fs_blocks_total : int64; (** Total blocks. *)
+ fs_blocksize : Int63.t; (** Block size (bytes). *)
+ fs_blocks_total : Int63.t; (** Total blocks. *)
fs_is_swap : bool; (** If swap, following not valid. *)
- fs_blocks_reserved : int64; (** Blocks reserved for super-user. *)
- fs_blocks_avail : int64; (** Blocks free (available). *)
- fs_blocks_used : int64; (** Blocks in use. *)
- fs_inodes_total : int64; (** Total inodes. *)
- fs_inodes_reserved : int64; (** Inodes reserved for super-user. *)
- fs_inodes_avail : int64; (** Inodes free (available). *)
- fs_inodes_used : int64; (** Inodes in use. *)
+ fs_blocks_reserved : Int63.t; (** Blocks reserved for super-user. *)
+ fs_blocks_avail : Int63.t; (** Blocks free (available). *)
+ fs_blocks_used : Int63.t; (** Blocks in use. *)
+ fs_inodes_total : Int63.t; (** Total inodes. *)
+ fs_inodes_reserved : Int63.t; (** Inodes reserved for super-user. *)
+ fs_inodes_avail : Int63.t; (** Inodes free (available). *)
+ fs_inodes_used : Int63.t; (** Inodes in use. *)
}
(** A filesystem, with superblock contents. *)
and pv = {
- lvm_plugin_id : lvm_plugin_id; (** The LVM plug-in which detected
+ pv_cb : lvm_callbacks; (** The LVM plug-in which detected
this. *)
+ pv_dev : device; (** Device covering whole PV. *)
pv_uuid : string; (** UUID. *)
}
and lv = {
}
(** Physical and logical volumes as used by LVM plug-ins. *)
-and parts_plugin_id
-and fs_plugin_id
-and lvm_plugin_id
- (** Opaque IDs used to refer to the plug-ins. *)
+and partitioner_callbacks
+and filesystem_callbacks
+and lvm_callbacks
+
+(** {2 Functions} *)
-val name_of_parts : parts_plugin_id -> string
-val name_of_filesystem : fs_plugin_id -> string
-val name_of_lvm : lvm_plugin_id -> string
- (** Convert plug-in IDs to printable strings. *)
+val name_of_filesystem : filesystem -> string
+ (** [name_of_filesystem fs] returns a printable name for
+ the filesystem.
+ *)
-(** {2 Scanning functions} *)
+(** {3 Create 'machine'} *)
val open_machine : string -> (string * string) list -> machine
(** [open_machine m_name devs]
opened by these devices.
*)
+(** {3 Scanning for filesystems} *)
+
val scan_machine : machine -> machine
(** This does a complete scan of all devices owned by a machine,
identifying all partitions, filesystems, physical and logical
Returns an updated {!machine} structure with the scan results.
*)
+(** {3 Create ownership tables} *)
+
+type ownership
+
+val create_ownership : machine -> ownership
+ (** This creates the ownership tables (mapping disk blocks to the
+ ultimate filesystem, etc., which owns each one).
+ *)
+
+type owner =
+ [ `Filesystem of filesystem
+ | `Partitions of partitions
+ | `PhysicalVolume of pv ]
+
+val get_owners_lookup : machine -> ownership -> block_device ->
+ (Int63.t -> (owner * Int63.t) list)
+ (** [get_owners_lookup machine disk] returns a specialized
+ function for looking up owners (filesystems, etc.)
+ which reside on block device [disk].
+
+ [disk] must be a block device of the machine.
+
+ The specialized lookup function that is returned
+ can be called as [lookup offset] to look up the
+ owners of byte offset [offset].
+
+ Returns a list of [(owner, owner_offset)] where [owner]
+ is the filesystem, etc., and [owner_offset] is the byte
+ offset relative to the owner.
+
+ It is common for there to be multiple owners: for example
+ in the case where a filesystem is created on a partition,
+ both the filesystem ([`Filesystem fs]) and
+ partition scheme ([`Partitions parts]) will be returned.
+
+ The specialized function is efficient. {!create_ownership}
+ 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