Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenext2.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
1.7.6.1
|