1 /*
2  * PROJECT:         ReactOS partitions tests/dump
3  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Open disk & partition trying to get information about volumes & MBR
5  * PROGRAMMER:      Pierre Schweitzer <pierre@reactos.org>
6  */
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <winternl.h>
11 
12 #ifndef NT_SUCCESS
13 # define NT_SUCCESS(_Status) (((NTSTATUS)(_Status)) >= 0)
14 #endif
15 
16 #define SECTOR_SIZE 512
17 #define BOOT_RECORD_SIGNATURE 0xAA55
18 
19 PCWSTR DiskFormat = L"\\Device\\Harddisk%lu\\Partition%lu";
20 
21 #include <pshpack1.h>
22 typedef struct {
23     unsigned char  magic0, res0, magic1;
24     unsigned char  OEMName[8];
25     unsigned short BytesPerSector;
26     unsigned char  SectorsPerCluster;
27     unsigned short ReservedSectors;
28     unsigned char  FATCount;
29     unsigned short RootEntries, Sectors;
30     unsigned char  Media;
31     unsigned short FATSectors, SectorsPerTrack, Heads;
32     unsigned long  HiddenSectors, SectorsHuge;
33     unsigned long  FATSectors32;
34     unsigned short ExtFlag;
35     unsigned short FSVersion;
36     unsigned long  RootCluster;
37     unsigned short FSInfoSector;
38     unsigned short BootBackup;
39     unsigned char  Res3[12];
40     unsigned char  Drive;
41     unsigned char  Res4;
42     unsigned char  ExtBootSignature;
43     unsigned long  VolumeID;
44     unsigned char  VolumeLabel[11], SysType[8];
45     unsigned char  Res2[420];
46     unsigned short Signature1;
47 } FATBootSector, *PFATBootSector;
48 
49 typedef struct {
50     UCHAR     Jump[3];
51     UCHAR     OEMID[8];
52     USHORT    BytesPerSector;
53     UCHAR     SectorsPerCluster;
54     UCHAR     Unused0[7];
55     UCHAR     MediaId;
56     UCHAR     Unused1[2];
57     USHORT    SectorsPerTrack;
58     USHORT    Heads;
59     UCHAR     Unused2[4];
60     UCHAR     Unused3[4];
61     USHORT    Unknown[2];
62     ULONGLONG SectorCount;
63     ULONGLONG MftLocation;
64     ULONGLONG MftMirrLocation;
65     CHAR      ClustersPerMftRecord;
66     UCHAR     Unused4[3];
67     CHAR      ClustersPerIndexRecord;
68     UCHAR     Unused5[3];
69     ULONGLONG SerialNumber;
70     UCHAR     Checksum[4];
71     UCHAR     BootStrap[426];
72     USHORT    EndSector;
73 } NTFSBootSector, *PNTFSBootSector;
74 
75 typedef struct {
76     UCHAR BootIndicator;
77     UCHAR StartHead;
78     UCHAR StartSector;
79     UCHAR StartCylinder;
80     UCHAR SystemIndicator;
81     UCHAR EndHead;
82     UCHAR EndSector;
83     UCHAR EndCylinder;
84     ULONG SectorCountBeforePartition;
85     ULONG PartitionSectorCount;
86 } PARTITION_TABLE_ENTRY, *PPARTITION_TABLE_ENTRY;
87 
88 typedef struct {
89     UCHAR MasterBootRecordCodeAndData[0x1B8];
90     ULONG Signature;
91     USHORT Reserved;
92     PARTITION_TABLE_ENTRY PartitionTable[4];
93     USHORT MasterBootRecordMagic;
94 } MASTER_BOOT_RECORD, *PMASTER_BOOT_RECORD;
95 #include <poppack.h>
96 
97 BOOL CheckAgainstFAT(PFATBootSector Sector)
98 {
99     if (Sector->Signature1 != 0xaa55)
100     {
101         return FALSE;
102     }
103 
104     if (Sector->BytesPerSector != 512 &&
105         Sector->BytesPerSector != 1024 &&
106         Sector->BytesPerSector != 2048 &&
107         Sector->BytesPerSector != 4096)
108     {
109         return FALSE;
110     }
111 
112     if (Sector->FATCount != 1 &&
113         Sector->FATCount != 2)
114     {
115         return FALSE;
116     }
117 
118     if (Sector->Media != 0xf0 &&
119         Sector->Media != 0xf8 &&
120         Sector->Media != 0xf9 &&
121         Sector->Media != 0xfa &&
122         Sector->Media != 0xfb &&
123         Sector->Media != 0xfc &&
124         Sector->Media != 0xfd &&
125         Sector->Media != 0xfe &&
126         Sector->Media != 0xff)
127     {
128         return FALSE;
129     }
130 
131     if (Sector->SectorsPerCluster != 1 &&
132         Sector->SectorsPerCluster != 2 &&
133         Sector->SectorsPerCluster != 4 &&
134         Sector->SectorsPerCluster != 8 &&
135         Sector->SectorsPerCluster != 16 &&
136         Sector->SectorsPerCluster != 32 &&
137         Sector->SectorsPerCluster != 64 &&
138         Sector->SectorsPerCluster != 128)
139     {
140         return FALSE;
141     }
142 
143     if (Sector->BytesPerSector * Sector->SectorsPerCluster > 32 * 1024)
144     {
145         return FALSE;
146     }
147 
148     return TRUE;
149 }
150 
151 BOOL CheckAgainstNTFS(PNTFSBootSector Sector)
152 {
153     ULONG k;
154     ULONG ClusterSize;
155 
156     /* OEMID: this field must be NTFS */
157     if (RtlCompareMemory(Sector->OEMID, "NTFS    ", 8) != 8)
158     {
159         return FALSE;
160     }
161 
162     /* Unused0: this field must be COMPLETELY null */
163     for (k = 0; k < 7; k++)
164     {
165         if (Sector->Unused0[k] != 0)
166         {
167             return FALSE;
168         }
169     }
170 
171     /* Unused3: this field must be COMPLETELY null */
172     for (k = 0; k < 4; k++)
173     {
174         if (Sector->Unused3[k] != 0)
175         {
176             return FALSE;
177         }
178     }
179 
180     /* Check cluster size */
181     ClusterSize = Sector->BytesPerSector * Sector->SectorsPerCluster;
182     if (ClusterSize != 512 && ClusterSize != 1024 &&
183         ClusterSize != 2048 && ClusterSize != 4096 &&
184         ClusterSize != 8192 && ClusterSize != 16384 &&
185         ClusterSize != 32768 && ClusterSize != 65536)
186     {
187         return FALSE;
188     }
189 
190     return TRUE;
191 }
192 
193 BOOL CheckAgainstMBR(PMASTER_BOOT_RECORD Sector)
194 {
195     if (Sector->MasterBootRecordMagic != BOOT_RECORD_SIGNATURE)
196     {
197         return FALSE;
198     }
199 
200     return TRUE;
201 }
202 
203 int main(int argc, char ** argv)
204 {
205     HANDLE FileHandle;
206     NTSTATUS Status;
207     OBJECT_ATTRIBUTES ObjectAttributes;
208     IO_STATUS_BLOCK IoStatusBlock;
209     WCHAR Buffer[MAX_PATH];
210     UNICODE_STRING Name;
211     PVOID Sector;
212 
213     Sector = malloc(SECTOR_SIZE);
214     if (Sector == NULL)
215     {
216         fprintf(stderr, "Failed allocating memory!\n");
217         return 0;
218     }
219 
220     /* We first open disk */
221     swprintf(Buffer, DiskFormat, 0, 0);
222     RtlInitUnicodeString(&Name, Buffer);
223     InitializeObjectAttributes(&ObjectAttributes,
224                                &Name,
225                                OBJ_CASE_INSENSITIVE,
226                                NULL,
227                                NULL);
228 
229     Status = NtOpenFile(&FileHandle,
230                         GENERIC_READ | SYNCHRONIZE,
231                         &ObjectAttributes,
232                         &IoStatusBlock,
233                         0,
234                         FILE_SYNCHRONOUS_IO_NONALERT);
235     if (!NT_SUCCESS(Status))
236     {
237         free(Sector);
238         fprintf(stderr, "Failed opening disk! %lx\n", Status);
239         return 0;
240     }
241 
242     /* Read first sector of the disk */
243     Status = NtReadFile(FileHandle,
244                         NULL,
245                         NULL,
246                         NULL,
247                         &IoStatusBlock,
248                         Sector,
249                         SECTOR_SIZE,
250                         NULL,
251                         NULL);
252     NtClose(FileHandle);
253     if (!NT_SUCCESS(Status))
254     {
255         free(Sector);
256         fprintf(stderr, "Failed reading sector 0! %lx\n", Status);
257         return 0;
258     }
259 
260     /* Is it FAT? */
261     if (CheckAgainstFAT(Sector))
262     {
263         printf("Sector 0 seems to be FAT boot sector\n");
264     }
265     /* Is it NTFS? */
266     else if (CheckAgainstNTFS(Sector))
267     {
268         printf("Sector 0 seems to be NTFS boot sector\n");
269     }
270     /* Is it MBR? */
271     else if (CheckAgainstMBR(Sector))
272     {
273         printf("Sector 0 might be MBR\n");
274     }
275     /* We don't support anything else */
276     else
277     {
278         printf("Sector 0 not recognized\n");
279     }
280 
281     /* Redo it with first partition */
282     swprintf(Buffer, DiskFormat, 0, 1);
283     RtlInitUnicodeString(&Name, Buffer);
284     InitializeObjectAttributes(&ObjectAttributes,
285                                &Name,
286                                OBJ_CASE_INSENSITIVE,
287                                NULL,
288                                NULL);
289 
290     Status = NtOpenFile(&FileHandle,
291                         GENERIC_READ | SYNCHRONIZE,
292                         &ObjectAttributes,
293                         &IoStatusBlock,
294                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
295                         FILE_SYNCHRONOUS_IO_NONALERT);
296     if (!NT_SUCCESS(Status))
297     {
298         free(Sector);
299         fprintf(stderr, "Failed opening partition! %lx\n", Status);
300         return 0;
301     }
302 
303     /* Read first sector of the partition */
304     Status = NtReadFile(FileHandle,
305                         NULL,
306                         NULL,
307                         NULL,
308                         &IoStatusBlock,
309                         Sector,
310                         SECTOR_SIZE,
311                         NULL,
312                         NULL);
313     if (!NT_SUCCESS(Status))
314     {
315         free(Sector);
316         fprintf(stderr, "Failed reading first sector of the partition! %lx\n", Status);
317         return 0;
318     }
319 
320     /* Is it FAT? */
321     if (CheckAgainstFAT(Sector))
322     {
323         printf("Seems to be a FAT partittion\n");
324     }
325     /* Is it NTFS? */
326     else if (CheckAgainstNTFS(Sector))
327     {
328         printf("Seems to be a NTFS partition\n");
329     }
330     /* Is it MBR? */
331     else if (CheckAgainstMBR(Sector))
332     {
333         printf("Seems to be MBR\n");
334     }
335     /* We don't support anything else */
336     else
337     {
338         printf("Not recognized\n");
339     }
340 
341     free(Sector);
342 
343     return 0;
344 }
345