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 } 213