mirror of
https://github.com/reactos/reactos.git
synced 2024-08-24 20:28:57 +00:00
![Pierre Schweitzer](/assets/img/avatar_default.png)
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
243 lines
8.1 KiB
C
243 lines
8.1 KiB
C
/*
|
|
* 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;
|
|
}
|