[NTFS]
authorPierre Schweitzer <pierre@reactos.org>
Wed, 26 Aug 2015 18:20:04 +0000 (18:20 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Wed, 26 Aug 2015 18:20:04 +0000 (18:20 +0000)
Totally rewrite the way MFT records attributes are handled.
Up to now, we were having really similar loops, only looking at the resident part of the attribute list, not really caring about how the loop was going.

This was leading to some issues:
- In case the attribute we were looking for was stored in the non-resident part of the attribute list, we would miss it (excepted in the case of FindAttribute() which was properly browsing the whole attribute list).
- In the specific case of FindAttribute(), one would have been able to setup a broken MFT record with the resident attribute list pointing on the non resident attribute list which itself would point to the resident attribute list. In such case, the driver would loop forever caught on the loop, allocating tones of memory. It was possible to trigger this by user space, from a non-privileged user, just by browsing the right directory entry.
- In the case of the other loops (non FindAttribute()), another issue (other than missing attributes) was present, one would have been able to setup a broken MFT record with an attribute of null-length. This would have caused the driver to loop forever on the attribute list. This could be triggered from usermode too. And could be triggered by a non-privileged user.

This commit introduces a new set of functions for attributes browsing: FindFirstAttribute(), FindNextAttribute(), FindCloseAttribute(). It allows safely browsing attributes and handles broken cases. It also performs reading of the attribute list when present and makes sure there's only one read. This method should be the only one to use to browse the attributes.
The whole NTFS code base has been converted to use this newly set of functions. This really simplifies the implementation of FindAttribute(), and prevent unsafe code duplication.

CORE-10037 #resolve #comment Fixed with r68829

svn path=/trunk/; revision=68829

reactos/drivers/filesystems/ntfs/attrib.c
reactos/drivers/filesystems/ntfs/create.c
reactos/drivers/filesystems/ntfs/dirctl.c
reactos/drivers/filesystems/ntfs/fcb.c
reactos/drivers/filesystems/ntfs/finfo.c
reactos/drivers/filesystems/ntfs/fsctl.c
reactos/drivers/filesystems/ntfs/mft.c
reactos/drivers/filesystems/ntfs/ntfs.h
reactos/drivers/filesystems/ntfs/rw.c

index e75219a..7b4b9e4 100644 (file)
@@ -23,6 +23,7 @@
  * PROGRAMMERS:      Eric Kohl
  *                   Valentin Verkhovsky
  *                   Hervé Poussineau (hpoussin@reactos.org)
  * PROGRAMMERS:      Eric Kohl
  *                   Valentin Verkhovsky
  *                   Hervé Poussineau (hpoussin@reactos.org)
+ *                   Pierre Schweitzer (pierre@reactos.org)
  */
 
 /* INCLUDES *****************************************************************/
  */
 
 /* INCLUDES *****************************************************************/
@@ -92,6 +93,207 @@ FindRun(PNTFS_ATTR_RECORD NresAttr,
     return TRUE;
 }
 
     return TRUE;
 }
 
+static
+NTSTATUS
+InternalReadNonResidentAttributes(PFIND_ATTR_CONTXT Context)
+{
+    ULONGLONG ListSize;
+    PNTFS_ATTR_RECORD Attribute;
+    PNTFS_ATTR_CONTEXT ListContext;
+
+    DPRINT("InternalReadNonResidentAttributes(%p)\n", Context);
+
+    Attribute = Context->CurrAttr;
+    ASSERT(Attribute->Type == AttributeAttributeList);
+
+    if (Context->OnlyResident)
+    {
+        Context->NonResidentStart = NULL;
+        Context->NonResidentEnd = NULL;
+        return STATUS_SUCCESS;
+    }
+
+    if (Context->NonResidentStart != NULL)
+    {
+        return STATUS_FILE_CORRUPT_ERROR;
+    }
+
+    ListContext = PrepareAttributeContext(Attribute);
+    ListSize = AttributeDataLength(&ListContext->Record);
+    if (ListSize > 0xFFFFFFFF)
+    {
+        ReleaseAttributeContext(ListContext);
+        return STATUS_BUFFER_OVERFLOW;
+    }
+
+    Context->NonResidentStart = ExAllocatePoolWithTag(NonPagedPool, (ULONG)ListSize, TAG_NTFS);
+    if (Context->NonResidentStart == NULL)
+    {
+        ReleaseAttributeContext(ListContext);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (ReadAttribute(Context->Vcb, ListContext, 0, (PCHAR)Context->NonResidentStart, (ULONG)ListSize) != ListSize)
+    {
+        ExFreePoolWithTag(Context->NonResidentStart, TAG_NTFS);
+        Context->NonResidentStart = NULL;
+        ReleaseAttributeContext(ListContext);
+        return STATUS_FILE_CORRUPT_ERROR;
+    }
+
+    ReleaseAttributeContext(ListContext);
+    Context->NonResidentEnd = (PNTFS_ATTR_RECORD)((PCHAR)Context->NonResidentStart + ListSize);
+    return STATUS_SUCCESS;
+}
+
+static
+PNTFS_ATTR_RECORD
+InternalGetNextAttribute(PFIND_ATTR_CONTXT Context)
+{
+    if (Context->CurrAttr == (PVOID)-1)
+    {
+        return NULL;
+    }
+
+    if (Context->CurrAttr >= Context->FirstAttr &&
+        Context->CurrAttr < Context->LastAttr)
+    {
+        if (Context->CurrAttr->Length == 0)
+        {
+            DPRINT1("Broken length!\n");
+            Context->CurrAttr = (PVOID)-1;
+            return NULL;
+        }
+
+        Context->CurrAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)Context->CurrAttr + Context->CurrAttr->Length);
+        if (Context->CurrAttr < Context->LastAttr &&
+            Context->CurrAttr->Type != AttributeEnd)
+        {
+            return Context->CurrAttr;
+        }
+    }
+
+    if (Context->NonResidentStart == NULL)
+    {
+        Context->CurrAttr = (PVOID)-1;
+        return NULL;
+    }
+
+    if (Context->CurrAttr < Context->NonResidentStart ||
+        Context->CurrAttr >= Context->NonResidentEnd)
+    {
+        Context->CurrAttr = Context->NonResidentStart;
+    }
+    else if (Context->CurrAttr->Length != 0)
+    {
+        Context->CurrAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)Context->CurrAttr + Context->CurrAttr->Length);
+    }
+    else
+    {
+        DPRINT1("Broken length!\n");
+        Context->CurrAttr = (PVOID)-1;
+        return NULL;
+    }
+
+    if (Context->CurrAttr < Context->NonResidentEnd &&
+        Context->CurrAttr->Type != AttributeEnd)
+    {
+        return Context->CurrAttr;
+    }
+
+    Context->CurrAttr = (PVOID)-1;
+    return NULL;
+}
+
+NTSTATUS
+FindFirstAttribute(PFIND_ATTR_CONTXT Context,
+                   PDEVICE_EXTENSION Vcb,
+                   PFILE_RECORD_HEADER FileRecord,
+                   BOOLEAN OnlyResident,
+                   PNTFS_ATTR_RECORD * Attribute)
+{
+    NTSTATUS Status;
+
+    DPRINT("FindFistAttribute(%p, %p, %p, %p, %u, %p)\n", Context, Vcb, FileRecord, OnlyResident, Attribute);
+
+    Context->Vcb = Vcb;
+    Context->OnlyResident = OnlyResident;
+    Context->FirstAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
+    Context->CurrAttr = Context->FirstAttr;
+    Context->LastAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse);
+    Context->NonResidentStart = NULL;
+    Context->NonResidentEnd = NULL;
+
+    if (Context->FirstAttr->Type == AttributeEnd)
+    {
+        Context->CurrAttr = (PVOID)-1;
+        return STATUS_END_OF_FILE;
+    }
+    else if (Context->FirstAttr->Type == AttributeAttributeList)
+    {
+        Status = InternalReadNonResidentAttributes(Context);
+        if (!NT_SUCCESS(Status))
+        {
+            return Status;
+        }
+
+        *Attribute = InternalGetNextAttribute(Context);
+        if (*Attribute == NULL)
+        {
+            return STATUS_END_OF_FILE;
+        }
+    }
+    else
+    {
+        *Attribute = Context->CurrAttr;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+FindNextAttribute(PFIND_ATTR_CONTXT Context,
+                  PNTFS_ATTR_RECORD * Attribute)
+{
+    NTSTATUS Status;
+
+    DPRINT("FindNextAttribute(%p, %p)\n", Context, Attribute);
+
+    *Attribute = InternalGetNextAttribute(Context);
+    if (*Attribute == NULL)
+    {
+        return STATUS_END_OF_FILE;
+    }
+
+    if (Context->CurrAttr->Type != AttributeAttributeList)
+    {
+        return STATUS_SUCCESS;
+    }
+
+    Status = InternalReadNonResidentAttributes(Context);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    *Attribute = InternalGetNextAttribute(Context);
+    if (*Attribute == NULL)
+    {
+        return STATUS_END_OF_FILE;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+VOID
+FindCloseAttribute(PFIND_ATTR_CONTXT Context)
+{
+    if (Context->NonResidentStart != NULL)
+    {
+        ExFreePoolWithTag(Context->NonResidentStart, TAG_NTFS);
+        Context->NonResidentStart = NULL;
+    }
+}
 
 static
 VOID
 
 static
 VOID
@@ -341,27 +543,33 @@ VOID
 NtfsDumpFileAttributes(PDEVICE_EXTENSION Vcb,
                        PFILE_RECORD_HEADER FileRecord)
 {
 NtfsDumpFileAttributes(PDEVICE_EXTENSION Vcb,
                        PFILE_RECORD_HEADER FileRecord)
 {
+    NTSTATUS Status;
+    FIND_ATTR_CONTXT Context;
     PNTFS_ATTR_RECORD Attribute;
 
     PNTFS_ATTR_RECORD Attribute;
 
-    Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
-    while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
-           Attribute->Type != AttributeEnd)
+    Status = FindFirstAttribute(&Context, Vcb, FileRecord, FALSE, &Attribute);
+    while (NT_SUCCESS(Status))
     {
         NtfsDumpAttribute(Vcb, Attribute);
 
     {
         NtfsDumpAttribute(Vcb, Attribute);
 
-        Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
+        Status = FindNextAttribute(&Context, &Attribute);
     }
     }
+
+    FindCloseAttribute(&Context);
 }
 
 PFILENAME_ATTRIBUTE
 }
 
 PFILENAME_ATTRIBUTE
-GetFileNameFromRecord(PFILE_RECORD_HEADER FileRecord, UCHAR NameType)
+GetFileNameFromRecord(PDEVICE_EXTENSION Vcb,
+                      PFILE_RECORD_HEADER FileRecord,
+                      UCHAR NameType)
 {
 {
+    FIND_ATTR_CONTXT Context;
     PNTFS_ATTR_RECORD Attribute;
     PFILENAME_ATTRIBUTE Name;
     PNTFS_ATTR_RECORD Attribute;
     PFILENAME_ATTRIBUTE Name;
+    NTSTATUS Status;
 
 
-    Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
-    while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
-           Attribute->Type != AttributeEnd)
+    Status = FindFirstAttribute(&Context, Vcb, FileRecord, FALSE, &Attribute);
+    while (NT_SUCCESS(Status))
     {
         if (Attribute->Type == AttributeFileName)
         {
     {
         if (Attribute->Type == AttributeFileName)
         {
@@ -370,50 +578,57 @@ GetFileNameFromRecord(PFILE_RECORD_HEADER FileRecord, UCHAR NameType)
                 (Name->NameType == NTFS_FILE_NAME_WIN32_AND_DOS && NameType == NTFS_FILE_NAME_WIN32) ||
                 (Name->NameType == NTFS_FILE_NAME_WIN32_AND_DOS && NameType == NTFS_FILE_NAME_DOS))
             {
                 (Name->NameType == NTFS_FILE_NAME_WIN32_AND_DOS && NameType == NTFS_FILE_NAME_WIN32) ||
                 (Name->NameType == NTFS_FILE_NAME_WIN32_AND_DOS && NameType == NTFS_FILE_NAME_DOS))
             {
+                FindCloseAttribute(&Context);
                 return Name;
             }
         }
 
                 return Name;
             }
         }
 
-        Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
+        Status = FindNextAttribute(&Context, &Attribute);
     }
 
     }
 
+    FindCloseAttribute(&Context);
     return NULL;
 }
 
 PSTANDARD_INFORMATION
     return NULL;
 }
 
 PSTANDARD_INFORMATION
-GetStandardInformationFromRecord(PFILE_RECORD_HEADER FileRecord)
+GetStandardInformationFromRecord(PDEVICE_EXTENSION Vcb,
+                                 PFILE_RECORD_HEADER FileRecord)
 {
 {
+    NTSTATUS Status;
+    FIND_ATTR_CONTXT Context;
     PNTFS_ATTR_RECORD Attribute;
     PSTANDARD_INFORMATION StdInfo;
 
     PNTFS_ATTR_RECORD Attribute;
     PSTANDARD_INFORMATION StdInfo;
 
-    Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
-    while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
-           Attribute->Type != AttributeEnd)
+    Status = FindFirstAttribute(&Context, Vcb, FileRecord, FALSE, &Attribute);
+    while (NT_SUCCESS(Status))
     {
         if (Attribute->Type == AttributeStandardInformation)
         {
             StdInfo = (PSTANDARD_INFORMATION)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
     {
         if (Attribute->Type == AttributeStandardInformation)
         {
             StdInfo = (PSTANDARD_INFORMATION)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
+            FindCloseAttribute(&Context);
             return StdInfo;
         }
 
             return StdInfo;
         }
 
-        Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
+        Status = FindNextAttribute(&Context, &Attribute);
     }
 
     }
 
+    FindCloseAttribute(&Context);
     return NULL;
 }
 
 PFILENAME_ATTRIBUTE
     return NULL;
 }
 
 PFILENAME_ATTRIBUTE
-GetBestFileNameFromRecord(PFILE_RECORD_HEADER FileRecord)
+GetBestFileNameFromRecord(PDEVICE_EXTENSION Vcb,
+                          PFILE_RECORD_HEADER FileRecord)
 {
     PFILENAME_ATTRIBUTE FileName;
 
 {
     PFILENAME_ATTRIBUTE FileName;
 
-    FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_POSIX);
+    FileName = GetFileNameFromRecord(Vcb, FileRecord, NTFS_FILE_NAME_POSIX);
     if (FileName == NULL)
     {
     if (FileName == NULL)
     {
-        FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_WIN32);
+        FileName = GetFileNameFromRecord(Vcb, FileRecord, NTFS_FILE_NAME_WIN32);
         if (FileName == NULL)
         {
         if (FileName == NULL)
         {
-            FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
+            FileName = GetFileNameFromRecord(Vcb, FileRecord, NTFS_FILE_NAME_DOS);
         }
     }
 
         }
     }
 
index efb9c81..d8ad708 100644 (file)
@@ -135,7 +135,7 @@ NtfsMoonWalkID(PDEVICE_EXTENSION DeviceExt,
             break;
         }
 
             break;
         }
 
-        FileName = GetBestFileNameFromRecord(MftRecord);
+        FileName = GetBestFileNameFromRecord(DeviceExt, MftRecord);
         if (FileName == NULL)
         {
             DPRINT1("$FILE_NAME attribute not found for %I64x\n", Id);
         if (FileName == NULL)
         {
             DPRINT1("$FILE_NAME attribute not found for %I64x\n", Id);
index d7ff4da..a9d16fd 100644 (file)
@@ -73,7 +73,7 @@ NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt,
 
     DPRINT("NtfsGetNameInformation() called\n");
 
 
     DPRINT("NtfsGetNameInformation() called\n");
 
-    FileName = GetBestFileNameFromRecord(FileRecord);
+    FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
     if (FileName == NULL)
     {
         DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
     if (FileName == NULL)
     {
         DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
@@ -107,7 +107,7 @@ NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
 
     DPRINT("NtfsGetDirectoryInformation() called\n");
 
 
     DPRINT("NtfsGetDirectoryInformation() called\n");
 
-    FileName = GetBestFileNameFromRecord(FileRecord);
+    FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
     if (FileName == NULL)
     {
         DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
     if (FileName == NULL)
     {
         DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
@@ -115,7 +115,7 @@ NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
         return STATUS_OBJECT_NAME_NOT_FOUND;
     }
 
         return STATUS_OBJECT_NAME_NOT_FOUND;
     }
 
-    StdInfo = GetStandardInformationFromRecord(FileRecord);
+    StdInfo = GetStandardInformationFromRecord(DeviceExt, FileRecord);
     ASSERT(StdInfo != NULL);
 
     Length = FileName->NameLength * sizeof (WCHAR);
     ASSERT(StdInfo != NULL);
 
     Length = FileName->NameLength * sizeof (WCHAR);
@@ -156,7 +156,7 @@ NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
 
     DPRINT("NtfsGetFullDirectoryInformation() called\n");
 
 
     DPRINT("NtfsGetFullDirectoryInformation() called\n");
 
-    FileName = GetBestFileNameFromRecord(FileRecord);
+    FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
     if (FileName == NULL)
     {
         DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
     if (FileName == NULL)
     {
         DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
@@ -164,7 +164,7 @@ NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
         return STATUS_OBJECT_NAME_NOT_FOUND;
     }
 
         return STATUS_OBJECT_NAME_NOT_FOUND;
     }
 
-    StdInfo = GetStandardInformationFromRecord(FileRecord);
+    StdInfo = GetStandardInformationFromRecord(DeviceExt, FileRecord);
     ASSERT(StdInfo != NULL);
 
     Length = FileName->NameLength * sizeof (WCHAR);
     ASSERT(StdInfo != NULL);
 
     Length = FileName->NameLength * sizeof (WCHAR);
@@ -206,16 +206,16 @@ NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
 
     DPRINT("NtfsGetBothDirectoryInformation() called\n");
 
 
     DPRINT("NtfsGetBothDirectoryInformation() called\n");
 
-    FileName = GetBestFileNameFromRecord(FileRecord);
+    FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
     if (FileName == NULL)
     {
         DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
         NtfsDumpFileAttributes(DeviceExt, FileRecord);
         return STATUS_OBJECT_NAME_NOT_FOUND;
     }
     if (FileName == NULL)
     {
         DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
         NtfsDumpFileAttributes(DeviceExt, FileRecord);
         return STATUS_OBJECT_NAME_NOT_FOUND;
     }
-    ShortFileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
+    ShortFileName = GetFileNameFromRecord(DeviceExt, FileRecord, NTFS_FILE_NAME_DOS);
 
 
-    StdInfo = GetStandardInformationFromRecord(FileRecord);
+    StdInfo = GetStandardInformationFromRecord(DeviceExt, FileRecord);
     ASSERT(StdInfo != NULL);
 
     Length = FileName->NameLength * sizeof (WCHAR);
     ASSERT(StdInfo != NULL);
 
     Length = FileName->NameLength * sizeof (WCHAR);
index 7d3d070..02bbb10 100644 (file)
@@ -319,7 +319,7 @@ NtfsMakeRootFCB(PNTFS_VCB Vcb)
         return NULL;
     }
 
         return NULL;
     }
 
-    FileName = GetFileNameFromRecord(MftRecord, NTFS_FILE_NAME_WIN32);
+    FileName = GetFileNameFromRecord(Vcb, MftRecord, NTFS_FILE_NAME_WIN32);
     if (!FileName)
     {
         ExFreePoolWithTag(MftRecord, TAG_NTFS);
     if (!FileName)
     {
         ExFreePoolWithTag(MftRecord, TAG_NTFS);
@@ -387,7 +387,7 @@ NtfsMakeFCBFromDirEntry(PNTFS_VCB Vcb,
 
     DPRINT1("NtfsMakeFCBFromDirEntry(%p, %p, %wZ, %p, %p, %p)\n", Vcb, DirectoryFCB, Name, Stream, Record, fileFCB);
 
 
     DPRINT1("NtfsMakeFCBFromDirEntry(%p, %p, %wZ, %p, %p, %p)\n", Vcb, DirectoryFCB, Name, Stream, Record, fileFCB);
 
-    FileName = GetBestFileNameFromRecord(Record);
+    FileName = GetBestFileNameFromRecord(Vcb, Record);
     if (!FileName)
     {
         return STATUS_OBJECT_NAME_NOT_FOUND; // Not sure that's the best here
     if (!FileName)
     {
         return STATUS_OBJECT_NAME_NOT_FOUND; // Not sure that's the best here
@@ -428,7 +428,7 @@ NtfsMakeFCBFromDirEntry(PNTFS_VCB Vcb,
     rcFCB->RFCB.ValidDataLength.QuadPart = Size;
     rcFCB->RFCB.AllocationSize.QuadPart = AllocatedSize;
 
     rcFCB->RFCB.ValidDataLength.QuadPart = Size;
     rcFCB->RFCB.AllocationSize.QuadPart = AllocatedSize;
 
-    StdInfo = GetStandardInformationFromRecord(Record);
+    StdInfo = GetStandardInformationFromRecord(Vcb, Record);
     if (StdInfo != NULL)
     {
         rcFCB->Entry.FileAttributes |= StdInfo->FileAttribute;
     if (StdInfo != NULL)
     {
         rcFCB->Entry.FileAttributes |= StdInfo->FileAttribute;
index 9b1ad8c..50604f8 100644 (file)
@@ -22,6 +22,7 @@
  * PURPOSE:          NTFS filesystem driver
  * PROGRAMMERS:      Eric Kohl
  *                   Hervé Poussineau (hpoussin@reactos.org)
  * PURPOSE:          NTFS filesystem driver
  * PROGRAMMERS:      Eric Kohl
  *                   Hervé Poussineau (hpoussin@reactos.org)
+ *                   Pierre Schweitzer (pierre@reactos.org)
  */
 
 /* INCLUDES *****************************************************************/
  */
 
 /* INCLUDES *****************************************************************/
@@ -225,9 +226,10 @@ NtfsGetSteamInformation(PNTFS_FCB Fcb,
                         PFILE_STREAM_INFORMATION StreamInfo,
                         PULONG BufferLength)
 {
                         PFILE_STREAM_INFORMATION StreamInfo,
                         PULONG BufferLength)
 {
-    NTSTATUS Status;
     ULONG CurrentSize;
     ULONG CurrentSize;
+    FIND_ATTR_CONTXT Context;
     PNTFS_ATTR_RECORD Attribute;
     PNTFS_ATTR_RECORD Attribute;
+    NTSTATUS Status, BrowseStatus;
     PFILE_RECORD_HEADER FileRecord;
     PFILE_STREAM_INFORMATION CurrentInfo = StreamInfo, Previous = NULL;
 
     PFILE_RECORD_HEADER FileRecord;
     PFILE_STREAM_INFORMATION CurrentInfo = StreamInfo, Previous = NULL;
 
@@ -249,10 +251,8 @@ NtfsGetSteamInformation(PNTFS_FCB Fcb,
         return Status;
     }
 
         return Status;
     }
 
-    Status = STATUS_SUCCESS;
-    Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
-    while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
-           Attribute->Type != AttributeEnd)
+    BrowseStatus = FindFirstAttribute(&Context, DeviceExt, FileRecord, FALSE, &Attribute);
+    while (NT_SUCCESS(BrowseStatus))
     {
         if (Attribute->Type == AttributeData)
         {
     {
         if (Attribute->Type == AttributeData)
         {
@@ -281,9 +281,10 @@ NtfsGetSteamInformation(PNTFS_FCB Fcb,
             *BufferLength -= CurrentSize;
         }
 
             *BufferLength -= CurrentSize;
         }
 
-        Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
+        BrowseStatus = FindNextAttribute(&Context, &Attribute);
     }
 
     }
 
+    FindCloseAttribute(&Context);
     ExFreePoolWithTag(FileRecord, TAG_NTFS);
     return Status;
 }
     ExFreePoolWithTag(FileRecord, TAG_NTFS);
     return Status;
 }
index 0fffc33..f5ec6b3 100644 (file)
@@ -570,6 +570,8 @@ GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt,
     PIO_STACK_LOCATION Stack;
     PNTFS_VOLUME_DATA_BUFFER DataBuffer;
     PNTFS_ATTR_RECORD Attribute;
     PIO_STACK_LOCATION Stack;
     PNTFS_VOLUME_DATA_BUFFER DataBuffer;
     PNTFS_ATTR_RECORD Attribute;
+    FIND_ATTR_CONTXT Context;
+    NTSTATUS Status;
 
     DataBuffer = (PNTFS_VOLUME_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer;
     Stack = IoGetCurrentIrpStackLocation(Irp);
 
     DataBuffer = (PNTFS_VOLUME_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer;
     Stack = IoGetCurrentIrpStackLocation(Irp);
@@ -595,9 +597,8 @@ GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt,
     DataBuffer->MftZoneStart.QuadPart = 0; // FIXME
     DataBuffer->MftZoneEnd.QuadPart = 0; // FIXME
 
     DataBuffer->MftZoneStart.QuadPart = 0; // FIXME
     DataBuffer->MftZoneEnd.QuadPart = 0; // FIXME
 
-    Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DeviceExt->MasterFileTable + DeviceExt->MasterFileTable->AttributeOffset);
-    while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)DeviceExt->MasterFileTable + DeviceExt->MasterFileTable->BytesInUse) &&
-           Attribute->Type != AttributeEnd)
+    Status = FindFirstAttribute(&Context, DeviceExt, DeviceExt->MasterFileTable, FALSE, &Attribute);
+    while (NT_SUCCESS(Status))
     {
         if (Attribute->Type == AttributeData)
         {
     {
         if (Attribute->Type == AttributeData)
         {
@@ -607,8 +608,9 @@ GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt,
             break;
         }
 
             break;
         }
 
-        Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
+        Status = FindNextAttribute(&Context, &Attribute);
     }
     }
+    FindCloseAttribute(&Context);
 
     Irp->IoStatus.Information = sizeof(NTFS_VOLUME_DATA_BUFFER);
 
 
     Irp->IoStatus.Information = sizeof(NTFS_VOLUME_DATA_BUFFER);
 
index 484d9f2..a28c811 100644 (file)
@@ -79,95 +79,6 @@ ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
 }
 
 
 }
 
 
-PNTFS_ATTR_CONTEXT
-FindAttributeHelper(PDEVICE_EXTENSION Vcb,
-                    PNTFS_ATTR_RECORD AttrRecord,
-                    PNTFS_ATTR_RECORD AttrRecordEnd,
-                    ULONG Type,
-                    PCWSTR Name,
-                    ULONG NameLength)
-{
-    DPRINT("FindAttributeHelper(%p, %p, %p, 0x%x, %S, %u)\n", Vcb, AttrRecord, AttrRecordEnd, Type, Name, NameLength);
-
-    while (AttrRecord < AttrRecordEnd)
-    {
-        DPRINT("AttrRecord->Type = 0x%x\n", AttrRecord->Type);
-
-        if (AttrRecord->Type == AttributeEnd)
-            break;
-
-        if (AttrRecord->Type == AttributeAttributeList)
-        {
-            PNTFS_ATTR_CONTEXT Context;
-            PNTFS_ATTR_CONTEXT ListContext;
-            PVOID ListBuffer;
-            ULONGLONG ListSize;
-            PNTFS_ATTR_RECORD ListAttrRecord;
-            PNTFS_ATTR_RECORD ListAttrRecordEnd;
-
-            ListContext = PrepareAttributeContext(AttrRecord);
-
-            ListSize = AttributeDataLength(&ListContext->Record);
-            if(ListSize <= 0xFFFFFFFF)
-                ListBuffer = ExAllocatePoolWithTag(NonPagedPool, (ULONG)ListSize, TAG_NTFS);
-            else
-                ListBuffer = NULL;
-
-            if(!ListBuffer)
-            {
-                DPRINT("Failed to allocate memory: %x\n", (ULONG)ListSize);
-                continue;
-            }
-
-            ListAttrRecord = (PNTFS_ATTR_RECORD)ListBuffer;
-            ListAttrRecordEnd = (PNTFS_ATTR_RECORD)((PCHAR)ListBuffer + ListSize);
-
-            if (ReadAttribute(Vcb, ListContext, 0, ListBuffer, (ULONG)ListSize) == ListSize)
-            {
-                Context = FindAttributeHelper(Vcb, ListAttrRecord, ListAttrRecordEnd,
-                                              Type, Name, NameLength);
-
-                ReleaseAttributeContext(ListContext);
-                ExFreePoolWithTag(ListBuffer, TAG_NTFS);
-
-                if (Context != NULL)
-                {
-                    if (AttrRecord->IsNonResident) DPRINT("Found context = %p\n", Context);
-                    return Context;
-                }
-            }
-        }
-
-        if (AttrRecord->Type == Type)
-        {
-            if (AttrRecord->NameLength == NameLength)
-            {
-                PWCHAR AttrName;
-
-                AttrName = (PWCHAR)((PCHAR)AttrRecord + AttrRecord->NameOffset);
-                DPRINT("%.*S, %.*S\n", AttrRecord->NameLength, AttrName, NameLength, Name);
-                if (RtlCompareMemory(AttrName, Name, NameLength << 1) == (NameLength << 1))
-                {
-                    /* Found it, fill up the context and return. */
-                    DPRINT("Found context\n");
-                    return PrepareAttributeContext(AttrRecord);
-                }
-            }
-        }
-
-        if (AttrRecord->Length == 0)
-        {
-            DPRINT("Null length attribute record\n");
-            return NULL;
-        }
-        AttrRecord = (PNTFS_ATTR_RECORD)((PCHAR)AttrRecord + AttrRecord->Length);
-    }
-
-    DPRINT("Ended\n");
-    return NULL;
-}
-
-
 NTSTATUS
 FindAttribute(PDEVICE_EXTENSION Vcb,
               PFILE_RECORD_HEADER MftRecord,
 NTSTATUS
 FindAttribute(PDEVICE_EXTENSION Vcb,
               PFILE_RECORD_HEADER MftRecord,
@@ -176,21 +87,36 @@ FindAttribute(PDEVICE_EXTENSION Vcb,
               ULONG NameLength,
               PNTFS_ATTR_CONTEXT * AttrCtx)
 {
               ULONG NameLength,
               PNTFS_ATTR_CONTEXT * AttrCtx)
 {
-    PNTFS_ATTR_RECORD AttrRecord;
-    PNTFS_ATTR_RECORD AttrRecordEnd;
+    NTSTATUS Status;
+    FIND_ATTR_CONTXT Context;
+    PNTFS_ATTR_RECORD Attribute;
 
     DPRINT("FindAttribute(%p, %p, 0x%x, %S, %u, %p)\n", Vcb, MftRecord, Type, Name, NameLength, AttrCtx);
 
 
     DPRINT("FindAttribute(%p, %p, 0x%x, %S, %u, %p)\n", Vcb, MftRecord, Type, Name, NameLength, AttrCtx);
 
-    AttrRecord = (PNTFS_ATTR_RECORD)((PCHAR)MftRecord + MftRecord->AttributeOffset);
-    AttrRecordEnd = (PNTFS_ATTR_RECORD)((PCHAR)MftRecord + Vcb->NtfsInfo.BytesPerFileRecord);
-
-    *AttrCtx = FindAttributeHelper(Vcb, AttrRecord, AttrRecordEnd, Type, Name, NameLength);
-    if (*AttrCtx == NULL)
+    Status = FindFirstAttribute(&Context, Vcb, MftRecord, FALSE, &Attribute);
+    while (NT_SUCCESS(Status))
     {
     {
-        return STATUS_OBJECT_NAME_NOT_FOUND;
+        if (Attribute->Type == Type && Attribute->NameLength == NameLength)
+        {
+            PWCHAR AttrName;
+
+            AttrName = (PWCHAR)((PCHAR)Attribute + Attribute->NameOffset);
+            DPRINT("%.*S, %.*S\n", Attribute->NameLength, AttrName, NameLength, Name);
+            if (RtlCompareMemory(AttrName, Name, NameLength << 1) == (NameLength << 1))
+            {
+                /* Found it, fill up the context and return. */
+                DPRINT("Found context\n");
+                *AttrCtx = PrepareAttributeContext(Attribute);
+                FindCloseAttribute(&Context);
+                return STATUS_SUCCESS;
+            }
+        }
+
+        Status = FindNextAttribute(&Context, &Attribute);
     }
 
     }
 
-    return STATUS_SUCCESS;
+    FindCloseAttribute(&Context);
+    return STATUS_OBJECT_NAME_NOT_FOUND;
 }
 
 
 }
 
 
index 3886258..6366b3c 100644 (file)
@@ -462,6 +462,17 @@ typedef struct _FCB
 
 } NTFS_FCB, *PNTFS_FCB;
 
 
 } NTFS_FCB, *PNTFS_FCB;
 
+typedef struct _FIND_ATTR_CONTXT
+{
+    PDEVICE_EXTENSION Vcb;
+    BOOLEAN OnlyResident;
+    PNTFS_ATTR_RECORD FirstAttr;
+    PNTFS_ATTR_RECORD CurrAttr;
+    PNTFS_ATTR_RECORD LastAttr;
+    PNTFS_ATTR_RECORD NonResidentStart;
+    PNTFS_ATTR_RECORD NonResidentEnd;
+} FIND_ATTR_CONTXT, *PFIND_ATTR_CONTXT;
+
 extern PNTFS_GLOBAL_DATA NtfsGlobalData;
 
 FORCEINLINE
 extern PNTFS_GLOBAL_DATA NtfsGlobalData;
 
 FORCEINLINE
@@ -487,16 +498,35 @@ DecodeRun(PUCHAR DataRun,
           ULONGLONG *DataRunLength);
 
 VOID
           ULONGLONG *DataRunLength);
 
 VOID
-NtfsDumpFileAttributes(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord);
+NtfsDumpFileAttributes(PDEVICE_EXTENSION Vcb,
+                       PFILE_RECORD_HEADER FileRecord);
 
 PSTANDARD_INFORMATION
 
 PSTANDARD_INFORMATION
-GetStandardInformationFromRecord(PFILE_RECORD_HEADER FileRecord);
+GetStandardInformationFromRecord(PDEVICE_EXTENSION Vcb,
+                                 PFILE_RECORD_HEADER FileRecord);
 
 PFILENAME_ATTRIBUTE
 
 PFILENAME_ATTRIBUTE
-GetFileNameFromRecord(PFILE_RECORD_HEADER FileRecord, UCHAR NameType);
+GetFileNameFromRecord(PDEVICE_EXTENSION Vcb,
+                      PFILE_RECORD_HEADER FileRecord,
+                      UCHAR NameType);
 
 PFILENAME_ATTRIBUTE
 
 PFILENAME_ATTRIBUTE
-GetBestFileNameFromRecord(PFILE_RECORD_HEADER FileRecord);
+GetBestFileNameFromRecord(PDEVICE_EXTENSION Vcb,
+                          PFILE_RECORD_HEADER FileRecord);
+
+NTSTATUS
+FindFirstAttribute(PFIND_ATTR_CONTXT Context,
+                   PDEVICE_EXTENSION Vcb,
+                   PFILE_RECORD_HEADER FileRecord,
+                   BOOLEAN OnlyResident,
+                   PNTFS_ATTR_RECORD * Attribute);
+
+NTSTATUS
+FindNextAttribute(PFIND_ATTR_CONTXT Context,
+                  PNTFS_ATTR_RECORD * Attribute);
+
+VOID
+FindCloseAttribute(PFIND_ATTR_CONTXT Context);
 
 /* blockdev.c */
 
 
 /* blockdev.c */
 
index 336e107..cfccd04 100644 (file)
@@ -98,13 +98,14 @@ NtfsReadFile(PDEVICE_EXTENSION DeviceExt,
     Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext);
     if (!NT_SUCCESS(Status))
     {
     Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext);
     if (!NT_SUCCESS(Status))
     {
+        NTSTATUS BrowseStatus;
+        FIND_ATTR_CONTXT Context;
         PNTFS_ATTR_RECORD Attribute;
 
         DPRINT1("No '%S' data stream associated with file!\n", Fcb->Stream);
 
         PNTFS_ATTR_RECORD Attribute;
 
         DPRINT1("No '%S' data stream associated with file!\n", Fcb->Stream);
 
-        Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
-        while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
-               Attribute->Type != AttributeEnd)
+        BrowseStatus = FindFirstAttribute(&Context, DeviceExt, FileRecord, FALSE, &Attribute);
+        while (NT_SUCCESS(BrowseStatus))
         {
             if (Attribute->Type == AttributeData)
             {
         {
             if (Attribute->Type == AttributeData)
             {
@@ -116,8 +117,9 @@ NtfsReadFile(PDEVICE_EXTENSION DeviceExt,
                 DPRINT1("Data stream: '%wZ' available\n", &Name);
             }
 
                 DPRINT1("Data stream: '%wZ' available\n", &Name);
             }
 
-            Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
+            BrowseStatus = FindNextAttribute(&Context, &Attribute);
         }
         }
+        FindCloseAttribute(&Context);
 
         ReleaseAttributeContext(DataContext);
         ExFreePoolWithTag(FileRecord, TAG_NTFS);
 
         ReleaseAttributeContext(DataContext);
         ExFreePoolWithTag(FileRecord, TAG_NTFS);