From d849794a3529e94364f2f8e5d748a5b65bbf2e01 Mon Sep 17 00:00:00 2001 From: Pierre Schweitzer Date: Sat, 20 Jan 2018 22:25:46 +0100 Subject: [PATCH] [NFI] Rewrite the way files are handled, this allows querying handling a new file while already handling one. This is useful to fix the problem when a directory wasn't in cache yet, but one of its files is to be displayed. --- .../applications/rosinternals/nfi/nfi.c | 186 ++++++++++++------ 1 file changed, 121 insertions(+), 65 deletions(-) diff --git a/modules/rosapps/applications/rosinternals/nfi/nfi.c b/modules/rosapps/applications/rosinternals/nfi/nfi.c index 3aa54a6d6b1..377826b4375 100644 --- a/modules/rosapps/applications/rosinternals/nfi/nfi.c +++ b/modules/rosapps/applications/rosinternals/nfi/nfi.c @@ -164,15 +164,37 @@ void PrintUsage(void) /* FIXME */ } -void AddToCache(PWSTR Name, DWORD Length, ULONGLONG MftId) +PNAME_CACHE_ENTRY FindInCache(ULONGLONG MftId) { PNAME_CACHE_ENTRY CacheEntry; + for (CacheEntry = CacheHead; CacheEntry != NULL; CacheEntry = CacheEntry->Next) + { + if (MftId == CacheEntry->MftId) + { + return CacheEntry; + } + } + + return NULL; +} + +PNAME_CACHE_ENTRY AddToCache(PWSTR Name, DWORD Length, ULONGLONG MftId) +{ + PNAME_CACHE_ENTRY CacheEntry; + + /* Don't add in cache if already there! */ + CacheEntry = FindInCache(MftId); + if (CacheEntry != NULL) + { + return CacheEntry; + } + /* Allocate an entry big enough to store name and cache info */ CacheEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(NAME_CACHE_ENTRY) + Length); if (CacheEntry == NULL) { - return; + return NULL; } /* Insert in head (likely more perf) */ @@ -182,28 +204,34 @@ void AddToCache(PWSTR Name, DWORD Length, ULONGLONG MftId) CacheEntry->MftId = MftId; CacheEntry->NameLen = Length; CopyMemory(CacheEntry->Name, Name, Length); + + return CacheEntry; } -void PrintPrettyName(PNTFS_ATTR_RECORD Attributes, PNTFS_ATTR_RECORD AttributesEnd, ULONGLONG MftId) +PNAME_CACHE_ENTRY HandleFile(HANDLE VolumeHandle, PNTFS_VOLUME_DATA_BUFFER VolumeInfo, ULONGLONG Id, PNTFS_FILE_RECORD_OUTPUT_BUFFER OutputBuffer, BOOLEAN Silent); + +PNAME_CACHE_ENTRY PrintPrettyName(HANDLE VolumeHandle, PNTFS_VOLUME_DATA_BUFFER VolumeInfo, PNTFS_ATTR_RECORD Attributes, PNTFS_ATTR_RECORD AttributesEnd, ULONGLONG MftId, BOOLEAN Silent) { - BOOLEAN FirstRun, Found; + BOOLEAN FirstRun; PNTFS_ATTR_RECORD Attribute; FirstRun = TRUE; - Found = FALSE; /* Setup name for "standard" files */ if (MftId <= NTFS_FILE_EXTEND) { - _tprintf(_T("%s\n"), KnownEntries[MftId]); + if (!Silent) + { + _tprintf(_T("%s\n"), KnownEntries[MftId]); + } /* $Extend can contain entries, add it in cache */ if (MftId == NTFS_FILE_EXTEND) { - AddToCache(L"\\$Extend", sizeof(L"\\$Extend") - sizeof(UNICODE_NULL), NTFS_FILE_EXTEND); + return AddToCache(L"\\$Extend", sizeof(L"\\$Extend") - sizeof(UNICODE_NULL), NTFS_FILE_EXTEND); } - return; + return NULL; } /* We'll first try to use the Win32 name @@ -218,6 +246,7 @@ TryAgain: PFILENAME_ATTRIBUTE Name; ULONGLONG ParentId; ULONG Length; + PNAME_CACHE_ENTRY CacheEntry; /* Move to the next arg if: * - Not a file name @@ -251,19 +280,25 @@ TryAgain: /* Default case */ else { - PNAME_CACHE_ENTRY CacheEntry; - /* Did we already cache the name? */ - for (CacheEntry = CacheHead; CacheEntry != NULL; CacheEntry = CacheEntry->Next) + CacheEntry = FindInCache(ParentId); + + /* It wasn't in cache? Try to get it in! */ + if (CacheEntry == NULL) { - if (ParentId == CacheEntry->MftId) + PNTFS_FILE_RECORD_OUTPUT_BUFFER OutputBuffer; + + OutputBuffer = HeapAlloc(GetProcessHeap(), 0, VolumeInfo->BytesPerFileRecordSegment + sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER)); + if (OutputBuffer != NULL) { - break; + CacheEntry = HandleFile(VolumeHandle, VolumeInfo, ParentId, OutputBuffer, TRUE); + HeapFree(GetProcessHeap(), 0, OutputBuffer); } } /* Nothing written yet */ Length = 0; + /* We cached it */ if (CacheEntry != NULL) { @@ -275,7 +310,6 @@ TryAgain: } else { - /* FIXME: Do something, like trying to read parent... */ _tprintf(_T("Parent: %I64d\n"), ParentId); } @@ -285,20 +319,25 @@ TryAgain: Display[Length] = UNICODE_NULL; } - /* Display the name */ - _tprintf(_T("%s\n"), Display); + if (!Silent) + { + /* Display the name */ + _tprintf(_T("%s\n"), Display); + } + + /* Reset cache entry */ + CacheEntry = NULL; /* If that's a directory, put it in the cache */ if (Name->FileAttributes & NTFS_FILE_TYPE_DIRECTORY) { - AddToCache(Display, Length * sizeof(WCHAR), MftId); + CacheEntry = AddToCache(Display, Length * sizeof(WCHAR), MftId); } /* Now, just quit */ FirstRun = FALSE; - Found = TRUE; - break; + return CacheEntry; } /* If was first run (Win32 search), retry with other names */ @@ -309,10 +348,12 @@ TryAgain: } /* If we couldn't find a name, print unknown */ - if (!Found) + if (!Silent) { _tprintf(_T("(unknown/unnamed)\n")); } + + return NULL; } PUCHAR DecodeRun(PUCHAR DataRun, LONGLONG *DataRunOffset, ULONGLONG *DataRunLength) @@ -463,6 +504,65 @@ void PrintAttributeInfo(PNTFS_ATTR_RECORD Attribute, DWORD MaxSize) } } +PNAME_CACHE_ENTRY HandleFile(HANDLE VolumeHandle, PNTFS_VOLUME_DATA_BUFFER VolumeInfo, ULONGLONG Id, PNTFS_FILE_RECORD_OUTPUT_BUFFER OutputBuffer, BOOLEAN Silent) +{ + NTFS_FILE_RECORD_INPUT_BUFFER InputBuffer; + PFILE_RECORD_HEADER FileRecord; + PNTFS_ATTR_RECORD Attribute, AttributesEnd; + DWORD LengthReturned; + PNAME_CACHE_ENTRY CacheEntry; + + /* Get the file record */ + InputBuffer.FileReferenceNumber.QuadPart = Id; + if (!DeviceIoControl(VolumeHandle, FSCTL_GET_NTFS_FILE_RECORD, &InputBuffer, sizeof(InputBuffer), + OutputBuffer, VolumeInfo->BytesPerFileRecordSegment + sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER), + &LengthReturned, NULL)) + { + return NULL; + } + + /* Don't deal with it if we already browsed it + * FSCTL_GET_NTFS_FILE_RECORD always returns previous record if demanded + * isn't allocated + */ + if (OutputBuffer->FileReferenceNumber.QuadPart != Id) + { + return NULL; + } + + /* Sanity check */ + FileRecord = (PFILE_RECORD_HEADER)OutputBuffer->FileRecordBuffer; + if (FileRecord->Ntfs.Type != NRH_FILE_TYPE) + { + return NULL; + } + + if (!Silent) + { + /* Print ID */ + _tprintf(_T("\nFile %I64d\n"), OutputBuffer->FileReferenceNumber.QuadPart); + } + + /* Get attributes list */ + Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset); + AttributesEnd = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse); + + /* Print the file name */ + CacheEntry = PrintPrettyName(VolumeHandle, VolumeInfo, Attribute, AttributesEnd, Id, Silent); + + if (!Silent) + { + /* And print attributes information for each attribute */ + while (Attribute < AttributesEnd && Attribute->Type != AttributeEnd) + { + PrintAttributeInfo(Attribute, VolumeInfo->BytesPerFileRecordSegment); + Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length); + } + } + + return CacheEntry; +} + int __cdecl _tmain(int argc, const TCHAR *argv[]) @@ -526,51 +626,7 @@ _tmain(int argc, const TCHAR *argv[]) /* Forever loop, extract all the files! */ for (File = 0;; ++File) { - NTFS_FILE_RECORD_INPUT_BUFFER InputBuffer; - PFILE_RECORD_HEADER FileRecord; - PNTFS_ATTR_RECORD Attribute, AttributesEnd; - - /* Get the file record */ - InputBuffer.FileReferenceNumber.QuadPart = File; - if (!DeviceIoControl(VolumeHandle, FSCTL_GET_NTFS_FILE_RECORD, &InputBuffer, sizeof(InputBuffer), - OutputBuffer, VolumeInfo.BytesPerFileRecordSegment + sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER), - &LengthReturned, NULL)) - { - continue; - } - - /* Don't deal with it if we already browsed it - * FSCTL_GET_NTFS_FILE_RECORD always returns previous record if demanded - * isn't allocated - */ - if (OutputBuffer->FileReferenceNumber.QuadPart != File) - { - continue; - } - - /* Sanity check */ - FileRecord = (PFILE_RECORD_HEADER)OutputBuffer->FileRecordBuffer; - if (FileRecord->Ntfs.Type != NRH_FILE_TYPE) - { - continue; - } - - /* Print ID */ - _tprintf(_T("\nFile %I64d\n"), OutputBuffer->FileReferenceNumber.QuadPart); - - /* Get attributes list */ - Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset); - AttributesEnd = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse); - - /* Print the file name */ - PrintPrettyName(Attribute, AttributesEnd, File); - - /* And print attributes information for each attribute */ - while (Attribute < AttributesEnd && Attribute->Type != AttributeEnd) - { - PrintAttributeInfo(Attribute, VolumeInfo.BytesPerFileRecordSegment); - Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length); - } + HandleFile(VolumeHandle, &VolumeInfo, File, OutputBuffer, FALSE); } /* Free memory! */