From: Pierre Schweitzer Date: Sat, 1 Nov 2014 09:56:33 +0000 (+0000) Subject: [NTFS_TEST] X-Git-Tag: backups/tcpip_revolution@71025~138 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=67656096bd8b56d15037c350fee9b51e106124f9;hp=ce5999a8ebf8157d66322ebe7f9c650ef4f27a16;ds=sidebyside [NTFS_TEST] Add a simple application (à la NTFSInfo & nfi) to dump the data about a NTFS volume using the FSCTL control codes. This is for both demonstrating how it works and to assess our driver behavior against Windows behavior of these FSCTL. CORE-8725 svn path=/trunk/; revision=65165 --- diff --git a/rostests/tests/ntfs/CMakeLists.txt b/rostests/tests/ntfs/CMakeLists.txt new file mode 100644 index 00000000000..2779b956d0c --- /dev/null +++ b/rostests/tests/ntfs/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(ntfs_test ntfs.c) +set_module_type(ntfs_test win32cui) +add_importlibs(ntfs_test msvcrt kernel32) diff --git a/rostests/tests/ntfs/ntfs.c b/rostests/tests/ntfs/ntfs.c new file mode 100644 index 00000000000..7e1f6fed3a8 --- /dev/null +++ b/rostests/tests/ntfs/ntfs.c @@ -0,0 +1,242 @@ +/* + * PROJECT: ReactOS NTFS tests/dump + * LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory + * PURPOSE: Query information from NTFS volume using FSCTL and dumps $MFT + * PROGRAMMER: Pierre Schweitzer + */ + +#include +#include + +typedef struct +{ + ULONG Type; + USHORT UsaOffset; + USHORT UsaCount; + ULONGLONG Lsn; +} NTFS_RECORD_HEADER, *PNTFS_RECORD_HEADER; + +#define NRH_FILE_TYPE 0x454C4946 + +typedef struct _FILE_RECORD_HEADER +{ + NTFS_RECORD_HEADER Ntfs; + USHORT SequenceNumber; + USHORT LinkCount; + USHORT AttributeOffset; + USHORT Flags; + ULONG BytesInUse; + ULONG BytesAllocated; + ULONGLONG BaseFileRecord; + USHORT NextAttributeNumber; +} FILE_RECORD_HEADER, *PFILE_RECORD_HEADER; + +typedef enum +{ + AttributeStandardInformation = 0x10, + AttributeAttributeList = 0x20, + AttributeFileName = 0x30, + AttributeObjectId = 0x40, + AttributeSecurityDescriptor = 0x50, + AttributeVolumeName = 0x60, + AttributeVolumeInformation = 0x70, + AttributeData = 0x80, + AttributeIndexRoot = 0x90, + AttributeIndexAllocation = 0xA0, + AttributeBitmap = 0xB0, + AttributeReparsePoint = 0xC0, + AttributeEAInformation = 0xD0, + AttributeEA = 0xE0, + AttributePropertySet = 0xF0, + AttributeLoggedUtilityStream = 0x100, + AttributeEnd = 0xFFFFFFFF +} ATTRIBUTE_TYPE, *PATTRIBUTE_TYPE; + +typedef struct +{ + ULONG Type; + ULONG Length; + UCHAR IsNonResident; + UCHAR NameLength; + USHORT NameOffset; + USHORT Flags; + USHORT Instance; + union + { + struct + { + ULONG ValueLength; + USHORT ValueOffset; + UCHAR Flags; + UCHAR Reserved; + } Resident; + struct + { + ULONGLONG LowestVCN; + ULONGLONG HighestVCN; + USHORT MappingPairsOffset; + USHORT CompressionUnit; + UCHAR Reserved[4]; + LONGLONG AllocatedSize; + LONGLONG DataSize; + LONGLONG InitializedSize; + LONGLONG CompressedSize; + } NonResident; + }; +} NTFS_ATTR_RECORD, *PNTFS_ATTR_RECORD; + +typedef struct +{ + ULONGLONG CreationTime; + ULONGLONG ChangeTime; + ULONGLONG LastWriteTime; + ULONGLONG LastAccessTime; + ULONG FileAttribute; + ULONG AlignmentOrReserved[3]; +} STANDARD_INFORMATION, *PSTANDARD_INFORMATION; + +typedef struct +{ + ULONGLONG DirectoryFileReferenceNumber; + ULONGLONG CreationTime; + ULONGLONG ChangeTime; + ULONGLONG LastWriteTime; + ULONGLONG LastAccessTime; + ULONGLONG AllocatedSize; + ULONGLONG DataSize; + ULONG FileAttributes; + ULONG AlignmentOrReserved; + UCHAR NameLength; + UCHAR NameType; + WCHAR Name[1]; +} FILENAME_ATTRIBUTE, *PFILENAME_ATTRIBUTE; + +int main(int argc, char **argv) +{ + static WCHAR VolumeName[] = L"\\\\.\\E:"; + HANDLE VolumeHandle; + struct { + NTFS_VOLUME_DATA_BUFFER Data; + NTFS_EXTENDED_VOLUME_DATA Extended; + } VolumeInfo; + DWORD LengthReturned; + NTFS_FILE_RECORD_INPUT_BUFFER InputBuffer; + PNTFS_FILE_RECORD_OUTPUT_BUFFER OutputBuffer; + DWORD OutputLength; + PFILE_RECORD_HEADER FileRecord; + PNTFS_ATTR_RECORD Attribute; + DWORD k; + + VolumeHandle = CreateFileW(VolumeName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); + if (VolumeHandle == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "Failed opening volume!\n"); + return -1; + } + + if (!DeviceIoControl(VolumeHandle, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &VolumeInfo, sizeof(VolumeInfo), &LengthReturned, NULL)) + { + fprintf(stderr, "Failed requesting volume data!\n"); + CloseHandle(VolumeHandle); + return -1; + } + + printf("Using NTFS: %u.%u\n", VolumeInfo.Extended.MajorVersion, VolumeInfo.Extended.MinorVersion); + + InputBuffer.FileReferenceNumber.QuadPart = 0LL; + OutputLength = sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER) + VolumeInfo.Data.BytesPerFileRecordSegment; + OutputBuffer = malloc(OutputLength); + if (OutputBuffer == NULL) + { + fprintf(stderr, "Allocation failure!\n"); + CloseHandle(VolumeHandle); + } + + if (!DeviceIoControl(VolumeHandle, FSCTL_GET_NTFS_FILE_RECORD, &InputBuffer, sizeof(InputBuffer), OutputBuffer, OutputLength, &LengthReturned, NULL)) + { + fprintf(stderr, "Failed opening $MFT!\n"); + free(OutputBuffer); + CloseHandle(VolumeHandle); + return -1; + } + + if (OutputBuffer->FileReferenceNumber.QuadPart != 0LL) + { + fprintf(stderr, "Wrong entry read! %I64x\n", OutputBuffer->FileReferenceNumber.QuadPart); + free(OutputBuffer); + CloseHandle(VolumeHandle); + return -1; + } + + FileRecord = (PFILE_RECORD_HEADER)OutputBuffer->FileRecordBuffer; + if (FileRecord->Ntfs.Type != NRH_FILE_TYPE) + { + fprintf(stderr, "Wrong type read! %lx\n", FileRecord->Ntfs.Type); + free(OutputBuffer); + CloseHandle(VolumeHandle); + return -1; + } + + printf("File record size: %lu. Read file record size: %lu\n", VolumeInfo.Data.BytesPerFileRecordSegment, OutputBuffer->FileRecordLength); + printf("SequenceNumber: %u\n", FileRecord->SequenceNumber); + printf("LinkCount: %u\n", FileRecord->LinkCount); + printf("AttributeOffset: %u\n", FileRecord->AttributeOffset); + printf("Flags: %u\n", FileRecord->Flags); + printf("BytesInUse: %lu\n", FileRecord->BytesInUse); + printf("BytesAllocated: %lu\n", FileRecord->BytesAllocated); + printf("BaseFileRecord: %I64x\n", FileRecord->BaseFileRecord); + printf("NextAttributeNumber: %u\n", FileRecord->NextAttributeNumber); + + Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset); + while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) && + Attribute->Type != AttributeEnd) + { + PSTANDARD_INFORMATION StdInfo; + PFILENAME_ATTRIBUTE FileName; + + if (!Attribute->IsNonResident) + { + switch (Attribute->Type) + { + case AttributeStandardInformation: + StdInfo = (PSTANDARD_INFORMATION)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset); + printf("\t$STANDARD_INFORMATION:\n"); + printf("\tCreationTime: %I64u\n", StdInfo->CreationTime); + printf("\tChangeTime: %I64u\n", StdInfo->ChangeTime); + printf("\tLastWriteTime: %I64u\n", StdInfo->LastWriteTime); + printf("\tLastAccessTime: %I64u\n", StdInfo->LastAccessTime); + printf("\tFileAttribute: %lu\n", StdInfo->FileAttribute); + break; + + case AttributeFileName: + FileName = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset); + printf("\t$FILE_NAME:\n"); + printf("\tDirectoryFileReferenceNumber: %I64u\n", FileName->DirectoryFileReferenceNumber); + printf("\tCreationTime: %I64u\n", FileName->CreationTime); + printf("\tChangeTime: %I64u\n", FileName->ChangeTime); + printf("\tLastWriteTime: %I64u\n", FileName->LastWriteTime); + printf("\tLastAccessTime: %I64u\n", FileName->LastAccessTime); + printf("\tAllocatedSize: %I64u\n", FileName->AllocatedSize); + printf("\tDataSize: %I64u\n", FileName->DataSize); + printf("\tFileAttributes: %lu\n", FileName->FileAttributes); + printf("\tAlignmentOrReserved: %lu\n", FileName->AlignmentOrReserved); + printf("\tNameLength: %u\n", FileName->NameLength); + printf("\tNameType: %u\n", FileName->NameType); + printf("\tName: "); + for (k = 0; k < FileName->NameLength; ++k) + { + wprintf(L"%C", FileName->Name[k]); + } + printf("\n"); + break; + } + } + + Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length); + } + + free(OutputBuffer); + CloseHandle(VolumeHandle); + + return 0; +}