Updated MANIFEST
[virt-df.git] / lib / diskimage_ext2.ml
index 2226255..994ae34 100644 (file)
@@ -2,19 +2,20 @@
    (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
    http://libvirt.org/
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version,
+   with the OCaml linking exception described in ../COPYING.LIB.
 
-   This program is distributed in the hope that it will be useful,
+   This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 
    Support for EXT2/EXT3 filesystems.
 *)
 open Unix
 open Printf
 
-open Diskimage_utils
+open Diskimage_impl
 
-let plugin_id = "ext2"
-let superblock_offset = 1024L
+open Int63.Operators
 
-let probe dev =
+let ( +* ) = Int32.add
+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
+
+(* 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 1024 in
+  let bits = dev#read_bitstring superblock_offset superblock_len in
 
   (* The structure is straight from /usr/include/linux/ext3_fs.h *)
   bitmatch bits with
@@ -83,20 +160,76 @@ let 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 block_size = ~^1024 <^< Int32.to_int s_log_block_size 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 }
 
-   (* Work out the block size in bytes. *)
-   let s_log_block_size = Int32.to_int s_log_block_size in
-   let block_size = 1024L in
-   let block_size = Int64.shift_left block_size s_log_block_size in
+  | { _ } ->
+      raise Not_found                  (* Not an EXT2/3 superblock. *)
 
-   (* Number of groups. *)
-   let s_groups_count =
-     Int64.of_int32 (
-       (s_blocks_count -* s_first_data_block -* 1l)
-       /* s_blocks_per_group +* 1l
-     ) in
+let rec probe dev =
+  let sb = parse_ext2_sb dev in                (* May raise Not_found. *)
 
 (*
       (* Number of group descriptors per block. *)
@@ -110,36 +243,53 @@ let probe dev =
    (* Calculate the block overhead (used by superblocks, inodes, etc.)
     * See fs/ext2/super.c.
     *)
-   let overhead = Int64.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 (Int64.to_int block_size) dev in
+   let fs_dev = new blocksize_overlay sb.block_size dev in
 
-   {
-     fs_plugin_id = plugin_id;
+   let fs = {
+     fs_cb = callbacks ();
      fs_dev = fs_dev;
 
-     fs_blocksize = Int64.to_int block_size;
-     fs_blocks_total = Int64.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 = Int64.of_int32 s_r_blocks_count;
-     fs_blocks_avail = Int64.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 =
-       Int64.of_int32 s_blocks_count -^ overhead
-       -^ Int64.of_int32 s_free_blocks_count;
-     fs_inodes_total = Int64.of_int32 s_inodes_count;
-     fs_inodes_reserved = 0L;  (* XXX? *)
-     fs_inodes_avail = Int64.of_int32 s_free_inodes_count;
-     fs_inodes_used = Int64.of_int32 s_inodes_count
-       (*-^ 0L*)
-       -^ Int64.of_int32 s_free_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 sb.s_free_inodes_count;
+     fs_inodes_used = Int63.of_int32 sb.s_inodes_count
+       (*-^ 0*)
+       -^ 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
+
+and callbacks =
+  let i = ref 0 in
+  fun () -> {
+    fs_cb_uq = (incr i; !i);
+    fs_cb_name = id;
+    fs_cb_printable_name = "Linux ext2/3";
+    fs_cb_offset_is_free = offset_is_free;
+  }
+
+(* Register the plugin. *)
+let () = register_plugin ~filesystem:probe id