ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

iso.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.