[NTFS_TEST]
authorPierre Schweitzer <pierre@reactos.org>
Sat, 1 Nov 2014 09:56:33 +0000 (09:56 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Sat, 1 Nov 2014 09:56:33 +0000 (09:56 +0000)
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

rostests/tests/ntfs/CMakeLists.txt [new file with mode: 0644]
rostests/tests/ntfs/ntfs.c [new file with mode: 0644]

diff --git a/rostests/tests/ntfs/CMakeLists.txt b/rostests/tests/ntfs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2779b95
--- /dev/null
@@ -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 (file)
index 0000000..7e1f6fe
--- /dev/null
@@ -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 <pierre@reactos.org>
+ */
+
+#include <windows.h>
+#include <stdio.h>
+
+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;
+}