From: Richard W.M. Jones Date: Tue, 1 Apr 2008 19:10:45 +0000 (+0000) Subject: Fixed byte swaps so that now ext3 superblock can be parsed. X-Git-Url: http://git.annexia.org/?a=commitdiff_plain;h=3be31e79a87b15872a222d11714e1dc4046fad4d;p=ocaml-bitstring.git Fixed byte swaps so that now ext3 superblock can be parsed. --- diff --git a/bitmatch.ml b/bitmatch.ml index 0c9edc0..2cba403 100644 --- a/bitmatch.ml +++ b/bitmatch.ml @@ -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%!" diff --git a/bitmatch.mli b/bitmatch.mli index d2afc30..7ed9e63 100644 --- a/bitmatch.mli +++ b/bitmatch.mli @@ -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 diff --git a/pa_bitmatch.ml b/pa_bitmatch.ml index f25a49d..6673a21 100644 --- a/pa_bitmatch.ml +++ b/pa_bitmatch.ml @@ -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$ >> diff --git a/tests/.cvsignore b/tests/.cvsignore index b4fbc01..8ca81f0 100644 --- a/tests/.cvsignore +++ b/tests/.cvsignore @@ -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 index 0000000..e8cebb4 --- /dev/null +++ b/tests/70_ext3_sb.ml @@ -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 index 0000000..3cbc044 Binary files /dev/null and b/tests/ext3_sb differ