@@ -39,6 +39,8 @@ DBG_DEFAULT_CHANNEL(FILESYSTEM);
3939#define TAG_NTFS_VOLUME 'VftN'
4040#define TAG_NTFS_DATA 'DftN'
4141
42+ #define NTFS_MAX_ATTRIBUTE_LIST_RECURSION 8
43+
4244typedef struct _NTFS_VOLUME_INFO
4345{
4446 NTFS_BOOTSECTOR BootSector ;
@@ -371,21 +373,101 @@ static ULONG NtfsReadAttribute(PNTFS_VOLUME_INFO Volume, PNTFS_ATTR_CONTEXT Cont
371373 return AlreadyRead ;
372374}
373375
374- static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper (PNTFS_VOLUME_INFO Volume , PNTFS_ATTR_RECORD AttrRecord , PNTFS_ATTR_RECORD AttrRecordEnd , ULONG Type , const WCHAR * Name , ULONG NameLength )
376+ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper (
377+ PNTFS_VOLUME_INFO Volume ,
378+ PNTFS_ATTR_RECORD AttrRecord ,
379+ PNTFS_ATTR_RECORD AttrRecordEnd ,
380+ ULONG Type ,
381+ const WCHAR * Name ,
382+ ULONG NameLength ,
383+ ULONG Recursion );
384+ static BOOLEAN NtfsReadMftRecord (PNTFS_VOLUME_INFO Volume , ULONGLONG MFTIndex , PNTFS_MFT_RECORD Buffer );
385+
386+ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelperList (
387+ PNTFS_VOLUME_INFO Volume ,
388+ PNTFS_ATTR_LIST_ATTR AttrListRecord ,
389+ PNTFS_ATTR_LIST_ATTR AttrListRecordEnd ,
390+ ULONG Type ,
391+ const WCHAR * Name ,
392+ ULONG NameLength ,
393+ ULONG Recursion )
394+ {
395+ PNTFS_MFT_RECORD MftRecord = FrLdrTempAlloc (Volume -> MftRecordSize , TAG_NTFS_MFT );
396+ if (!MftRecord )
397+ return NULL ;
398+
399+ while (AttrListRecord < AttrListRecordEnd )
400+ {
401+ ULONGLONG MftIndex = AttrListRecord -> BaseFileRef & 0xFFFFFFFFFFFF ;
402+ ULONG AttrType = AttrListRecord -> Type ;
403+
404+ if (AttrType == NTFS_ATTR_TYPE_END )
405+ break ;
406+
407+ TRACE ("Recursion = %u, AttrListRecord->Type = 0x%x\n" , Recursion , AttrType );
408+
409+ if (AttrType == Type &&
410+ AttrListRecord -> NameLength == NameLength )
411+ {
412+ PWCHAR AttrListName ;
413+
414+ AttrListName = (PWCHAR )((PCHAR )AttrListRecord + AttrListRecord -> NameOffset );
415+ if (RtlEqualMemory (AttrListName , Name , NameLength << 1 ))
416+ {
417+ PNTFS_ATTR_CONTEXT Context ;
418+ PNTFS_ATTR_RECORD AttrRecord ;
419+ PNTFS_ATTR_RECORD AttrRecordEnd ;
420+
421+ if (!NtfsReadMftRecord (Volume , MftIndex , MftRecord ))
422+ goto skip ;
423+
424+ AttrRecord = (PNTFS_ATTR_RECORD )((PCHAR )MftRecord + MftRecord -> AttributesOffset );
425+ AttrRecordEnd = (PNTFS_ATTR_RECORD )((PCHAR )MftRecord + Volume -> MftRecordSize );
426+
427+ Context = NtfsFindAttributeHelper (Volume , AttrRecord , AttrRecordEnd , Type , Name , NameLength , NTFS_MAX_ATTRIBUTE_LIST_RECURSION );
428+ if (Context )
429+ {
430+ FrLdrTempFree (MftRecord , TAG_NTFS_MFT );
431+ return Context ;
432+ }
433+ }
434+ }
435+
436+ skip :
437+ if (AttrListRecord -> RecLength == 0 )
438+ break ;
439+ AttrListRecord = (PNTFS_ATTR_LIST_ATTR )((PCHAR )AttrListRecord + AttrListRecord -> RecLength );
440+ }
441+
442+ FrLdrTempFree (MftRecord , TAG_NTFS_MFT );
443+ return NULL ;
444+ }
445+
446+ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper (
447+ PNTFS_VOLUME_INFO Volume ,
448+ PNTFS_ATTR_RECORD AttrRecord ,
449+ PNTFS_ATTR_RECORD AttrRecordEnd ,
450+ ULONG Type ,
451+ const WCHAR * Name ,
452+ ULONG NameLength ,
453+ ULONG Recursion )
375454{
376455 while (AttrRecord < AttrRecordEnd )
377456 {
378457 if (AttrRecord -> Type == NTFS_ATTR_TYPE_END )
379458 break ;
380459
381- if (AttrRecord -> Type == NTFS_ATTR_TYPE_ATTRIBUTE_LIST )
460+ TRACE ("Recursion = %u, AttrRecord->Type = 0x%x\n" , Recursion , AttrRecord -> Type );
461+
462+ /* Limit the $ATTRIBUTE_LIST recursion or else infinity loop */
463+ if (AttrRecord -> Type == NTFS_ATTR_TYPE_ATTRIBUTE_LIST && Recursion < NTFS_MAX_ATTRIBUTE_LIST_RECURSION )
382464 {
383465 PNTFS_ATTR_CONTEXT Context ;
384466 PNTFS_ATTR_CONTEXT ListContext ;
385467 PVOID ListBuffer ;
386468 ULONGLONG ListSize ;
387- PNTFS_ATTR_RECORD ListAttrRecord ;
388- PNTFS_ATTR_RECORD ListAttrRecordEnd ;
469+ PNTFS_ATTR_LIST_ATTR ListAttrRecord ;
470+ PNTFS_ATTR_LIST_ATTR ListAttrRecordEnd ;
389471
390472 ListContext = NtfsPrepareAttributeContext (AttrRecord );
391473
@@ -401,13 +483,13 @@ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(PNTFS_VOLUME_INFO Volume, PNTF
401483 continue ;
402484 }
403485
404- ListAttrRecord = (PNTFS_ATTR_RECORD )ListBuffer ;
405- ListAttrRecordEnd = (PNTFS_ATTR_RECORD )((PCHAR )ListBuffer + ListSize );
486+ ListAttrRecord = (PNTFS_ATTR_LIST_ATTR )ListBuffer ;
487+ ListAttrRecordEnd = (PNTFS_ATTR_LIST_ATTR )((PCHAR )ListBuffer + ListSize );
406488
407489 if (NtfsReadAttribute (Volume , ListContext , 0 , ListBuffer , (ULONG )ListSize ) == ListSize )
408490 {
409- Context = NtfsFindAttributeHelper (Volume , ListAttrRecord , ListAttrRecordEnd ,
410- Type , Name , NameLength );
491+ Context = NtfsFindAttributeHelperList (Volume , ListAttrRecord , ListAttrRecordEnd ,
492+ Type , Name , NameLength , Recursion + 1 );
411493
412494 NtfsReleaseAttributeContext (ListContext );
413495 FrLdrTempFree (ListBuffer , TAG_NTFS_LIST );
@@ -417,23 +499,22 @@ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(PNTFS_VOLUME_INFO Volume, PNTF
417499 }
418500 }
419501
420- if (AttrRecord -> Type == Type )
502+ if (AttrRecord -> Type == Type &&
503+ AttrRecord -> NameLength == NameLength &&
504+ NtfsGetAttributeSize (AttrRecord ) != 0 )
421505 {
422- if (AttrRecord -> NameLength == NameLength )
423- {
424- PWCHAR AttrName ;
506+ PWCHAR AttrName ;
425507
426- AttrName = (PWCHAR )((PCHAR )AttrRecord + AttrRecord -> NameOffset );
427- if (RtlEqualMemory (AttrName , Name , NameLength << 1 ))
428- {
429- /* Found it, fill up the context and return. */
430- return NtfsPrepareAttributeContext (AttrRecord );
431- }
508+ AttrName = (PWCHAR )((PCHAR )AttrRecord + AttrRecord -> NameOffset );
509+ if (RtlEqualMemory (AttrName , Name , NameLength << 1 ))
510+ {
511+ /* Found it, fill up the context and return. */
512+ return NtfsPrepareAttributeContext (AttrRecord );
432513 }
433514 }
434515
435516 if (AttrRecord -> Length == 0 )
436- return NULL ;
517+ break ;
437518 AttrRecord = (PNTFS_ATTR_RECORD )((PCHAR )AttrRecord + AttrRecord -> Length );
438519 }
439520
@@ -451,7 +532,7 @@ static PNTFS_ATTR_CONTEXT NtfsFindAttribute(PNTFS_VOLUME_INFO Volume, PNTFS_MFT_
451532 for (NameLength = 0 ; Name [NameLength ] != 0 ; NameLength ++ )
452533 ;
453534
454- return NtfsFindAttributeHelper (Volume , AttrRecord , AttrRecordEnd , Type , Name , NameLength );
535+ return NtfsFindAttributeHelper (Volume , AttrRecord , AttrRecordEnd , Type , Name , NameLength , 0 );
455536}
456537
457538static BOOLEAN NtfsFixupRecord (PNTFS_VOLUME_INFO Volume , PNTFS_RECORD Record )
@@ -592,6 +673,7 @@ static BOOLEAN NtfsFindMftRecord(PNTFS_VOLUME_INFO Volume, ULONGLONG MFTIndex, P
592673 while (IndexEntry < IndexEntryEnd &&
593674 !(IndexEntry -> Flags & NTFS_INDEX_ENTRY_END ))
594675 {
676+ TRACE ("%s " , FileName );
595677 if (NtfsCompareFileName (FileName , IndexEntry ))
596678 {
597679 * OutMFTIndex = (IndexEntry -> Data .Directory .IndexedFile & NTFS_MFT_MASK );
@@ -675,6 +757,7 @@ static BOOLEAN NtfsFindMftRecord(PNTFS_VOLUME_INFO Volume, ULONGLONG MFTIndex, P
675757 while (IndexEntry < IndexEntryEnd &&
676758 !(IndexEntry -> Flags & NTFS_INDEX_ENTRY_END ))
677759 {
760+ TRACE ("%s " , FileName );
678761 if (NtfsCompareFileName (FileName , IndexEntry ))
679762 {
680763 TRACE ("File found\n" );
0 commit comments