From 6eaf85113be1a221874ecae2fc884e97ee357c3c Mon Sep 17 00:00:00 2001 From: "rjones@intel.home.annexia.org" Date: Mon, 12 May 2008 15:01:58 +0100 Subject: [PATCH] Separate functions --- lib/diskimage_ntfs.ml | 237 ++++++++++++++++++++++++++------------------------ 1 file changed, 125 insertions(+), 112 deletions(-) diff --git a/lib/diskimage_ntfs.ml b/lib/diskimage_ntfs.ml index 6c1aafb..4e950e3 100644 --- a/lib/diskimage_ntfs.ml +++ b/lib/diskimage_ntfs.ml @@ -32,7 +32,11 @@ let attach_private_data, get_private_data = let id = "ntfs" let rec probe dev = - (* Load the boot sector. *) + let fs = probe_superblock dev in + fs + +and probe_superblock dev = + (* Load the boot sector / superblock. *) let bits = dev#read_bitstring ~^0 ~^512 in (* Most of this data comes from ntfsprogs' layout.h header file. *) @@ -74,127 +78,136 @@ let rec probe dev = dev#name blocksize volume_serial_number; let blocksize = Int63.of_int blocksize 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 blocksize dev in + + (* Get the location and size of the Master File Table. *) let mft_lcn = Int63.of_int64 mft_lcn *^ blocksize in let mft_size = Int63.of_int clusters_per_mft_record *^ blocksize in - (* Read the whole of the MFT. *) - let bits = dev#read_bitstring mft_lcn mft_size in - (* ... and turn the MFT into records. *) - let rec loop bits = - if Bitmatch.bitstring_length bits > 0 then ( - bitmatch bits with - | { "FILE" : 32 : string; - (* Assume 3 USAs starting at offset 0x30. XXX? *) - 0x30 : 16 : littleendian; - 0x03 : 16 : littleendian; - _ : 64; (* lsn *) - _ : 16; (* sequence_number *) - _ : 16; (* link_count *) - _ : 16; (* attrs_offset *) - _ : 16; (* MFT_RECORD_FLAGS *) - bytes_in_use : 32 : littleendian; - record_size : 32 : littleendian; - _ : 64; (* base_mft_record *) - _ : 16; (* next_attr_instance *) - _ : 16; (* reserved *) - _ : 32; (* mft_record_number *) - _ : 64; (* USN, 3 * USAs -- see above. *) - - (* The attributes. Subtract header size (0x30 bytes) - * and space for the USN/USAs (8 bytes). - *) - attrs : (Int32.to_int record_size - 0x30 - 8)*8 : bitstring; - - (* Subsequent MFT records: *) - rest : -1 : bitstring } -> - - if !debug then - eprintf "got an MFT record, now parsing attributes ...\n%!"; - - (* Parse the MFT record attributes. *) - let rec loop2 attrs = - bitmatch attrs with - | { 0xFFFFFFFF_l : 32 : littleendian } -> (* AT_END *) - if !debug then - eprintf "found AT_END, end of attributes\n%!"; - () - - | { attr_type : 32 : littleendian; - attr_size : 32 : littleendian; - 0 : 8; (* means attribute is resident *) - pad : 24*8 - 8 - 64 : bitstring; (* actually meaningful *) - attr : (Int32.to_int attr_size - 24) * 8 : bitstring; - rest : -1 : bitstring } -> - - (match attr_type with - | 0x30_l -> (* AT_FILE_NAME *) - (bitmatch attr with - | { _ : 64; (* parent directory ref *) - _ : 64; (* creation time *) - _ : 64; (* last change time *) - _ : 64; (* last MFT change time *) - _ : 64; (* last access time *) - allocated_size : 64 : littleendian; - data_size : 64 : littleendian; - _ : 32; - _ : 32; - name_len : 8; - name_type_flags : 8; - name : name_len*16 : string } -> - - let name = ucs2_to_utf8 name name_len in - if !debug then - eprintf "filename: %s (size: %Ld bytes)\n" - name data_size - - | { _ } -> - if !debug then - eprintf "cannot parse AT_FILE_NAME\n%!"; - ); - | _ -> - if !debug then - eprintf "unknown resident attribute %lx\n%!" - attr_type - ); - - loop2 rest - - | { attr_type : 32 : littleendian; - attr_size : 32 : littleendian; - 1 : 8; (* non-resident attribute *) - pad : (Int32.to_int attr_size - 9) * 8 : bitstring; - rest : -1 : bitstring } -> - if !debug then - eprintf "cannot parse non-resident attr %lx\n%!" - attr_type; - loop2 rest - - | { _ } -> - if !debug then - eprintf "corrupt MFT attribute entry\n%!" - in - loop2 attrs; - - loop rest (* loop rest of MFT records *) - - (* Just assume that the end of the list of MFT records - * is marked by all zeroes. This seems to be the - * case, but not sure if it is generally true. - * XXX? + let mft = parse_mft dev mft_lcn mft_size in + + raise Not_found (* XXX *) + + | { _ } -> raise Not_found (* Not an NTFS boot sector. *) + +and parse_mft dev mft_lcn mft_size = + (* Read the whole of the MFT (which is an array of MFT records) ... *) + let bits = dev#read_bitstring mft_lcn mft_size in + + (* ... and turn the MFT into records. *) + let rec loop bits = + if Bitmatch.bitstring_length bits > 0 then ( + bitmatch bits with + | { "FILE" : 32 : string; + (* Assume 3 USAs starting at offset 0x30. XXX? *) + 0x30 : 16 : littleendian; + 0x03 : 16 : littleendian; + _ : 64; (* lsn *) + _ : 16; (* sequence_number *) + _ : 16; (* link_count *) + _ : 16; (* attrs_offset *) + _ : 16; (* MFT_RECORD_FLAGS *) + bytes_in_use : 32 : littleendian; + record_size : 32 : littleendian; + _ : 64; (* base_mft_record *) + _ : 16; (* next_attr_instance *) + _ : 16; (* reserved *) + _ : 32; (* mft_record_number *) + _ : 64; (* USN, 3 * USAs -- see above. *) + + (* The attributes. Subtract header size (0x30 bytes) + * and space for the USN/USAs (8 bytes). *) - | { 0x00000000_l : 32 } -> - () - ) in - let mft_records = loop bits in + attrs : (Int32.to_int record_size - 0x30 - 8)*8 : bitstring; - + (* Subsequent MFT records: *) + rest : -1 : bitstring } -> + if !debug then + eprintf "got an MFT record, now parsing attributes ...\n%!"; + let attrs = parse_attrs attrs in - raise Not_found; + loop rest (* loop rest of MFT records *) - | { _ } -> raise Not_found (* Not an NTFS boot sector. *) + (* Just assume that the end of the list of MFT records + * is marked by all zeroes. This seems to be the + * case, but not sure if it is generally true. + * XXX? + *) + | { 0x00000000_l : 32 } -> + () + ) in + let mft_records = loop bits in + mft_records + +and parse_attrs attrs = + (* Parse the MFT record attributes. *) + bitmatch attrs with + | { 0xFFFFFFFF_l : 32 : littleendian } -> (* AT_END *) + if !debug then + eprintf "found AT_END, end of attributes\n%!"; + () + + | { attr_type : 32 : littleendian; + attr_size : 32 : littleendian; + 0 : 8; (* means attribute is resident *) + pad : 24*8 - 8 - 64 : bitstring; (* actually meaningful *) + attr : (Int32.to_int attr_size - 24) * 8 : bitstring; + rest : -1 : bitstring } -> + + (* XXX let attr = *) parse_resident_attr attr_type attr; + parse_attrs rest + + | { attr_type : 32 : littleendian; + attr_size : 32 : littleendian; + 1 : 8; (* non-resident attribute *) + pad : (Int32.to_int attr_size - 9) * 8 : bitstring; + rest : -1 : bitstring } -> + if !debug then + eprintf "cannot parse non-resident attr %lx\n%!" attr_type; + parse_attrs rest + | { _ } -> + if !debug then + eprintf "corrupt MFT attribute entry\n%!" + +and parse_resident_attr attr_type attr = + match attr_type with + | 0x30_l -> (* AT_FILE_NAME *) + (bitmatch attr with + | { _ : 64; (* parent directory ref *) + _ : 64; (* creation time *) + _ : 64; (* last change time *) + _ : 64; (* last MFT change time *) + _ : 64; (* last access time *) + allocated_size : 64 : littleendian; + data_size : 64 : littleendian; + _ : 32; + _ : 32; + name_len : 8; + name_type_flags : 8; + name : name_len*16 : string } -> + + let name = ucs2_to_utf8 name name_len in + if !debug then + eprintf "filename: %s (size: %Ld bytes)\n" + name data_size + + | { _ } -> + if !debug then + eprintf "cannot parse AT_FILE_NAME\n%!"; + ); + + | _ -> (* unknown attribute - just ignore *) + if !debug then + eprintf "unknown resident attribute %lx\n%!" + attr_type (* Poor man's little-endian UCS-2 to UTF-8 conversion. * XXX Should use Camomile. -- 1.8.3.1