Patch by Valentin Verkhovsky: Ntfs driver is updated now and ready for testing.
authorEmanuele Aliberti <ea@iol.it>
Mon, 15 Sep 2003 16:01:16 +0000 (16:01 +0000)
committerEmanuele Aliberti <ea@iol.it>
Mon, 15 Sep 2003 16:01:16 +0000 (16:01 +0000)
I've been working on MFT processing for while.
Thus driver performs  only  files & attribute enumerating
by VCN-LCN pair mapping   like M$ Nfi  utility.

For me it compiles and the image loads correctly.

svn path=/trunk/; revision=6087

reactos/drivers/fs/ntfs/attrib.c
reactos/drivers/fs/ntfs/fsctl.c
reactos/drivers/fs/ntfs/mft.c
reactos/drivers/fs/ntfs/ntfs.h

index 8b015e5..efff474 100644 (file)
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: attrib.c,v 1.5 2003/08/07 11:47:32 silverblade Exp $
+/* $Id: attrib.c,v 1.6 2003/09/15 16:01:16 ea Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * FILE:             drivers/fs/ntfs/attrib.c
  * PURPOSE:          NTFS filesystem driver
  * PROGRAMMER:       Eric Kohl
+ * Updated     by       Valentin Verkhovsky  2003/09/12 
  */
 
 /* INCLUDES *****************************************************************/
 
 /* FUNCTIONS ****************************************************************/
 
+
+
+ULONG RunLength(PUCHAR run)
+{
+  return(*run & 0x0f) + ((*run >> 4) & 0x0f) + 1;
+}
+
+
+LONGLONG RunLCN(PUCHAR run)
+{
+       UCHAR n1 = *run & 0x0f;
+       UCHAR n2 = (*run >> 4) & 0x0f;
+       LONGLONG lcn = n2 == 0 ? 0 : (CHAR)(run[n1 + n2]);
+       LONG i = 0;
+       
+       for (i = n1 +n2 - 1; i > n1; i--)
+               lcn = (lcn << 8) + run[i];
+       return lcn;
+}
+
+
+
+ULONGLONG RunCount(PUCHAR run)
+{
+       UCHAR n =  *run & 0xf;
+       ULONGLONG count = 0;
+       ULONG i = 0;
+
+       for (i = n; i > 0; i--)
+               count = (count << 8) + run[i];
+       return count;
+}
+
+
 VOID
 NtfsDumpFileNameAttribute(PATTRIBUTE Attribute)
 {
   PRESIDENT_ATTRIBUTE ResAttr;
   PFILENAME_ATTRIBUTE FileNameAttr;
 
-  DbgPrint("  $FILE_NAME ");
+  DbgPrint("  FILE_NAME ");
 
   ResAttr = (PRESIDENT_ATTRIBUTE)Attribute;
 //  DbgPrint(" Length %lu  Offset %hu ", ResAttr->ValueLength, ResAttr->ValueOffset);
@@ -90,7 +125,7 @@ NtfsDumpVolumeInformationAttribute(PATTRIBUTE Attribute)
 }
 
 
-VOID
+BOOL
 NtfsDumpAttribute(PATTRIBUTE Attribute)
 {
   PNONRESIDENT_ATTRIBUTE NresAttr;
@@ -100,9 +135,16 @@ NtfsDumpAttribute(PATTRIBUTE Attribute)
   UCHAR RunHeader;
   ULONG RunLength;
   ULONG RunStart;
+  
 
   switch (Attribute->AttributeType)
     {
+     
+       case AttributeFileName:
+       NtfsDumpFileNameAttribute(Attribute);
+       break;
+  
+  
       case AttributeStandardInformation:
        DbgPrint("  $STANDARD_INFORMATION ");
        break;
@@ -111,9 +153,7 @@ NtfsDumpAttribute(PATTRIBUTE Attribute)
        DbgPrint("  $ATTRIBUTE_LIST ");
        break;
 
-      case AttributeFileName:
-       NtfsDumpFileNameAttribute(Attribute);
-       break;
+   
 
       case AttributeObjectId:
        DbgPrint("  $OBJECT_ID ");
@@ -133,6 +173,7 @@ NtfsDumpAttribute(PATTRIBUTE Attribute)
 
       case AttributeData:
        DbgPrint("  $DATA ");
+       //DataBuf = ExAllocatePool(NonPagedPool,AttributeLengthAllocated(Attribute));
        break;
 
       case AttributeIndexRoot:
@@ -184,85 +225,23 @@ NtfsDumpAttribute(PATTRIBUTE Attribute)
 
   DbgPrint("(%s)\n",
           Attribute->Nonresident ? "non-resident" : "resident");
+    
+     
 
-  if (Attribute->Nonresident != 0)
+
+    if (Attribute->Nonresident != 0)
     {
-      NresAttr = (PNONRESIDENT_ATTRIBUTE)Attribute;
-      Ptr = (PUCHAR)((ULONG)NresAttr + NresAttr->RunArrayOffset);
-      while (*Ptr != 0)
-       {
-         RunHeader = *Ptr++;
-
-         switch (RunHeader & 0x0F)
-           {
-             case 1:
-               RunLength = (ULONG)*Ptr++;
-               break;
-
-             case 2:
-               RunLength = *((PUSHORT)Ptr);
-               Ptr += 2;
-               break;
-
-             case 3:
-               RunLength = *Ptr++;
-               RunLength += *Ptr++ << 8;
-               RunLength += *Ptr++ << 16;
-               break;
-
-             case 4:
-               RunLength = *((PULONG)Ptr);
-               Ptr += 4;
-               break;
-
-             default:
-               DbgPrint("RunLength size of %hu not implemented!\n", RunHeader & 0x0F);
-               KEBUGCHECK(0);
-           }
-
-         switch (RunHeader >> 4)
-           {
-             case 1:
-               RunStart = (ULONG)*Ptr;
-               Ptr++;
-               break;
-
-             case 2:
-               RunStart = *((PUSHORT)Ptr);
-               Ptr += 2;
-               break;
-
-             case 3:
-               RunStart = *Ptr++;
-               RunStart += *Ptr++ << 8;
-               RunStart += *Ptr++ << 16;
-               break;
-
-             case 4:
-               RunStart = *((PULONG)Ptr);
-               Ptr += 4;
-               break;
-
-             default:
-               DbgPrint("RunStart size of %hu not implemented!\n", RunHeader >> 4);
-               KEBUGCHECK(0);
-           }
-
-         DbgPrint("    AllocatedSize %I64d  DataSize %I64d\n", NresAttr->AllocatedSize, NresAttr->DataSize);
-//       DbgPrint("    Run: Header %hx  Start %lu  Length %lu\n", RunHeader, RunStart, RunLength);
-         if (RunLength == 1)
-           {
-             DbgPrint("    logical sector %lu (0x%lx)\n", RunStart, RunStart);
-           }
-         else
-           {
-             DbgPrint("    logical sectors %lu-%lu (0x%lx-0x%lx)\n",
-                      RunStart, RunStart + RunLength - 1,
-                      RunStart, RunStart + RunLength - 1);
-           }
+
+       return TRUE;
        }
-    }
 
+    return FALSE;
+
+  
+       
+
+
+       
 
 }
 
index b471989..036bb8b 100644 (file)
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: fsctl.c,v 1.7 2003/07/17 13:31:39 chorns Exp $
+/* $Id: fsctl.c,v 1.8 2003/09/15 16:01:16 ea Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * FILE:             services/fs/ntfs/fsctl.c
  * PURPOSE:          NTFS filesystem driver
  * PROGRAMMER:       Eric Kohl
+ * Updated     by       Valentin Verkhovsky  2003/09/12
  */
 
 /* INCLUDES *****************************************************************/
 
 #include <ddk/ntddk.h>
 
-//#define NDEBUG
+#define NDEBUG
 #include <debug.h>
 
 #include "ntfs.h"
@@ -163,6 +164,7 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
       Vcb->NtfsInfo.MftStart.QuadPart = BootSector->MftLocation;
       Vcb->NtfsInfo.MftMirrStart.QuadPart = BootSector->MftMirrLocation;
       Vcb->NtfsInfo.SerialNumber = BootSector->SerialNumber;
+      Vcb->NtfsInfo.ClustersPerFileRecord = BootSector->ClustersPerMftRecord;
 
 //#indef NDEBUG
       DbgPrint("Boot sector information:\n");
index f0d6247..ac21419 100644 (file)
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: mft.c,v 1.1 2002/07/15 15:37:33 ekohl Exp $
+/* $Id: mft.c,v 1.2 2003/09/15 16:01:16 ea Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * FILE:             services/fs/ntfs/mft.c
  * PURPOSE:          NTFS filesystem driver
- * PROGRAMMER:       Eric Kohl
+ * PROGRAMMER:       Eric Kohl 
+ * Updated     by       Valentin Verkhovsky  2003/09/12                        
  */
 
 /* INCLUDES *****************************************************************/
@@ -35,6 +36,9 @@
 #include "ntfs.h"
 
 
+#define __min(a,b)  (((a) < (b)) ? (a) : (b))
+
+
 /* FUNCTIONS ****************************************************************/
 
 
@@ -43,58 +47,379 @@ NtfsOpenMft(PDEVICE_OBJECT DeviceObject,
            PDEVICE_EXTENSION Vcb)
 {
   PVOID Buffer;
-  PFILE_RECORD_HEADER RecordHeader;
+  PVOID Bitmap;
+  PFILE_RECORD_HEADER MftRecord;
+  PFILE_RECORD_HEADER file;
   PATTRIBUTE Attribute;
-  NTSTATUS Status;
+  PATTRIBUTE AttrData;
+  PRESIDENT_ATTRIBUTE ResAttr;
 
+  NTSTATUS Status;
+  ULONG BytesPerFileRecord;    
   DPRINT1("NtfsOpenMft() called\n");
+  ULONG n = 0;
 
+  BytesPerFileRecord = Vcb->NtfsInfo.ClustersPerFileRecord * 
+                                               Vcb->NtfsInfo.BytesPerCluster;
+  
   Buffer = ExAllocatePool(NonPagedPool,
-                         Vcb->NtfsInfo.BytesPerCluster);
+                         BytesPerFileRecord);
   if (Buffer == NULL)
     {
       return(STATUS_INSUFFICIENT_RESOURCES);
     }
-
-
-  /* read first MFT cluster */
+  
   Status = NtfsReadRawSectors(DeviceObject,
                              Vcb->NtfsInfo.MftStart.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster,
-                             Vcb->NtfsInfo.SectorsPerCluster,
+                             BytesPerFileRecord / Vcb->NtfsInfo.BytesPerSector,
                              Vcb->NtfsInfo.BytesPerSector,
                              (PVOID)Buffer);
-  if (NT_SUCCESS(Status))
+
+
+    if (NT_SUCCESS(Status))
     {
-      /* Enumerate MFT records */
-      RecordHeader = Buffer;
-      while (((ULONG)RecordHeader - (ULONG)Buffer) < Vcb->NtfsInfo.BytesPerCluster)
+      
+      DbgPrint("Enumerate  MFT \n");
+      MftRecord = Buffer;
+
+      FixupUpdateSequenceArray(MftRecord);
+    
+         ULONG i;
+         Attribute = FindAttribute(MftRecord, AttributeBitmap, 0);
+               
+       
+      /* Get number of file records*/
+         n = AttributeLength(FindAttribute(MftRecord, AttributeData,0))
+                 / BytesPerFileRecord;
+                         
+         file = ExAllocatePool(NonPagedPool, BytesPerFileRecord);
+        
+         if (file == NULL)
+         {
+                 return(STATUS_INSUFFICIENT_RESOURCES);
+         }
+     
+      /* Enumerate MFT Records */ 
+         
+         for ( i=0; i < n; i++)
+         {
+          
+                        
+                 ReadFileRecord(i, file, Vcb, MftRecord, DeviceObject);
+                        
+                 if (file->Ntfs.Type == 'ELIF' && (file->Flags & 1) != 0)
+                 {
+                        
+                         DbgPrint("\n");
+                         DbgPrint("File  %lu\n", i);
+              DbgPrint("\n");
+                         /* Enumerate attributtes */
+
+                 EnumerAttribute(file, Vcb, DeviceObject);
+                         DbgPrint("\n");
+              DbgPrint("\n");
+                                       
+               
+                 }
+
+         }
+
+
+  
+       }
+    
+       ExFreePool(Buffer);
+  
+       ExFreePool(file);
+
+
+  return(Status);
+}
+
+PATTRIBUTE FindAttribute(PFILE_RECORD_HEADER file,
+
+                                                ATTRIBUTE_TYPE type, PWSTR name)
+{
+       PATTRIBUTE attr = (PATTRIBUTE)((PVOID)file + file->AttributeOffset);
+       
+       while (attr->AttributeType !=-1)
        {
-         DbgPrint("\n");
-//       DbgPrint("Magic: %.04s\n", (PCHAR)&RecordHeader->Ntfs.Type);
-//       DbgPrint("Real size: %lx\n", RecordHeader->RealSize);
-//       DbgPrint("AllocSize: %lx\n", RecordHeader->AllocSize);
+               
+        if(attr->AttributeType == type) {
+            return attr;
+               }
+      attr = (PATTRIBUTE)((ULONG)attr + attr->Length);
+       }
 
-         /* Enumerate attributes */
-         Attribute = (PATTRIBUTE)((ULONG)RecordHeader + 
-                                  RecordHeader->Ntfs.UsnOffset +
-                                  RecordHeader->Ntfs.UsnSize * sizeof(USHORT));
-         while (Attribute->AttributeType != 0xFFFFFFFF)
-           {
-             NtfsDumpAttribute(Attribute);
+       return 0;
+}
 
-             Attribute = (PATTRIBUTE)((ULONG)Attribute + Attribute->Length);
-           }
 
+ULONG AttributeLengthAllocated(PATTRIBUTE attr)
+{
+       
+       PRESIDENT_ATTRIBUTE ResAttr;
+       PNONRESIDENT_ATTRIBUTE NresAttr;
+        if(attr->Nonresident == FALSE)
+        {
+                ResAttr  = (PRESIDENT_ATTRIBUTE)attr;
+                return ResAttr->ValueLength;
+        }
 
-         RecordHeader = (PFILE_RECORD_HEADER)((ULONG)RecordHeader + RecordHeader->BytesAllocated);
+       else  
+       {
+               NresAttr = (PNONRESIDENT_ATTRIBUTE)attr;
+               
+               return NresAttr->AllocatedSize;
        }
+       
 
-    }
+}
+
+VOID ReadAttribute(PATTRIBUTE attr, PVOID buffer, PDEVICE_EXTENSION Vcb, 
+                                   PDEVICE_OBJECT DeviceObject)
+{
+       if(attr->Nonresident == FALSE)
+       {
+               PRESIDENT_ATTRIBUTE ResAttr = (PRESIDENT_ATTRIBUTE)attr;
+               memcpy(buffer, (PRESIDENT_ATTRIBUTE)((PVOID)ResAttr + ResAttr->ValueOffset),
+                       ResAttr->ValueLength);
 
-  ExFreePool(Buffer);
+        
+       }
+
+       
+               PNONRESIDENT_ATTRIBUTE NresAttr = (PNONRESIDENT_ATTRIBUTE)attr;
+               ReadExternalAttribute(NresAttr, 0, (ULONG)(NresAttr->LastVcn) + 1,
+                       buffer, Vcb, DeviceObject);
+    
+
+
+
+}
+
+
+
+ULONG AttributeLength(PATTRIBUTE  attr)
+{
+       PRESIDENT_ATTRIBUTE ResAttr;
+       PNONRESIDENT_ATTRIBUTE NresAttr;
+       
+       if(attr->Nonresident == FALSE)
+       {
+               ResAttr = (PRESIDENT_ATTRIBUTE)attr;
+               return ResAttr->ValueLength;
+       }
+
+       else
+       {
+               NresAttr = (PNONRESIDENT_ATTRIBUTE)attr;
+               return NresAttr->DataSize;
+       }
 
-  return(Status);
 }
 
 
-/* EOF */
+
+VOID ReadFileRecord(ULONG index, PFILE_RECORD_HEADER file,
+                                         PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER Mft,
+                                          PDEVICE_OBJECT DeviceObject)
+
+{
+       
+       PVOID p;
+       ULONG clusters = Vcb->NtfsInfo.ClustersPerFileRecord;
+    ULONG BytesPerFileRecord = clusters * Vcb->NtfsInfo.BytesPerCluster;
+       
+
+       p =  ExAllocatePool(NonPagedPool, BytesPerFileRecord);
+
+       ULONGLONG vcn = index * BytesPerFileRecord / Vcb->NtfsInfo.BytesPerCluster;
+
+       ReadVCN(Mft, AttributeData, vcn, clusters, p, Vcb,DeviceObject);
+
+       LONG m = (Vcb->NtfsInfo.BytesPerCluster / BytesPerFileRecord) - 1; 
+               
+       ULONG n = m > 0 ? (index & m) : 0;
+
+       memcpy(file, p + n * BytesPerFileRecord, BytesPerFileRecord);
+
+       ExFreePool(p);
+       FixupUpdateSequenceArray(file);
+
+
+}
+
+
+
+VOID ReadExternalAttribute(PNONRESIDENT_ATTRIBUTE NresAttr,
+                                                  ULONGLONG vcn, ULONG count, PVOID buffer,
+                                                                      PDEVICE_EXTENSION Vcb,
+                                                                                          PDEVICE_OBJECT DeviceObject)
+{
+       
+
+       ULONGLONG lcn, runcount;
+       ULONG readcount, left;
+
+    PUCHAR bytes = (PUCHAR)buffer;
+
+       for (left = count; left>0; left -=readcount) 
+       {
+               FindRun(NresAttr, vcn, &lcn, &runcount);
+
+               readcount = (ULONG)(__min(runcount, left));
+
+               
+               ULONG n = readcount * Vcb->NtfsInfo.BytesPerCluster;
+       
+               if (lcn == 0)
+                       memset(bytes, 0, n);
+               else
+                 ReadLCN(lcn, readcount, bytes, Vcb, DeviceObject);
+
+               vcn += readcount;
+               bytes += n;
+
+       
+       }
+       
+
+}
+
+
+BOOL FindRun(PNONRESIDENT_ATTRIBUTE NresAttr, ULONGLONG vcn,
+                        PULONGLONG lcn, PULONGLONG count)
+{
+       PUCHAR run; 
+
+       ULONGLONG base = NresAttr->StartVcn;
+
+       if (vcn < NresAttr->StartVcn || vcn > NresAttr->LastVcn)
+               return FALSE;
+
+       *lcn = 0;
+
+
+    for (run = (PUCHAR)((ULONG)NresAttr + NresAttr->RunArrayOffset);
+       *run != 0; run += RunLength(run))  {
+       
+               *lcn += RunLCN(run);
+               *count = RunCount(run);
+               
+               if(base <= vcn && vcn < base + *count)
+               {
+                       *lcn = RunLCN(run) == 0 ? 0 : *lcn + vcn - base;
+                       *count -= (ULONG)(vcn - base);
+    
+               
+                       return TRUE;
+               }
+               else
+                       base += *count;
+               
+                               
+       }
+    
+       return FALSE;
+}
+
+
+
+VOID ReadVCN(PFILE_RECORD_HEADER file, ATTRIBUTE_TYPE type,
+                        ULONGLONG vcn, ULONG count, PVOID buffer,
+                        PDEVICE_EXTENSION Vcb, PDEVICE_OBJECT DeviceObject)
+{
+
+       PNONRESIDENT_ATTRIBUTE NresAttr;
+       PATTRIBUTE attr;
+       attr = FindAttribute(file, type,0);
+       
+       NresAttr = (PNONRESIDENT_ATTRIBUTE) attr;
+
+       if (NresAttr == 0 || (vcn < NresAttr->StartVcn ||vcn > NresAttr->LastVcn))
+       {
+               
+         PATTRIBUTE attrList = FindAttribute(file,AttributeAttributeList,0);
+         DbgPrint("Exeption \n");
+         //KeDebugCheck(0);
+       }
+
+       ReadExternalAttribute(NresAttr, vcn, count, buffer, Vcb, DeviceObject);
+
+
+}
+
+BOOL bitset(PUCHAR bitmap, ULONG i)
+{
+       return (bitmap[i>>3] & (1 << (i & 7))) !=0;
+}
+
+
+VOID FixupUpdateSequenceArray(PFILE_RECORD_HEADER file)
+{
+       PUSHORT usa = (PUSHORT)((PVOID)file + file->Ntfs.UsaOffset);
+       PUSHORT sector = (PUSHORT)file;
+    ULONG i;
+
+       for( i =1; i < file->Ntfs.UsaCount; i++)
+       {
+               sector[255] = usa[i];
+               sector += 256;
+
+       }
+
+}
+
+
+VOID ReadLCN(ULONGLONG lcn, ULONG count, PVOID buffer, PDEVICE_EXTENSION Vcb,
+                        PDEVICE_OBJECT DeviceObject)
+{
+       
+       LARGE_INTEGER DiskSector;
+       DiskSector.QuadPart = lcn;
+       
+       
+       NtfsReadRawSectors(DeviceObject, DiskSector.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster, 
+        count * Vcb->NtfsInfo.SectorsPerCluster, Vcb->NtfsInfo.BytesPerSector, buffer);
+}
+
+
+VOID EnumerAttribute(PFILE_RECORD_HEADER file, PDEVICE_EXTENSION Vcb,
+                                        PDEVICE_OBJECT DeviceObject)
+                                                
+{
+       
+       ULONGLONG lcn;
+       ULONGLONG runcount;
+       ULONG  size;
+       PATTRIBUTE attr = (PATTRIBUTE)((PVOID)file + file->AttributeOffset);
+       
+       while (attr->AttributeType !=-1)
+       {
+               
+         if(NtfsDumpAttribute(attr))
+         {
+
+                 PNONRESIDENT_ATTRIBUTE NresAttr = (PNONRESIDENT_ATTRIBUTE)attr;
+
+
+          FindRun(NresAttr,0,&lcn, &runcount);
+                 
+                 DbgPrint("  AllocatedSize %I64d  DataSize %I64d\n", NresAttr->AllocatedSize, NresAttr->DataSize);
+                 DbgPrint("  logical sectors:  %lu", lcn);
+                 DbgPrint("-%lu\n", lcn + runcount -1);  
+                 
+         }
+          attr = (PATTRIBUTE)((ULONG)attr + attr->Length);
+       
+       }
+
+
+}
+
+
+
+       /* EOF */
index 4b67eb7..2e21a0b 100644 (file)
@@ -50,6 +50,7 @@ typedef struct _NTFS_INFO
   ULARGE_INTEGER MftStart;
   ULARGE_INTEGER MftMirrStart;
   ULONGLONG SerialNumber;
+  ULONG ClustersPerFileRecord;
 
 } NTFS_INFO, *PNTFS_INFO;
 
@@ -153,8 +154,8 @@ typedef enum
 typedef struct
 {
   ULONG Type;             /* Magic number 'FILE' */
-  USHORT UsnOffset;       /* Offset to the update sequence */
-  USHORT UsnSize;         /* Size in words of Update Sequence Number & Array (S) */
+  USHORT UsaOffset;       /* Offset to the update sequence */
+  USHORT UsaCount;         /* Size in words of Update Sequence Number & Array (S) */
   ULONGLONG Lsn;          /* $LogFile Sequence Number (LSN) */
 } NTFS_RECORD_HEADER, *PNTFS_RECORD_HEADER;
 
@@ -280,9 +281,12 @@ extern PNTFS_GLOBAL_DATA NtfsGlobalData;
 
 /* attrib.c */
 
-VOID
+BOOL
 NtfsDumpAttribute(PATTRIBUTE Attribute);
 
+LONGLONG RunLCN(PUCHAR run);
+
+ULONG RunLength(PUCHAR run);
 
 /* blockdev.c */
 
@@ -399,6 +403,42 @@ NtfsOpenMft(PDEVICE_OBJECT DeviceObject,
            PDEVICE_EXTENSION Vcb);
 
 
+VOID ReadAttribute(PATTRIBUTE attr, PVOID buffer, PDEVICE_EXTENSION Vcb, 
+                                   PDEVICE_OBJECT DeviceObject);
+
+ULONG AttributeLength(PATTRIBUTE  attr);
+
+VOID ReadFileRecord(ULONG index, PFILE_RECORD_HEADER file,
+                                         PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER Mft,
+                                          PDEVICE_OBJECT DeviceObject);
+
+
+PATTRIBUTE FindAttribute(PFILE_RECORD_HEADER file,
+
+                                                ATTRIBUTE_TYPE type, PWSTR name);
+
+
+ULONG AttributeLengthAllocated(PATTRIBUTE attr);
+
+VOID ReadVCN(PFILE_RECORD_HEADER file, ATTRIBUTE_TYPE type,
+                        ULONGLONG vcn, ULONG count, PVOID buffer,
+                        PDEVICE_EXTENSION Vcb, PDEVICE_OBJECT DeviceObject);
+
+
+VOID FixupUpdateSequenceArray(PFILE_RECORD_HEADER file);
+
+VOID ReadExternalAttribute(PNONRESIDENT_ATTRIBUTE NresAttr,
+                                                  ULONGLONG vcn, ULONG count, PVOID buffer,
+                                                                      PDEVICE_EXTENSION Vcb,
+                                                                                          PDEVICE_OBJECT DeviceObject);
+
+VOID ReadLCN(ULONGLONG lcn, ULONG count, PVOID buffer, PDEVICE_EXTENSION Vcb,
+                        PDEVICE_OBJECT DeviceObject);
+
+
+VOID EnumerAttribute(PFILE_RECORD_HEADER file,PDEVICE_EXTENSION Vcb, 
+                                        PDEVICE_OBJECT DeviceObject );
+
 #if 0
 /* misc.c */