Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygeniso.c
Go to the documentation of this file.
00001 /* 00002 * FreeLoader 00003 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com> 00004 * Copyright (C) 2009 Hervé Poussineau <hpoussin@reactos.org> 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License along 00017 * with this program; if not, write to the Free Software Foundation, Inc., 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00019 */ 00020 00021 #ifndef _M_ARM 00022 #include <freeldr.h> 00023 #include <debug.h> 00024 00025 #define SECTORSIZE 2048 00026 00027 DBG_DEFAULT_CHANNEL(FILESYSTEM); 00028 00029 static BOOLEAN IsoSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectoryLength, PCHAR FileName, PISO_FILE_INFO IsoFileInfoPointer) 00030 { 00031 PDIR_RECORD Record; 00032 ULONG Offset; 00033 ULONG i; 00034 CHAR Name[32]; 00035 00036 TRACE("IsoSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectoryLength = %d FileName = %s\n", DirectoryBuffer, DirectoryLength, FileName); 00037 00038 RtlZeroMemory(Name, 32 * sizeof(UCHAR)); 00039 00040 Offset = 0; 00041 Record = (PDIR_RECORD)DirectoryBuffer; 00042 while (TRUE) 00043 { 00044 Offset = Offset + Record->RecordLength; 00045 Record = (PDIR_RECORD)((ULONG_PTR)DirectoryBuffer + Offset); 00046 00047 if (Record->RecordLength == 0) 00048 { 00049 Offset = ROUND_UP(Offset, SECTORSIZE); 00050 Record = (PDIR_RECORD)((ULONG_PTR)DirectoryBuffer + Offset); 00051 } 00052 00053 if (Offset >= DirectoryLength) 00054 return FALSE; 00055 00056 if (Record->FileIdLength == 1 && Record->FileId[0] == 0) 00057 { 00058 TRACE("Name '.'\n"); 00059 } 00060 else if (Record->FileIdLength == 1 && Record->FileId[0] == 1) 00061 { 00062 TRACE("Name '..'\n"); 00063 } 00064 else 00065 { 00066 for (i = 0; i < Record->FileIdLength && Record->FileId[i] != ';'; i++) 00067 Name[i] = Record->FileId[i]; 00068 Name[i] = 0; 00069 TRACE("Name '%s'\n", Name); 00070 00071 if (strlen(FileName) == strlen(Name) && _stricmp(FileName, Name) == 0) 00072 { 00073 IsoFileInfoPointer->FileStart = Record->ExtentLocationL; 00074 IsoFileInfoPointer->FileSize = Record->DataLengthL; 00075 IsoFileInfoPointer->FilePointer = 0; 00076 IsoFileInfoPointer->Directory = (Record->FileFlags & 0x02)?TRUE:FALSE; 00077 00078 return TRUE; 00079 } 00080 00081 } 00082 00083 RtlZeroMemory(Name, 32 * sizeof(UCHAR)); 00084 } 00085 00086 return FALSE; 00087 } 00088 00089 00090 /* 00091 * IsoBufferDirectory() 00092 * This function allocates a buffer, reads the specified directory 00093 * and returns a pointer to that buffer into pDirectoryBuffer. The 00094 * function returns an ARC error code. The directory is specified 00095 * by its starting sector and length. 00096 */ 00097 static LONG IsoBufferDirectory(ULONG DeviceId, ULONG DirectoryStartSector, ULONG DirectoryLength, 00098 PVOID* pDirectoryBuffer) 00099 { 00100 PVOID DirectoryBuffer; 00101 ULONG SectorCount; 00102 LARGE_INTEGER Position; 00103 ULONG Count; 00104 ULONG ret; 00105 00106 TRACE("IsoBufferDirectory() DirectoryStartSector = %d DirectoryLength = %d\n", DirectoryStartSector, DirectoryLength); 00107 00108 SectorCount = ROUND_UP(DirectoryLength, SECTORSIZE) / SECTORSIZE; 00109 TRACE("Trying to read (DirectoryCount) %d sectors.\n", SectorCount); 00110 00111 // 00112 // Attempt to allocate memory for directory buffer 00113 // 00114 TRACE("Trying to allocate (DirectoryLength) %d bytes.\n", DirectoryLength); 00115 DirectoryBuffer = MmHeapAlloc(DirectoryLength); 00116 if (!DirectoryBuffer) 00117 return ENOMEM; 00118 00119 // 00120 // Now read directory contents into DirectoryBuffer 00121 // 00122 Position.HighPart = 0; 00123 Position.LowPart = DirectoryStartSector * SECTORSIZE; 00124 ret = ArcSeek(DeviceId, &Position, SeekAbsolute); 00125 if (ret != ESUCCESS) 00126 { 00127 MmHeapFree(DirectoryBuffer); 00128 return ret; 00129 } 00130 ret = ArcRead(DeviceId, DirectoryBuffer, SectorCount * SECTORSIZE, &Count); 00131 if (ret != ESUCCESS || Count != SectorCount * SECTORSIZE) 00132 { 00133 MmHeapFree(DirectoryBuffer); 00134 return EIO; 00135 } 00136 00137 *pDirectoryBuffer = DirectoryBuffer; 00138 return ESUCCESS; 00139 } 00140 00141 00142 /* 00143 * IsoLookupFile() 00144 * This function searches the file system for the 00145 * specified filename and fills in an ISO_FILE_INFO structure 00146 * with info describing the file, etc. returns ARC error code 00147 */ 00148 static LONG IsoLookupFile(PCSTR FileName, ULONG DeviceId, PISO_FILE_INFO IsoFileInfoPointer) 00149 { 00150 UCHAR Buffer[SECTORSIZE]; 00151 PPVD Pvd = (PPVD)Buffer; 00152 UINT32 i; 00153 ULONG NumberOfPathParts; 00154 CHAR PathPart[261]; 00155 PVOID DirectoryBuffer; 00156 ULONG DirectorySector; 00157 ULONG DirectoryLength; 00158 ISO_FILE_INFO IsoFileInfo; 00159 LARGE_INTEGER Position; 00160 ULONG Count; 00161 LONG ret; 00162 00163 TRACE("IsoLookupFile() FileName = %s\n", FileName); 00164 00165 RtlZeroMemory(IsoFileInfoPointer, sizeof(ISO_FILE_INFO)); 00166 RtlZeroMemory(&IsoFileInfo, sizeof(ISO_FILE_INFO)); 00167 00168 // 00169 // Read The Primary Volume Descriptor 00170 // 00171 Position.HighPart = 0; 00172 Position.LowPart = 16 * SECTORSIZE; 00173 ret = ArcSeek(DeviceId, &Position, SeekAbsolute); 00174 if (ret != ESUCCESS) 00175 return ret; 00176 ret = ArcRead(DeviceId, Pvd, SECTORSIZE, &Count); 00177 if (ret != ESUCCESS || Count < sizeof(PVD)) 00178 return EIO; 00179 00180 DirectorySector = Pvd->RootDirRecord.ExtentLocationL; 00181 DirectoryLength = Pvd->RootDirRecord.DataLengthL; 00182 00183 // 00184 // Figure out how many sub-directories we are nested in 00185 // 00186 NumberOfPathParts = FsGetNumPathParts(FileName); 00187 00188 // 00189 // Loop once for each part 00190 // 00191 for (i=0; i<NumberOfPathParts; i++) 00192 { 00193 // 00194 // Get first path part 00195 // 00196 FsGetFirstNameFromPath(PathPart, FileName); 00197 00198 // 00199 // Advance to the next part of the path 00200 // 00201 for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++) 00202 { 00203 } 00204 FileName++; 00205 00206 // 00207 // Buffer the directory contents 00208 // 00209 ret = IsoBufferDirectory(DeviceId, DirectorySector, DirectoryLength, &DirectoryBuffer); 00210 if (ret != ESUCCESS) 00211 return ret; 00212 00213 // 00214 // Search for file name in directory 00215 // 00216 if (!IsoSearchDirectoryBufferForFile(DirectoryBuffer, DirectoryLength, PathPart, &IsoFileInfo)) 00217 { 00218 MmHeapFree(DirectoryBuffer); 00219 return ENOENT; 00220 } 00221 00222 MmHeapFree(DirectoryBuffer); 00223 00224 // 00225 // If we have another sub-directory to go then 00226 // grab the start sector and file size 00227 // 00228 if ((i+1) < NumberOfPathParts) 00229 { 00230 DirectorySector = IsoFileInfo.FileStart; 00231 DirectoryLength = IsoFileInfo.FileSize; 00232 } 00233 00234 } 00235 00236 RtlCopyMemory(IsoFileInfoPointer, &IsoFileInfo, sizeof(ISO_FILE_INFO)); 00237 00238 return ESUCCESS; 00239 } 00240 00241 LONG IsoClose(ULONG FileId) 00242 { 00243 PISO_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); 00244 00245 MmHeapFree(FileHandle); 00246 00247 return ESUCCESS; 00248 } 00249 00250 LONG IsoGetFileInformation(ULONG FileId, FILEINFORMATION* Information) 00251 { 00252 PISO_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); 00253 00254 TRACE("IsoGetFileInformation() FileSize = %d\n", FileHandle->FileSize); 00255 TRACE("IsoGetFileInformation() FilePointer = %d\n", FileHandle->FilePointer); 00256 00257 RtlZeroMemory(Information, sizeof(FILEINFORMATION)); 00258 Information->EndingAddress.LowPart = FileHandle->FileSize; 00259 Information->CurrentAddress.LowPart = FileHandle->FilePointer; 00260 00261 return ESUCCESS; 00262 } 00263 00264 LONG IsoOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId) 00265 { 00266 ISO_FILE_INFO TempFileInfo; 00267 PISO_FILE_INFO FileHandle; 00268 ULONG DeviceId; 00269 LONG ret; 00270 00271 if (OpenMode != OpenReadOnly) 00272 return EACCES; 00273 00274 DeviceId = FsGetDeviceId(*FileId); 00275 00276 TRACE("IsoOpen() FileName = %s\n", Path); 00277 00278 RtlZeroMemory(&TempFileInfo, sizeof(TempFileInfo)); 00279 ret = IsoLookupFile(Path, DeviceId, &TempFileInfo); 00280 if (ret != ESUCCESS) 00281 return ENOENT; 00282 00283 FileHandle = MmHeapAlloc(sizeof(ISO_FILE_INFO)); 00284 if (!FileHandle) 00285 return ENOMEM; 00286 00287 RtlCopyMemory(FileHandle, &TempFileInfo, sizeof(ISO_FILE_INFO)); 00288 00289 FsSetDeviceSpecific(*FileId, FileHandle); 00290 return ESUCCESS; 00291 } 00292 00293 LONG IsoRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count) 00294 { 00295 PISO_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); 00296 UCHAR SectorBuffer[SECTORSIZE]; 00297 LARGE_INTEGER Position; 00298 ULONG DeviceId; 00299 ULONG FilePointer; 00300 ULONG SectorNumber; 00301 ULONG OffsetInSector; 00302 ULONG LengthInSector; 00303 ULONG NumberOfSectors; 00304 ULONG BytesRead; 00305 LONG ret; 00306 00307 TRACE("IsoRead() Buffer = %p, N = %lu\n", Buffer, N); 00308 00309 DeviceId = FsGetDeviceId(FileId); 00310 *Count = 0; 00311 00312 // 00313 // If they are trying to read past the 00314 // end of the file then return success 00315 // with Count == 0 00316 // 00317 FilePointer = FileHandle->FilePointer; 00318 if (FilePointer >= FileHandle->FileSize) 00319 { 00320 return ESUCCESS; 00321 } 00322 00323 // 00324 // If they are trying to read more than there is to read 00325 // then adjust the amount to read 00326 // 00327 if (FilePointer + N > FileHandle->FileSize) 00328 { 00329 N = FileHandle->FileSize - FilePointer; 00330 } 00331 00332 // 00333 // Ok, now we have to perform at most 3 calculations 00334 // I'll draw you a picture (using nifty ASCII art): 00335 // 00336 // CurrentFilePointer -+ 00337 // | 00338 // +----------------+ 00339 // | 00340 // +-----------+-----------+-----------+-----------+ 00341 // | Sector 1 | Sector 2 | Sector 3 | Sector 4 | 00342 // +-----------+-----------+-----------+-----------+ 00343 // | | 00344 // +---------------+--------------------+ 00345 // | 00346 // N -----------------+ 00347 // 00348 // 1 - The first calculation (and read) will align 00349 // the file pointer with the next sector 00350 // boundary (if we are supposed to read that much) 00351 // 2 - The next calculation (and read) will read 00352 // in all the full sectors that the requested 00353 // amount of data would cover (in this case 00354 // sectors 2 & 3). 00355 // 3 - The last calculation (and read) would read 00356 // in the remainder of the data requested out of 00357 // the last sector. 00358 // 00359 00360 00361 // 00362 // Only do the first read if we 00363 // aren't aligned on a cluster boundary 00364 // 00365 if (FilePointer % SECTORSIZE) 00366 { 00367 // 00368 // Do the math for our first read 00369 // 00370 SectorNumber = FileHandle->FileStart + (FilePointer / SECTORSIZE); 00371 OffsetInSector = FilePointer % SECTORSIZE; 00372 LengthInSector = (N > (SECTORSIZE - OffsetInSector)) ? (SECTORSIZE - OffsetInSector) : N; 00373 00374 // 00375 // Now do the read and update Count, N, FilePointer, & Buffer 00376 // 00377 Position.HighPart = 0; 00378 Position.LowPart = SectorNumber * SECTORSIZE; 00379 ret = ArcSeek(DeviceId, &Position, SeekAbsolute); 00380 if (ret != ESUCCESS) 00381 { 00382 return ret; 00383 } 00384 ret = ArcRead(DeviceId, SectorBuffer, SECTORSIZE, &BytesRead); 00385 if (ret != ESUCCESS || BytesRead != SECTORSIZE) 00386 { 00387 return EIO; 00388 } 00389 RtlCopyMemory(Buffer, SectorBuffer + OffsetInSector, LengthInSector); 00390 *Count += LengthInSector; 00391 N -= LengthInSector; 00392 FilePointer += LengthInSector; 00393 Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInSector); 00394 } 00395 00396 // 00397 // Do the math for our second read (if any data left) 00398 // 00399 if (N > 0) 00400 { 00401 // 00402 // Determine how many full clusters we need to read 00403 // 00404 NumberOfSectors = (N / SECTORSIZE); 00405 00406 SectorNumber = FileHandle->FileStart + (FilePointer / SECTORSIZE); 00407 00408 // 00409 // Now do the read and update Count, N, FilePointer, & Buffer 00410 // 00411 Position.HighPart = 0; 00412 Position.LowPart = SectorNumber * SECTORSIZE; 00413 ret = ArcSeek(DeviceId, &Position, SeekAbsolute); 00414 if (ret != ESUCCESS) 00415 { 00416 return ret; 00417 } 00418 ret = ArcRead(DeviceId, Buffer, NumberOfSectors * SECTORSIZE, &BytesRead); 00419 if (ret != ESUCCESS || BytesRead != NumberOfSectors * SECTORSIZE) 00420 { 00421 return EIO; 00422 } 00423 00424 *Count += NumberOfSectors * SECTORSIZE; 00425 N -= NumberOfSectors * SECTORSIZE; 00426 FilePointer += NumberOfSectors * SECTORSIZE; 00427 Buffer = (PVOID)((ULONG_PTR)Buffer + NumberOfSectors * SECTORSIZE); 00428 } 00429 00430 // 00431 // Do the math for our third read (if any data left) 00432 // 00433 if (N > 0) 00434 { 00435 SectorNumber = FileHandle->FileStart + (FilePointer / SECTORSIZE); 00436 00437 // 00438 // Now do the read and update Count, N, FilePointer, & Buffer 00439 // 00440 Position.HighPart = 0; 00441 Position.LowPart = SectorNumber * SECTORSIZE; 00442 ret = ArcSeek(DeviceId, &Position, SeekAbsolute); 00443 if (ret != ESUCCESS) 00444 { 00445 return ret; 00446 } 00447 ret = ArcRead(DeviceId, SectorBuffer, SECTORSIZE, &BytesRead); 00448 if (ret != ESUCCESS || BytesRead != SECTORSIZE) 00449 { 00450 return EIO; 00451 } 00452 RtlCopyMemory(Buffer, SectorBuffer, N); 00453 *Count += N; 00454 FilePointer += N; 00455 } 00456 00457 TRACE("IsoRead() done\n"); 00458 00459 return ESUCCESS; 00460 } 00461 00462 LONG IsoSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode) 00463 { 00464 PISO_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); 00465 00466 TRACE("IsoSeek() NewFilePointer = %lu\n", Position->LowPart); 00467 00468 if (SeekMode != SeekAbsolute) 00469 return EINVAL; 00470 if (Position->HighPart != 0) 00471 return EINVAL; 00472 if (Position->LowPart >= FileHandle->FileSize) 00473 return EINVAL; 00474 00475 FileHandle->FilePointer = Position->LowPart; 00476 return ESUCCESS; 00477 } 00478 00479 const DEVVTBL Iso9660FuncTable = 00480 { 00481 IsoClose, 00482 IsoGetFileInformation, 00483 IsoOpen, 00484 IsoRead, 00485 IsoSeek, 00486 L"cdfs", 00487 }; 00488 00489 const DEVVTBL* IsoMount(ULONG DeviceId) 00490 { 00491 UCHAR Buffer[SECTORSIZE]; 00492 PPVD Pvd = (PPVD)Buffer; 00493 LARGE_INTEGER Position; 00494 ULONG Count; 00495 LONG ret; 00496 00497 // 00498 // Read The Primary Volume Descriptor 00499 // 00500 Position.HighPart = 0; 00501 Position.LowPart = 16 * SECTORSIZE; 00502 ret = ArcSeek(DeviceId, &Position, SeekAbsolute); 00503 if (ret != ESUCCESS) 00504 return NULL; 00505 ret = ArcRead(DeviceId, Pvd, SECTORSIZE, &Count); 00506 if (ret != ESUCCESS || Count < sizeof(PVD)) 00507 return NULL; 00508 00509 // 00510 // Check if PVD is valid. If yes, return ISO9660 function table 00511 // 00512 if (Pvd->VdType == 1 && RtlEqualMemory(Pvd->StandardId, "CD001", 5)) 00513 return &Iso9660FuncTable; 00514 else 00515 return NULL; 00516 } 00517 00518 #endif 00519 Generated on Sun May 27 2012 04:17:10 for ReactOS by
1.7.6.1
|