Separate functions
authorrjones@intel.home.annexia.org <rjones@intel.home.annexia.org>
Mon, 12 May 2008 14:01:58 +0000 (15:01 +0100)
committerrjones@intel.home.annexia.org <rjones@intel.home.annexia.org>
Mon, 12 May 2008 14:01:58 +0000 (15:01 +0100)
lib/diskimage_ntfs.ml

index 6c1aafb..4e950e3 100644 (file)
@@ -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.