let ( ** ) = Int32.mul
let ( /* ) = Int32.div
+(* The fields in an ext2/3 superblock. *)
+type ext2_sb = {
+ s_inodes_count : int32;
+ s_blocks_count : int32;
+ s_r_blocks_count : int32;
+ s_free_blocks_count : int32;
+ s_free_inodes_count : int32;
+ s_first_data_block : int32;
+ s_log_block_size : int32;
+ s_log_frag_size : int32;
+ s_blocks_per_group : int32;
+ s_frags_per_group : int32;
+ s_inodes_per_group : int32;
+ s_mtime : int32;
+ s_wtime : int32;
+ s_mnt_count : int;
+ s_max_mnt_count : int;
+ s_state : int;
+ s_errors : int;
+ s_minor_rev_level : int;
+ s_lastcheck : int32;
+ s_checkinterval : int32;
+ s_creator_os : int32;
+ s_rev_level : int32;
+ s_def_resuid : int;
+ s_def_resgid : int;
+ s_first_ino : int32;
+ s_inode_size : int;
+ s_block_group_nr : int;
+ s_feature_compat : int32;
+ s_feature_incompat : int32;
+ s_feature_ro_compat : int32;
+ s_uuid : string;
+ s_volume_name : string;
+ s_last_mounted : string;
+ s_algorithm_usage_bitmap : int32;
+ s_prealloc_blocks : int;
+ s_prealloc_dir_blocks : int;
+ s_reserved_gdt_blocks : int;
+ s_journal_uuid : string;
+ s_journal_inum : int32;
+ s_journal_dev : int32;
+ s_last_orphan : int32;
+ s_hash_seed0 : int32;
+ s_hash_seed1 : int32;
+ s_hash_seed2 : int32;
+ s_hash_seed3 : int32;
+ s_def_hash_version : int;
+ s_reserved_char_pad : int;
+ s_reserved_word_pad : int;
+ s_default_mount_opts : int32;
+ s_first_meta_bg : int32;
+
+ (* Computed fields, don't appear in superblock: *)
+ block_size : int63;
+ groups_count : int63;
+}
+
+(* Private data functions. *)
+let attach_private_data, get_private_data =
+ private_data_functions (fun {fs_cb = {fs_cb_uq = u}} -> u)
+
let id = "ext2"
let superblock_offset = ~^1024
let superblock_len = ~^1024
-let rec probe dev =
+(* Parse ext2/3 superblock and return a big structure containing
+ * all the fields. Also there are some extra fields which don't
+ * appear in the superblock itself, but are computed from other fields.
+ *
+ * If the device doesn't contain a superblock, raises Not_found.
+ *)
+let parse_ext2_sb dev =
(* Load the superblock. *)
let bits = dev#read_bitstring superblock_offset superblock_len in
s_reserved_char_pad : 8;
s_reserved_word_pad : 16 : littleendian;
s_default_mount_opts : 32 : littleendian;
- s_first_meta_bg : 32 : littleendian; (* First metablock block group *)
- _ : 6080 : bitstring } -> (* Padding to the end of the block *)
+ s_first_meta_bg : 32 : littleendian } -> (* First metablock block group *)
- (* Work out the block size in bytes. *)
- let s_log_block_size = Int32.to_int s_log_block_size in
- let block_size = ~^1024 <^< s_log_block_size in
+ (* Work out the block size in bytes. *)
+ let block_size = ~^1024 <^< Int32.to_int s_log_block_size in
- (* Number of groups. *)
- let s_groups_count =
- Int64.of_int32 (
- (s_blocks_count -* s_first_data_block -* 1l)
- /* s_blocks_per_group +* 1l
- ) in
+ (* Number of groups. *)
+ let groups_count =
+ Int63.of_int32 (
+ (s_blocks_count -* s_first_data_block -* 1l)
+ /* s_blocks_per_group +* 1l
+ ) in
+
+ { s_inodes_count = s_inodes_count;
+ s_blocks_count = s_blocks_count;
+ s_r_blocks_count = s_r_blocks_count;
+ s_free_blocks_count = s_free_blocks_count;
+ s_free_inodes_count = s_free_inodes_count;
+ s_first_data_block = s_first_data_block;
+ s_log_block_size = s_log_block_size;
+ s_log_frag_size = s_log_frag_size;
+ s_blocks_per_group = s_blocks_per_group;
+ s_frags_per_group = s_frags_per_group;
+ s_inodes_per_group = s_inodes_per_group;
+ s_mtime = s_mtime;
+ s_wtime = s_wtime;
+ s_mnt_count = s_mnt_count;
+ s_max_mnt_count = s_max_mnt_count;
+ s_state = s_state;
+ s_errors = s_errors;
+ s_minor_rev_level = s_minor_rev_level;
+ s_lastcheck = s_lastcheck;
+ s_checkinterval = s_checkinterval;
+ s_creator_os = s_creator_os;
+ s_rev_level = s_rev_level;
+ s_def_resuid = s_def_resuid;
+ s_def_resgid = s_def_resgid;
+ s_first_ino = s_first_ino;
+ s_inode_size = s_inode_size;
+ s_block_group_nr = s_block_group_nr;
+ s_feature_compat = s_feature_compat;
+ s_feature_incompat = s_feature_incompat;
+ s_feature_ro_compat = s_feature_ro_compat;
+ s_uuid = s_uuid;
+ s_volume_name = s_volume_name;
+ s_last_mounted = s_last_mounted;
+ s_algorithm_usage_bitmap = s_algorithm_usage_bitmap;
+ s_prealloc_blocks = s_prealloc_blocks;
+ s_prealloc_dir_blocks = s_prealloc_dir_blocks;
+ s_reserved_gdt_blocks = s_reserved_gdt_blocks;
+ s_journal_uuid = s_journal_uuid;
+ s_journal_inum = s_journal_inum;
+ s_journal_dev = s_journal_dev;
+ s_last_orphan = s_last_orphan;
+ s_hash_seed0 = s_hash_seed0;
+ s_hash_seed1 = s_hash_seed1;
+ s_hash_seed2 = s_hash_seed2;
+ s_hash_seed3 = s_hash_seed3;
+ s_def_hash_version = s_def_hash_version;
+ s_reserved_char_pad = s_reserved_char_pad;
+ s_reserved_word_pad = s_reserved_word_pad;
+ s_default_mount_opts = s_default_mount_opts;
+ s_first_meta_bg = s_first_meta_bg;
+ block_size = block_size;
+ groups_count = groups_count }
+
+ | { _ } ->
+ raise Not_found (* Not an EXT2/3 superblock. *)
+
+let rec probe dev =
+ let sb = parse_ext2_sb dev in (* May raise Not_found. *)
(*
(* Number of group descriptors per block. *)
(* Calculate the block overhead (used by superblocks, inodes, etc.)
* See fs/ext2/super.c.
*)
- let overhead = Int63.of_int32 s_first_data_block in
+ let overhead = Int63.of_int32 sb.s_first_data_block in
let overhead = (* XXX *) overhead in
(* The blocksize of the filesystem is likely to be quite different
* from that of the underlying device, so create an overlay device
* with the natural filesystem blocksize.
*)
- let fs_dev = new blocksize_overlay block_size dev in
+ let fs_dev = new blocksize_overlay sb.block_size dev in
- {
+ let fs = {
fs_cb = callbacks ();
fs_dev = fs_dev;
- fs_blocksize = block_size;
- fs_blocks_total = Int63.of_int32 s_blocks_count -^ overhead;
+ fs_blocksize = sb.block_size;
+ fs_blocks_total = Int63.of_int32 sb.s_blocks_count -^ overhead;
fs_is_swap = false;
- fs_blocks_reserved = Int63.of_int32 s_r_blocks_count;
- fs_blocks_avail = Int63.of_int32 s_free_blocks_count;
+ fs_blocks_reserved = Int63.of_int32 sb.s_r_blocks_count;
+ fs_blocks_avail = Int63.of_int32 sb.s_free_blocks_count;
fs_blocks_used =
- Int63.of_int32 s_blocks_count -^ overhead
- -^ Int63.of_int32 s_free_blocks_count;
- fs_inodes_total = Int63.of_int32 s_inodes_count;
+ Int63.of_int32 sb.s_blocks_count -^ overhead
+ -^ Int63.of_int32 sb.s_free_blocks_count;
+ fs_inodes_total = Int63.of_int32 sb.s_inodes_count;
fs_inodes_reserved = ~^0; (* XXX? *)
- fs_inodes_avail = Int63.of_int32 s_free_inodes_count;
- fs_inodes_used = Int63.of_int32 s_inodes_count
+ fs_inodes_avail = Int63.of_int32 sb.s_free_inodes_count;
+ fs_inodes_used = Int63.of_int32 sb.s_inodes_count
(*-^ 0*)
- -^ Int63.of_int32 s_free_inodes_count;
- }
+ -^ Int63.of_int32 sb.s_free_inodes_count;
+ } in
- | { _ } ->
- raise Not_found (* Not an EXT2/3 superblock. *)
+ (* Attach the original superblock as private data so we can
+ * get to it quickly in other callbacks.
+ *)
+ attach_private_data fs sb;
+ fs
and offset_is_free _ _ = false