[NTFS] Correctly find attributes stored in another file record in MFT (and referenced...
[reactos.git] / drivers / filesystems / ntfs / mft.c
index c4328a0..e1411f0 100644 (file)
@@ -42,9 +42,7 @@ PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord)
 {
     PNTFS_ATTR_CONTEXT Context;
 
-    Context = ExAllocatePoolWithTag(NonPagedPool,
-                                    sizeof(NTFS_ATTR_CONTEXT),
-                                    TAG_NTFS);
+    Context = ExAllocateFromNPagedLookasideList(&NtfsGlobalData->AttrCtxtLookasideList);
     if(!Context)
     {
         DPRINT1("Error: Unable to allocate memory for context!\n");
@@ -56,7 +54,7 @@ PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord)
     if(!Context->pRecord)
     {
         DPRINT1("Error: Unable to allocate memory for attribute record!\n");
-        ExFreePoolWithTag(Context, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&NtfsGlobalData->AttrCtxtLookasideList, Context);
         return NULL;
     }
 
@@ -93,7 +91,7 @@ PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord)
         {
             DPRINT1("Unable to convert data runs to MCB!\n");
             ExFreePoolWithTag(Context->pRecord, TAG_NTFS);
-            ExFreePoolWithTag(Context, TAG_NTFS);
+            ExFreeToNPagedLookasideList(&NtfsGlobalData->AttrCtxtLookasideList, Context);
             return NULL;
         }
     }
@@ -105,15 +103,17 @@ PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord)
 VOID
 ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
 {
-    if (Context->pRecord->IsNonResident)
+    if (Context->pRecord)
     {
-        FsRtlUninitializeLargeMcb(&Context->DataRunsMCB);
-    }
+        if (Context->pRecord->IsNonResident)
+        {
+            FsRtlUninitializeLargeMcb(&Context->DataRunsMCB);
+        }
 
-    if(Context->pRecord)
         ExFreePoolWithTag(Context->pRecord, TAG_NTFS);
+    }
 
-    ExFreePoolWithTag(Context, TAG_NTFS);
+    ExFreeToNPagedLookasideList(&NtfsGlobalData->AttrCtxtLookasideList, Context);
 }
 
 
@@ -140,6 +140,7 @@ FindAttribute(PDEVICE_EXTENSION Vcb,
     NTSTATUS Status;
     FIND_ATTR_CONTXT Context;
     PNTFS_ATTR_RECORD Attribute;
+    PNTFS_ATTRIBUTE_LIST_ITEM AttrListItem;
 
     DPRINT("FindAttribute(%p, %p, 0x%x, %S, %lu, %p, %p)\n", Vcb, MftRecord, Type, Name, NameLength, AttrCtx, Offset);
 
@@ -184,6 +185,61 @@ FindAttribute(PDEVICE_EXTENSION Vcb,
         Status = FindNextAttribute(&Context, &Attribute);
     }
 
+    /* No attribute found, check if it is referenced in another file record */
+    Status = FindFirstAttributeListItem(&Context, &AttrListItem);
+    while (NT_SUCCESS(Status))
+    {
+        if (AttrListItem->Type == Type && AttrListItem->NameLength == NameLength)
+        {
+            if (NameLength != 0)
+            {
+                PWCHAR AttrName;
+
+                AttrName = (PWCHAR)((PCHAR)AttrListItem + AttrListItem->NameOffset);
+                DPRINT("%.*S, %.*S\n", AttrListItem->NameLength, AttrName, NameLength, Name);
+                if (RtlCompareMemory(AttrName, Name, NameLength * sizeof(WCHAR)) == (NameLength  * sizeof(WCHAR)))
+                {
+                    Found = TRUE;
+                }
+            }
+            else
+            {
+                Found = TRUE;
+            }
+
+            if (Found == TRUE)
+            {
+                /* Get the MFT Index of attribute */
+                ULONGLONG MftIndex;
+                PFILE_RECORD_HEADER RemoteHdr;
+
+                MftIndex = AttrListItem->MFTIndex & NTFS_MFT_MASK;
+                RemoteHdr = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
+
+                if (RemoteHdr == NULL)
+                {
+                    FindCloseAttribute(&Context);
+                    return STATUS_INSUFFICIENT_RESOURCES;
+                }
+
+                /* Check we are not reading ourselves */
+                if (MftRecord->MFTRecordNumber == MftIndex)
+                {
+                    DPRINT1("Attribute list references missing attribute to this file entry !");
+                    ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, RemoteHdr);
+                    FindCloseAttribute(&Context);
+                    return STATUS_OBJECT_NAME_NOT_FOUND;
+                }
+                /* Read the new file record */
+                ReadFileRecord(Vcb, MftIndex, RemoteHdr);
+                Status = FindAttribute(Vcb, RemoteHdr, Type, Name, NameLength, AttrCtx, Offset);
+                ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, RemoteHdr);
+                FindCloseAttribute(&Context);
+                return Status;
+            }
+        }
+        Status = FindNextAttributeListItem(&Context, &AttrListItem);
+    }
     FindCloseAttribute(&Context);
     return STATUS_OBJECT_NAME_NOT_FOUND;
 }
@@ -277,7 +333,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
-        ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
         ExReleaseResourceLite(&(Vcb->DirResource));
         return Status;
     }
@@ -308,7 +364,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
     if (!BitmapBuffer)
     {
         DPRINT1("ERROR: Unable to allocate memory for bitmap attribute!\n");
-        ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
         ExReleaseResourceLite(&(Vcb->DirResource));
         ReleaseAttributeContext(BitmapContext);
         return STATUS_INSUFFICIENT_RESOURCES;
@@ -326,7 +382,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
     if (BytesRead != BitmapSize.LowPart)
     {
         DPRINT1("ERROR: Bytes read != Bitmap size!\n");
-        ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
         ExReleaseResourceLite(&(Vcb->DirResource));
         ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
         ReleaseAttributeContext(BitmapContext);
@@ -338,7 +394,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("ERROR: Failed to set size of $MFT data attribute!\n");
-        ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
         ExReleaseResourceLite(&(Vcb->DirResource));
         ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
         ReleaseAttributeContext(BitmapContext);
@@ -351,7 +407,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
-        ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
         ExReleaseResourceLite(&(Vcb->DirResource));
         return Status;
     }
@@ -369,7 +425,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("ERROR: Failed to set size of bitmap attribute!\n");
-            ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
+            ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
             ExReleaseResourceLite(&(Vcb->DirResource));
             ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
             ReleaseAttributeContext(BitmapContext);
@@ -384,7 +440,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("ERROR: Failed to update $MFT file record!\n");
-        ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
         ExReleaseResourceLite(&(Vcb->DirResource));
         ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
         ReleaseAttributeContext(BitmapContext);
@@ -395,7 +451,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
     Status = WriteAttribute(Vcb, BitmapContext, 0, BitmapBuffer, NewBitmapSize, &LengthWritten, Vcb->MasterFileTable);
     if (!NT_SUCCESS(Status))
     {
-        ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
         ExReleaseResourceLite(&(Vcb->DirResource));
         ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
         ReleaseAttributeContext(BitmapContext);
@@ -410,7 +466,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("ERROR: Failed to write blank file record!\n");
-            ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
+            ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
             ExReleaseResourceLite(&(Vcb->DirResource));
             ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
             ReleaseAttributeContext(BitmapContext);
@@ -422,7 +478,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
     Status = UpdateMftMirror(Vcb);
 
     // Cleanup
-    ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
+    ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
     ExReleaseResourceLite(&(Vcb->DirResource));
     ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
     ReleaseAttributeContext(BitmapContext);
@@ -948,6 +1004,7 @@ SetResidentAttributeDataLength(PDEVICE_EXTENSION Vcb,
                     DPRINT1("Unable to create LargeMcb!\n");
                     if (AttribDataSize.QuadPart > 0)
                         ExFreePoolWithTag(AttribData, TAG_NTFS);
+                    ExFreePoolWithTag(NewRecord, TAG_NTFS);
                     _SEH2_YIELD(return _SEH2_GetExceptionCode());
                 } _SEH2_END;
 
@@ -961,6 +1018,7 @@ SetResidentAttributeDataLength(PDEVICE_EXTENSION Vcb,
                     DPRINT1("ERROR: Couldn't update file record to continue migration!\n");
                     if (AttribDataSize.QuadPart > 0)
                         ExFreePoolWithTag(AttribData, TAG_NTFS);
+                    ExFreePoolWithTag(NewRecord, TAG_NTFS);
                     return Status;
                 }
 
@@ -1064,6 +1122,10 @@ ReadAttribute(PDEVICE_EXTENSION Vcb,
         //TEMPTEMP
         ULONG UsedBufferSize;
         TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+        if (TempBuffer == NULL)
+        {
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
 
         LastLCN = 0;
         CurrentOffset = 0;
@@ -1099,6 +1161,7 @@ ReadAttribute(PDEVICE_EXTENSION Vcb,
 
             if (*DataRun == 0)
             {
+                ExFreePoolWithTag(TempBuffer, TAG_NTFS);
                 return AlreadyRead;
             }
 
@@ -1296,7 +1359,7 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
         // Do we need to read the file record?
         if (FileRecord == NULL)
         {
-            FileRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+            FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
             if (!FileRecord)
             {
                 DPRINT1("Error: Couldn't allocate file record!\n");
@@ -1321,7 +1384,7 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
         {
             DPRINT1("ERROR: Couldn't find matching attribute!\n");
             if(FileRecordAllocated)
-                ExFreePoolWithTag(FileRecord, TAG_NTFS);
+                ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
             return Status;
         }
 
@@ -1335,7 +1398,7 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
             DPRINT1("DRIVER ERROR: Data being written extends past end of file record!\n");
             ReleaseAttributeContext(FoundContext);
             if (FileRecordAllocated)
-                ExFreePoolWithTag(FileRecord, TAG_NTFS);
+                ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
             return STATUS_INVALID_PARAMETER;
         }
 
@@ -1350,7 +1413,7 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
 
         ReleaseAttributeContext(FoundContext);
         if (FileRecordAllocated)
-            ExFreePoolWithTag(FileRecord, TAG_NTFS);
+            ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
 
         if (NT_SUCCESS(Status))
             *RealLengthWritten = Length;
@@ -1379,7 +1442,11 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
         CurrentOffset = 0;  
 
         // This will be rewritten in the next iteration to just use the DataRuns MCB directly
-        TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);        
+        TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+        if (TempBuffer == NULL)
+        {
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
 
         ConvertLargeMCBToDataRuns(&Context->DataRunsMCB,
                                   TempBuffer,
@@ -1404,7 +1471,8 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
                 // (it may require increasing the allocation size).
                 DataRunStartLCN = -1;
                 DPRINT1("FIXME: Writing to sparse files is not supported yet!\n");
-                return STATUS_NOT_IMPLEMENTED;
+                Status = STATUS_NOT_IMPLEMENTED;
+                goto Cleanup;
             }
 
             // Have we reached the data run we're trying to write to?
@@ -1421,7 +1489,8 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
                 // (Presently, this code will rarely be reached, the write will usually have already failed by now)
                 // [We can reach here by creating a new file record when the MFT isn't large enough]
                 DPRINT1("FIXME: Master File Table needs to be enlarged.\n");
-                return STATUS_END_OF_FILE;
+                Status = STATUS_END_OF_FILE;
+                goto Cleanup;
             }
 
             CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
@@ -1455,7 +1524,7 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
         Context->CacheRunLastLCN = LastLCN;
         Context->CacheRunCurrentOffset = CurrentOffset;
 
-        return Status;
+        goto Cleanup;
     }
 
     Length -= WriteLength;
@@ -1488,7 +1557,8 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
         if (DataRunStartLCN == -1)
         {
             DPRINT1("FIXME: Don't know how to write to sparse files yet! (DataRunStartLCN == -1)\n");
-            return STATUS_NOT_IMPLEMENTED;
+            Status = STATUS_NOT_IMPLEMENTED;
+            goto Cleanup;
         }
         else
         {
@@ -1519,7 +1589,8 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
             {
                 // Failed sanity check.
                 DPRINT1("Encountered EOF before expected!\n");
-                return STATUS_END_OF_FILE;
+                Status = STATUS_END_OF_FILE;
+                goto Cleanup;
             }
 
             break;
@@ -1541,10 +1612,6 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
         }
     } // end while (Length > 0) [more data to write]
 
-    // TEMPTEMP
-    if (Context->pRecord->IsNonResident)
-        ExFreePoolWithTag(TempBuffer, TAG_NTFS);
-
     Context->CacheRun = DataRun;
     Context->CacheRunOffset = Offset + *RealLengthWritten;
     Context->CacheRunStartLCN = DataRunStartLCN;
@@ -1552,6 +1619,11 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
     Context->CacheRunLastLCN = LastLCN;
     Context->CacheRunCurrentOffset = CurrentOffset;
 
+Cleanup:
+    // TEMPTEMP
+    if (Context->pRecord->IsNonResident)
+        ExFreePoolWithTag(TempBuffer, TAG_NTFS);
+
     return Status;
 }
 
@@ -1610,9 +1682,7 @@ UpdateFileNameRecord(PDEVICE_EXTENSION Vcb,
            NewAllocationSize,
            CaseSensitive ? "TRUE" : "FALSE");
 
-    MftRecord = ExAllocatePoolWithTag(NonPagedPool,
-                                      Vcb->NtfsInfo.BytesPerFileRecord,
-                                      TAG_NTFS);
+    MftRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
     if (MftRecord == NULL)
     {
         return STATUS_INSUFFICIENT_RESOURCES;
@@ -1621,7 +1691,7 @@ UpdateFileNameRecord(PDEVICE_EXTENSION Vcb,
     Status = ReadFileRecord(Vcb, ParentMFTIndex, MftRecord);
     if (!NT_SUCCESS(Status))
     {
-        ExFreePoolWithTag(MftRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
         return Status;
     }
 
@@ -1629,7 +1699,7 @@ UpdateFileNameRecord(PDEVICE_EXTENSION Vcb,
     Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, L"$I30", 4, &IndexRootCtx, NULL);
     if (!NT_SUCCESS(Status))
     {
-        ExFreePoolWithTag(MftRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
         return Status;
     }
 
@@ -1637,7 +1707,7 @@ UpdateFileNameRecord(PDEVICE_EXTENSION Vcb,
     if (IndexRecord == NULL)
     {
         ReleaseAttributeContext(IndexRootCtx);
-        ExFreePoolWithTag(MftRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
@@ -1647,7 +1717,8 @@ UpdateFileNameRecord(PDEVICE_EXTENSION Vcb,
         DPRINT1("ERROR: Failed to read Index Root!\n");
         ExFreePoolWithTag(IndexRecord, TAG_NTFS);
         ReleaseAttributeContext(IndexRootCtx);
-        ExFreePoolWithTag(MftRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
+        return Status;
     }
 
     IndexRoot = (PINDEX_ROOT_ATTRIBUTE)IndexRecord;
@@ -1685,7 +1756,7 @@ UpdateFileNameRecord(PDEVICE_EXTENSION Vcb,
 
     ReleaseAttributeContext(IndexRootCtx);
     ExFreePoolWithTag(IndexRecord, TAG_NTFS);
-    ExFreePoolWithTag(MftRecord, TAG_NTFS);
+    ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
 
     return Status;
 }
@@ -1988,6 +2059,7 @@ AddNewMftEntry(PFILE_RECORD_HEADER FileRecord,
         ReleaseAttributeContext(BitmapContext);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
+    RtlZeroMemory(BitmapBuffer, BitmapDataSize + sizeof(ULONG));
 
     // Get a ULONG-aligned pointer for the bitmap itself
     BitmapData = (PUCHAR)ALIGN_UP_BY((ULONG_PTR)BitmapBuffer, sizeof(ULONG));
@@ -2138,11 +2210,12 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
     ULONG MaxIndexRootSize;
     PB_TREE_KEY NewLeftKey;
     PB_TREE_FILENAME_NODE NewRightHandNode;
+    LARGE_INTEGER MinIndexRootSize;
+    ULONG NewMaxIndexRootSize;
+    ULONG NodeSize;
 
     // Allocate memory for the parent directory
-    ParentFileRecord = ExAllocatePoolWithTag(NonPagedPool,
-                                             DeviceExt->NtfsInfo.BytesPerFileRecord,
-                                             TAG_NTFS);
+    ParentFileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
     if (!ParentFileRecord)
     {
         DPRINT1("ERROR: Couldn't allocate memory for file record!\n");
@@ -2153,7 +2226,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
     Status = ReadFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
     if (!NT_SUCCESS(Status))
     {
-        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
         DPRINT1("ERROR: Couldn't read parent directory with index %I64u\n",
                 DirectoryMftIndex);
         return Status;
@@ -2176,7 +2249,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
     {
         DPRINT1("ERROR: Couldn't find $I30 $INDEX_ROOT attribute for parent directory with MFT #: %I64u!\n",
                 DirectoryMftIndex);
-        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
         return Status;
     }
 
@@ -2212,7 +2285,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
     {
         DPRINT1("ERROR: Couldn't allocate memory for index root attribute!\n");
         ReleaseAttributeContext(IndexRootContext);
-        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
@@ -2223,7 +2296,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
         DPRINT1("ERROR: Couln't read index root attribute for Mft index #%I64u\n", DirectoryMftIndex);
         ReleaseAttributeContext(IndexRootContext);
         ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
-        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
         return Status;
     }
 
@@ -2238,7 +2311,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
         DPRINT1("ERROR: Failed to create B-Tree from Index!\n");
         ReleaseAttributeContext(IndexRootContext);
         ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
-        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
         return Status;
     }
 
@@ -2262,7 +2335,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
         DestroyBTree(NewTree);
         ReleaseAttributeContext(IndexRootContext);
         ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
-        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
         return Status;
     }
 
@@ -2287,7 +2360,6 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
     // This a bit hacky, but it seems to be functional.
 
     // Calculate the minimum size of the index root attribute, considering one dummy key and one VCN
-    LARGE_INTEGER MinIndexRootSize;
     MinIndexRootSize.QuadPart = sizeof(INDEX_ROOT_ATTRIBUTE) // size of the index root headers
                                 + 0x18; // Size of dummy key with a VCN for a subnode
     ASSERT(MinIndexRootSize.QuadPart % ATTR_RECORD_ALIGNMENT == 0);
@@ -2312,7 +2384,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
         DestroyBTree(NewTree);
         ReleaseAttributeContext(IndexRootContext);
         ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
-        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
         return Status;
     }
 
@@ -2324,7 +2396,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
         DestroyBTree(NewTree);
         ReleaseAttributeContext(IndexRootContext);
         ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
-        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
         return Status;
     }
 
@@ -2335,7 +2407,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
 
     // Find the maximum index root size given what the file record can hold
     // First, find the max index size assuming index root is the last attribute
-    ULONG NewMaxIndexRootSize =
+    NewMaxIndexRootSize =
        DeviceExt->NtfsInfo.BytesPerFileRecord                // Start with the size of a file record
         - IndexRootOffset                                    // Subtract the length of everything that comes before index root
         - IndexRootContext->pRecord->Resident.ValueOffset    // Subtract the length of the attribute header for index root
@@ -2361,7 +2433,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
 
     // The index allocation and index bitmap may have grown, leaving less room for the index root,
     // so now we need to double-check that index root isn't too large 
-    ULONG NodeSize = GetSizeOfIndexEntries(NewTree->RootNode);
+    NodeSize = GetSizeOfIndexEntries(NewTree->RootNode);
     if (NodeSize > NewMaxIndexRootSize)
     {
         DPRINT1("Demoting index root.\nNodeSize: 0x%lx\nNewMaxIndexRootSize: 0x%lx\n", NodeSize, NewMaxIndexRootSize);
@@ -2373,7 +2445,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
             DestroyBTree(NewTree);
             ReleaseAttributeContext(IndexRootContext);
             ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
-            ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+            ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
             return Status;
         }
 
@@ -2385,7 +2457,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
             DestroyBTree(NewTree);
             ReleaseAttributeContext(IndexRootContext);
             ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
-            ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+            ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
             return Status;
         }
 
@@ -2427,7 +2499,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
         DestroyBTree(NewTree);
         ReleaseAttributeContext(IndexRootContext);
         ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
-        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
         return Status;
     }
 
@@ -2454,7 +2526,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
             ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
             ReleaseAttributeContext(IndexRootContext);
             ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
-            ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+            ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
             DPRINT1("ERROR: Unable to set resident attribute length!\n");
             return Status;
         }
@@ -2467,7 +2539,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("ERROR: Failed to update file record of directory with index: %llx\n", DirectoryMftIndex);
-        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
         ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
         ReleaseAttributeContext(IndexRootContext);
         ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
@@ -2488,7 +2560,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
         ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
         ReleaseAttributeContext(IndexRootContext);
         ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
-        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
         return Status;
     }
 
@@ -2522,7 +2594,7 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
     ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
     ReleaseAttributeContext(IndexRootContext);
     ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
-    ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+    ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
 
     return Status;
 }
@@ -2624,7 +2696,7 @@ CompareFileName(PUNICODE_STRING FileName,
 * @param Vcb
 * Pointer to an NTFS_VCB for the volume whose Mft mirror is being updated.
 *
-* @returninja livecd
+* @return
 
 * STATUS_SUCCESS on success.
 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed.
@@ -2651,7 +2723,7 @@ UpdateMftMirror(PNTFS_VCB Vcb)
     ULONG LengthWritten;
 
     // Allocate memory for the Mft mirror file record
-    MirrorFileRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+    MirrorFileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
     if (!MirrorFileRecord)
     {
         DPRINT1("Error: Failed to allocate memory for $MFTMirr!\n");
@@ -2663,7 +2735,7 @@ UpdateMftMirror(PNTFS_VCB Vcb)
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("ERROR: Failed to read $MFTMirr!\n");
-        ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
         return Status;
     }
 
@@ -2672,7 +2744,7 @@ UpdateMftMirror(PNTFS_VCB Vcb)
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("ERROR: Couldn't find $DATA attribute!\n");
-        ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
         return Status;
     }
 
@@ -2682,7 +2754,7 @@ UpdateMftMirror(PNTFS_VCB Vcb)
     {
         DPRINT1("ERROR: Couldn't find $DATA attribute!\n");
         ReleaseAttributeContext(MirrDataContext);
-        ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
         return Status;
     }
 
@@ -2698,7 +2770,7 @@ UpdateMftMirror(PNTFS_VCB Vcb)
         DPRINT1("Error: Couldn't allocate memory for $DATA buffer!\n");
         ReleaseAttributeContext(MftDataContext);
         ReleaseAttributeContext(MirrDataContext);
-        ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
@@ -2712,7 +2784,7 @@ UpdateMftMirror(PNTFS_VCB Vcb)
         ReleaseAttributeContext(MftDataContext);
         ReleaseAttributeContext(MirrDataContext);
         ExFreePoolWithTag(DataBuffer, TAG_NTFS);
-        ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
         return STATUS_UNSUCCESSFUL;
     }
 
@@ -2733,7 +2805,7 @@ UpdateMftMirror(PNTFS_VCB Vcb)
     ReleaseAttributeContext(MftDataContext);
     ReleaseAttributeContext(MirrDataContext);
     ExFreePoolWithTag(DataBuffer, TAG_NTFS);
-    ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
+    ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
 
     return Status;
 }
@@ -2763,10 +2835,155 @@ DumpIndexEntry(PINDEX_ENTRY_ATTRIBUTE IndexEntry)
 }
 #endif
 
+NTSTATUS
+BrowseSubNodeIndexEntries(PNTFS_VCB Vcb,
+                          PFILE_RECORD_HEADER MftRecord,
+                          ULONG IndexBlockSize,
+                          PUNICODE_STRING FileName,
+                          PNTFS_ATTR_CONTEXT IndexAllocationContext,
+                          PRTL_BITMAP Bitmap,
+                          ULONGLONG VCN,
+                          PULONG StartEntry,
+                          PULONG CurrentEntry,
+                          BOOLEAN DirSearch,
+                          BOOLEAN CaseSensitive,
+                          ULONGLONG *OutMFTIndex)
+{
+    PINDEX_BUFFER IndexRecord;
+    ULONGLONG Offset;
+    ULONG BytesRead;
+    PINDEX_ENTRY_ATTRIBUTE FirstEntry;
+    PINDEX_ENTRY_ATTRIBUTE LastEntry;
+    PINDEX_ENTRY_ATTRIBUTE IndexEntry;
+    ULONG NodeNumber;
+    NTSTATUS Status;
+
+    DPRINT("BrowseSubNodeIndexEntries(%p, %p, %lu, %wZ, %p, %p, %I64d, %lu, %lu, %s, %s, %p)\n",
+           Vcb,
+           MftRecord,
+           IndexBlockSize,
+           FileName,
+           IndexAllocationContext,
+           Bitmap,
+           VCN,
+           *StartEntry,
+           *CurrentEntry,
+           "FALSE",
+           DirSearch ? "TRUE" : "FALSE",
+           CaseSensitive ? "TRUE" : "FALSE",
+           OutMFTIndex);
+
+    // Calculate node number as VCN / Clusters per index record
+    NodeNumber = VCN / (Vcb->NtfsInfo.BytesPerIndexRecord / Vcb->NtfsInfo.BytesPerCluster);
+
+    // Is the bit for this node clear in the bitmap?
+    if (!RtlCheckBit(Bitmap, NodeNumber))
+    {
+        DPRINT1("File system corruption detected, node with VCN %I64u is marked as deleted.\n", VCN);
+        return STATUS_DATA_ERROR;
+    }
+
+    // Allocate memory for the index record
+    IndexRecord = ExAllocatePoolWithTag(NonPagedPool, IndexBlockSize, TAG_NTFS);
+    if (!IndexRecord)
+    {
+        DPRINT1("Unable to allocate memory for index record!\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    // Calculate offset of index record
+    Offset = VCN * Vcb->NtfsInfo.BytesPerCluster;
+
+    // Read the index record
+    BytesRead = ReadAttribute(Vcb, IndexAllocationContext, Offset, (PCHAR)IndexRecord, IndexBlockSize);
+    if (BytesRead != IndexBlockSize)
+    {
+        DPRINT1("Unable to read index record!\n");
+        ExFreePoolWithTag(IndexRecord, TAG_NTFS);
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    // Assert that we're dealing with an index record here
+    ASSERT(IndexRecord->Ntfs.Type == NRH_INDX_TYPE);
+
+    // Apply the fixup array to the index record
+    Status = FixupUpdateSequenceArray(Vcb, &((PFILE_RECORD_HEADER)IndexRecord)->Ntfs);
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(IndexRecord, TAG_NTFS);
+        DPRINT1("Failed to apply fixup array!\n");
+        return Status;
+    }
+
+    ASSERT(IndexRecord->Header.AllocatedSize + FIELD_OFFSET(INDEX_BUFFER, Header) == IndexBlockSize);
+    FirstEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexRecord->Header + IndexRecord->Header.FirstEntryOffset);
+    LastEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexRecord->Header + IndexRecord->Header.TotalSizeOfEntries);
+    ASSERT(LastEntry <= (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexRecord + IndexBlockSize));
+
+    // Loop through all Index Entries of index, starting with FirstEntry
+    IndexEntry = FirstEntry;
+    while (IndexEntry <= LastEntry)
+    {
+        // Does IndexEntry have a sub-node?
+        if (IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
+        {
+            if (!(IndexRecord->Header.Flags & INDEX_NODE_LARGE) || !IndexAllocationContext)
+            {
+                DPRINT1("Filesystem corruption detected!\n");
+            }
+            else
+            {
+                Status = BrowseSubNodeIndexEntries(Vcb,
+                                                   MftRecord,
+                                                   IndexBlockSize,
+                                                   FileName,
+                                                   IndexAllocationContext,
+                                                   Bitmap,
+                                                   GetIndexEntryVCN(IndexEntry),
+                                                   StartEntry,
+                                                   CurrentEntry,
+                                                   DirSearch,
+                                                   CaseSensitive,
+                                                   OutMFTIndex);
+                if (NT_SUCCESS(Status))
+                {
+                    ExFreePoolWithTag(IndexRecord, TAG_NTFS);
+                    return Status;
+                }
+            }
+        }
+
+        // Are we done?
+        if (IndexEntry->Flags & NTFS_INDEX_ENTRY_END)
+            break;
+
+        // If we've found a file whose index is greater than or equal to StartEntry that matches the search criteria
+        if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) >= NTFS_FILE_FIRST_USER_FILE &&
+            *CurrentEntry >= *StartEntry &&
+            IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
+            CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
+        {
+            *StartEntry = *CurrentEntry;
+            *OutMFTIndex = (IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK);
+            ExFreePoolWithTag(IndexRecord, TAG_NTFS);
+            return STATUS_SUCCESS;
+        }
+
+        // Advance to the next index entry
+        (*CurrentEntry) += 1;
+        ASSERT(IndexEntry->Length >= sizeof(INDEX_ENTRY_ATTRIBUTE));
+        IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
+    }
+
+    ExFreePoolWithTag(IndexRecord, TAG_NTFS);
+
+    return STATUS_OBJECT_PATH_NOT_FOUND;
+}
+
 NTSTATUS
 BrowseIndexEntries(PDEVICE_EXTENSION Vcb,
                    PFILE_RECORD_HEADER MftRecord,
-                   PCHAR IndexRecord,
+                   PINDEX_ROOT_ATTRIBUTE IndexRecord,
                    ULONG IndexBlockSize,
                    PINDEX_ENTRY_ATTRIBUTE FirstEntry,
                    PINDEX_ENTRY_ATTRIBUTE LastEntry,
@@ -2778,11 +2995,12 @@ BrowseIndexEntries(PDEVICE_EXTENSION Vcb,
                    ULONGLONG *OutMFTIndex)
 {
     NTSTATUS Status;
-    ULONG RecordOffset;
     PINDEX_ENTRY_ATTRIBUTE IndexEntry;
-    PNTFS_ATTR_CONTEXT IndexAllocationCtx;
-    ULONGLONG IndexAllocationSize;
-    PINDEX_BUFFER IndexBuffer;
+    PNTFS_ATTR_CONTEXT IndexAllocationContext;
+    PNTFS_ATTR_CONTEXT BitmapContext;
+    PCHAR *BitmapMem;
+    ULONG *BitmapPtr;
+    RTL_BITMAP  Bitmap;
 
     DPRINT("BrowseIndexEntries(%p, %p, %p, %lu, %p, %p, %wZ, %lu, %lu, %s, %s, %p)\n",
            Vcb,
@@ -2798,10 +3016,100 @@ BrowseIndexEntries(PDEVICE_EXTENSION Vcb,
            CaseSensitive ? "TRUE" : "FALSE",
            OutMFTIndex);
 
+    // Find the $I30 index allocation, if there is one
+    Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationContext, NULL);
+    if (NT_SUCCESS(Status))
+    {
+        ULONGLONG BitmapLength;
+        // Find the bitmap attribute for the index
+        Status = FindAttribute(Vcb, MftRecord, AttributeBitmap, L"$I30", 4, &BitmapContext, NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Potential file system corruption detected!\n");
+            ReleaseAttributeContext(IndexAllocationContext);
+            return Status;
+        }
+
+        // Get the length of the bitmap attribute
+        BitmapLength = AttributeDataLength(BitmapContext->pRecord);
+
+        // Allocate memory for the bitmap, including some padding; RtlInitializeBitmap() wants a pointer 
+        // that's ULONG-aligned, and it wants the size of the memory allocated for it to be a ULONG-multiple.
+        BitmapMem = ExAllocatePoolWithTag(NonPagedPool, BitmapLength + sizeof(ULONG), TAG_NTFS);
+        if (!BitmapMem)
+        {
+            DPRINT1("Error: failed to allocate bitmap!");
+            ReleaseAttributeContext(BitmapContext);
+            ReleaseAttributeContext(IndexAllocationContext);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        RtlZeroMemory(BitmapMem, BitmapLength + sizeof(ULONG));
+
+        // RtlInitializeBitmap() wants a pointer that's ULONG-aligned.
+        BitmapPtr = (PULONG)ALIGN_UP_BY((ULONG_PTR)BitmapMem, sizeof(ULONG));
+
+        // Read the existing bitmap data
+        Status = ReadAttribute(Vcb, BitmapContext, 0, (PCHAR)BitmapPtr, BitmapLength);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("ERROR: Failed to read bitmap attribute!\n");
+            ExFreePoolWithTag(BitmapMem, TAG_NTFS);
+            ReleaseAttributeContext(BitmapContext);
+            ReleaseAttributeContext(IndexAllocationContext);
+            return Status;
+        }
+
+        // Initialize bitmap
+        RtlInitializeBitMap(&Bitmap, BitmapPtr, BitmapLength * 8);
+    }
+    else
+    {
+        // Couldn't find an index allocation
+        IndexAllocationContext = NULL;
+    }
+    
+
+    // Loop through all Index Entries of index, starting with FirstEntry
     IndexEntry = FirstEntry;
-    while (IndexEntry < LastEntry &&
-           !(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
+    while (IndexEntry <= LastEntry)
     {
+        // Does IndexEntry have a sub-node?
+        if (IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
+        {
+            if (!(IndexRecord->Header.Flags & INDEX_ROOT_LARGE) || !IndexAllocationContext)
+            {
+                DPRINT1("Filesystem corruption detected!\n");
+            }
+            else
+            {
+                Status = BrowseSubNodeIndexEntries(Vcb,
+                                                   MftRecord,
+                                                   IndexBlockSize,
+                                                   FileName,
+                                                   IndexAllocationContext,
+                                                   &Bitmap,
+                                                   GetIndexEntryVCN(IndexEntry),
+                                                   StartEntry,
+                                                   CurrentEntry,
+                                                   DirSearch,
+                                                   CaseSensitive,
+                                                   OutMFTIndex);
+                if (NT_SUCCESS(Status))
+                {
+                    ExFreePoolWithTag(BitmapMem, TAG_NTFS);
+                    ReleaseAttributeContext(BitmapContext);
+                    ReleaseAttributeContext(IndexAllocationContext);
+                    return Status;
+                }
+            }
+        }
+
+        // Are we done?
+        if (IndexEntry->Flags & NTFS_INDEX_ENTRY_END)
+            break;
+
+        // If we've found a file whose index is greater than or equal to StartEntry that matches the search criteria
         if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) >= NTFS_FILE_FIRST_USER_FILE &&
             *CurrentEntry >= *StartEntry &&
             IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
@@ -2809,71 +3117,29 @@ BrowseIndexEntries(PDEVICE_EXTENSION Vcb,
         {
             *StartEntry = *CurrentEntry;
             *OutMFTIndex = (IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK);
+            if (IndexAllocationContext)
+            {
+                ExFreePoolWithTag(BitmapMem, TAG_NTFS);
+                ReleaseAttributeContext(BitmapContext);
+                ReleaseAttributeContext(IndexAllocationContext);
+            }
             return STATUS_SUCCESS;
         }
 
+        // Advance to the next index entry
         (*CurrentEntry) += 1;
         ASSERT(IndexEntry->Length >= sizeof(INDEX_ENTRY_ATTRIBUTE));
         IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
     }
 
-    /* If we're already browsing a subnode */
-    if (IndexRecord == NULL)
+    if (IndexAllocationContext)
     {
-        return STATUS_OBJECT_PATH_NOT_FOUND;
-    }
-
-    /* If there's no subnode */
-    if (!(IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE))
-    {
-        return STATUS_OBJECT_PATH_NOT_FOUND; 
-    }
-
-    Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationCtx, NULL);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("Corrupted filesystem!\n");
-        return Status;
-    }
-
-    IndexAllocationSize = AttributeDataLength(IndexAllocationCtx->pRecord);
-    Status = STATUS_OBJECT_PATH_NOT_FOUND;
-    for (RecordOffset = 0; RecordOffset < IndexAllocationSize; RecordOffset += IndexBlockSize)
-    {
-        ReadAttribute(Vcb, IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize);
-        Status = FixupUpdateSequenceArray(Vcb, &((PFILE_RECORD_HEADER)IndexRecord)->Ntfs);
-        if (!NT_SUCCESS(Status))
-        {
-            break;
-        }
-
-        IndexBuffer = (PINDEX_BUFFER)IndexRecord;
-        ASSERT(IndexBuffer->Ntfs.Type == NRH_INDX_TYPE);
-        ASSERT(IndexBuffer->Header.AllocatedSize + FIELD_OFFSET(INDEX_BUFFER, Header) == IndexBlockSize);
-        FirstEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexBuffer->Header + IndexBuffer->Header.FirstEntryOffset);
-        LastEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexBuffer->Header + IndexBuffer->Header.TotalSizeOfEntries);
-        ASSERT(LastEntry <= (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexBuffer + IndexBlockSize));
-
-        Status = BrowseIndexEntries(NULL,
-                                    NULL,
-                                    NULL,
-                                    0,
-                                    FirstEntry,
-                                    LastEntry,
-                                    FileName,
-                                    StartEntry,
-                                    CurrentEntry,
-                                    DirSearch,
-                                    CaseSensitive,
-                                    OutMFTIndex);
-        if (NT_SUCCESS(Status))
-        {
-            break;
-        }
+        ExFreePoolWithTag(BitmapMem, TAG_NTFS);
+        ReleaseAttributeContext(BitmapContext);
+        ReleaseAttributeContext(IndexAllocationContext);
     }
 
-    ReleaseAttributeContext(IndexAllocationCtx);
-    return Status;    
+    return STATUS_OBJECT_PATH_NOT_FOUND;
 }
 
 NTSTATUS
@@ -2902,9 +3168,7 @@ NtfsFindMftRecord(PDEVICE_EXTENSION Vcb,
            CaseSensitive ? "TRUE" : "FALSE",
            OutMFTIndex);
 
-    MftRecord = ExAllocatePoolWithTag(NonPagedPool,
-                                      Vcb->NtfsInfo.BytesPerFileRecord,
-                                      TAG_NTFS);
+    MftRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
     if (MftRecord == NULL)
     {
         return STATUS_INSUFFICIENT_RESOURCES;
@@ -2913,7 +3177,7 @@ NtfsFindMftRecord(PDEVICE_EXTENSION Vcb,
     Status = ReadFileRecord(Vcb, MFTIndex, MftRecord);
     if (!NT_SUCCESS(Status))
     {
-        ExFreePoolWithTag(MftRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
         return Status;
     }
 
@@ -2921,7 +3185,7 @@ NtfsFindMftRecord(PDEVICE_EXTENSION Vcb,
     Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, L"$I30", 4, &IndexRootCtx, NULL);
     if (!NT_SUCCESS(Status))
     {
-        ExFreePoolWithTag(MftRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
         return Status;
     }
 
@@ -2929,7 +3193,7 @@ NtfsFindMftRecord(PDEVICE_EXTENSION Vcb,
     if (IndexRecord == NULL)
     {
         ReleaseAttributeContext(IndexRootCtx);
-        ExFreePoolWithTag(MftRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
@@ -2944,7 +3208,7 @@ NtfsFindMftRecord(PDEVICE_EXTENSION Vcb,
 
     Status = BrowseIndexEntries(Vcb,
                                 MftRecord,
-                                IndexRecord,
+                                (PINDEX_ROOT_ATTRIBUTE)IndexRecord,
                                 IndexRoot->SizeOfEntry,
                                 IndexEntry,
                                 IndexEntryEnd,
@@ -2956,7 +3220,7 @@ NtfsFindMftRecord(PDEVICE_EXTENSION Vcb,
                                 OutMFTIndex);
 
     ExFreePoolWithTag(IndexRecord, TAG_NTFS);
-    ExFreePoolWithTag(MftRecord, TAG_NTFS);
+    ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
 
     return Status;
 }
@@ -2999,7 +3263,7 @@ NtfsLookupFileAt(PDEVICE_EXTENSION Vcb,
         FsRtlDissectName(Current, &Current, &Remaining);
     }
 
-    *FileRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+    *FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
     if (*FileRecord == NULL)
     {
         DPRINT("NtfsLookupFileAt: Can't allocate MFT record\n");
@@ -3010,7 +3274,7 @@ NtfsLookupFileAt(PDEVICE_EXTENSION Vcb,
     if (!NT_SUCCESS(Status))
     {
         DPRINT("NtfsLookupFileAt: Can't read MFT record\n");
-        ExFreePoolWithTag(*FileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, *FileRecord);
         return Status;
     }
 
@@ -3029,6 +3293,24 @@ NtfsLookupFile(PDEVICE_EXTENSION Vcb,
     return NtfsLookupFileAt(Vcb, PathName, CaseSensitive, FileRecord, MFTIndex, NTFS_FILE_ROOT);
 }
 
+void
+NtfsDumpData(ULONG_PTR Buffer, ULONG Length)
+{
+    ULONG i, j;
+
+    // dump binary data, 8 bytes at a time
+    for (i = 0; i < Length; i += 8)
+    {
+        // display current offset, in hex
+        DbgPrint("\t%03x\t", i);
+
+        // display hex value of each of the next 8 bytes
+        for (j = 0; j < 8; j++)
+            DbgPrint("%02x ", *(PUCHAR)(Buffer + i + j));
+        DbgPrint("\n");
+    }
+}
+
 /**
 * @name NtfsDumpFileRecord
 * @implemented
@@ -3096,7 +3378,7 @@ NtfsFindFileAt(PDEVICE_EXTENSION Vcb,
         return Status;
     }
 
-    *FileRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+    *FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
     if (*FileRecord == NULL)
     {
         DPRINT("NtfsFindFileAt: Can't allocate MFT record\n");
@@ -3107,7 +3389,7 @@ NtfsFindFileAt(PDEVICE_EXTENSION Vcb,
     if (!NT_SUCCESS(Status))
     {
         DPRINT("NtfsFindFileAt: Can't read MFT record\n");
-        ExFreePoolWithTag(*FileRecord, TAG_NTFS);
+        ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, *FileRecord);
         return Status;
     }