Better LBA support
[reactos.git] / freeldr / freeldr / fs / fs.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 <fs.h>
22 #include "filesys.h"
23 #include "fat.h"
24 #include <disk.h>
25 #include <rtl.h>
26 #include <ui.h>
27 #include <asmcode.h>
28 #include <debug.h>
29
30
31 /////////////////////////////////////////////////////////////////////////////////////////////
32 // DATA
33 /////////////////////////////////////////////////////////////////////////////////////////////
34
35 ULONG FileSystemType = 0; // Type of filesystem on boot device, set by OpenDiskDrive()
36
37 /////////////////////////////////////////////////////////////////////////////////////////////
38 // FUNCTIONS
39 /////////////////////////////////////////////////////////////////////////////////////////////
40
41 VOID FileSystemError(PUCHAR ErrorString)
42 {
43 DbgPrint((DPRINT_FILESYSTEM, "%s\n", ErrorString));
44
45 if (UserInterfaceUp)
46 {
47 MessageBox(ErrorString);
48 }
49 else
50 {
51 printf("%s", ErrorString);
52 printf("\nPress any key\n");
53 getch();
54 }
55 }
56
57 /*
58 *
59 * BOOL OpenDiskDrive(ULONG DriveNumber, ULONG PartitionNumber);
60 *
61 * This function is called to open a disk drive for file access.
62 * It must be called before any of the file functions will work.
63 * It takes two parameters:
64 *
65 * Drive: The BIOS drive number of the disk to open
66 * Partition: This is zero for floppy drives.
67 * If the disk is a hard disk then this specifies
68 * The partition number to open (1 - 4)
69 * If it is zero then it opens the active (bootable) partition
70 *
71 */
72 BOOL OpenDiskDrive(ULONG DriveNumber, ULONG PartitionNumber)
73 {
74 MASTER_BOOT_RECORD DriveMasterBootRecord;
75 PARTITION_TABLE_ENTRY PartitionTableEntry;
76
77 DbgPrint((DPRINT_FILESYSTEM, "OpenDiskDrive() DriveNumber: 0x%x PartitionNumber: 0x%x\n", DriveNumber, PartitionNumber));
78
79 // Check and see if it is a floppy drive
80 // If so then just assume FAT12 file system type
81 if (FsInternalIsDiskPartitioned(DriveNumber) == FALSE)
82 {
83 DbgPrint((DPRINT_FILESYSTEM, "Drive is a floppy diskette drive. Assuming FAT12 file system.\n"));
84
85 FileSystemType = FS_FAT;
86 return FatOpenVolume(DriveNumber, 0);
87 }
88
89 //
90 // Read master boot record
91 //
92 if (!BiosInt13Read(DriveNumber, 0, 0, 1, 1, &DriveMasterBootRecord))
93 {
94 FileSystemError("Disk read error.");
95 return FALSE;
96 }
97
98
99 #ifdef DEBUG
100
101 DbgPrint((DPRINT_FILESYSTEM, "Drive is a hard disk, dumping partition table:\n"));
102 DbgPrint((DPRINT_FILESYSTEM, "sizeof(MASTER_BOOT_RECORD) = 0x%x.\n", sizeof(MASTER_BOOT_RECORD)));
103
104 for (BootPartition=0; BootPartition<4; BootPartition++)
105 {
106 DbgPrint((DPRINT_FILESYSTEM, "-------------------------------------------\n"));
107 DbgPrint((DPRINT_FILESYSTEM, "Partition %d\n", (BootPartition + 1)));
108 DbgPrint((DPRINT_FILESYSTEM, "BootIndicator: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].BootIndicator));
109 DbgPrint((DPRINT_FILESYSTEM, "StartHead: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].StartHead));
110 DbgPrint((DPRINT_FILESYSTEM, "StartSector (Plus 2 cylinder bits): 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].StartSector));
111 DbgPrint((DPRINT_FILESYSTEM, "StartCylinder: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].StartCylinder));
112 DbgPrint((DPRINT_FILESYSTEM, "SystemIndicator: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].SystemIndicator));
113 DbgPrint((DPRINT_FILESYSTEM, "EndHead: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].EndHead));
114 DbgPrint((DPRINT_FILESYSTEM, "EndSector (Plus 2 cylinder bits): 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].EndSector));
115 DbgPrint((DPRINT_FILESYSTEM, "EndCylinder: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].EndCylinder));
116 DbgPrint((DPRINT_FILESYSTEM, "SectorCountBeforePartition: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].SectorCountBeforePartition));
117 DbgPrint((DPRINT_FILESYSTEM, "PartitionSectorCount: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].PartitionSectorCount));
118 }
119
120 #endif // defined DEBUG
121
122
123 // Check the partition table magic value
124 if (DriveMasterBootRecord.MasterBootRecordMagic != 0xaa55)
125 {
126 FileSystemError("Invalid partition table magic (0xaa55)");
127 return FALSE;
128 }
129
130 // Get the requested partition entry
131 if (PartitionNumber == 0)
132 {
133 // Partition requested was zero which means the boot partition
134 if (FsInternalGetActivePartitionEntry(DriveNumber, &PartitionTableEntry) == FALSE)
135 {
136 return FALSE;
137 }
138 }
139 else
140 {
141 // Get requested partition
142 if (FsInternalGetPartitionEntry(DriveNumber, PartitionNumber, &PartitionTableEntry) == FALSE)
143 {
144 return FALSE;
145 }
146 }
147
148 // Check for valid partition
149 if (PartitionTableEntry.SystemIndicator == PARTITION_ENTRY_UNUSED)
150 {
151 FileSystemError("Invalid partition.");
152 return FALSE;
153 }
154
155 switch (PartitionTableEntry.SystemIndicator)
156 {
157 case PARTITION_FAT_12:
158 case PARTITION_FAT_16:
159 case PARTITION_HUGE:
160 case PARTITION_XINT13:
161 case PARTITION_FAT32:
162 case PARTITION_FAT32_XINT13:
163 FileSystemType = FS_FAT;
164 return FatOpenVolume(DriveNumber, PartitionTableEntry.StartSector);
165 default:
166 FileSystemType = 0;
167 FileSystemError("Unsupported file system.");
168 return FALSE;
169 }
170
171 return TRUE;
172 }
173
174 BOOL FsInternalIsDiskPartitioned(ULONG DriveNumber)
175 {
176 // Hard disks use drive numbers >= 0x80
177 // So if the drive number indicates a hard disk
178 // then return TRUE
179 if (DriveNumber >= 0x80)
180 {
181 return TRUE;
182 }
183
184 // Drive is a floppy diskette so return FALSE
185 return FALSE;
186 }
187
188 BOOL FsInternalGetActivePartitionEntry(ULONG DriveNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
189 {
190 ULONG BootablePartitionCount = 0;
191 MASTER_BOOT_RECORD MasterBootRecord;
192
193 // Read master boot record
194 if (!BiosInt13Read(DriveNumber, 0, 0, 1, 1, &MasterBootRecord))
195 {
196 FileSystemError("Disk read error.");
197 return FALSE;
198 }
199
200 // Count the bootable partitions
201 if (MasterBootRecord.PartitionTable[0].BootIndicator == 0x80)
202 {
203 BootablePartitionCount++;
204 BootPartition = 0;
205 }
206 if (MasterBootRecord.PartitionTable[1].BootIndicator == 0x80)
207 {
208 BootablePartitionCount++;
209 BootPartition = 1;
210 }
211 if (MasterBootRecord.PartitionTable[2].BootIndicator == 0x80)
212 {
213 BootablePartitionCount++;
214 BootPartition = 2;
215 }
216 if (MasterBootRecord.PartitionTable[3].BootIndicator == 0x80)
217 {
218 BootablePartitionCount++;
219 BootPartition = 3;
220 }
221
222 // Make sure there was only one bootable partition
223 if (BootablePartitionCount != 1)
224 {
225 FileSystemError("Too many bootable partitions or none found.");
226 return FALSE;
227 }
228
229 // Copy the partition table entry
230 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord.PartitionTable[BootPartition], sizeof(PARTITION_TABLE_ENTRY));
231
232 return TRUE;
233 }
234
235 BOOL FsInternalGetPartitionEntry(ULONG DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
236 {
237 MASTER_BOOT_RECORD MasterBootRecord;
238
239 // Read master boot record
240 if (!BiosInt13Read(DriveNumber, 0, 0, 1, 1, &MasterBootRecord))
241 {
242 FileSystemError("Disk read error.");
243 return FALSE;
244 }
245
246 // PartitionNumber is one-based and we need it zero-based
247 PartitionNumber--;
248
249 // Copy the partition table entry
250 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord.PartitionTable[PartitionNumber], sizeof(PARTITION_TABLE_ENTRY));
251
252 return TRUE;
253 }
254
255 PFILE OpenFile(PUCHAR FileName)
256 {
257 PFILE FileHandle = NULL;
258
259 //
260 // Print status message
261 //
262 DbgPrint((DPRINT_FILESYSTEM, "Opening file '%s'...\n", FileName));
263
264 //
265 // Check file system type and pass off to appropriate handler
266 //
267 if (FileSystemType == FS_FAT)
268 {
269 FileHandle = FatOpenFile(FileName);
270 }
271 else
272 {
273 FileSystemError("Error: Unknown filesystem.");
274 }
275
276 #ifdef DEBUG
277 //
278 // Check return value
279 //
280 if (FileHandle != NULL)
281 {
282 DbgPrint((DPRINT_FILESYSTEM, "OpenFile() succeeded. FileHandle: 0x%x\n", FileHandle));
283 }
284 else
285 {
286 DbgPrint((DPRINT_FILESYSTEM, "OpenFile() failed.\n"));
287 }
288 #endif // defined DEBUG
289
290 return FileHandle;
291 }
292
293 VOID CloseFile(PFILE FileHandle)
294 {
295 }
296
297 /*
298 * ReadFile()
299 * returns number of bytes read or EOF
300 */
301 BOOL ReadFile(PFILE FileHandle, ULONG BytesToRead, PULONG BytesRead, PVOID Buffer)
302 {
303 //
304 // Set the number of bytes read equal to zero
305 //
306 if (BytesRead !=NULL)
307 {
308 *BytesRead = 0;
309 }
310
311 switch (FileSystemType)
312 {
313 case FS_FAT:
314
315 return FatReadFile(FileHandle, BytesToRead, BytesRead, Buffer);
316
317 default:
318
319 FileSystemError("Unknown file system.");
320 return FALSE;
321 }
322
323 return FALSE;
324 }
325
326 ULONG GetFileSize(PFILE FileHandle)
327 {
328 switch (FileSystemType)
329 {
330 case FS_FAT:
331
332 return FatGetFileSize(FileHandle);
333
334 default:
335 FileSystemError("Unknown file system.");
336 break;
337 }
338
339 return 0;
340 }
341
342 VOID SetFilePointer(PFILE FileHandle, ULONG NewFilePointer)
343 {
344 switch (FileSystemType)
345 {
346 case FS_FAT:
347
348 FatSetFilePointer(FileHandle, NewFilePointer);
349 break;
350
351 default:
352 FileSystemError("Unknown file system.");
353 break;
354 }
355 }
356
357 ULONG GetFilePointer(PFILE FileHandle)
358 {
359 switch (FileSystemType)
360 {
361 case FS_FAT:
362
363 return FatGetFilePointer(FileHandle);
364 break;
365
366 default:
367 FileSystemError("Unknown file system.");
368 break;
369 }
370
371 return 0;
372 }
373
374 BOOL IsEndOfFile(PFILE FileHandle)
375 {
376 if (GetFilePointer(FileHandle) >= GetFileSize(FileHandle))
377 {
378 return TRUE;
379 }
380 else
381 {
382 return FALSE;
383 }
384 }