Initial revision
[reactos.git] / freeldr / freeldr / fs.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1999, 2000, 2001 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 "fat.h"
23 #include "stdlib.h"
24 #include "tui.h"
25 #include "asmcode.h"
26 #include "debug.h"
27
28
29 /////////////////////////////////////////////////////////////////////////////////////////////
30 // DATA
31 /////////////////////////////////////////////////////////////////////////////////////////////
32
33 GEOMETRY DriveGeometry;
34 ULONG VolumeHiddenSectors;
35 ULONG CurrentlyOpenDriveNumber;
36 ULONG FileSystemType = 0; // Type of filesystem on boot device, set by OpenDiskDrive()
37
38 /////////////////////////////////////////////////////////////////////////////////////////////
39 // FUNCTIONS
40 /////////////////////////////////////////////////////////////////////////////////////////////
41
42 VOID FileSystemError(PUCHAR ErrorString)
43 {
44 DbgPrint((DPRINT_FILESYSTEM, "%s\n", ErrorString));
45
46 if (UserInterfaceUp)
47 {
48 MessageBox(ErrorString);
49 }
50 else
51 {
52 printf("%s", ErrorString);
53 printf("\nPress any key\n");
54 getch();
55 }
56 }
57
58 /*
59 *
60 * BOOL OpenDiskDrive(ULONG DriveNumber, ULONG PartitionNumber);
61 *
62 * This function is called to open a disk drive for file access.
63 * It must be called before any of the file functions will work.
64 * It takes two parameters:
65 *
66 * Drive: The BIOS drive number of the disk to open
67 * Partition: This is zero for floppy drives.
68 * If the disk is a hard disk then this specifies
69 * The partition number to open (1 - 4)
70 * If it is zero then it opens the active (bootable) partition
71 *
72 */
73 BOOL OpenDiskDrive(ULONG DriveNumber, ULONG PartitionNumber)
74 {
75 ULONG BootablePartitionCount = 0;
76 ULONG BootPartition = 0;
77 ULONG PartitionStartHead;
78 ULONG PartitionStartSector;
79 ULONG PartitionStartCylinder;
80 MASTER_BOOT_RECORD DriveMasterBootRecord;
81
82 DbgPrint((DPRINT_FILESYSTEM, "OpenDiskDrive() DriveNumber: 0x%x PartitionNumber: 0x%x\n", DriveNumber, PartitionNumber));
83
84 CurrentlyOpenDriveNumber = DriveNumber;
85
86 //
87 // Check and see if it is a floppy drive
88 // If so then just assume FAT12 file system type
89 //
90 if (DriveNumber < 0x80)
91 {
92 DbgPrint((DPRINT_FILESYSTEM, "Drive is a floppy diskette drive. Assuming FAT12 file system.\n"));
93
94 FileSystemType = FS_FAT;
95 return FatOpenVolume(DriveNumber, 0, 0, 1, FAT12);
96 }
97
98 //
99 // Read master boot record
100 //
101 if (!BiosInt13Read(DriveNumber, 0, 0, 1, 1, &DriveMasterBootRecord))
102 {
103 FileSystemError("Disk read error.");
104 return FALSE;
105 }
106
107
108 #ifdef DEBUG
109
110 DbgPrint((DPRINT_FILESYSTEM, "Drive is a hard disk, dumping partition table:\n"));
111 DbgPrint((DPRINT_FILESYSTEM, "sizeof(MASTER_BOOT_RECORD) = 0x%x.\n", sizeof(MASTER_BOOT_RECORD)));
112
113 for (BootPartition=0; BootPartition<4; BootPartition++)
114 {
115 DbgPrint((DPRINT_FILESYSTEM, "-------------------------------------------\n"));
116 DbgPrint((DPRINT_FILESYSTEM, "Partition %d\n", (BootPartition + 1)));
117 DbgPrint((DPRINT_FILESYSTEM, "BootIndicator: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].BootIndicator));
118 DbgPrint((DPRINT_FILESYSTEM, "StartHead: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].StartHead));
119 DbgPrint((DPRINT_FILESYSTEM, "StartSector (Plus 2 cylinder bits): 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].StartSector));
120 DbgPrint((DPRINT_FILESYSTEM, "StartCylinder: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].StartCylinder));
121 DbgPrint((DPRINT_FILESYSTEM, "SystemIndicator: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].SystemIndicator));
122 DbgPrint((DPRINT_FILESYSTEM, "EndHead: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].EndHead));
123 DbgPrint((DPRINT_FILESYSTEM, "EndSector (Plus 2 cylinder bits): 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].EndSector));
124 DbgPrint((DPRINT_FILESYSTEM, "EndCylinder: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].EndCylinder));
125 DbgPrint((DPRINT_FILESYSTEM, "SectorCountBeforePartition: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].SectorCountBeforePartition));
126 DbgPrint((DPRINT_FILESYSTEM, "PartitionSectorCount: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].PartitionSectorCount));
127 }
128
129 #endif // defined DEBUG
130
131
132 //
133 // Check the partition table magic value
134 //
135 if (DriveMasterBootRecord.MasterBootRecordMagic != 0xaa55)
136 {
137 FileSystemError("Invalid partition table magic (0xaa55)");
138 return FALSE;
139 }
140
141 if (PartitionNumber == 0)
142 {
143 //
144 // Count the bootable partitions
145 //
146 if (DriveMasterBootRecord.PartitionTable[0].BootIndicator == 0x80)
147 {
148 BootablePartitionCount++;
149 BootPartition = 1;
150 }
151 if (DriveMasterBootRecord.PartitionTable[1].BootIndicator == 0x80)
152 {
153 BootablePartitionCount++;
154 BootPartition = 2;
155 }
156 if (DriveMasterBootRecord.PartitionTable[2].BootIndicator == 0x80)
157 {
158 BootablePartitionCount++;
159 BootPartition = 3;
160 }
161 if (DriveMasterBootRecord.PartitionTable[3].BootIndicator == 0x80)
162 {
163 BootablePartitionCount++;
164 BootPartition = 4;
165 }
166
167 //
168 // Make sure there was only one bootable partition
169 //
170 if (BootablePartitionCount != 1)
171 {
172 FileSystemError("Too many bootable partitions or none found.");
173 return FALSE;
174 }
175 else
176 {
177 //
178 // We found the boot partition, so set the partition number
179 //
180 PartitionNumber = BootPartition;
181 }
182 }
183
184 //
185 // Right now the partition number is one-based
186 // and we need zero based
187 //
188 PartitionNumber--;
189
190 //
191 // Check for valid partition
192 //
193 if (DriveMasterBootRecord.PartitionTable[PartitionNumber].SystemIndicator == PARTITION_ENTRY_UNUSED)
194 {
195 FileSystemError("Invalid partition.");
196 return FALSE;
197 }
198
199 PartitionStartHead = DriveMasterBootRecord.PartitionTable[PartitionNumber].StartHead;
200 PartitionStartSector = DriveMasterBootRecord.PartitionTable[PartitionNumber].StartSector & 0x3F;
201 PartitionStartCylinder = MAKE_CYLINDER(
202 DriveMasterBootRecord.PartitionTable[PartitionNumber].StartCylinder,
203 DriveMasterBootRecord.PartitionTable[PartitionNumber].StartSector);
204
205 DbgPrint((DPRINT_FILESYSTEM, "PartitionStartHead: %d\n", PartitionStartHead));
206 DbgPrint((DPRINT_FILESYSTEM, "PartitionStartSector: %d\n", PartitionStartSector));
207 DbgPrint((DPRINT_FILESYSTEM, "PartitionStartCylinder: %d\n", PartitionStartCylinder));
208 DbgPrint((DPRINT_FILESYSTEM, "PartitionNumber: %d\n", PartitionNumber));
209
210 switch (DriveMasterBootRecord.PartitionTable[PartitionNumber].SystemIndicator)
211 {
212 case PARTITION_FAT_12:
213 FileSystemType = FS_FAT;
214 return FatOpenVolume(DriveNumber, PartitionStartHead, PartitionStartCylinder, PartitionStartSector, FAT12);
215 case PARTITION_FAT_16:
216 case PARTITION_HUGE:
217 case PARTITION_XINT13:
218 FileSystemType = FS_FAT;
219 return FatOpenVolume(DriveNumber, PartitionStartHead, PartitionStartCylinder, PartitionStartSector, FAT16);
220 case PARTITION_FAT32:
221 case PARTITION_FAT32_XINT13:
222 FileSystemType = FS_FAT;
223 return FatOpenVolume(DriveNumber, PartitionStartHead, PartitionStartCylinder, PartitionStartSector, FAT32);
224 default:
225 FileSystemType = 0;
226 FileSystemError("Unsupported file system.");
227 return FALSE;
228 }
229
230 return TRUE;
231 }
232
233 VOID SetDriveGeometry(ULONG Cylinders, ULONG Heads, ULONG Sectors, ULONG BytesPerSector)
234 {
235 DriveGeometry.Cylinders = Cylinders;
236 DriveGeometry.Heads = Heads;
237 DriveGeometry.Sectors = Sectors;
238 DriveGeometry.BytesPerSector = BytesPerSector;
239
240 DbgPrint((DPRINT_FILESYSTEM, "DriveGeometry.Cylinders: %d\n", DriveGeometry.Cylinders));
241 DbgPrint((DPRINT_FILESYSTEM, "DriveGeometry.Heads: %d\n", DriveGeometry.Heads));
242 DbgPrint((DPRINT_FILESYSTEM, "DriveGeometry.Sectors: %d\n", DriveGeometry.Sectors));
243 DbgPrint((DPRINT_FILESYSTEM, "DriveGeometry.BytesPerSector: %d\n", DriveGeometry.BytesPerSector));
244 }
245
246 VOID SetVolumeProperties(ULONG HiddenSectors)
247 {
248 VolumeHiddenSectors = HiddenSectors;
249 }
250
251 BOOL ReadMultipleLogicalSectors(ULONG SectorNumber, ULONG SectorCount, PVOID Buffer)
252 {
253 /*BOOL bRetVal;
254 int PhysicalSector;
255 int PhysicalHead;
256 int PhysicalTrack;
257 int nNum;
258
259 nSect += nHiddenSectors;
260
261 while (nNumberOfSectors)
262 {
263 PhysicalSector = 1 + (nSect % nSectorsPerTrack);
264 PhysicalHead = (nSect / nSectorsPerTrack) % nNumberOfHeads;
265 PhysicalTrack = nSect / (nSectorsPerTrack * nNumberOfHeads);
266
267 if (PhysicalSector > 1)
268 {
269 if (nNumberOfSectors >= (nSectorsPerTrack - (PhysicalSector - 1)))
270 nNum = (nSectorsPerTrack - (PhysicalSector - 1));
271 else
272 nNum = nNumberOfSectors;
273 }
274 else
275 {
276 if (nNumberOfSectors >= nSectorsPerTrack)
277 nNum = nSectorsPerTrack;
278 else
279 nNum = nNumberOfSectors;
280 }
281
282 bRetVal = biosdisk(CurrentlyOpenDriveNumber, PhysicalHead, PhysicalTrack, PhysicalSector, nNum, pBuffer);
283
284 if (!bRetVal)
285 {
286 FS_DO_ERROR("Disk Error");
287 return FALSE;
288 }
289
290 pBuffer += (nNum * 512);
291 nNumberOfSectors -= nNum;
292 nSect += nNum;
293 }*/
294
295 ULONG CurrentSector;
296 PVOID RealBuffer = Buffer;
297
298 for (CurrentSector=SectorNumber; CurrentSector<(SectorNumber + SectorCount); CurrentSector++)
299 {
300 if (!ReadLogicalSector(CurrentSector, RealBuffer) )
301 {
302 return FALSE;
303 }
304
305 RealBuffer += DriveGeometry.BytesPerSector;
306 }
307
308 return TRUE;
309 }
310
311 BOOL ReadLogicalSector(ULONG SectorNumber, PVOID Buffer)
312 {
313 ULONG PhysicalSector;
314 ULONG PhysicalHead;
315 ULONG PhysicalTrack;
316
317 DbgPrint((DPRINT_FILESYSTEM, "ReadLogicalSector() SectorNumber: %d Buffer: 0x%x\n", SectorNumber, Buffer));
318
319 SectorNumber += VolumeHiddenSectors;
320 PhysicalSector = 1 + (SectorNumber % DriveGeometry.Sectors);
321 PhysicalHead = (SectorNumber / DriveGeometry.Sectors) % DriveGeometry.Heads;
322 PhysicalTrack = (SectorNumber / DriveGeometry.Sectors) / DriveGeometry.Heads;
323
324 //DbgPrint((DPRINT_FILESYSTEM, "Calling BiosInt13Read() with PhysicalHead: %d\n", PhysicalHead));
325 //DbgPrint((DPRINT_FILESYSTEM, "Calling BiosInt13Read() with PhysicalTrack: %d\n", PhysicalTrack));
326 //DbgPrint((DPRINT_FILESYSTEM, "Calling BiosInt13Read() with PhysicalSector: %d\n", PhysicalSector));
327 if (PhysicalHead >= DriveGeometry.Heads)
328 {
329 BugCheck((DPRINT_FILESYSTEM, "PhysicalHead >= DriveGeometry.Heads\nPhysicalHead = %d\nDriveGeometry.Heads = %d\n", PhysicalHead, DriveGeometry.Heads));
330 }
331 if (PhysicalTrack >= DriveGeometry.Cylinders)
332 {
333 BugCheck((DPRINT_FILESYSTEM, "PhysicalTrack >= DriveGeometry.Cylinders\nPhysicalTrack = %d\nDriveGeometry.Cylinders = %d\n", PhysicalTrack, DriveGeometry.Cylinders));
334 }
335 if (PhysicalSector > DriveGeometry.Sectors)
336 {
337 BugCheck((DPRINT_FILESYSTEM, "PhysicalSector > DriveGeometry.Sectors\nPhysicalSector = %d\nDriveGeometry.Sectors = %d\n", PhysicalSector, DriveGeometry.Sectors));
338 }
339
340 if ((CurrentlyOpenDriveNumber >= 0x80) &&
341 (BiosInt13ExtensionsSupported(CurrentlyOpenDriveNumber)) &&
342 (SectorNumber > (DriveGeometry.Cylinders * DriveGeometry.Heads * DriveGeometry.Sectors)))
343 {
344 DbgPrint((DPRINT_FILESYSTEM, "Using Int 13 Extensions for read. BiosInt13ExtensionsSupported(%d) = %s\n", CurrentlyOpenDriveNumber, BiosInt13ExtensionsSupported(CurrentlyOpenDriveNumber) ? "TRUE" : "FALSE"));
345 if ( !BiosInt13ReadExtended(CurrentlyOpenDriveNumber, SectorNumber, 1, Buffer) )
346 {
347 FileSystemError("Disk read error.");
348 return FALSE;
349 }
350 }
351 else
352 {
353 if ( !BiosInt13Read(CurrentlyOpenDriveNumber, PhysicalHead, PhysicalTrack, PhysicalSector, 1, Buffer) )
354 {
355 FileSystemError("Disk read error.");
356 return FALSE;
357 }
358 }
359
360 return TRUE;
361 }
362
363 PFILE OpenFile(PUCHAR FileName)
364 {
365 PFILE FileHandle = NULL;
366
367 //
368 // Print status message
369 //
370 DbgPrint((DPRINT_FILESYSTEM, "Opening file '%s'...\n", FileName));
371
372 //
373 // Check file system type and pass off to appropriate handler
374 //
375 if (FileSystemType == FS_FAT)
376 {
377 FileHandle = FatOpenFile(FileName);
378 }
379 else
380 {
381 FileSystemError("Error: Unknown filesystem.");
382 }
383
384 #ifdef DEBUG
385 //
386 // Check return value
387 //
388 if (FileHandle != NULL)
389 {
390 DbgPrint((DPRINT_FILESYSTEM, "OpenFile() succeeded. FileHandle: 0x%x\n", FileHandle));
391 }
392 else
393 {
394 DbgPrint((DPRINT_FILESYSTEM, "OpenFile() failed.\n"));
395 }
396 #endif // defined DEBUG
397
398 return FileHandle;
399 }
400
401 VOID CloseFile(PFILE FileHandle)
402 {
403 }
404
405 /*
406 * ReadFile()
407 * returns number of bytes read or EOF
408 */
409 BOOL ReadFile(PFILE FileHandle, ULONG BytesToRead, PULONG BytesRead, PVOID Buffer)
410 {
411 //
412 // Set the number of bytes read equal to zero
413 //
414 if (BytesRead !=NULL)
415 {
416 *BytesRead = 0;
417 }
418
419 switch (FileSystemType)
420 {
421 case FS_FAT:
422
423 return FatReadFile(FileHandle, BytesToRead, BytesRead, Buffer);
424
425 default:
426
427 FileSystemError("Unknown file system.");
428 return FALSE;
429 }
430
431 return FALSE;
432 }
433
434 ULONG GetFileSize(PFILE FileHandle)
435 {
436 switch (FileSystemType)
437 {
438 case FS_FAT:
439
440 return FatGetFileSize(FileHandle);
441
442 default:
443 FileSystemError("Unknown file system.");
444 break;
445 }
446
447 return 0;
448 }
449
450 VOID SetFilePointer(PFILE FileHandle, ULONG NewFilePointer)
451 {
452 switch (FileSystemType)
453 {
454 case FS_FAT:
455
456 FatSetFilePointer(FileHandle, NewFilePointer);
457 break;
458
459 default:
460 FileSystemError("Unknown file system.");
461 break;
462 }
463 }
464
465 ULONG GetFilePointer(PFILE FileHandle)
466 {
467 switch (FileSystemType)
468 {
469 case FS_FAT:
470
471 return FatGetFilePointer(FileHandle);
472 break;
473
474 default:
475 FileSystemError("Unknown file system.");
476 break;
477 }
478
479 return 0;
480 }
481
482 BOOL IsEndOfFile(PFILE FileHandle)
483 {
484 if (GetFilePointer(FileHandle) >= GetFileSize(FileHandle))
485 {
486 return TRUE;
487 }
488 else
489 {
490 return FALSE;
491 }
492 }