Full memory management support (memory.c & memory.h & mem.S)
[reactos.git] / freeldr / freeldr / fs.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1999, 2000 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 "stdlib.h"
23 #include "tui.h"
24 #include "asmcode.h"
25
26 #define FS_DO_ERROR(s) \
27 { \
28 if (UserInterfaceUp) \
29 MessageBox(s); \
30 else \
31 { \
32 printf(s); \
33 printf("\nPress any key\n"); \
34 getch(); \
35 } \
36 }
37
38
39 int nSectorBuffered = -1; // Tells us which sector was read into SectorBuffer[]
40
41 BYTE SectorBuffer[512]; // 512 byte buffer space for read operations, ReadOneSector reads to here
42
43 int FSType = NULL; // Type of filesystem on boot device, set by OpenDiskDrive()
44
45 char *pFileSysData = (char *)(FILESYSADDR); // Load address for filesystem data
46 char *pFat32FATCacheIndex = (char *)(FILESYSADDR); // Load address for filesystem data
47
48 BOOL OpenDiskDrive(int nDrive, int nPartition)
49 {
50 int num_bootable_partitions = 0;
51 int boot_partition = 0;
52 int partition_type = 0;
53 int head, sector, cylinder;
54 int offset;
55
56 // Check and see if it is a floppy drive
57 if (nDrive < 0x80)
58 {
59 // Read boot sector
60 if (!biosdisk(_DISK_READ, nDrive, 0, 0, 1, 1, SectorBuffer))
61 {
62 FS_DO_ERROR("Disk Read Error");
63 return FALSE;
64 }
65
66 // Check for validity
67 if (*((WORD*)(SectorBuffer + 0x1fe)) != 0xaa55)//(SectorBuffer[0x1FE] != 0x55) || (SectorBuffer[0x1FF] != 0xAA))
68 {
69 FS_DO_ERROR("Invalid boot sector magic (0xaa55)");
70 return FALSE;
71 }
72 }
73 else
74 {
75 // Read master boot record
76 if (!biosdisk(_DISK_READ, nDrive, 0, 0, 1, 1, SectorBuffer))
77 {
78 FS_DO_ERROR("Disk Read Error");
79 return FALSE;
80 }
81
82 // Check for validity
83 if (*((WORD*)(SectorBuffer + 0x1fe)) != 0xaa55)//(SectorBuffer[0x1FE] != 0x55) || (SectorBuffer[0x1FF] != 0xAA))
84 {
85 FS_DO_ERROR("Invalid partition table magic (0xaa55)");
86 return FALSE;
87 }
88
89 if (nPartition == 0)
90 {
91 // Check for bootable partitions
92 if (SectorBuffer[0x1BE] == 0x80)
93 num_bootable_partitions++;
94 if (SectorBuffer[0x1CE] == 0x80)
95 {
96 num_bootable_partitions++;
97 boot_partition = 1;
98 }
99 if (SectorBuffer[0x1DE] == 0x80)
100 {
101 num_bootable_partitions++;
102 boot_partition = 2;
103 }
104 if (SectorBuffer[0x1EE] == 0x80)
105 {
106 num_bootable_partitions++;
107 boot_partition = 3;
108 }
109
110 // Make sure there was only one bootable partition
111 if (num_bootable_partitions > 1)
112 {
113 FS_DO_ERROR("Too many boot partitions");
114 return FALSE;
115 }
116
117 offset = 0x1BE + (boot_partition * 0x10);
118 }
119 else
120 offset = 0x1BE + ((nPartition-1) * 0x10);
121
122 partition_type = SectorBuffer[offset + 4];
123
124 // Check for valid partition
125 if (partition_type == 0)
126 {
127 FS_DO_ERROR("Invalid boot partition");
128 return FALSE;
129 }
130
131 head = SectorBuffer[offset + 1];
132 sector = (SectorBuffer[offset + 2] & 0x3F);
133 cylinder = SectorBuffer[offset + 3];
134 if (SectorBuffer[offset + 2] & 0x80)
135 cylinder += 0x200;
136 if (SectorBuffer[offset + 2] & 0x40)
137 cylinder += 0x100;
138
139 // Read partition boot sector
140 if (!biosdisk(_DISK_READ, nDrive, head, cylinder, sector, 1, SectorBuffer))
141 {
142 FS_DO_ERROR("Disk Read Error");
143 return FALSE;
144 }
145
146 // Check for validity
147 if (*((WORD*)(SectorBuffer + 0x1fe)) != 0xaa55)//(SectorBuffer[0x1FE] != 0x55) || (SectorBuffer[0x1FF] != 0xAA))
148 {
149 FS_DO_ERROR("Invalid boot sector magic (0xaa55)");
150 return FALSE;
151 }
152 }
153
154
155 // Reset data
156 nBytesPerSector = 0;
157 nSectorsPerCluster = 0;
158 nReservedSectors = 0;
159 nNumberOfFATs = 0;
160 nRootDirEntries = 0;
161 nTotalSectors16 = 0;
162 nSectorsPerFAT16 = 0;
163 nSectorsPerTrack = 0;
164 nNumberOfHeads = 0;
165 nHiddenSectors = 0;
166 nTotalSectors32 = 0;
167
168 nSectorsPerFAT32 = 0;
169 nExtendedFlags = 0;
170 nFileSystemVersion = 0;
171 nRootDirStartCluster = 0;
172
173 nRootDirSectorStart = 0;
174 nDataSectorStart = 0;
175 nSectorsPerFAT = 0;
176 nRootDirSectors = 0;
177 nTotalSectors = 0;
178 nNumberOfClusters = 0;
179
180 // Get data
181 memcpy(&nBytesPerSector, SectorBuffer + BPB_BYTESPERSECTOR, 2);
182 memcpy(&nSectorsPerCluster, SectorBuffer + BPB_SECTORSPERCLUSTER, 1);
183 memcpy(&nReservedSectors, SectorBuffer + BPB_RESERVEDSECTORS, 2);
184 memcpy(&nNumberOfFATs, SectorBuffer + BPB_NUMBEROFFATS, 1);
185 memcpy(&nRootDirEntries, SectorBuffer + BPB_ROOTDIRENTRIES, 2);
186 memcpy(&nTotalSectors16, SectorBuffer + BPB_TOTALSECTORS16, 2);
187 memcpy(&nSectorsPerFAT16, SectorBuffer + BPB_SECTORSPERFAT16, 2);
188 memcpy(&nSectorsPerTrack, SectorBuffer + BPB_SECTORSPERTRACK, 2);
189 memcpy(&nNumberOfHeads, SectorBuffer + BPB_NUMBEROFHEADS, 2);
190 memcpy(&nHiddenSectors, SectorBuffer + BPB_HIDDENSECTORS, 4);
191 memcpy(&nTotalSectors32, SectorBuffer + BPB_TOTALSECTORS32, 4);
192
193 memcpy(&nSectorsPerFAT32, SectorBuffer + BPB_SECTORSPERFAT32, 4);
194 memcpy(&nExtendedFlags, SectorBuffer + BPB_EXTENDEDFLAGS32, 2);
195 memcpy(&nFileSystemVersion, SectorBuffer + BPB_FILESYSTEMVERSION32, 2);
196 memcpy(&nRootDirStartCluster, SectorBuffer + BPB_ROOTDIRSTARTCLUSTER32, 4);
197
198 // Calc some stuff
199 if (nTotalSectors16 != 0)
200 nTotalSectors = nTotalSectors16;
201 else
202 nTotalSectors = nTotalSectors32;
203
204 if (nSectorsPerFAT16 != 0)
205 nSectorsPerFAT = nSectorsPerFAT16;
206 else
207 nSectorsPerFAT = nSectorsPerFAT32;
208
209 nRootDirSectorStart = (nNumberOfFATs * nSectorsPerFAT) + nReservedSectors;
210 nRootDirSectors = ((nRootDirEntries * 32) + (nBytesPerSector - 1)) / nBytesPerSector;
211 nDataSectorStart = nReservedSectors + (nNumberOfFATs * nSectorsPerFAT) + nRootDirSectors;
212 nNumberOfClusters = (nTotalSectors - nDataSectorStart) / nSectorsPerCluster;
213
214 // Determine FAT type
215 if (nNumberOfClusters < 4085)
216 {
217 /* Volume is FAT12 */
218 nFATType = FAT12;
219 }
220 else if (nNumberOfClusters < 65525)
221 {
222 /* Volume is FAT16 */
223 nFATType = FAT16;
224 }
225 else
226 {
227 /* Volume is FAT32 */
228 nFATType = FAT32;
229
230 // Check version
231 // we only work with version 0
232 if (*((WORD*)(SectorBuffer + BPB_FILESYSTEMVERSION32)) != 0)
233 {
234 FS_DO_ERROR("Error: FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
235 return FALSE;
236 }
237 }
238
239 FSType = FS_FAT;
240
241 // Buffer the FAT table if it is small enough
242 if ((FSType == FS_FAT) && (nFATType == FAT12))
243 {
244 if (!ReadMultipleSectors(nReservedSectors, nSectorsPerFAT, pFileSysData))
245 return FALSE;
246 }
247 else if ((FSType == FS_FAT) && (nFATType == FAT16))
248 {
249 if (!ReadMultipleSectors(nReservedSectors, nSectorsPerFAT, pFileSysData))
250 return FALSE;
251 }
252 else if ((FSType == FS_FAT) && (nFATType == FAT32))
253 {
254 // The FAT table is too big to be buffered so
255 // we will initialize our cache and cache it
256 // on demand
257 for (offset=0; offset<256; offset++)
258 ((int*)pFat32FATCacheIndex)[offset] = -1;
259 }
260
261 return TRUE;
262 }
263
264 BOOL ReadMultipleSectors(int nSect, int nNumberOfSectors, void *pBuffer)
265 {
266 BOOL bRetVal;
267 int PhysicalSector;
268 int PhysicalHead;
269 int PhysicalTrack;
270 int nNum;
271
272 nSect += nHiddenSectors;
273
274 while (nNumberOfSectors)
275 {
276 PhysicalSector = 1 + (nSect % nSectorsPerTrack);
277 PhysicalHead = (nSect / nSectorsPerTrack) % nNumberOfHeads;
278 PhysicalTrack = nSect / (nSectorsPerTrack * nNumberOfHeads);
279
280 if (PhysicalSector > 1)
281 {
282 if (nNumberOfSectors >= (nSectorsPerTrack - (PhysicalSector - 1)))
283 nNum = (nSectorsPerTrack - (PhysicalSector - 1));
284 else
285 nNum = nNumberOfSectors;
286 }
287 else
288 {
289 if (nNumberOfSectors >= nSectorsPerTrack)
290 nNum = nSectorsPerTrack;
291 else
292 nNum = nNumberOfSectors;
293 }
294
295 bRetVal = biosdisk(_DISK_READ, BootDrive, PhysicalHead, PhysicalTrack, PhysicalSector, nNum, pBuffer);
296
297 if (!bRetVal)
298 {
299 FS_DO_ERROR("Disk Error");
300 return FALSE;
301 }
302
303 pBuffer += (nNum * 512);
304 nNumberOfSectors -= nNum;
305 nSect += nNum;
306 }
307
308 return TRUE;
309 }
310
311 BOOL ReadOneSector(int nSect)
312 {
313 BOOL bRetVal;
314 int PhysicalSector;
315 int PhysicalHead;
316 int PhysicalTrack;
317
318 nSectorBuffered = nSect;
319
320 nSect += nHiddenSectors;
321 PhysicalSector = 1 + (nSect % nSectorsPerTrack);
322 PhysicalHead = (nSect / nSectorsPerTrack) % nNumberOfHeads;
323 PhysicalTrack = nSect / (nSectorsPerTrack * nNumberOfHeads);
324
325
326 bRetVal = biosdisk(_DISK_READ, BootDrive, PhysicalHead, PhysicalTrack, PhysicalSector, 1, SectorBuffer);
327
328 if (!bRetVal)
329 {
330 FS_DO_ERROR("Disk Error");
331 return FALSE;
332 }
333
334 return TRUE;
335 }
336
337 BOOL OpenFile(char *filename, FILE *pFile)
338 {
339 switch(FSType)
340 {
341 case FS_FAT:
342 if(!FATOpenFile(filename, &(pFile->fat)))
343 return FALSE;
344 pFile->filesize = pFile->fat.dwSize;
345 break;
346 default:
347 FS_DO_ERROR("Error: Unknown filesystem.");
348 return FALSE;
349 break;
350 }
351
352 return TRUE;
353 }
354
355 /*
356 * ReadFile()
357 * returns number of bytes read or EOF
358 */
359 int ReadFile(FILE *pFile, int count, void *buffer)
360 {
361 switch(FSType)
362 {
363 case FS_FAT:
364 return FATRead(&(pFile->fat), count, buffer);
365 default:
366 FS_DO_ERROR("Error: Unknown filesystem.");
367 return EOF;
368 }
369
370 return 0;
371 }
372
373 DWORD GetFileSize(FILE *pFile)
374 {
375 return pFile->filesize;
376 }
377
378 DWORD Rewind(FILE *pFile)
379 {
380 switch (FSType)
381 {
382 case FS_FAT:
383 pFile->fat.dwCurrentCluster = pFile->fat.dwStartCluster;
384 pFile->fat.dwCurrentReadOffset = 0;
385 break;
386 default:
387 FS_DO_ERROR("Error: Unknown filesystem.");
388 break;
389 }
390
391 return pFile->filesize;
392 }
393
394 int feof(FILE *pFile)
395 {
396 switch (FSType)
397 {
398 case FS_FAT:
399 if (pFile->fat.dwCurrentReadOffset >= pFile->fat.dwSize)
400 return TRUE;
401 else
402 return FALSE;
403 break;
404 default:
405 FS_DO_ERROR("Error: Unknown filesystem.");
406 return TRUE;
407 break;
408 }
409
410 return TRUE;
411 }
412
413 int fseek(FILE *pFile, DWORD offset)
414 {
415 switch (FSType)
416 {
417 case FS_FAT:
418 return FATfseek(&(pFile->fat), offset);
419 break;
420 default:
421 FS_DO_ERROR("Error: Unknown filesystem.");
422 break;
423 }
424
425 return -1;
426 }