2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NTFS Information tool
4 * FILE: cmdutils/ntfsinfo/ntfsinfo.c
5 * PURPOSE: Query information from NTFS volume using FSCTL
6 * PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org>
19 } NTFS_RECORD_HEADER
, *PNTFS_RECORD_HEADER
;
21 #define NRH_FILE_TYPE 0x454C4946
22 #define ATTRIBUTE_TYPE_DATA 0x80
23 #define ATTRIBUTE_TYPE_END 0xFFFFFFFF
25 typedef struct _FILE_RECORD_HEADER
27 NTFS_RECORD_HEADER Ntfs
;
28 USHORT SequenceNumber
;
30 USHORT AttributeOffset
;
34 ULONGLONG BaseFileRecord
;
35 USHORT NextAttributeNumber
;
36 } FILE_RECORD_HEADER
, *PFILE_RECORD_HEADER
;
60 USHORT MappingPairsOffset
;
61 USHORT CompressionUnit
;
63 LONGLONG AllocatedSize
;
65 LONGLONG InitializedSize
;
66 LONGLONG CompressedSize
;
69 } NTFS_ATTR_RECORD
, *PNTFS_ATTR_RECORD
;
71 static TCHAR
* MetaDataFiles
[] = {
89 _tmain(int argc
, const TCHAR
*argv
[])
91 TCHAR VolumeName
[] = _T("\\\\.\\C:");
93 NTFS_VOLUME_DATA_BUFFER VolumeInfo
;
96 ULONGLONG MftClusters
;
98 PNTFS_FILE_RECORD_OUTPUT_BUFFER OutputBuffer
;
102 TCHAR Letter
= argv
[1][0];
104 if ((Letter
>= 'A' && Letter
<= 'Z') ||
105 (Letter
>= 'a' && Letter
<= 'z'))
107 VolumeName
[4] = Letter
;
111 VolumeHandle
= CreateFile(VolumeName
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, 0 );
112 if (VolumeHandle
== INVALID_HANDLE_VALUE
)
114 _ftprintf(stderr
, _T("Failed opening the volume '%s' (%lx)\n"), VolumeName
, GetLastError());
118 if (!DeviceIoControl(VolumeHandle
, FSCTL_GET_NTFS_VOLUME_DATA
, NULL
, 0, &VolumeInfo
, sizeof(VolumeInfo
), &LengthReturned
, NULL
))
120 _ftprintf(stderr
, _T("Failed requesting volume '%s' data (%lx)\n"), VolumeName
, GetLastError());
121 CloseHandle(VolumeHandle
);
125 if (LengthReturned
< sizeof(VolumeInfo
))
127 _ftprintf(stderr
, _T("Failed reading volume '%s' data (%lx)\n"), VolumeName
, GetLastError());
128 CloseHandle(VolumeHandle
);
132 _tprintf(_T("Volume Size\n-----------\n"));
133 VolumeSize
= VolumeInfo
.TotalClusters
.QuadPart
* VolumeInfo
.BytesPerCluster
;
134 _tprintf(_T("Volume size\t\t: %I64u MB\n"), VolumeSize
>> 20);
135 _tprintf(_T("Total sectors\t\t: %I64u\n"), VolumeInfo
.NumberSectors
.QuadPart
);
136 _tprintf(_T("Total clusters\t\t: %I64u\n"), VolumeInfo
.TotalClusters
.QuadPart
);
137 _tprintf(_T("Free clusters\t\t: %I64u\n"), VolumeInfo
.FreeClusters
.QuadPart
);
138 _tprintf(_T("Free space\t\t: %I64u MB (%u%% of drive)\n"), (VolumeInfo
.FreeClusters
.QuadPart
* VolumeInfo
.BytesPerCluster
) >> 20, (VolumeInfo
.FreeClusters
.QuadPart
* 100) / VolumeInfo
.TotalClusters
.QuadPart
);
140 _tprintf(_T("\nAllocation Size\n---------------\n"));
141 _tprintf(_T("Bytes per sector\t: %lu\n"), VolumeInfo
.BytesPerSector
);
142 _tprintf(_T("Bytes per cluster\t: %lu\n"), VolumeInfo
.BytesPerCluster
);
143 _tprintf(_T("Bytes per MFT record:\t: %lu\n"), VolumeInfo
.BytesPerFileRecordSegment
);
144 _tprintf(_T("Clusters per MFT record\t: %lu\n"), VolumeInfo
.ClustersPerFileRecordSegment
);
146 _tprintf(_T("\nMFT Information\n---------------\n"));
147 _tprintf(_T("MFT size\t\t: %I64u MB (%u%% of drive)\n"), VolumeInfo
.MftValidDataLength
.QuadPart
>> 20, (VolumeInfo
.MftValidDataLength
.QuadPart
* 100) / VolumeSize
);
148 _tprintf(_T("MFT start cluster\t: %I64u\n"), VolumeInfo
.MftStartLcn
.QuadPart
);
149 _tprintf(_T("MFT zone clusters\t: %I64u - %I64u\n"), VolumeInfo
.MftZoneStart
.QuadPart
, VolumeInfo
.MftZoneEnd
.QuadPart
);
150 MftClusters
= VolumeInfo
.MftZoneEnd
.QuadPart
- VolumeInfo
.MftZoneStart
.QuadPart
;
151 _tprintf(_T("MFT zone size\t\t: %I64u MB (%u%% of drive)\n"), (MftClusters
* VolumeInfo
.BytesPerCluster
) >> 20, (MftClusters
* 100) / VolumeInfo
.TotalClusters
.QuadPart
);
152 _tprintf(_T("MFT mirror start\t: %I64u\n"), VolumeInfo
.Mft2StartLcn
.QuadPart
);
154 _tprintf(_T("\nMeta-Data files\n---------------\n"));
155 OutputBuffer
= HeapAlloc(GetProcessHeap(), 0, VolumeInfo
.BytesPerFileRecordSegment
+ sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER
));
156 while (MetaDataFiles
[File
] != NULL
)
158 NTFS_FILE_RECORD_INPUT_BUFFER InputBuffer
;
159 PFILE_RECORD_HEADER FileRecord
;
160 PNTFS_ATTR_RECORD Attribute
;
169 InputBuffer
.FileReferenceNumber
.QuadPart
= File
;
170 if (!DeviceIoControl(VolumeHandle
, FSCTL_GET_NTFS_FILE_RECORD
, &InputBuffer
, sizeof(InputBuffer
),
171 OutputBuffer
, VolumeInfo
.BytesPerFileRecordSegment
+ sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER
),
172 &LengthReturned
, NULL
))
178 if (OutputBuffer
->FileReferenceNumber
.QuadPart
!= File
)
184 FileRecord
= (PFILE_RECORD_HEADER
)OutputBuffer
->FileRecordBuffer
;
185 if (FileRecord
->Ntfs
.Type
!= NRH_FILE_TYPE
)
191 Attribute
= (PNTFS_ATTR_RECORD
)((ULONG_PTR
)FileRecord
+ FileRecord
->AttributeOffset
);
192 while (Attribute
< (PNTFS_ATTR_RECORD
)((ULONG_PTR
)FileRecord
+ FileRecord
->BytesInUse
) &&
193 Attribute
->Type
!= ATTRIBUTE_TYPE_END
)
195 if (Attribute
->Type
== ATTRIBUTE_TYPE_DATA
)
197 Size
= (Attribute
->IsNonResident
) ? Attribute
->NonResident
.AllocatedSize
: Attribute
->Resident
.ValueLength
;
201 Attribute
= (PNTFS_ATTR_RECORD
)((ULONG_PTR
)Attribute
+ Attribute
->Length
);
204 _tprintf(_T("%s%I64u bytes\n"), MetaDataFiles
[File
], Size
);
209 HeapFree(GetProcessHeap(), 0, OutputBuffer
);
210 CloseHandle(VolumeHandle
);