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

ext2.c
Go to the documentation of this file.
00001 /*
00002  *  FreeLoader
00003  *  Copyright (C) 1998-2003  Brian Palmer  <brianp@sginet.com>
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License along
00016  *  with this program; if not, write to the Free Software Foundation, Inc.,
00017  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00018  */
00019 
00020 #ifndef _M_ARM
00021 #include <freeldr.h>
00022 #include <debug.h>
00023 
00024 DBG_DEFAULT_CHANNEL(FILESYSTEM);
00025 
00026 BOOLEAN Ext2OpenVolume(UCHAR DriveNumber, ULONGLONG VolumeStartSector, ULONGLONG PartitionSectorCount);
00027 PEXT2_FILE_INFO Ext2OpenFile(PCSTR FileName);
00028 BOOLEAN Ext2LookupFile(PCSTR FileName, PEXT2_FILE_INFO Ext2FileInfoPointer);
00029 BOOLEAN Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry);
00030 BOOLEAN Ext2ReadVolumeSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer);
00031 
00032 BOOLEAN Ext2ReadFileBig(PEXT2_FILE_INFO Ext2FileInfo, ULONGLONG BytesToRead, ULONGLONG* BytesRead, PVOID Buffer);
00033 BOOLEAN Ext2ReadSuperBlock(VOID);
00034 BOOLEAN Ext2ReadGroupDescriptors(VOID);
00035 BOOLEAN Ext2ReadDirectory(ULONG Inode, PVOID* DirectoryBuffer, PEXT2_INODE InodePointer);
00036 BOOLEAN Ext2ReadBlock(ULONG BlockNumber, PVOID Buffer);
00037 BOOLEAN Ext2ReadPartialBlock(ULONG BlockNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer);
00038 ULONG       Ext2GetGroupDescBlockNumber(ULONG Group);
00039 ULONG       Ext2GetGroupDescOffsetInBlock(ULONG Group);
00040 ULONG       Ext2GetInodeGroupNumber(ULONG Inode);
00041 ULONG       Ext2GetInodeBlockNumber(ULONG Inode);
00042 ULONG       Ext2GetInodeOffsetInBlock(ULONG Inode);
00043 BOOLEAN Ext2ReadInode(ULONG Inode, PEXT2_INODE InodeBuffer);
00044 BOOLEAN Ext2ReadGroupDescriptor(ULONG Group, PEXT2_GROUP_DESC GroupBuffer);
00045 ULONG*  Ext2ReadBlockPointerList(PEXT2_INODE Inode);
00046 ULONGLONG       Ext2GetInodeFileSize(PEXT2_INODE Inode);
00047 BOOLEAN Ext2CopyIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock);
00048 BOOLEAN Ext2CopyDoubleIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock);
00049 BOOLEAN Ext2CopyTripleIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock);
00050 
00051 GEOMETRY        Ext2DiskGeometry;               // Ext2 file system disk geometry
00052 
00053 PEXT2_SUPER_BLOCK   Ext2SuperBlock = NULL;          // Ext2 file system super block
00054 PEXT2_GROUP_DESC    Ext2GroupDescriptors = NULL;    // Ext2 file system group descriptors
00055 
00056 UCHAR                   Ext2DriveNumber = 0;            // Ext2 file system drive number
00057 ULONGLONG               Ext2VolumeStartSector = 0;      // Ext2 file system starting sector
00058 ULONG                   Ext2BlockSizeInBytes = 0;       // Block size in bytes
00059 ULONG                   Ext2BlockSizeInSectors = 0;     // Block size in sectors
00060 ULONG                   Ext2FragmentSizeInBytes = 0;    // Fragment size in bytes
00061 ULONG                   Ext2FragmentSizeInSectors = 0;  // Fragment size in sectors
00062 ULONG                   Ext2GroupCount = 0;             // Number of groups in this file system
00063 ULONG                   Ext2InodesPerBlock = 0;         // Number of inodes in one block
00064 ULONG                   Ext2GroupDescPerBlock = 0;      // Number of group descriptors in one block
00065 
00066 BOOLEAN DiskGetBootVolume(PUCHAR DriveNumber, PULONGLONG StartSector, PULONGLONG SectorCount, int *FsType)
00067 {
00068     *DriveNumber = 0;
00069     *StartSector = 0;
00070     *SectorCount = 0;
00071     *FsType = 0;
00072     return FALSE;
00073 }
00074 
00075 BOOLEAN Ext2OpenVolume(UCHAR DriveNumber, ULONGLONG VolumeStartSector, ULONGLONG PartitionSectorCount)
00076 {
00077 
00078     TRACE("Ext2OpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber, VolumeStartSector);
00079 
00080     // Store the drive number and start sector
00081     Ext2DriveNumber = DriveNumber;
00082     Ext2VolumeStartSector = VolumeStartSector;
00083 
00084     if (!MachDiskGetDriveGeometry(DriveNumber, &Ext2DiskGeometry))
00085     {
00086         return FALSE;
00087     }
00088 
00089     //
00090     // Initialize the disk cache for this drive
00091     //
00092     if (!CacheInitializeDrive(DriveNumber))
00093     {
00094         return FALSE;
00095     }
00096 
00097     // Read in the super block
00098     if (!Ext2ReadSuperBlock())
00099     {
00100         return FALSE;
00101     }
00102 
00103     // Read in the group descriptors
00104     if (!Ext2ReadGroupDescriptors())
00105     {
00106         return FALSE;
00107     }
00108 
00109     return TRUE;
00110 }
00111 
00112 /*
00113  * Ext2OpenFile()
00114  * Tries to open the file 'name' and returns true or false
00115  * for success and failure respectively
00116  */
00117 PEXT2_FILE_INFO Ext2OpenFile(PCSTR FileName)
00118 {
00119     EXT2_FILE_INFO      TempExt2FileInfo;
00120     PEXT2_FILE_INFO     FileHandle;
00121     CHAR            SymLinkPath[EXT2_NAME_LEN];
00122     CHAR            FullPath[EXT2_NAME_LEN * 2];
00123     ULONG_PTR       Index;
00124 
00125     TRACE("Ext2OpenFile() FileName = %s\n", FileName);
00126 
00127     RtlZeroMemory(SymLinkPath, sizeof(SymLinkPath));
00128 
00129     // Lookup the file in the file system
00130     if (!Ext2LookupFile(FileName, &TempExt2FileInfo))
00131     {
00132         return NULL;
00133     }
00134 
00135     // If we got a symbolic link then fix up the path
00136     // and re-call this function
00137     if ((TempExt2FileInfo.Inode.mode & EXT2_S_IFMT) == EXT2_S_IFLNK)
00138     {
00139         TRACE("File is a symbolic link\n");
00140 
00141         // Now read in the symbolic link path
00142         if (!Ext2ReadFileBig(&TempExt2FileInfo, TempExt2FileInfo.FileSize, NULL, SymLinkPath))
00143         {
00144             if (TempExt2FileInfo.FileBlockList != NULL)
00145             {
00146                 MmHeapFree(TempExt2FileInfo.FileBlockList);
00147             }
00148 
00149             return NULL;
00150         }
00151 
00152         TRACE("Symbolic link path = %s\n", SymLinkPath);
00153 
00154         // Get the full path
00155         if (SymLinkPath[0] == '/' || SymLinkPath[0] == '\\')
00156         {
00157             // Symbolic link is an absolute path
00158             // So copy it to FullPath, but skip over
00159             // the '/' char at the beginning
00160             strcpy(FullPath, &SymLinkPath[1]);
00161         }
00162         else
00163         {
00164             // Symbolic link is a relative path
00165             // Copy the first part of the path
00166             strcpy(FullPath, FileName);
00167 
00168             // Remove the last part of the path
00169             for (Index=strlen(FullPath); Index>0; )
00170             {
00171                 Index--;
00172                 if (FullPath[Index] == '/' || FullPath[Index] == '\\')
00173                 {
00174                     break;
00175                 }
00176             }
00177             FullPath[Index] = '\0';
00178 
00179             // Concatenate the symbolic link
00180             strcat(FullPath, Index == 0 ? "" : "/");
00181             strcat(FullPath, SymLinkPath);
00182         }
00183 
00184         TRACE("Full file path = %s\n", FullPath);
00185 
00186         if (TempExt2FileInfo.FileBlockList != NULL)
00187         {
00188             MmHeapFree(TempExt2FileInfo.FileBlockList);
00189         }
00190 
00191         return Ext2OpenFile(FullPath);
00192     }
00193     else
00194     {
00195         FileHandle = MmHeapAlloc(sizeof(EXT2_FILE_INFO));
00196 
00197         if (FileHandle == NULL)
00198         {
00199             if (TempExt2FileInfo.FileBlockList != NULL)
00200             {
00201                 MmHeapFree(TempExt2FileInfo.FileBlockList);
00202             }
00203 
00204             return NULL;
00205         }
00206 
00207         RtlCopyMemory(FileHandle, &TempExt2FileInfo, sizeof(EXT2_FILE_INFO));
00208 
00209         return FileHandle;
00210     }
00211 }
00212 
00213 /*
00214  * Ext2LookupFile()
00215  * This function searches the file system for the
00216  * specified filename and fills in a EXT2_FILE_INFO structure
00217  * with info describing the file, etc. returns true
00218  * if the file exists or false otherwise
00219  */
00220 BOOLEAN Ext2LookupFile(PCSTR FileName, PEXT2_FILE_INFO Ext2FileInfoPointer)
00221 {
00222     UINT32      i;
00223     ULONG       NumberOfPathParts;
00224     CHAR        PathPart[261];
00225     PVOID       DirectoryBuffer;
00226     ULONG       DirectoryInode = EXT2_ROOT_INO;
00227     EXT2_INODE  InodeData;
00228     EXT2_DIR_ENTRY  DirectoryEntry;
00229 
00230     TRACE("Ext2LookupFile() FileName = %s\n", FileName);
00231 
00232     RtlZeroMemory(Ext2FileInfoPointer, sizeof(EXT2_FILE_INFO));
00233 
00234     //
00235     // Figure out how many sub-directories we are nested in
00236     //
00237     NumberOfPathParts = FsGetNumPathParts(FileName);
00238 
00239     //
00240     // Loop once for each part
00241     //
00242     for (i=0; i<NumberOfPathParts; i++)
00243     {
00244         //
00245         // Get first path part
00246         //
00247         FsGetFirstNameFromPath(PathPart, FileName);
00248 
00249         //
00250         // Advance to the next part of the path
00251         //
00252         for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
00253         {
00254         }
00255         FileName++;
00256 
00257         //
00258         // Buffer the directory contents
00259         //
00260         if (!Ext2ReadDirectory(DirectoryInode, &DirectoryBuffer, &InodeData))
00261         {
00262             return FALSE;
00263         }
00264 
00265         //
00266         // Search for file name in directory
00267         //
00268         if (!Ext2SearchDirectoryBufferForFile(DirectoryBuffer, (ULONG)Ext2GetInodeFileSize(&InodeData), PathPart, &DirectoryEntry))
00269         {
00270             MmHeapFree(DirectoryBuffer);
00271             return FALSE;
00272         }
00273 
00274         MmHeapFree(DirectoryBuffer);
00275 
00276         DirectoryInode = DirectoryEntry.inode;
00277     }
00278 
00279     if (!Ext2ReadInode(DirectoryInode, &InodeData))
00280     {
00281         return FALSE;
00282     }
00283 
00284     if (((InodeData.mode & EXT2_S_IFMT) != EXT2_S_IFREG) &&
00285         ((InodeData.mode & EXT2_S_IFMT) != EXT2_S_IFLNK))
00286     {
00287         FileSystemError("Inode is not a regular file or symbolic link.");
00288         return FALSE;
00289     }
00290 
00291     // Set the drive number
00292     Ext2FileInfoPointer->DriveNumber = Ext2DriveNumber;
00293 
00294     // If it's a regular file or a regular symbolic link
00295     // then get the block pointer list otherwise it must
00296     // be a fast symbolic link which doesn't have a block list
00297     if (((InodeData.mode & EXT2_S_IFMT) == EXT2_S_IFREG) ||
00298         ((InodeData.mode & EXT2_S_IFMT) == EXT2_S_IFLNK && InodeData.size > FAST_SYMLINK_MAX_NAME_SIZE))
00299     {
00300         Ext2FileInfoPointer->FileBlockList = Ext2ReadBlockPointerList(&InodeData);
00301 
00302         if (Ext2FileInfoPointer->FileBlockList == NULL)
00303         {
00304             return FALSE;
00305         }
00306     }
00307     else
00308     {
00309         Ext2FileInfoPointer->FileBlockList = NULL;
00310     }
00311 
00312     Ext2FileInfoPointer->FilePointer = 0;
00313     Ext2FileInfoPointer->FileSize = Ext2GetInodeFileSize(&InodeData);
00314     RtlCopyMemory(&Ext2FileInfoPointer->Inode, &InodeData, sizeof(EXT2_INODE));
00315 
00316     return TRUE;
00317 }
00318 
00319 BOOLEAN Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry)
00320 {
00321     ULONG       CurrentOffset;
00322     PEXT2_DIR_ENTRY CurrentDirectoryEntry;
00323 
00324     TRACE("Ext2SearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = %s\n", DirectoryBuffer, DirectorySize, FileName);
00325 
00326     for (CurrentOffset=0; CurrentOffset<DirectorySize; )
00327     {
00328         CurrentDirectoryEntry = (PEXT2_DIR_ENTRY)((ULONG_PTR)DirectoryBuffer + CurrentOffset);
00329 
00330         if (CurrentDirectoryEntry->direntlen == 0)
00331         {
00332             break;
00333         }
00334 
00335         if ((CurrentDirectoryEntry->direntlen + CurrentOffset) > DirectorySize)
00336         {
00337             FileSystemError("Directory entry extends past end of directory file.");
00338             return FALSE;
00339         }
00340 
00341         TRACE("Dumping directory entry at offset %d:\n", CurrentOffset);
00342         DbgDumpBuffer(DPRINT_FILESYSTEM, CurrentDirectoryEntry, CurrentDirectoryEntry->direntlen);
00343 
00344         if ((_strnicmp(FileName, CurrentDirectoryEntry->name, CurrentDirectoryEntry->namelen) == 0) &&
00345             (strlen(FileName) == CurrentDirectoryEntry->namelen))
00346         {
00347             RtlCopyMemory(DirectoryEntry, CurrentDirectoryEntry, sizeof(EXT2_DIR_ENTRY));
00348 
00349             TRACE("EXT2 Directory Entry:\n");
00350             TRACE("inode = %d\n", DirectoryEntry->inode);
00351             TRACE("direntlen = %d\n", DirectoryEntry->direntlen);
00352             TRACE("namelen = %d\n", DirectoryEntry->namelen);
00353             TRACE("filetype = %d\n", DirectoryEntry->filetype);
00354             TRACE("name = ");
00355             for (CurrentOffset=0; CurrentOffset<DirectoryEntry->namelen; CurrentOffset++)
00356             {
00357                 TRACE("%c", DirectoryEntry->name[CurrentOffset]);
00358             }
00359             TRACE("\n");
00360 
00361             return TRUE;
00362         }
00363 
00364         CurrentOffset += CurrentDirectoryEntry->direntlen;
00365     }
00366 
00367     return FALSE;
00368 }
00369 
00370 /*
00371  * Ext2ReadFileBig()
00372  * Reads BytesToRead from open file and
00373  * returns the number of bytes read in BytesRead
00374  */
00375 BOOLEAN Ext2ReadFileBig(PEXT2_FILE_INFO Ext2FileInfo, ULONGLONG BytesToRead, ULONGLONG* BytesRead, PVOID Buffer)
00376 {
00377     ULONG               BlockNumber;
00378     ULONG               BlockNumberIndex;
00379     ULONG               OffsetInBlock;
00380     ULONG               LengthInBlock;
00381     ULONG               NumberOfBlocks;
00382 
00383     TRACE("Ext2ReadFileBig() BytesToRead = %d Buffer = 0x%x\n", (ULONG)BytesToRead, Buffer);
00384 
00385     if (BytesRead != NULL)
00386     {
00387         *BytesRead = 0;
00388     }
00389 
00390     // Make sure we have the block pointer list if we need it
00391     if (Ext2FileInfo->FileBlockList == NULL)
00392     {
00393         // Block pointer list is NULL
00394         // so this better be a fast symbolic link or else
00395         if (((Ext2FileInfo->Inode.mode & EXT2_S_IFMT) != EXT2_S_IFLNK) ||
00396             (Ext2FileInfo->FileSize > FAST_SYMLINK_MAX_NAME_SIZE))
00397         {
00398             FileSystemError("Block pointer list is NULL and file is not a fast symbolic link.");
00399             return FALSE;
00400         }
00401     }
00402 
00403     //
00404     // If they are trying to read past the
00405     // end of the file then return success
00406     // with BytesRead == 0
00407     //
00408     if (Ext2FileInfo->FilePointer >= Ext2FileInfo->FileSize)
00409     {
00410         return TRUE;
00411     }
00412 
00413     //
00414     // If they are trying to read more than there is to read
00415     // then adjust the amount to read
00416     //
00417     if ((Ext2FileInfo->FilePointer + BytesToRead) > Ext2FileInfo->FileSize)
00418     {
00419         BytesToRead = (Ext2FileInfo->FileSize - Ext2FileInfo->FilePointer);
00420     }
00421 
00422     // Check if this is a fast symbolic link
00423     // if so then the read is easy
00424     if (((Ext2FileInfo->Inode.mode & EXT2_S_IFMT) == EXT2_S_IFLNK) &&
00425         (Ext2FileInfo->FileSize <= FAST_SYMLINK_MAX_NAME_SIZE))
00426     {
00427         TRACE("Reading fast symbolic link data\n");
00428 
00429         // Copy the data from the link
00430         RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Ext2FileInfo->FilePointer + Ext2FileInfo->Inode.symlink), (ULONG)BytesToRead);
00431 
00432         if (BytesRead != NULL)
00433         {
00434             *BytesRead = BytesToRead;
00435         }
00436 
00437         return TRUE;
00438     }
00439 
00440     //
00441     // Ok, now we have to perform at most 3 calculations
00442     // I'll draw you a picture (using nifty ASCII art):
00443     //
00444     // CurrentFilePointer -+
00445     //                     |
00446     //    +----------------+
00447     //    |
00448     // +-----------+-----------+-----------+-----------+
00449     // | Block 1   | Block 2   | Block 3   | Block 4   |
00450     // +-----------+-----------+-----------+-----------+
00451     //    |                                    |
00452     //    +---------------+--------------------+
00453     //                    |
00454     // BytesToRead -------+
00455     //
00456     // 1 - The first calculation (and read) will align
00457     //     the file pointer with the next block.
00458     //     boundary (if we are supposed to read that much)
00459     // 2 - The next calculation (and read) will read
00460     //     in all the full blocks that the requested
00461     //     amount of data would cover (in this case
00462     //     blocks 2 & 3).
00463     // 3 - The last calculation (and read) would read
00464     //     in the remainder of the data requested out of
00465     //     the last block.
00466     //
00467 
00468     //
00469     // Only do the first read if we
00470     // aren't aligned on a block boundary
00471     //
00472     if (Ext2FileInfo->FilePointer % Ext2BlockSizeInBytes)
00473     {
00474         //
00475         // Do the math for our first read
00476         //
00477         BlockNumberIndex = (ULONG)(Ext2FileInfo->FilePointer / Ext2BlockSizeInBytes);
00478         BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
00479         OffsetInBlock = (Ext2FileInfo->FilePointer % Ext2BlockSizeInBytes);
00480         LengthInBlock = (ULONG)((BytesToRead > (Ext2BlockSizeInBytes - OffsetInBlock)) ? (Ext2BlockSizeInBytes - OffsetInBlock) : BytesToRead);
00481 
00482         //
00483         // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
00484         //
00485         if (!Ext2ReadPartialBlock(BlockNumber, OffsetInBlock, LengthInBlock, Buffer))
00486         {
00487             return FALSE;
00488         }
00489         if (BytesRead != NULL)
00490         {
00491             *BytesRead += LengthInBlock;
00492         }
00493         BytesToRead -= LengthInBlock;
00494         Ext2FileInfo->FilePointer += LengthInBlock;
00495         Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInBlock);
00496     }
00497 
00498     //
00499     // Do the math for our second read (if any data left)
00500     //
00501     if (BytesToRead > 0)
00502     {
00503         //
00504         // Determine how many full clusters we need to read
00505         //
00506         NumberOfBlocks = (ULONG)(BytesToRead / Ext2BlockSizeInBytes);
00507 
00508         while (NumberOfBlocks > 0)
00509         {
00510             BlockNumberIndex = (ULONG)(Ext2FileInfo->FilePointer / Ext2BlockSizeInBytes);
00511             BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
00512 
00513             //
00514             // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
00515             //
00516             if (!Ext2ReadBlock(BlockNumber, Buffer))
00517             {
00518                 return FALSE;
00519             }
00520             if (BytesRead != NULL)
00521             {
00522                 *BytesRead += Ext2BlockSizeInBytes;
00523             }
00524             BytesToRead -= Ext2BlockSizeInBytes;
00525             Ext2FileInfo->FilePointer += Ext2BlockSizeInBytes;
00526             Buffer = (PVOID)((ULONG_PTR)Buffer + Ext2BlockSizeInBytes);
00527             NumberOfBlocks--;
00528         }
00529     }
00530 
00531     //
00532     // Do the math for our third read (if any data left)
00533     //
00534     if (BytesToRead > 0)
00535     {
00536         BlockNumberIndex = (ULONG)(Ext2FileInfo->FilePointer / Ext2BlockSizeInBytes);
00537         BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
00538 
00539         //
00540         // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
00541         //
00542         if (!Ext2ReadPartialBlock(BlockNumber, 0, (ULONG)BytesToRead, Buffer))
00543         {
00544             return FALSE;
00545         }
00546         if (BytesRead != NULL)
00547         {
00548             *BytesRead += BytesToRead;
00549         }
00550         Ext2FileInfo->FilePointer += BytesToRead;
00551         BytesToRead -= BytesToRead;
00552         Buffer = (PVOID)((ULONG_PTR)Buffer + (ULONG_PTR)BytesToRead);
00553     }
00554 
00555     return TRUE;
00556 }
00557 
00558 BOOLEAN Ext2ReadVolumeSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
00559 {
00560     //GEOMETRY  DiskGeometry;
00561     //BOOLEAN       ReturnValue;
00562     //if (!DiskGetDriveGeometry(DriveNumber, &DiskGeometry))
00563     //{
00564     //  return FALSE;
00565     //}
00566     //ReturnValue = MachDiskReadLogicalSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, (PVOID)DISKREADBUFFER);
00567     //RtlCopyMemory(Buffer, (PVOID)DISKREADBUFFER, SectorCount * DiskGeometry.BytesPerSector);
00568     //return ReturnValue;
00569 
00570     return CacheReadDiskSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, Buffer);
00571 }
00572 
00573 BOOLEAN Ext2ReadSuperBlock(VOID)
00574 {
00575 
00576     TRACE("Ext2ReadSuperBlock()\n");
00577 
00578     //
00579     // Free any memory previously allocated
00580     //
00581     if (Ext2SuperBlock != NULL)
00582     {
00583         MmHeapFree(Ext2SuperBlock);
00584 
00585         Ext2SuperBlock = NULL;
00586     }
00587 
00588     //
00589     // Now allocate the memory to hold the super block
00590     //
00591     Ext2SuperBlock = (PEXT2_SUPER_BLOCK)MmHeapAlloc(1024);
00592 
00593     //
00594     // Make sure we got the memory
00595     //
00596     if (Ext2SuperBlock == NULL)
00597     {
00598         FileSystemError("Out of memory.");
00599         return FALSE;
00600     }
00601 
00602     // Now try to read the super block
00603     // If this fails then abort
00604     if (!MachDiskReadLogicalSectors(Ext2DriveNumber, Ext2VolumeStartSector, 8, (PVOID)DISKREADBUFFER))
00605     {
00606         return FALSE;
00607     }
00608     RtlCopyMemory(Ext2SuperBlock, (PVOID)((ULONG_PTR)DISKREADBUFFER + 1024), 1024);
00609 
00610     TRACE("Dumping super block:\n");
00611     TRACE("total_inodes: %d\n", Ext2SuperBlock->total_inodes);
00612     TRACE("total_blocks: %d\n", Ext2SuperBlock->total_blocks);
00613     TRACE("reserved_blocks: %d\n", Ext2SuperBlock->reserved_blocks);
00614     TRACE("free_blocks: %d\n", Ext2SuperBlock->free_blocks);
00615     TRACE("free_inodes: %d\n", Ext2SuperBlock->free_inodes);
00616     TRACE("first_data_block: %d\n", Ext2SuperBlock->first_data_block);
00617     TRACE("log2_block_size: %d\n", Ext2SuperBlock->log2_block_size);
00618     TRACE("log2_fragment_size: %d\n", Ext2SuperBlock->log2_fragment_size);
00619     TRACE("blocks_per_group: %d\n", Ext2SuperBlock->blocks_per_group);
00620     TRACE("fragments_per_group: %d\n", Ext2SuperBlock->fragments_per_group);
00621     TRACE("inodes_per_group: %d\n", Ext2SuperBlock->inodes_per_group);
00622     TRACE("mtime: %d\n", Ext2SuperBlock->mtime);
00623     TRACE("utime: %d\n", Ext2SuperBlock->utime);
00624     TRACE("mnt_count: %d\n", Ext2SuperBlock->mnt_count);
00625     TRACE("max_mnt_count: %d\n", Ext2SuperBlock->max_mnt_count);
00626     TRACE("magic: 0x%x\n", Ext2SuperBlock->magic);
00627     TRACE("fs_state: %d\n", Ext2SuperBlock->fs_state);
00628     TRACE("error_handling: %d\n", Ext2SuperBlock->error_handling);
00629     TRACE("minor_revision_level: %d\n", Ext2SuperBlock->minor_revision_level);
00630     TRACE("lastcheck: %d\n", Ext2SuperBlock->lastcheck);
00631     TRACE("checkinterval: %d\n", Ext2SuperBlock->checkinterval);
00632     TRACE("creator_os: %d\n", Ext2SuperBlock->creator_os);
00633     TRACE("revision_level: %d\n", Ext2SuperBlock->revision_level);
00634     TRACE("uid_reserved: %d\n", Ext2SuperBlock->uid_reserved);
00635     TRACE("gid_reserved: %d\n", Ext2SuperBlock->gid_reserved);
00636     TRACE("first_inode: %d\n", Ext2SuperBlock->first_inode);
00637     TRACE("inode_size: %d\n", Ext2SuperBlock->inode_size);
00638     TRACE("block_group_number: %d\n", Ext2SuperBlock->block_group_number);
00639     TRACE("feature_compatibility: 0x%x\n", Ext2SuperBlock->feature_compatibility);
00640     TRACE("feature_incompat: 0x%x\n", Ext2SuperBlock->feature_incompat);
00641     TRACE("feature_ro_compat: 0x%x\n", Ext2SuperBlock->feature_ro_compat);
00642     TRACE("unique_id = { 0x%x, 0x%x, 0x%x, 0x%x }\n",
00643         Ext2SuperBlock->unique_id[0], Ext2SuperBlock->unique_id[1], Ext2SuperBlock->unique_id[2], Ext2SuperBlock->unique_id[3]);
00644     TRACE("volume_name = '%.16s'\n", Ext2SuperBlock->volume_name);
00645     TRACE("last_mounted_on = '%.64s'\n", Ext2SuperBlock->last_mounted_on);
00646     TRACE("compression_info = 0x%x\n", Ext2SuperBlock->compression_info);
00647 
00648     //
00649     // Check the super block magic
00650     //
00651     if (Ext2SuperBlock->magic != EXT2_MAGIC)
00652     {
00653         FileSystemError("Invalid super block magic (0xef53)");
00654         return FALSE;
00655     }
00656 
00657     //
00658     // Check the revision level
00659     //
00660     if (Ext2SuperBlock->revision_level > EXT2_DYNAMIC_REVISION)
00661     {
00662         FileSystemError("FreeLoader does not understand the revision of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
00663         return FALSE;
00664     }
00665 
00666     //
00667     // Check the feature set
00668     // Don't need to check the compatible or read-only compatible features
00669     // because we only mount the filesystem as read-only
00670     //
00671     if ((Ext2SuperBlock->revision_level >= EXT2_DYNAMIC_REVISION) &&
00672         (/*((Ext2SuperBlock->s_feature_compat & ~EXT3_FEATURE_COMPAT_SUPP) != 0) ||*/
00673          /*((Ext2SuperBlock->s_feature_ro_compat & ~EXT3_FEATURE_RO_COMPAT_SUPP) != 0) ||*/
00674          ((Ext2SuperBlock->feature_incompat & ~EXT3_FEATURE_INCOMPAT_SUPP) != 0)))
00675     {
00676         FileSystemError("FreeLoader does not understand features of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
00677         return FALSE;
00678     }
00679 
00680     // Calculate the group count
00681     Ext2GroupCount = (Ext2SuperBlock->total_blocks - Ext2SuperBlock->first_data_block + Ext2SuperBlock->blocks_per_group - 1) / Ext2SuperBlock->blocks_per_group;
00682     TRACE("Ext2GroupCount: %d\n", Ext2GroupCount);
00683 
00684     // Calculate the block size
00685     Ext2BlockSizeInBytes = 1024 << Ext2SuperBlock->log2_block_size;
00686     Ext2BlockSizeInSectors = Ext2BlockSizeInBytes / Ext2DiskGeometry.BytesPerSector;
00687     TRACE("Ext2BlockSizeInBytes: %d\n", Ext2BlockSizeInBytes);
00688     TRACE("Ext2BlockSizeInSectors: %d\n", Ext2BlockSizeInSectors);
00689 
00690     // Calculate the fragment size
00691     if (Ext2SuperBlock->log2_fragment_size >= 0)
00692     {
00693         Ext2FragmentSizeInBytes = 1024 << Ext2SuperBlock->log2_fragment_size;
00694     }
00695     else
00696     {
00697         Ext2FragmentSizeInBytes = 1024 >> -(Ext2SuperBlock->log2_fragment_size);
00698     }
00699     Ext2FragmentSizeInSectors = Ext2FragmentSizeInBytes / Ext2DiskGeometry.BytesPerSector;
00700     TRACE("Ext2FragmentSizeInBytes: %d\n", Ext2FragmentSizeInBytes);
00701     TRACE("Ext2FragmentSizeInSectors: %d\n", Ext2FragmentSizeInSectors);
00702 
00703     // Verify that the fragment size and the block size are equal
00704     if (Ext2BlockSizeInBytes != Ext2FragmentSizeInBytes)
00705     {
00706         FileSystemError("The fragment size must be equal to the block size.");
00707         return FALSE;
00708     }
00709 
00710     // Calculate the number of inodes in one block
00711     Ext2InodesPerBlock = Ext2BlockSizeInBytes / EXT2_INODE_SIZE(Ext2SuperBlock);
00712     TRACE("Ext2InodesPerBlock: %d\n", Ext2InodesPerBlock);
00713 
00714     // Calculate the number of group descriptors in one block
00715     Ext2GroupDescPerBlock = EXT2_DESC_PER_BLOCK(Ext2SuperBlock);
00716     TRACE("Ext2GroupDescPerBlock: %d\n", Ext2GroupDescPerBlock);
00717 
00718     return TRUE;
00719 }
00720 
00721 BOOLEAN Ext2ReadGroupDescriptors(VOID)
00722 {
00723     ULONG       GroupDescBlockCount;
00724     ULONG       CurrentGroupDescBlock;
00725 
00726     TRACE("Ext2ReadGroupDescriptors()\n");
00727 
00728     //
00729     // Free any memory previously allocated
00730     //
00731     if (Ext2GroupDescriptors != NULL)
00732     {
00733         MmHeapFree(Ext2GroupDescriptors);
00734 
00735         Ext2GroupDescriptors = NULL;
00736     }
00737 
00738     //
00739     // Now allocate the memory to hold the group descriptors
00740     //
00741     GroupDescBlockCount = ROUND_UP(Ext2GroupCount, Ext2GroupDescPerBlock) / Ext2GroupDescPerBlock;
00742     Ext2GroupDescriptors = (PEXT2_GROUP_DESC)MmHeapAlloc(GroupDescBlockCount * Ext2BlockSizeInBytes);
00743 
00744     //
00745     // Make sure we got the memory
00746     //
00747     if (Ext2GroupDescriptors == NULL)
00748     {
00749         FileSystemError("Out of memory.");
00750         return FALSE;
00751     }
00752 
00753     // Now read the group descriptors
00754     for (CurrentGroupDescBlock=0; CurrentGroupDescBlock<GroupDescBlockCount; CurrentGroupDescBlock++)
00755     {
00756         if (!Ext2ReadBlock(Ext2SuperBlock->first_data_block + 1 + CurrentGroupDescBlock, (PVOID)FILESYSBUFFER))
00757         {
00758             return FALSE;
00759         }
00760 
00761         RtlCopyMemory((Ext2GroupDescriptors + (CurrentGroupDescBlock * Ext2BlockSizeInBytes)), (PVOID)FILESYSBUFFER, Ext2BlockSizeInBytes);
00762     }
00763 
00764     return TRUE;
00765 }
00766 
00767 BOOLEAN Ext2ReadDirectory(ULONG Inode, PVOID* DirectoryBuffer, PEXT2_INODE InodePointer)
00768 {
00769     EXT2_FILE_INFO  DirectoryFileInfo;
00770 
00771     TRACE("Ext2ReadDirectory() Inode = %d\n", Inode);
00772 
00773     // Read the directory inode
00774     if (!Ext2ReadInode(Inode, InodePointer))
00775     {
00776         return FALSE;
00777     }
00778 
00779     // Make sure it is a directory inode
00780     if ((InodePointer->mode & EXT2_S_IFMT) != EXT2_S_IFDIR)
00781     {
00782         FileSystemError("Inode is not a directory.");
00783         return FALSE;
00784     }
00785 
00786     // Fill in file info struct so we can call Ext2ReadFileBig()
00787     RtlZeroMemory(&DirectoryFileInfo, sizeof(EXT2_FILE_INFO));
00788     DirectoryFileInfo.DriveNumber = Ext2DriveNumber;
00789     DirectoryFileInfo.FileBlockList = Ext2ReadBlockPointerList(InodePointer);
00790     DirectoryFileInfo.FilePointer = 0;
00791     DirectoryFileInfo.FileSize = Ext2GetInodeFileSize(InodePointer);
00792 
00793     if (DirectoryFileInfo.FileBlockList == NULL)
00794     {
00795         return FALSE;
00796     }
00797 
00798     //
00799     // Now allocate the memory to hold the group descriptors
00800     //
00801     ASSERT(DirectoryFileInfo.FileSize <= 0xFFFFFFFF);
00802     *DirectoryBuffer = (PEXT2_DIR_ENTRY)MmHeapAlloc((ULONG)DirectoryFileInfo.FileSize);
00803 
00804     //
00805     // Make sure we got the memory
00806     //
00807     if (*DirectoryBuffer == NULL)
00808     {
00809         MmHeapFree(DirectoryFileInfo.FileBlockList);
00810         FileSystemError("Out of memory.");
00811         return FALSE;
00812     }
00813 
00814     // Now read the root directory data
00815     if (!Ext2ReadFileBig(&DirectoryFileInfo, DirectoryFileInfo.FileSize, NULL, *DirectoryBuffer))
00816     {
00817         MmHeapFree(*DirectoryBuffer);
00818         *DirectoryBuffer = NULL;
00819         MmHeapFree(DirectoryFileInfo.FileBlockList);
00820         return FALSE;
00821     }
00822 
00823     MmHeapFree(DirectoryFileInfo.FileBlockList);
00824     return TRUE;
00825 }
00826 
00827 BOOLEAN Ext2ReadBlock(ULONG BlockNumber, PVOID Buffer)
00828 {
00829     CHAR    ErrorString[80];
00830 
00831     TRACE("Ext2ReadBlock() BlockNumber = %d Buffer = 0x%x\n", BlockNumber, Buffer);
00832 
00833     // Make sure its a valid block
00834     if (BlockNumber > Ext2SuperBlock->total_blocks)
00835     {
00836         sprintf(ErrorString, "Error reading block %d - block out of range.", (int) BlockNumber);
00837         FileSystemError(ErrorString);
00838         return FALSE;
00839     }
00840 
00841     // Check to see if this is a sparse block
00842     if (BlockNumber == 0)
00843     {
00844         TRACE("Block is part of a sparse file. Zeroing input buffer.\n");
00845 
00846         RtlZeroMemory(Buffer, Ext2BlockSizeInBytes);
00847 
00848         return TRUE;
00849     }
00850 
00851     return Ext2ReadVolumeSectors(Ext2DriveNumber, (ULONGLONG)BlockNumber * Ext2BlockSizeInSectors, Ext2BlockSizeInSectors, Buffer);
00852 }
00853 
00854 /*
00855  * Ext2ReadPartialBlock()
00856  * Reads part of a block into memory
00857  */
00858 BOOLEAN Ext2ReadPartialBlock(ULONG BlockNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer)
00859 {
00860 
00861     TRACE("Ext2ReadPartialBlock() BlockNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", BlockNumber, StartingOffset, Length, Buffer);
00862 
00863     if (!Ext2ReadBlock(BlockNumber, (PVOID)FILESYSBUFFER))
00864     {
00865         return FALSE;
00866     }
00867 
00868     memcpy(Buffer, (PVOID)((ULONG_PTR)FILESYSBUFFER + StartingOffset), Length);
00869 
00870     return TRUE;
00871 }
00872 
00873 ULONG Ext2GetGroupDescBlockNumber(ULONG Group)
00874 {
00875     return (((Group * sizeof(EXT2_GROUP_DESC)) / Ext2GroupDescPerBlock) + Ext2SuperBlock->first_data_block + 1);
00876 }
00877 
00878 ULONG Ext2GetGroupDescOffsetInBlock(ULONG Group)
00879 {
00880     return ((Group * sizeof(EXT2_GROUP_DESC)) % Ext2GroupDescPerBlock);
00881 }
00882 
00883 ULONG Ext2GetInodeGroupNumber(ULONG Inode)
00884 {
00885     return ((Inode - 1) / Ext2SuperBlock->inodes_per_group);
00886 }
00887 
00888 ULONG Ext2GetInodeBlockNumber(ULONG Inode)
00889 {
00890     return (((Inode - 1) % Ext2SuperBlock->inodes_per_group) / Ext2InodesPerBlock);
00891 }
00892 
00893 ULONG Ext2GetInodeOffsetInBlock(ULONG Inode)
00894 {
00895     return (((Inode - 1) % Ext2SuperBlock->inodes_per_group) % Ext2InodesPerBlock);
00896 }
00897 
00898 BOOLEAN Ext2ReadInode(ULONG Inode, PEXT2_INODE InodeBuffer)
00899 {
00900     ULONG       InodeGroupNumber;
00901     ULONG       InodeBlockNumber;
00902     ULONG       InodeOffsetInBlock;
00903     CHAR        ErrorString[80];
00904     EXT2_GROUP_DESC GroupDescriptor;
00905 
00906     TRACE("Ext2ReadInode() Inode = %d\n", Inode);
00907 
00908     // Make sure its a valid inode
00909     if ((Inode < 1) || (Inode > Ext2SuperBlock->total_inodes))
00910     {
00911         sprintf(ErrorString, "Error reading inode %ld - inode out of range.", Inode);
00912         FileSystemError(ErrorString);
00913         return FALSE;
00914     }
00915 
00916     // Get inode group & block number and offset in block
00917     InodeGroupNumber = Ext2GetInodeGroupNumber(Inode);
00918     InodeBlockNumber = Ext2GetInodeBlockNumber(Inode);
00919     InodeOffsetInBlock = Ext2GetInodeOffsetInBlock(Inode);
00920     TRACE("InodeGroupNumber = %d\n", InodeGroupNumber);
00921     TRACE("InodeBlockNumber = %d\n", InodeBlockNumber);
00922     TRACE("InodeOffsetInBlock = %d\n", InodeOffsetInBlock);
00923 
00924     // Read the group descriptor
00925     if (!Ext2ReadGroupDescriptor(InodeGroupNumber, &GroupDescriptor))
00926     {
00927         return FALSE;
00928     }
00929 
00930     // Add the start block of the inode table to the inode block number
00931     InodeBlockNumber += GroupDescriptor.inode_table_id;
00932     TRACE("InodeBlockNumber (after group desc correction) = %d\n", InodeBlockNumber);
00933 
00934     // Read the block
00935     if (!Ext2ReadBlock(InodeBlockNumber, (PVOID)FILESYSBUFFER))
00936     {
00937         return FALSE;
00938     }
00939 
00940     // Copy the data to their buffer
00941     RtlCopyMemory(InodeBuffer, (PVOID)((ULONG_PTR)FILESYSBUFFER + (InodeOffsetInBlock * EXT2_INODE_SIZE(Ext2SuperBlock))), sizeof(EXT2_INODE));
00942 
00943     TRACE("Dumping inode information:\n");
00944     TRACE("mode = 0x%x\n", InodeBuffer->mode);
00945     TRACE("uid = %d\n", InodeBuffer->uid);
00946     TRACE("size = %d\n", InodeBuffer->size);
00947     TRACE("atime = %d\n", InodeBuffer->atime);
00948     TRACE("ctime = %d\n", InodeBuffer->ctime);
00949     TRACE("mtime = %d\n", InodeBuffer->mtime);
00950     TRACE("dtime = %d\n", InodeBuffer->dtime);
00951     TRACE("gid = %d\n", InodeBuffer->gid);
00952     TRACE("nlinks = %d\n", InodeBuffer->nlinks);
00953     TRACE("blockcnt = %d\n", InodeBuffer->blockcnt);
00954     TRACE("flags = 0x%x\n", InodeBuffer->flags);
00955     TRACE("osd1 = 0x%x\n", InodeBuffer->osd1);
00956     TRACE("dir_blocks = { %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u }\n",
00957         InodeBuffer->blocks.dir_blocks[0], InodeBuffer->blocks.dir_blocks[1], InodeBuffer->blocks.dir_blocks[ 2], InodeBuffer->blocks.dir_blocks[ 3],
00958         InodeBuffer->blocks.dir_blocks[4], InodeBuffer->blocks.dir_blocks[5], InodeBuffer->blocks.dir_blocks[ 6], InodeBuffer->blocks.dir_blocks[ 7],
00959         InodeBuffer->blocks.dir_blocks[8], InodeBuffer->blocks.dir_blocks[9], InodeBuffer->blocks.dir_blocks[10], InodeBuffer->blocks.dir_blocks[11]);
00960     TRACE("indir_block = %u\n", InodeBuffer->blocks.indir_block);
00961     TRACE("double_indir_block = %u\n", InodeBuffer->blocks.double_indir_block);
00962     TRACE("tripple_indir_block = %u\n", InodeBuffer->blocks.tripple_indir_block);
00963     TRACE("version = %d\n", InodeBuffer->version);
00964     TRACE("acl = %d\n", InodeBuffer->acl);
00965     TRACE("dir_acl = %d\n", InodeBuffer->dir_acl);
00966     TRACE("fragment_addr = %d\n", InodeBuffer->fragment_addr);
00967     TRACE("osd2 = { %d, %d, %d }\n",
00968         InodeBuffer->osd2[0], InodeBuffer->osd2[1], InodeBuffer->osd2[2]);
00969 
00970     return TRUE;
00971 }
00972 
00973 BOOLEAN Ext2ReadGroupDescriptor(ULONG Group, PEXT2_GROUP_DESC GroupBuffer)
00974 {
00975     TRACE("Ext2ReadGroupDescriptor()\n");
00976 
00977     /*if (!Ext2ReadBlock(Ext2GetGroupDescBlockNumber(Group), (PVOID)FILESYSBUFFER))
00978     {
00979         return FALSE;
00980     }
00981 
00982     RtlCopyMemory(GroupBuffer, (PVOID)(FILESYSBUFFER + Ext2GetGroupDescOffsetInBlock(Group)), sizeof(EXT2_GROUP_DESC));*/
00983 
00984     RtlCopyMemory(GroupBuffer, &Ext2GroupDescriptors[Group], sizeof(EXT2_GROUP_DESC));
00985 
00986     TRACE("Dumping group descriptor:\n");
00987     TRACE("block_id = %d\n", GroupBuffer->block_id);
00988     TRACE("inode_id = %d\n", GroupBuffer->inode_id);
00989     TRACE("inode_table_id = %d\n", GroupBuffer->inode_table_id);
00990     TRACE("free_blocks = %d\n", GroupBuffer->free_blocks);
00991     TRACE("free_inodes = %d\n", GroupBuffer->free_inodes);
00992     TRACE("used_dirs = %d\n", GroupBuffer->used_dirs);
00993 
00994     return TRUE;
00995 }
00996 
00997 ULONG* Ext2ReadBlockPointerList(PEXT2_INODE Inode)
00998 {
00999     ULONGLONG       FileSize;
01000     ULONG       BlockCount;
01001     ULONG*  BlockList;
01002     ULONG       CurrentBlockInList;
01003     ULONG       CurrentBlock;
01004 
01005     TRACE("Ext2ReadBlockPointerList()\n");
01006 
01007     // Get the number of blocks this file occupies
01008     // I would just use Inode->i_blocks but it
01009     // doesn't seem to be the number of blocks
01010     // the file size corresponds to, but instead
01011     // it is much bigger.
01012     //BlockCount = Inode->i_blocks;
01013     FileSize = Ext2GetInodeFileSize(Inode);
01014     FileSize = ROUND_UP(FileSize, Ext2BlockSizeInBytes);
01015     BlockCount = (ULONG)(FileSize / Ext2BlockSizeInBytes);
01016 
01017     // Allocate the memory for the block list
01018     BlockList = MmHeapAlloc(BlockCount * sizeof(ULONG));
01019     if (BlockList == NULL)
01020     {
01021         return NULL;
01022     }
01023 
01024     RtlZeroMemory(BlockList, BlockCount * sizeof(ULONG));
01025 
01026     // Copy the direct block pointers
01027     for (CurrentBlockInList = CurrentBlock = 0;
01028          CurrentBlockInList < BlockCount && CurrentBlock < INDIRECT_BLOCKS;
01029          CurrentBlock++, CurrentBlockInList++)
01030     {
01031         BlockList[CurrentBlockInList] = Inode->blocks.dir_blocks[CurrentBlock];
01032     }
01033 
01034     // Copy the indirect block pointers
01035     if (CurrentBlockInList < BlockCount)
01036     {
01037         if (!Ext2CopyIndirectBlockPointers(BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.indir_block))
01038         {
01039             MmHeapFree(BlockList);
01040             return FALSE;
01041         }
01042     }
01043 
01044     // Copy the double indirect block pointers
01045     if (CurrentBlockInList < BlockCount)
01046     {
01047         if (!Ext2CopyDoubleIndirectBlockPointers(BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.double_indir_block))
01048         {
01049             MmHeapFree(BlockList);
01050             return FALSE;
01051         }
01052     }
01053 
01054     // Copy the triple indirect block pointers
01055     if (CurrentBlockInList < BlockCount)
01056     {
01057         if (!Ext2CopyTripleIndirectBlockPointers(BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.tripple_indir_block))
01058         {
01059             MmHeapFree(BlockList);
01060             return FALSE;
01061         }
01062     }
01063 
01064     return BlockList;
01065 }
01066 
01067 ULONGLONG Ext2GetInodeFileSize(PEXT2_INODE Inode)
01068 {
01069     if ((Inode->mode & EXT2_S_IFMT) == EXT2_S_IFDIR)
01070     {
01071         return (ULONGLONG)(Inode->size);
01072     }
01073     else
01074     {
01075         return ((ULONGLONG)(Inode->size) | ((ULONGLONG)(Inode->dir_acl) << 32));
01076     }
01077 }
01078 
01079 BOOLEAN Ext2CopyIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock)
01080 {
01081     ULONG*  BlockBuffer = (ULONG*)FILESYSBUFFER;
01082     ULONG   CurrentBlock;
01083     ULONG   BlockPointersPerBlock;
01084 
01085     TRACE("Ext2CopyIndirectBlockPointers() BlockCount = %d\n", BlockCount);
01086 
01087     BlockPointersPerBlock = Ext2BlockSizeInBytes / sizeof(ULONG);
01088 
01089     if (!Ext2ReadBlock(IndirectBlock, BlockBuffer))
01090     {
01091         return FALSE;
01092     }
01093 
01094     for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
01095     {
01096         BlockList[(*CurrentBlockInList)] = BlockBuffer[CurrentBlock];
01097         (*CurrentBlockInList)++;
01098     }
01099 
01100     return TRUE;
01101 }
01102 
01103 BOOLEAN Ext2CopyDoubleIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock)
01104 {
01105     ULONG*  BlockBuffer;
01106     ULONG   CurrentBlock;
01107     ULONG   BlockPointersPerBlock;
01108 
01109     TRACE("Ext2CopyDoubleIndirectBlockPointers() BlockCount = %d\n", BlockCount);
01110 
01111     BlockPointersPerBlock = Ext2BlockSizeInBytes / sizeof(ULONG);
01112 
01113     BlockBuffer = (ULONG*)MmHeapAlloc(Ext2BlockSizeInBytes);
01114     if (BlockBuffer == NULL)
01115     {
01116         return FALSE;
01117     }
01118 
01119     if (!Ext2ReadBlock(DoubleIndirectBlock, BlockBuffer))
01120     {
01121         MmHeapFree(BlockBuffer);
01122         return FALSE;
01123     }
01124 
01125     for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
01126     {
01127         if (!Ext2CopyIndirectBlockPointers(BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
01128         {
01129             MmHeapFree(BlockBuffer);
01130             return FALSE;
01131         }
01132     }
01133 
01134     MmHeapFree(BlockBuffer);
01135     return TRUE;
01136 }
01137 
01138 BOOLEAN Ext2CopyTripleIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock)
01139 {
01140     ULONG*  BlockBuffer;
01141     ULONG   CurrentBlock;
01142     ULONG   BlockPointersPerBlock;
01143 
01144     TRACE("Ext2CopyTripleIndirectBlockPointers() BlockCount = %d\n", BlockCount);
01145 
01146     BlockPointersPerBlock = Ext2BlockSizeInBytes / sizeof(ULONG);
01147 
01148     BlockBuffer = (ULONG*)MmHeapAlloc(Ext2BlockSizeInBytes);
01149     if (BlockBuffer == NULL)
01150     {
01151         return FALSE;
01152     }
01153 
01154     if (!Ext2ReadBlock(TripleIndirectBlock, BlockBuffer))
01155     {
01156         MmHeapFree(BlockBuffer);
01157         return FALSE;
01158     }
01159 
01160     for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
01161     {
01162         if (!Ext2CopyDoubleIndirectBlockPointers(BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
01163         {
01164             MmHeapFree(BlockBuffer);
01165             return FALSE;
01166         }
01167     }
01168 
01169     MmHeapFree(BlockBuffer);
01170     return TRUE;
01171 }
01172 
01173 LONG Ext2Close(ULONG FileId)
01174 {
01175     PEXT2_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId);
01176 
01177     MmHeapFree(FileHandle);
01178 
01179     return ESUCCESS;
01180 }
01181 
01182 LONG Ext2GetFileInformation(ULONG FileId, FILEINFORMATION* Information)
01183 {
01184     PEXT2_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId);
01185 
01186     RtlZeroMemory(Information, sizeof(FILEINFORMATION));
01187     Information->EndingAddress.QuadPart = FileHandle->FileSize;
01188     Information->CurrentAddress.QuadPart = FileHandle->FilePointer;
01189 
01190     TRACE("Ext2GetFileInformation() FileSize = %d\n",
01191         Information->EndingAddress.LowPart);
01192     TRACE("Ext2GetFileInformation() FilePointer = %d\n",
01193         Information->CurrentAddress.LowPart);
01194 
01195     return ESUCCESS;
01196 }
01197 
01198 LONG Ext2Open(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
01199 {
01200     PEXT2_FILE_INFO FileHandle;
01201     //ULONG DeviceId;
01202 
01203     if (OpenMode != OpenReadOnly)
01204         return EACCES;
01205 
01206     //DeviceId = FsGetDeviceId(*FileId);
01207 
01208     TRACE("Ext2Open() FileName = %s\n", Path);
01209 
01210     //
01211     // Call old open method
01212     //
01213     FileHandle = Ext2OpenFile(Path);
01214 
01215     //
01216     // Check for error
01217     //
01218     if (!FileHandle)
01219         return ENOENT;
01220 
01221     //
01222     // Success. Remember the handle
01223     //
01224     FsSetDeviceSpecific(*FileId, FileHandle);
01225     return ESUCCESS;
01226 }
01227 
01228 LONG Ext2Read(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
01229 {
01230     PEXT2_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId);
01231     ULONGLONG BytesReadBig;
01232     BOOLEAN ret;
01233 
01234     //
01235     // Read data
01236     //
01237     ret = Ext2ReadFileBig(FileHandle, N, &BytesReadBig, Buffer);
01238     *Count = (ULONG)BytesReadBig;
01239 
01240     //
01241     // Check for success
01242     //
01243     if (ret)
01244         return ESUCCESS;
01245     else
01246         return EIO;
01247 }
01248 
01249 LONG Ext2Seek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
01250 {
01251     PEXT2_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId);
01252 
01253     TRACE("Ext2Seek() NewFilePointer = %lu\n", Position->LowPart);
01254 
01255     if (SeekMode != SeekAbsolute)
01256         return EINVAL;
01257     if (Position->HighPart != 0)
01258         return EINVAL;
01259     if (Position->LowPart >= FileHandle->FileSize)
01260         return EINVAL;
01261 
01262     FileHandle->FilePointer = Position->LowPart;
01263     return ESUCCESS;
01264 }
01265 
01266 const DEVVTBL Ext2FuncTable =
01267 {
01268     Ext2Close,
01269     Ext2GetFileInformation,
01270     Ext2Open,
01271     Ext2Read,
01272     Ext2Seek,
01273     L"ext2",
01274 };
01275 
01276 const DEVVTBL* Ext2Mount(ULONG DeviceId)
01277 {
01278     EXT2_SUPER_BLOCK SuperBlock;
01279     LARGE_INTEGER Position;
01280     ULONG Count;
01281     LONG ret;
01282 
01283     //
01284     // Read the SuperBlock
01285     //
01286     Position.HighPart = 0;
01287     Position.LowPart = 2 * 512;
01288     ret = ArcSeek(DeviceId, &Position, SeekAbsolute);
01289     if (ret != ESUCCESS)
01290         return NULL;
01291     ret = ArcRead(DeviceId, &SuperBlock, sizeof(SuperBlock), &Count);
01292     if (ret != ESUCCESS || Count != sizeof(SuperBlock))
01293         return NULL;
01294 
01295     //
01296     // Check if SuperBlock is valid. If yes, return Ext2 function table
01297     //
01298     if (SuperBlock.magic == EXT2_MAGIC)
01299     {
01300         //
01301         // Compatibility hack as long as FS is not using underlying device DeviceId
01302         //
01303         UCHAR DriveNumber;
01304         ULONGLONG StartSector;
01305         ULONGLONG SectorCount;
01306         int Type;
01307         if (!DiskGetBootVolume(&DriveNumber, &StartSector, &SectorCount, &Type))
01308             return NULL;
01309         Ext2OpenVolume(DriveNumber, StartSector, SectorCount);
01310         return &Ext2FuncTable;
01311     }
01312     else
01313         return NULL;
01314 }
01315 
01316 #endif
01317 

Generated on Sat May 26 2012 04:17:57 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.