fixed some warnings with gcc4 (mostly assignment differs in signedness warnings)
[reactos.git] / reactos / boot / freeldr / freeldr / fs / iso.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 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 <disk.h>
23 #include <rtl.h>
24 #include <arch.h>
25 #include <mm.h>
26 #include <debug.h>
27 #include <cache.h>
28 #include <machine.h>
29
30 #include "iso.h"
31
32
33 #define SECTORSIZE 2048
34
35 static ULONG IsoRootSector; // Starting sector of the root directory
36 static ULONG IsoRootLength; // Length of the root directory
37
38 ULONG IsoDriveNumber = 0;
39
40
41 BOOL IsoOpenVolume(ULONG DriveNumber)
42 {
43 PPVD Pvd = (PPVD)DISKREADBUFFER;
44
45 DbgPrint((DPRINT_FILESYSTEM, "IsoOpenVolume() DriveNumber = 0x%x VolumeStartSector = 16\n", DriveNumber));
46
47 // Store the drive number
48 IsoDriveNumber = DriveNumber;
49
50 IsoRootSector = 0;
51 IsoRootLength = 0;
52
53 if (!MachDiskReadLogicalSectors(DriveNumber, 16, 1, Pvd))
54 {
55 FileSystemError("Failed to read the PVD.");
56 return FALSE;
57 }
58
59 IsoRootSector = Pvd->RootDirRecord.ExtentLocationL;
60 IsoRootLength = Pvd->RootDirRecord.DataLengthL;
61
62 DbgPrint((DPRINT_FILESYSTEM, "IsoRootSector = %u IsoRootLegth = %u\n", IsoRootSector, IsoRootLength));
63
64 return TRUE;
65 }
66
67
68 static BOOL IsoSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectoryLength, PCHAR FileName, PISO_FILE_INFO IsoFileInfoPointer)
69 {
70 PDIR_RECORD Record;
71 ULONG Offset;
72 ULONG i;
73 CHAR Name[32];
74
75 DbgPrint((DPRINT_FILESYSTEM, "IsoSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectoryLength = %d FileName = %s\n", DirectoryBuffer, DirectoryLength, FileName));
76
77 RtlZeroMemory(Name, 32 * sizeof(UCHAR));
78
79 Offset = 0;
80 Record = (PDIR_RECORD)DirectoryBuffer;
81 while (TRUE)
82 {
83 Offset = Offset + Record->RecordLength;
84 Record = (PDIR_RECORD)(DirectoryBuffer + Offset);
85
86 if (Record->RecordLength == 0)
87 {
88 Offset = ROUND_UP(Offset, SECTORSIZE);
89 Record = (PDIR_RECORD)(DirectoryBuffer + Offset);
90 }
91
92 if (Offset >= DirectoryLength)
93 return FALSE;
94
95 if (Record->FileIdLength == 1 && Record->FileId[0] == 0)
96 {
97 DbgPrint((DPRINT_FILESYSTEM, "Name '.'\n"));
98 }
99 else if (Record->FileIdLength == 1 && Record->FileId[0] == 1)
100 {
101 DbgPrint((DPRINT_FILESYSTEM, "Name '..'\n"));
102 }
103 else
104 {
105 for (i = 0; i < Record->FileIdLength && Record->FileId[i] != ';'; i++)
106 Name[i] = Record->FileId[i];
107 Name[i] = 0;
108 DbgPrint((DPRINT_FILESYSTEM, "Name '%s'\n", Name));
109
110 if (strlen(FileName) == strlen(Name) && stricmp(FileName, Name) == 0)
111 {
112 IsoFileInfoPointer->FileStart = Record->ExtentLocationL;
113 IsoFileInfoPointer->FileSize = Record->DataLengthL;
114 IsoFileInfoPointer->FilePointer = 0;
115 IsoFileInfoPointer->Directory = (Record->FileFlags & 0x02)?TRUE:FALSE;
116
117 return TRUE;
118 }
119
120 }
121
122 RtlZeroMemory(Name, 32 * sizeof(UCHAR));
123 }
124
125 return FALSE;
126 }
127
128
129 /*
130 * IsoBufferDirectory()
131 * This function allocates a buffer, reads the specified directory
132 * and returns a pointer to that buffer. The function returns NULL
133 * if allocation or read fails. The directory is specified by its
134 * starting sector and length.
135 */
136 static PVOID IsoBufferDirectory(ULONG DirectoryStartSector, ULONG DirectoryLength)
137 {
138 PVOID DirectoryBuffer;
139 PVOID Ptr;
140 ULONG SectorCount;
141 ULONG i;
142
143 DbgPrint((DPRINT_FILESYSTEM, "IsoBufferDirectory() DirectoryStartSector = %d DirectoryLength = %d\n", DirectoryStartSector, DirectoryLength));
144
145 SectorCount = ROUND_UP(DirectoryLength, SECTORSIZE) / SECTORSIZE;
146 DbgPrint((DPRINT_FILESYSTEM, "Trying to read (DirectoryCount) %d sectors.\n", SectorCount));
147
148 //
149 // Attempt to allocate memory for directory buffer
150 //
151 DbgPrint((DPRINT_FILESYSTEM, "Trying to allocate (DirectoryLength) %d bytes.\n", DirectoryLength));
152 DirectoryBuffer = MmAllocateMemory(DirectoryLength);
153
154 if (DirectoryBuffer == NULL)
155 {
156 return NULL;
157 }
158
159 //
160 // Now read directory contents into DirectoryBuffer
161 //
162 for (i = 0, Ptr = DirectoryBuffer; i < SectorCount; i++, Ptr += SECTORSIZE)
163 {
164 if (!MachDiskReadLogicalSectors(IsoDriveNumber, DirectoryStartSector + i, 1, (PVOID)DISKREADBUFFER))
165 {
166 MmFreeMemory(DirectoryBuffer);
167 return NULL;
168 }
169 RtlCopyMemory(Ptr, (PVOID)DISKREADBUFFER, SECTORSIZE);
170 }
171
172 return DirectoryBuffer;
173 }
174
175
176 /*
177 * IsoLookupFile()
178 * This function searches the file system for the
179 * specified filename and fills in an ISO_FILE_INFO structure
180 * with info describing the file, etc. returns true
181 * if the file exists or false otherwise
182 */
183 static BOOL IsoLookupFile(PCHAR FileName, PISO_FILE_INFO IsoFileInfoPointer)
184 {
185 int i;
186 ULONG NumberOfPathParts;
187 CHAR PathPart[261];
188 PVOID DirectoryBuffer;
189 ULONG DirectorySector;
190 ULONG DirectoryLength;
191 ISO_FILE_INFO IsoFileInfo;
192
193 DbgPrint((DPRINT_FILESYSTEM, "IsoLookupFile() FileName = %s\n", FileName));
194
195 RtlZeroMemory(IsoFileInfoPointer, sizeof(ISO_FILE_INFO));
196
197 //
198 // Figure out how many sub-directories we are nested in
199 //
200 NumberOfPathParts = FsGetNumPathParts(FileName);
201
202 DirectorySector = IsoRootSector;
203 DirectoryLength = IsoRootLength;
204
205 //
206 // Loop once for each part
207 //
208 for (i=0; i<NumberOfPathParts; i++)
209 {
210 //
211 // Get first path part
212 //
213 FsGetFirstNameFromPath(PathPart, FileName);
214
215 //
216 // Advance to the next part of the path
217 //
218 for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
219 {
220 }
221 FileName++;
222
223 //
224 // Buffer the directory contents
225 //
226 DirectoryBuffer = IsoBufferDirectory(DirectorySector, DirectoryLength);
227 if (DirectoryBuffer == NULL)
228 {
229 return FALSE;
230 }
231
232 //
233 // Search for file name in directory
234 //
235 if (!IsoSearchDirectoryBufferForFile(DirectoryBuffer, DirectoryLength, PathPart, &IsoFileInfo))
236 {
237 MmFreeMemory(DirectoryBuffer);
238 return FALSE;
239 }
240
241 MmFreeMemory(DirectoryBuffer);
242
243 //
244 // If we have another sub-directory to go then
245 // grab the start sector and file size
246 //
247 if ((i+1) < NumberOfPathParts)
248 {
249 DirectorySector = IsoFileInfo.FileStart;
250 DirectoryLength = IsoFileInfo.FileSize;
251 }
252
253 }
254
255 RtlCopyMemory(IsoFileInfoPointer, &IsoFileInfo, sizeof(ISO_FILE_INFO));
256
257 return TRUE;
258 }
259
260
261 /*
262 * IsoOpenFile()
263 * Tries to open the file 'name' and returns true or false
264 * for success and failure respectively
265 */
266 FILE* IsoOpenFile(PCHAR FileName)
267 {
268 ISO_FILE_INFO TempFileInfo;
269 PISO_FILE_INFO FileHandle;
270
271 DbgPrint((DPRINT_FILESYSTEM, "IsoOpenFile() FileName = %s\n", FileName));
272
273 if (!IsoLookupFile(FileName, &TempFileInfo))
274 {
275 return NULL;
276 }
277
278 FileHandle = MmAllocateMemory(sizeof(ISO_FILE_INFO));
279
280 if (FileHandle == NULL)
281 {
282 return NULL;
283 }
284
285 RtlCopyMemory(FileHandle, &TempFileInfo, sizeof(ISO_FILE_INFO));
286
287 return (FILE*)FileHandle;
288 }
289
290
291 /*
292 * IsoReadFile()
293 * Reads BytesToRead from open file and
294 * returns the number of bytes read in BytesRead
295 */
296 BOOL IsoReadFile(FILE *FileHandle, ULONG BytesToRead, ULONG* BytesRead, PVOID Buffer)
297 {
298 PISO_FILE_INFO IsoFileInfo = (PISO_FILE_INFO)FileHandle;
299 ULONG SectorNumber;
300 ULONG OffsetInSector;
301 ULONG LengthInSector;
302 ULONG NumberOfSectors;
303 ULONG i;
304
305 DbgPrint((DPRINT_FILESYSTEM, "IsoReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead, Buffer));
306
307 if (BytesRead != NULL)
308 {
309 *BytesRead = 0;
310 }
311
312 //
313 // If they are trying to read past the
314 // end of the file then return success
315 // with BytesRead == 0
316 //
317 if (IsoFileInfo->FilePointer >= IsoFileInfo->FileSize)
318 {
319 return TRUE;
320 }
321
322 //
323 // If they are trying to read more than there is to read
324 // then adjust the amount to read
325 //
326 if ((IsoFileInfo->FilePointer + BytesToRead) > IsoFileInfo->FileSize)
327 {
328 BytesToRead = (IsoFileInfo->FileSize - IsoFileInfo->FilePointer);
329 }
330
331 //
332 // Ok, now we have to perform at most 3 calculations
333 // I'll draw you a picture (using nifty ASCII art):
334 //
335 // CurrentFilePointer -+
336 // |
337 // +----------------+
338 // |
339 // +-----------+-----------+-----------+-----------+
340 // | Sector 1 | Sector 2 | Sector 3 | Sector 4 |
341 // +-----------+-----------+-----------+-----------+
342 // | |
343 // +---------------+--------------------+
344 // |
345 // BytesToRead -------+
346 //
347 // 1 - The first calculation (and read) will align
348 // the file pointer with the next sector
349 // boundary (if we are supposed to read that much)
350 // 2 - The next calculation (and read) will read
351 // in all the full sectors that the requested
352 // amount of data would cover (in this case
353 // sectors 2 & 3).
354 // 3 - The last calculation (and read) would read
355 // in the remainder of the data requested out of
356 // the last sector.
357 //
358
359
360 //
361 // Only do the first read if we
362 // aren't aligned on a cluster boundary
363 //
364 if (IsoFileInfo->FilePointer % SECTORSIZE)
365 {
366 //
367 // Do the math for our first read
368 //
369 SectorNumber = IsoFileInfo->FileStart + (IsoFileInfo->FilePointer / SECTORSIZE);
370 OffsetInSector = IsoFileInfo->FilePointer % SECTORSIZE;
371 LengthInSector = (BytesToRead > (SECTORSIZE - OffsetInSector)) ? (SECTORSIZE - OffsetInSector) : BytesToRead;
372
373 //
374 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
375 //
376 if (!MachDiskReadLogicalSectors(IsoDriveNumber, SectorNumber, 1, (PVOID)DISKREADBUFFER))
377 {
378 return FALSE;
379 }
380 RtlCopyMemory(Buffer, ((PVOID)DISKREADBUFFER + OffsetInSector), LengthInSector);
381 if (BytesRead != NULL)
382 {
383 *BytesRead += LengthInSector;
384 }
385 BytesToRead -= LengthInSector;
386 IsoFileInfo->FilePointer += LengthInSector;
387 Buffer += LengthInSector;
388 }
389
390 //
391 // Do the math for our second read (if any data left)
392 //
393 if (BytesToRead > 0)
394 {
395 //
396 // Determine how many full clusters we need to read
397 //
398 NumberOfSectors = (BytesToRead / SECTORSIZE);
399
400 for (i = 0; i < NumberOfSectors; i++)
401 {
402 SectorNumber = IsoFileInfo->FileStart + (IsoFileInfo->FilePointer / SECTORSIZE);
403
404 //
405 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
406 //
407 if (!MachDiskReadLogicalSectors(IsoDriveNumber, SectorNumber, 1, (PVOID)DISKREADBUFFER))
408 {
409 return FALSE;
410 }
411
412 RtlCopyMemory(Buffer, (PVOID)DISKREADBUFFER, SECTORSIZE);
413
414 if (BytesRead != NULL)
415 {
416 *BytesRead += SECTORSIZE;
417 }
418 BytesToRead -= SECTORSIZE;
419 IsoFileInfo->FilePointer += SECTORSIZE;
420 Buffer += SECTORSIZE;
421 }
422 }
423
424 //
425 // Do the math for our third read (if any data left)
426 //
427 if (BytesToRead > 0)
428 {
429 SectorNumber = IsoFileInfo->FileStart + (IsoFileInfo->FilePointer / SECTORSIZE);
430
431 //
432 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
433 //
434 if (!MachDiskReadLogicalSectors(IsoDriveNumber, SectorNumber, 1, (PVOID)DISKREADBUFFER))
435 {
436 return FALSE;
437 }
438 RtlCopyMemory(Buffer, (PVOID)DISKREADBUFFER, BytesToRead);
439 if (BytesRead != NULL)
440 {
441 *BytesRead += BytesToRead;
442 }
443 IsoFileInfo->FilePointer += BytesToRead;
444 BytesToRead -= BytesToRead;
445 Buffer += BytesToRead;
446 }
447
448 DbgPrint((DPRINT_FILESYSTEM, "IsoReadFile() done\n"));
449
450 return TRUE;
451 }
452
453
454 ULONG IsoGetFileSize(FILE *FileHandle)
455 {
456 PISO_FILE_INFO IsoFileHandle = (PISO_FILE_INFO)FileHandle;
457
458 DbgPrint((DPRINT_FILESYSTEM, "IsoGetFileSize() FileSize = %d\n", IsoFileHandle->FileSize));
459
460 return IsoFileHandle->FileSize;
461 }
462
463 VOID IsoSetFilePointer(FILE *FileHandle, ULONG NewFilePointer)
464 {
465 PISO_FILE_INFO IsoFileHandle = (PISO_FILE_INFO)FileHandle;
466
467 DbgPrint((DPRINT_FILESYSTEM, "IsoSetFilePointer() NewFilePointer = %d\n", NewFilePointer));
468
469 IsoFileHandle->FilePointer = NewFilePointer;
470 }
471
472 ULONG IsoGetFilePointer(FILE *FileHandle)
473 {
474 PISO_FILE_INFO IsoFileHandle = (PISO_FILE_INFO)FileHandle;
475
476 DbgPrint((DPRINT_FILESYSTEM, "IsoGetFilePointer() FilePointer = %d\n", IsoFileHandle->FilePointer));
477
478 return IsoFileHandle->FilePointer;
479 }