Store parsed superblock in private data.
authorRichard W.M. Jones <rjones@redhat.com>
Wed, 7 May 2008 11:07:21 +0000 (12:07 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Wed, 7 May 2008 11:07:21 +0000 (12:07 +0100)
lib/diskimage_ext2.ml

index 09c7c58..3ce0819 100644 (file)
@@ -31,11 +31,79 @@ let ( -* ) = Int32.sub
 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
 
@@ -91,19 +159,76 @@ let rec probe dev =
       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. *)
@@ -117,39 +242,42 @@ let rec probe dev =
    (* 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