Added ISO-9660 support.
[reactos.git] / freeldr / freeldr / disk / partition.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <freeldr.h>
21 #include <disk.h>
22 #include <rtl.h>
23 #include <mm.h>
24 #include <debug.h>
25 #include <arch.h>
26
27
28
29 BOOL DiskIsDriveRemovable(ULONG DriveNumber)
30 {
31 // Hard disks use drive numbers >= 0x80
32 // So if the drive number indicates a hard disk
33 // then return FALSE
34 if (DriveNumber >= 0x80)
35 {
36 return FALSE;
37 }
38
39 // Drive is a floppy diskette so return TRUE
40 return TRUE;
41 }
42
43
44 BOOL DiskIsDriveCdRom(ULONG DriveNumber)
45 {
46 PUCHAR Sector;
47 BOOL Result;
48
49 // Hard disks use drive numbers >= 0x80
50 // So if the drive number indicates a hard disk
51 // then return FALSE
52 if ((DriveNumber >= 0x80) && (BiosInt13ExtensionsSupported(DriveNumber)))
53 {
54 Sector = AllocateMemory(2048);
55
56 if (!BiosInt13ReadExtended(DriveNumber, 16, 1, Sector))
57 {
58 DiskError("Disk read error.");
59 FreeMemory(Sector);
60 return FALSE;
61 }
62
63 Result = (Sector[0] == 1 &&
64 Sector[1] == 'C' &&
65 Sector[2] == 'D' &&
66 Sector[3] == '0' &&
67 Sector[4] == '0' &&
68 Sector[5] == '1');
69
70 FreeMemory(Sector);
71
72 return Result;
73 }
74
75 // Drive is not CdRom so return FALSE
76 return FALSE;
77 }
78
79
80 BOOL DiskGetActivePartitionEntry(ULONG DriveNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
81 {
82 ULONG BootablePartitionCount = 0;
83 MASTER_BOOT_RECORD MasterBootRecord;
84
85 // Read master boot record
86 if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
87 {
88 return FALSE;
89 }
90
91 // Count the bootable partitions
92 if (MasterBootRecord.PartitionTable[0].BootIndicator == 0x80)
93 {
94 BootablePartitionCount++;
95 BootPartition = 0;
96 }
97 if (MasterBootRecord.PartitionTable[1].BootIndicator == 0x80)
98 {
99 BootablePartitionCount++;
100 BootPartition = 1;
101 }
102 if (MasterBootRecord.PartitionTable[2].BootIndicator == 0x80)
103 {
104 BootablePartitionCount++;
105 BootPartition = 2;
106 }
107 if (MasterBootRecord.PartitionTable[3].BootIndicator == 0x80)
108 {
109 BootablePartitionCount++;
110 BootPartition = 3;
111 }
112
113 // Make sure there was only one bootable partition
114 if (BootablePartitionCount != 1)
115 {
116 DiskError("Too many bootable partitions or none found.");
117 return FALSE;
118 }
119
120 // Copy the partition table entry
121 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord.PartitionTable[BootPartition], sizeof(PARTITION_TABLE_ENTRY));
122
123 return TRUE;
124 }
125
126 BOOL DiskGetPartitionEntry(ULONG DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
127 {
128 MASTER_BOOT_RECORD MasterBootRecord;
129 PARTITION_TABLE_ENTRY ExtendedPartitionTableEntry;
130 ULONG ExtendedPartitionNumber;
131 ULONG Index;
132
133 // Read master boot record
134 if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
135 {
136 return FALSE;
137 }
138
139 // If they are asking for a primary
140 // partition then things are easy
141 if (PartitionNumber < 5)
142 {
143 // PartitionNumber is one-based and we need it zero-based
144 PartitionNumber--;
145
146 // Copy the partition table entry
147 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord.PartitionTable[PartitionNumber], sizeof(PARTITION_TABLE_ENTRY));
148
149 return TRUE;
150 }
151 else
152 {
153 // They want an extended partition entry so we will need
154 // to loop through all the extended partitions on the disk
155 // and return the one they want.
156
157 ExtendedPartitionNumber = PartitionNumber - 5;
158
159 for (Index=0; Index<=ExtendedPartitionNumber; Index++)
160 {
161 // Get the extended partition table entry
162 if (!DiskGetFirstExtendedPartitionEntry(&MasterBootRecord, &ExtendedPartitionTableEntry))
163 {
164 return FALSE;
165 }
166
167 // Read the partition boot record
168 if (!DiskReadBootRecord(DriveNumber, ExtendedPartitionTableEntry.SectorCountBeforePartition, &MasterBootRecord))
169 {
170 return FALSE;
171 }
172
173 // Get the first real partition table entry
174 if (!DiskGetFirstPartitionEntry(&MasterBootRecord, PartitionTableEntry))
175 {
176 return FALSE;
177 }
178 }
179
180 // When we get here we should have the correct entry
181 // already stored in PartitionTableEntry
182 // so just return TRUE
183 return TRUE;
184 }
185
186 }
187
188 BOOL DiskGetFirstPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord, PPARTITION_TABLE_ENTRY PartitionTableEntry)
189 {
190 ULONG Index;
191
192 for (Index=0; Index<4; Index++)
193 {
194 // Check the system indicator
195 // If it's not an extended or unused partition
196 // then we're done
197 if ((MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_ENTRY_UNUSED) &&
198 (MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_EXTENDED) &&
199 (MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_XINT13_EXTENDED))
200 {
201 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord->PartitionTable[Index], sizeof(PARTITION_TABLE_ENTRY));
202 return TRUE;
203 }
204 }
205
206 return FALSE;
207 }
208
209 BOOL DiskGetFirstExtendedPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord, PPARTITION_TABLE_ENTRY PartitionTableEntry)
210 {
211 ULONG Index;
212
213 for (Index=0; Index<4; Index++)
214 {
215 // Check the system indicator
216 // If it an extended partition then we're done
217 if ((MasterBootRecord->PartitionTable[Index].SystemIndicator == PARTITION_EXTENDED) ||
218 (MasterBootRecord->PartitionTable[Index].SystemIndicator == PARTITION_XINT13_EXTENDED))
219 {
220 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord->PartitionTable[Index], sizeof(PARTITION_TABLE_ENTRY));
221 return TRUE;
222 }
223 }
224
225 return FALSE;
226 }
227
228 BOOL DiskReadBootRecord(ULONG DriveNumber, ULONG LogicalSectorNumber, PMASTER_BOOT_RECORD BootRecord)
229 {
230 ULONG Index;
231
232 // Read master boot record
233 if (!DiskReadLogicalSectors(DriveNumber, LogicalSectorNumber, 1, (PVOID)DISKREADBUFFER))
234 {
235 return FALSE;
236 }
237 RtlCopyMemory(BootRecord, (PVOID)DISKREADBUFFER, sizeof(MASTER_BOOT_RECORD));
238
239
240 #ifdef DEBUG
241
242 DbgPrint((DPRINT_DISK, "Dumping partition table for drive 0x%x:\n", DriveNumber));
243 DbgPrint((DPRINT_DISK, "Boot record logical start sector = %d\n", LogicalSectorNumber));
244 DbgPrint((DPRINT_DISK, "sizeof(MASTER_BOOT_RECORD) = 0x%x.\n", sizeof(MASTER_BOOT_RECORD)));
245
246 for (Index=0; Index<4; Index++)
247 {
248 DbgPrint((DPRINT_DISK, "-------------------------------------------\n"));
249 DbgPrint((DPRINT_DISK, "Partition %d\n", (Index + 1)));
250 DbgPrint((DPRINT_DISK, "BootIndicator: 0x%x\n", BootRecord->PartitionTable[Index].BootIndicator));
251 DbgPrint((DPRINT_DISK, "StartHead: 0x%x\n", BootRecord->PartitionTable[Index].StartHead));
252 DbgPrint((DPRINT_DISK, "StartSector (Plus 2 cylinder bits): 0x%x\n", BootRecord->PartitionTable[Index].StartSector));
253 DbgPrint((DPRINT_DISK, "StartCylinder: 0x%x\n", BootRecord->PartitionTable[Index].StartCylinder));
254 DbgPrint((DPRINT_DISK, "SystemIndicator: 0x%x\n", BootRecord->PartitionTable[Index].SystemIndicator));
255 DbgPrint((DPRINT_DISK, "EndHead: 0x%x\n", BootRecord->PartitionTable[Index].EndHead));
256 DbgPrint((DPRINT_DISK, "EndSector (Plus 2 cylinder bits): 0x%x\n", BootRecord->PartitionTable[Index].EndSector));
257 DbgPrint((DPRINT_DISK, "EndCylinder: 0x%x\n", BootRecord->PartitionTable[Index].EndCylinder));
258 DbgPrint((DPRINT_DISK, "SectorCountBeforePartition: 0x%x\n", BootRecord->PartitionTable[Index].SectorCountBeforePartition));
259 DbgPrint((DPRINT_DISK, "PartitionSectorCount: 0x%x\n", BootRecord->PartitionTable[Index].PartitionSectorCount));
260 }
261
262 #endif // defined DEBUG
263
264 // Check the partition table magic value
265 if (BootRecord->MasterBootRecordMagic != 0xaa55)
266 {
267 DiskError("Invalid partition table magic (0xaa55)");
268 return FALSE;
269 }
270
271 return TRUE;
272 }