c7022505c89f45fe410c91ac231d31fbd8eb2a67
[reactos.git] / modules / rosapps / applications / rosinternals / ntfsinfo / ntfsinfo.c
1 /*
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>
7 */
8
9 #include <windows.h>
10 #include <tchar.h>
11 #include <stdio.h>
12
13 typedef struct
14 {
15 ULONG Type;
16 USHORT UsaOffset;
17 USHORT UsaCount;
18 ULONGLONG Lsn;
19 } NTFS_RECORD_HEADER, *PNTFS_RECORD_HEADER;
20
21 #define NRH_FILE_TYPE 0x454C4946
22 #define ATTRIBUTE_TYPE_DATA 0x80
23 #define ATTRIBUTE_TYPE_END 0xFFFFFFFF
24
25 typedef struct _FILE_RECORD_HEADER
26 {
27 NTFS_RECORD_HEADER Ntfs;
28 USHORT SequenceNumber;
29 USHORT LinkCount;
30 USHORT AttributeOffset;
31 USHORT Flags;
32 ULONG BytesInUse;
33 ULONG BytesAllocated;
34 ULONGLONG BaseFileRecord;
35 USHORT NextAttributeNumber;
36 } FILE_RECORD_HEADER, *PFILE_RECORD_HEADER;
37
38 typedef struct
39 {
40 ULONG Type;
41 ULONG Length;
42 UCHAR IsNonResident;
43 UCHAR NameLength;
44 USHORT NameOffset;
45 USHORT Flags;
46 USHORT Instance;
47 union
48 {
49 struct
50 {
51 ULONG ValueLength;
52 USHORT ValueOffset;
53 UCHAR Flags;
54 UCHAR Reserved;
55 } Resident;
56 struct
57 {
58 ULONGLONG LowestVCN;
59 ULONGLONG HighestVCN;
60 USHORT MappingPairsOffset;
61 USHORT CompressionUnit;
62 UCHAR Reserved[4];
63 LONGLONG AllocatedSize;
64 LONGLONG DataSize;
65 LONGLONG InitializedSize;
66 LONGLONG CompressedSize;
67 } NonResident;
68 };
69 } NTFS_ATTR_RECORD, *PNTFS_ATTR_RECORD;
70
71 static TCHAR * MetaDataFiles[] = {
72 _T("$MFT\t\t"),
73 _T("$MFTMirr\t"),
74 _T("$LogFile\t"),
75 _T("$Volume\t\t"),
76 _T("$AttrDef\t"),
77 _T("."),
78 _T("$Bitmap\t\t"),
79 _T("$Boot\t\t"),
80 _T("$BadClus\t"),
81 _T("$Quota\t\t"),
82 _T("$UpCase\t\t"),
83 _T("$Extended\t"),
84 NULL,
85 };
86
87 int
88 __cdecl
89 _tmain(int argc, const TCHAR *argv[])
90 {
91 TCHAR VolumeName[] = _T("\\\\.\\C:");
92 HANDLE VolumeHandle;
93 NTFS_VOLUME_DATA_BUFFER VolumeInfo;
94 DWORD LengthReturned;
95 ULONGLONG VolumeSize;
96 ULONGLONG MftClusters;
97 UINT File = 0;
98 PNTFS_FILE_RECORD_OUTPUT_BUFFER OutputBuffer;
99
100 if (argc > 1)
101 {
102 TCHAR Letter = argv[1][0];
103
104 if ((Letter >= 'A' && Letter <= 'Z') ||
105 (Letter >= 'a' && Letter <= 'z'))
106 {
107 VolumeName[4] = Letter;
108 }
109 }
110
111 VolumeHandle = CreateFile(VolumeName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
112 if (VolumeHandle == INVALID_HANDLE_VALUE)
113 {
114 _ftprintf(stderr, _T("Failed opening the volume '%s' (%lx)\n"), VolumeName, GetLastError());
115 return 1;
116 }
117
118 if (!DeviceIoControl(VolumeHandle, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &VolumeInfo, sizeof(VolumeInfo), &LengthReturned, NULL))
119 {
120 _ftprintf(stderr, _T("Failed requesting volume '%s' data (%lx)\n"), VolumeName, GetLastError());
121 CloseHandle(VolumeHandle);
122 return 1;
123 }
124
125 if (LengthReturned < sizeof(VolumeInfo))
126 {
127 _ftprintf(stderr, _T("Failed reading volume '%s' data (%lx)\n"), VolumeName, GetLastError());
128 CloseHandle(VolumeHandle);
129 return 1;
130 }
131
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);
139
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);
145
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);
153
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)
157 {
158 NTFS_FILE_RECORD_INPUT_BUFFER InputBuffer;
159 PFILE_RECORD_HEADER FileRecord;
160 PNTFS_ATTR_RECORD Attribute;
161 ULONGLONG Size = 0;
162
163 if (File == 5)
164 {
165 ++File;
166 continue;
167 }
168
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))
173 {
174 ++File;
175 continue;
176 }
177
178 if (OutputBuffer->FileReferenceNumber.QuadPart != File)
179 {
180 ++File;
181 continue;
182 }
183
184 FileRecord = (PFILE_RECORD_HEADER)OutputBuffer->FileRecordBuffer;
185 if (FileRecord->Ntfs.Type != NRH_FILE_TYPE)
186 {
187 ++File;
188 continue;
189 }
190
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)
194 {
195 if (Attribute->Type == ATTRIBUTE_TYPE_DATA)
196 {
197 Size = (Attribute->IsNonResident) ? Attribute->NonResident.AllocatedSize : Attribute->Resident.ValueLength;
198 break;
199 }
200
201 Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
202 }
203
204 _tprintf(_T("%s%I64u bytes\n"), MetaDataFiles[File], Size);
205
206 ++File;
207 }
208
209 HeapFree(GetProcessHeap(), 0, OutputBuffer);
210 CloseHandle(VolumeHandle);
211 return 0;
212 }