Use tables of callbacks for the functions.
[virt-df.git] / lib / diskimage_ext2.ml
1 (* 'df' command for virtual domains.
2    (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
3    http://libvirt.org/
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19    Support for EXT2/EXT3 filesystems.
20 *)
21
22 open Unix
23 open Printf
24
25 open Diskimage_utils
26
27 open Int63.Operators
28
29 let ( +* ) = Int32.add
30 let ( -* ) = Int32.sub
31 let ( ** ) = Int32.mul
32 let ( /* ) = Int32.div
33
34 let plugin_id = "ext2"
35 let superblock_offset = ~^1024
36 let superblock_len = ~^1024
37
38 let probe dev =
39   (* Load the superblock. *)
40   let bits = dev#read_bitstring superblock_offset superblock_len in
41
42   (* The structure is straight from /usr/include/linux/ext3_fs.h *)
43   bitmatch bits with
44   | { s_inodes_count : 32 : littleendian;       (* Inodes count *)
45       s_blocks_count : 32 : littleendian;       (* Blocks count *)
46       s_r_blocks_count : 32 : littleendian;     (* Reserved blocks count *)
47       s_free_blocks_count : 32 : littleendian;  (* Free blocks count *)
48       s_free_inodes_count : 32 : littleendian;  (* Free inodes count *)
49       s_first_data_block : 32 : littleendian;   (* First Data Block *)
50       s_log_block_size : 32 : littleendian;     (* Block size *)
51       s_log_frag_size : 32 : littleendian;      (* Fragment size *)
52       s_blocks_per_group : 32 : littleendian;   (* # Blocks per group *)
53       s_frags_per_group : 32 : littleendian;    (* # Fragments per group *)
54       s_inodes_per_group : 32 : littleendian;   (* # Inodes per group *)
55       s_mtime : 32 : littleendian;              (* Mount time *)
56       s_wtime : 32 : littleendian;              (* Write time *)
57       s_mnt_count : 16 : littleendian;          (* Mount count *)
58       s_max_mnt_count : 16 : littleendian;      (* Maximal mount count *)
59       0xef53 : 16 : littleendian;               (* Magic signature *)
60       s_state : 16 : littleendian;              (* File system state *)
61       s_errors : 16 : littleendian;             (* Behaviour when detecting errors *)
62       s_minor_rev_level : 16 : littleendian;    (* minor revision level *)
63       s_lastcheck : 32 : littleendian;          (* time of last check *)
64       s_checkinterval : 32 : littleendian;      (* max. time between checks *)
65       s_creator_os : 32 : littleendian;         (* OS *)
66       s_rev_level : 32 : littleendian;          (* Revision level *)
67       s_def_resuid : 16 : littleendian;         (* Default uid for reserved blocks *)
68       s_def_resgid : 16 : littleendian;         (* Default gid for reserved blocks *)
69       s_first_ino : 32 : littleendian;          (* First non-reserved inode *)
70       s_inode_size : 16 : littleendian;         (* size of inode structure *)
71       s_block_group_nr : 16 : littleendian;     (* block group # of this superblock *)
72       s_feature_compat : 32 : littleendian;     (* compatible feature set *)
73       s_feature_incompat : 32 : littleendian;   (* incompatible feature set *)
74       s_feature_ro_compat : 32 : littleendian;  (* readonly-compatible feature set *)
75       s_uuid : 128 : string;                    (* 128-bit uuid for volume *)
76       s_volume_name : 128 : string;             (* volume name *)
77       s_last_mounted : 512 : string;            (* directory where last mounted *)
78       s_algorithm_usage_bitmap : 32 : littleendian; (* For compression *)
79       s_prealloc_blocks : 8;                    (* Nr of blocks to try to preallocate*)
80       s_prealloc_dir_blocks : 8;                (* Nr to preallocate for dirs *)
81       s_reserved_gdt_blocks : 16 : littleendian;(* Per group desc for online growth *)
82       s_journal_uuid : 128 : string;            (* uuid of journal superblock *)
83       s_journal_inum : 32 : littleendian;       (* inode number of journal file *)
84       s_journal_dev : 32 : littleendian;        (* device number of journal file *)
85       s_last_orphan : 32 : littleendian;        (* start of list of inodes to delete *)
86       s_hash_seed0 : 32 : littleendian;         (* HTREE hash seed *)
87       s_hash_seed1 : 32 : littleendian;
88       s_hash_seed2 : 32 : littleendian;
89       s_hash_seed3 : 32 : littleendian;
90       s_def_hash_version : 8;                   (* Default hash version to use *)
91       s_reserved_char_pad : 8;
92       s_reserved_word_pad : 16 : littleendian;
93       s_default_mount_opts : 32 : littleendian;
94       s_first_meta_bg : 32 : littleendian;      (* First metablock block group *)
95       _ : 6080 : bitstring } ->                 (* Padding to the end of the block *)
96
97    (* Work out the block size in bytes. *)
98    let s_log_block_size = Int32.to_int s_log_block_size in
99    let block_size = ~^1024 <^< s_log_block_size in
100
101    (* Number of groups. *)
102    let s_groups_count =
103      Int64.of_int32 (
104        (s_blocks_count -* s_first_data_block -* 1l)
105        /* s_blocks_per_group +* 1l
106      ) in
107
108 (*
109       (* Number of group descriptors per block. *)
110       let s_inodes_per_block = s_blocksize / 
111         let s_desc_per_block = block_size / s_inodes_per_block in
112         let db_count =
113           (s_groups_count +^ s_desc_per_block -^ 1L)
114           /^ s_desc_per_block
115 *)
116
117    (* Calculate the block overhead (used by superblocks, inodes, etc.)
118     * See fs/ext2/super.c.
119     *)
120    let overhead = Int63.of_int32 s_first_data_block in
121    let overhead = (* XXX *) overhead in
122
123    (* The blocksize of the filesystem is likely to be quite different
124     * from that of the underlying device, so create an overlay device
125     * with the natural filesystem blocksize.
126     *)
127    let fs_dev = new blocksize_overlay block_size dev in
128
129    {
130      fs_plugin_id = plugin_id;
131      fs_dev = fs_dev;
132
133      fs_blocksize = block_size;
134      fs_blocks_total = Int63.of_int32 s_blocks_count -^ overhead;
135
136      fs_is_swap = false;
137
138      fs_blocks_reserved = Int63.of_int32 s_r_blocks_count;
139      fs_blocks_avail = Int63.of_int32 s_free_blocks_count;
140      fs_blocks_used =
141        Int63.of_int32 s_blocks_count -^ overhead
142        -^ Int63.of_int32 s_free_blocks_count;
143      fs_inodes_total = Int63.of_int32 s_inodes_count;
144      fs_inodes_reserved = ~^0;  (* XXX? *)
145      fs_inodes_avail = Int63.of_int32 s_free_inodes_count;
146      fs_inodes_used = Int63.of_int32 s_inodes_count
147        (*-^ 0*)
148        -^ Int63.of_int32 s_free_inodes_count;
149    }
150
151   | { _ } ->
152       raise Not_found                   (* Not an EXT2/3 superblock. *)
153
154 let offset_is_free _ _ = false
155
156 let callbacks = {
157   fs_cb_probe = probe;
158   fs_cb_offset_is_free = offset_is_free;
159 }