Fixed byte swaps so that now ext3 superblock can be parsed.
authorRichard W.M. Jones <rich@annexia.org>
Tue, 1 Apr 2008 19:10:45 +0000 (19:10 +0000)
committerRichard W.M. Jones <rich@annexia.org>
Tue, 1 Apr 2008 19:10:45 +0000 (19:10 +0000)
bitmatch.ml
bitmatch.mli
pa_bitmatch.ml
tests/.cvsignore
tests/70_ext3_sb.ml [new file with mode: 0644]
tests/ext3_sb [new file with mode: 0644]

index 0c9edc0..2cba403 100644 (file)
@@ -1,5 +1,5 @@
 (* Bitmatch library.
- * $Id: bitmatch.ml,v 1.5 2008-04-01 17:05:37 rjones Exp $
+ * $Id: bitmatch.ml,v 1.6 2008-04-01 19:10:45 rjones Exp $
  *)
 
 open Printf
@@ -44,6 +44,101 @@ let bitstring_of_file fname =
 let bitstring_length (_, _, len) = len
 
 (*----------------------------------------------------------------------*)
+(* Bitwise functions.
+ *
+ * We try to isolate all bitwise functions within these modules.
+ *)
+
+module I = struct
+  (* Bitwise operations on ints.  Note that we assume int <= 31 bits. *)
+  let (<<) = (lsl)
+  let (>>) = (lsr)
+  let one = 1
+  let minus_one = -1
+  let ff = 0xff
+
+  (* Create a mask so many bits wide. *)
+  let mask bits =
+    if bits < 30 then
+      pred (one << bits)
+    else if bits = 30 then
+      max_int
+    else
+      minus_one
+
+  (* Byte swap an int of a given size. *)
+  let byteswap v bits =
+    if bits <= 8 then v
+    else if bits <= 16 then (
+      let shift = bits-8 in
+      let v1 = v >> shift in
+      let v2 = (v land (mask shift)) << 8 in
+      v2 lor v1
+    ) else if bits <= 24 then (
+      let shift = bits - 16 in
+      let v1 = v >> (8+shift) in
+      let v2 = ((v >> shift) land ff) << 8 in
+      let v3 = (v land (mask shift)) << 16 in
+      v3 lor v2 lor v1
+    ) else (
+      let shift = bits - 24 in
+      let v1 = v >> (16+shift) in
+      let v2 = ((v >> (8+shift)) land ff) << 8 in
+      let v3 = ((v >> shift) land ff) << 16 in
+      let v4 = (v land (mask shift)) << 24 in
+      v4 lor v3 lor v2 lor v1
+    )
+end
+
+module I32 = struct
+  (* Bitwise operations on int32s.  Note we try to keep it as similar
+   * as possible to the I module above, to make it easier to track
+   * down bugs.
+   *)
+  let (<<) = Int32.shift_left
+  let (>>) = Int32.shift_right_logical
+  let (land) = Int32.logand
+  let (lor) = Int32.logor
+  let pred = Int32.pred
+  let max_int = Int32.max_int
+  let one = Int32.one
+  let minus_one = Int32.minus_one
+  let ff = 0xff_l
+
+  (* Create a mask so many bits wide. *)
+  let mask bits =
+    if bits < 31 then
+      pred (one << bits)
+    else if bits = 31 then
+      max_int
+    else
+      minus_one
+
+  (* Byte swap an int of a given size. *)
+  let byteswap v bits =
+    if bits <= 8 then v
+    else if bits <= 16 then (
+      let shift = bits-8 in
+      let v1 = v >> shift in
+      let v2 = (v land (mask shift)) << 8 in
+      v2 lor v1
+    ) else if bits <= 24 then (
+      let shift = bits - 16 in
+      let v1 = v >> (8+shift) in
+      let v2 = ((v >> shift) land ff) << 8 in
+      let v3 = (v land (mask shift)) << 16 in
+      v3 lor v2 lor v1
+    ) else (
+      let shift = bits - 24 in
+      let v1 = v >> (16+shift) in
+      let v2 = ((v >> (8+shift)) land ff) << 8 in
+      let v3 = ((v >> shift) land ff) << 16 in
+      let v4 = (v land (mask shift)) << 24 in
+      v4 lor v3 lor v2 lor v1
+    )
+end
+
+(*----------------------------------------------------------------------*)
 (* Extraction functions.
  *
  * NB: internal functions, called from the generated macros, and
@@ -146,6 +241,11 @@ let extract_int_be_unsigned data off len flen =
     ) in
   word, off+flen, len-flen
 
+let extract_int_le_unsigned data off len flen =
+  let v, off, len = extract_int_be_unsigned data off len flen in
+  let v = I.byteswap v flen in
+  v, off, len
+
 let _make_int32_be c0 c1 c2 c3 =
   Int32.logor
     (Int32.logor
@@ -155,6 +255,15 @@ let _make_int32_be c0 c1 c2 c3 =
        (Int32.shift_left c2 8))
     c3
 
+let _make_int32_le c0 c1 c2 c3 =
+  Int32.logor
+    (Int32.logor
+       (Int32.logor
+         (Int32.shift_left c3 24)
+         (Int32.shift_left c2 16))
+       (Int32.shift_left c1 8))
+    c0
+
 (* Extract exactly 32 bits.  We have to consider endianness and signedness. *)
 let extract_int32_be_unsigned data off len flen =
   let byteoff = off lsr 3 in
@@ -187,6 +296,11 @@ let extract_int32_be_unsigned data off len flen =
     ) in
   word, off+flen, len-flen
 
+let extract_int32_le_unsigned data off len flen =
+  let v, off, len = extract_int32_be_unsigned data off len flen in
+  let v = I32.byteswap v flen in
+  v, off, len
+
 let _make_int64_be c0 c1 c2 c3 c4 c5 c6 c7 =
   Int64.logor
     (Int64.logor
@@ -426,6 +540,6 @@ let hexdump_bitstring chan (data, off, len) =
   if !linelen > 0 then (
     let skip = (16 - !linelen) * 3 + if !linelen < 8 then 1 else 0 in
     for i = 0 to skip-1 do fprintf chan " " done;
-    fprintf chan " |%s|\n" linechars
+    fprintf chan " |%s|\n%!" linechars
   ) else
-    fprintf chan "\n"
+    fprintf chan "\n%!"
index d2afc30..7ed9e63 100644 (file)
@@ -1,5 +1,5 @@
 (* Bitmatch library.
- * $Id: bitmatch.mli,v 1.5 2008-04-01 17:05:37 rjones Exp $
+ * $Id: bitmatch.mli,v 1.6 2008-04-01 19:10:45 rjones Exp $
  *)
 
 exception Construct_failure of string * string * int * int
@@ -46,8 +46,12 @@ val extract_char_unsigned : string -> int -> int -> int -> int * int * int
 
 val extract_int_be_unsigned : string -> int -> int -> int -> int * int * int
 
+val extract_int_le_unsigned : string -> int -> int -> int -> int * int * int
+
 val extract_int32_be_unsigned : string -> int -> int -> int -> int32 * int * int
 
+val extract_int32_le_unsigned : string -> int -> int -> int -> int32 * int * int
+
 val extract_int64_be_unsigned : string -> int -> int -> int -> int64 * int * int
 
 val construct_bit : Buffer.t -> bool -> int -> unit
index f25a49d..6673a21 100644 (file)
@@ -1,5 +1,5 @@
 (* Bitmatch syntax extension.
- * $Id: pa_bitmatch.ml,v 1.4 2008-04-01 17:05:37 rjones Exp $
+ * $Id: pa_bitmatch.ml,v 1.5 2008-04-01 19:10:45 rjones Exp $
  *)
 
 open Printf
@@ -551,6 +551,8 @@ let output_bitmatch _loc bs cases =
                Printf.eprintf "PA_BITMATCH: TEST:\n";
                Printf.eprintf "  %s\n" $str:field$;
                Printf.eprintf "  off %d len %d\n%!" $lid:off$ $lid:len$;
+               (*Bitmatch.hexdump_bitstring stderr
+                 ($lid:data$,$lid:off$,$lid:len$);*)
              );
              $expr$
            >>
index b4fbc01..8ca81f0 100644 (file)
@@ -12,3 +12,4 @@
 10_constr1
 20_varsize
 60_ping
+70_ext3_sb
diff --git a/tests/70_ext3_sb.ml b/tests/70_ext3_sb.ml
new file mode 100644 (file)
index 0000000..e8cebb4
--- /dev/null
@@ -0,0 +1,76 @@
+(* Parse an ext3 superblock.
+ * $Id: 70_ext3_sb.ml,v 1.1 2008-04-01 19:10:45 rjones Exp $
+ *)
+
+open Printf
+
+(*let () = Bitmatch.debug := true*)
+
+let bits = Bitmatch.bitstring_of_file "tests/ext3_sb"
+
+(* The structure is straight from /usr/include/linux/ext3_fs.h *)
+
+let () =
+  bitmatch bits with
+  | s_inodes_count : 32 : littleendian;                (* Inodes count *)
+    s_blocks_count : 32 : littleendian;                (* Blocks count *)
+    s_r_blocks_count : 32 : littleendian;      (* Reserved blocks count *)
+    s_free_blocks_count : 32 : littleendian;   (* Free blocks count *)
+    s_free_inodes_count : 32 : littleendian;   (* Free inodes count *)
+    s_first_data_block : 32 : littleendian;    (* First Data Block *)
+    s_log_block_size : 32 : littleendian;      (* Block size *)
+    s_log_frag_size : 32 : littleendian;       (* Fragment size *)
+    s_blocks_per_group : 32 : littleendian;    (* # Blocks per group *)
+    s_frags_per_group : 32 : littleendian;     (* # Fragments per group *)
+    s_inodes_per_group : 32 : littleendian;    (* # Inodes per group *)
+    s_mtime : 32 : littleendian;               (* Mount time *)
+    s_wtime : 32 : littleendian;               (* Write time *)
+    s_mnt_count : 16 : littleendian;           (* Mount count *)
+    s_max_mnt_count : 16 : littleendian;       (* Maximal mount count *)
+    0xef53 : 16 : littleendian;                        (* Magic signature *)
+    s_state : 16 : littleendian;               (* File system state *)
+    s_errors : 16 : littleendian;              (* Behaviour when detecting errors *)
+    s_minor_rev_level : 16 : littleendian;     (* minor revision level *)
+    s_lastcheck : 32 : littleendian;           (* time of last check *)
+    s_checkinterval : 32 : littleendian;       (* max. time between checks *)
+    s_creator_os : 32 : littleendian;          (* OS *)
+    s_rev_level : 32 : littleendian;           (* Revision level *)
+    s_def_resuid : 16 : littleendian;          (* Default uid for reserved blocks *)
+    s_def_resgid : 16 : littleendian;          (* Default gid for reserved blocks *)
+    s_first_ino : 32 : littleendian;           (* First non-reserved inode *)
+    s_inode_size : 16 : littleendian;          (* size of inode structure *)
+    s_block_group_nr : 16 : littleendian;      (* block group # of this superblock *)
+    s_feature_compat : 32 : littleendian;      (* compatible feature set *)
+    s_feature_incompat : 32 : littleendian;    (* incompatible feature set *)
+    s_feature_ro_compat : 32 : littleendian;   (* readonly-compatible feature set *)
+    s_uuid : 128 : bitstring;                  (* 128-bit uuid for volume *)
+    s_volume_name : 128 : bitstring;           (* volume name XXX string *)
+    s_last_mounted : 512 : bitstring;          (* directory where last mounted XXX string *)
+    s_algorithm_usage_bitmap : 32 : littleendian; (* For compression *)
+    s_prealloc_blocks : 8;                     (* Nr of blocks to try to preallocate*)
+    s_prealloc_dir_blocks : 8;                 (* Nr to preallocate for dirs *)
+    s_reserved_gdt_blocks : 16 : littleendian; (* Per group desc for online growth *)
+    s_journal_uuid : 128 : bitstring;          (* uuid of journal superblock *)
+    s_journal_inum : 32 : littleendian;                (* inode number of journal file *)
+    s_journal_dev : 32 : littleendian;         (* device number of journal file *)
+    s_last_orphan : 32 : littleendian;         (* start of list of inodes to delete *)
+    s_hash_seed0 : 32 : littleendian;          (* HTREE hash seed *)
+    s_hash_seed1 : 32 : littleendian;
+    s_hash_seed2 : 32 : littleendian;
+    s_hash_seed3 : 32 : littleendian;
+    s_def_hash_version : 8;                    (* Default hash version to use *)
+    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 *)
+    s_reserved : 6080 : bitstring ->            (* Padding to the end of the block *)
+
+    printf "ext3 superblock:\n";
+    printf "  s_inodes_count = %ld\n" s_inodes_count;
+    printf "  s_blocks_count = %ld\n" s_blocks_count;
+    printf "  s_free_inodes_count = %ld\n" s_free_inodes_count;
+    printf "  s_free_blocks_count = %ld\n" s_free_blocks_count
+
+  | _ ->
+    eprintf "not an ext3 superblock!\n%!";
+    exit 2
diff --git a/tests/ext3_sb b/tests/ext3_sb
new file mode 100644 (file)
index 0000000..3cbc044
Binary files /dev/null and b/tests/ext3_sb differ