1 /* 2 * FreeLoader 3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 #ifndef _M_ARM 21 #include <freeldr.h> 22 #include <debug.h> 23 24 DBG_DEFAULT_CHANNEL(FILESYSTEM); 25 26 BOOLEAN Ext2OpenVolume(UCHAR DriveNumber, ULONGLONG VolumeStartSector, ULONGLONG PartitionSectorCount); 27 PEXT2_FILE_INFO Ext2OpenFile(PCSTR FileName); 28 BOOLEAN Ext2LookupFile(PCSTR FileName, PEXT2_FILE_INFO Ext2FileInfoPointer); 29 BOOLEAN Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry); 30 BOOLEAN Ext2ReadVolumeSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer); 31 32 BOOLEAN Ext2ReadFileBig(PEXT2_FILE_INFO Ext2FileInfo, ULONGLONG BytesToRead, ULONGLONG* BytesRead, PVOID Buffer); 33 BOOLEAN Ext2ReadSuperBlock(VOID); 34 BOOLEAN Ext2ReadGroupDescriptors(VOID); 35 BOOLEAN Ext2ReadDirectory(ULONG Inode, PVOID* DirectoryBuffer, PEXT2_INODE InodePointer); 36 BOOLEAN Ext2ReadBlock(ULONG BlockNumber, PVOID Buffer); 37 BOOLEAN Ext2ReadPartialBlock(ULONG BlockNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer); 38 ULONG Ext2GetGroupDescBlockNumber(ULONG Group); 39 ULONG Ext2GetGroupDescOffsetInBlock(ULONG Group); 40 ULONG Ext2GetInodeGroupNumber(ULONG Inode); 41 ULONG Ext2GetInodeBlockNumber(ULONG Inode); 42 ULONG Ext2GetInodeOffsetInBlock(ULONG Inode); 43 BOOLEAN Ext2ReadInode(ULONG Inode, PEXT2_INODE InodeBuffer); 44 BOOLEAN Ext2ReadGroupDescriptor(ULONG Group, PEXT2_GROUP_DESC GroupBuffer); 45 ULONG* Ext2ReadBlockPointerList(PEXT2_INODE Inode); 46 ULONGLONG Ext2GetInodeFileSize(PEXT2_INODE Inode); 47 BOOLEAN Ext2CopyIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock); 48 BOOLEAN Ext2CopyDoubleIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock); 49 BOOLEAN Ext2CopyTripleIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock); 50 51 GEOMETRY Ext2DiskGeometry; // Ext2 file system disk geometry 52 53 PEXT2_SUPER_BLOCK Ext2SuperBlock = NULL; // Ext2 file system super block 54 PEXT2_GROUP_DESC Ext2GroupDescriptors = NULL; // Ext2 file system group descriptors 55 56 UCHAR Ext2DriveNumber = 0; // Ext2 file system drive number 57 ULONGLONG Ext2VolumeStartSector = 0; // Ext2 file system starting sector 58 ULONG Ext2BlockSizeInBytes = 0; // Block size in bytes 59 ULONG Ext2BlockSizeInSectors = 0; // Block size in sectors 60 ULONG Ext2FragmentSizeInBytes = 0; // Fragment size in bytes 61 ULONG Ext2FragmentSizeInSectors = 0; // Fragment size in sectors 62 ULONG Ext2GroupCount = 0; // Number of groups in this file system 63 ULONG Ext2InodesPerBlock = 0; // Number of inodes in one block 64 ULONG Ext2GroupDescPerBlock = 0; // Number of group descriptors in one block 65 66 #define TAG_EXT_BLOCK_LIST 'LtxE' 67 #define TAG_EXT_FILE 'FtxE' 68 #define TAG_EXT_BUFFER 'BtxE' 69 #define TAG_EXT_SUPER_BLOCK 'StxE' 70 #define TAG_EXT_GROUP_DESC 'GtxE' 71 72 BOOLEAN DiskGetBootVolume(PUCHAR DriveNumber, PULONGLONG StartSector, PULONGLONG SectorCount, int *FsType) 73 { 74 *DriveNumber = 0; 75 *StartSector = 0; 76 *SectorCount = 0; 77 *FsType = 0; 78 return FALSE; 79 } 80 81 BOOLEAN Ext2OpenVolume(UCHAR DriveNumber, ULONGLONG VolumeStartSector, ULONGLONG PartitionSectorCount) 82 { 83 84 TRACE("Ext2OpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber, VolumeStartSector); 85 86 // Store the drive number and start sector 87 Ext2DriveNumber = DriveNumber; 88 Ext2VolumeStartSector = VolumeStartSector; 89 90 if (!MachDiskGetDriveGeometry(DriveNumber, &Ext2DiskGeometry)) 91 { 92 return FALSE; 93 } 94 95 // 96 // Initialize the disk cache for this drive 97 // 98 if (!CacheInitializeDrive(DriveNumber)) 99 { 100 return FALSE; 101 } 102 103 // Read in the super block 104 if (!Ext2ReadSuperBlock()) 105 { 106 return FALSE; 107 } 108 109 // Read in the group descriptors 110 if (!Ext2ReadGroupDescriptors()) 111 { 112 return FALSE; 113 } 114 115 return TRUE; 116 } 117 118 /* 119 * Ext2OpenFile() 120 * Tries to open the file 'name' and returns true or false 121 * for success and failure respectively 122 */ 123 PEXT2_FILE_INFO Ext2OpenFile(PCSTR FileName) 124 { 125 EXT2_FILE_INFO TempExt2FileInfo; 126 PEXT2_FILE_INFO FileHandle; 127 CHAR SymLinkPath[EXT2_NAME_LEN]; 128 CHAR FullPath[EXT2_NAME_LEN * 2]; 129 ULONG_PTR Index; 130 131 TRACE("Ext2OpenFile() FileName = %s\n", FileName); 132 133 RtlZeroMemory(SymLinkPath, sizeof(SymLinkPath)); 134 135 // Lookup the file in the file system 136 if (!Ext2LookupFile(FileName, &TempExt2FileInfo)) 137 { 138 return NULL; 139 } 140 141 // If we got a symbolic link then fix up the path 142 // and re-call this function 143 if ((TempExt2FileInfo.Inode.mode & EXT2_S_IFMT) == EXT2_S_IFLNK) 144 { 145 TRACE("File is a symbolic link\n"); 146 147 // Now read in the symbolic link path 148 if (!Ext2ReadFileBig(&TempExt2FileInfo, TempExt2FileInfo.FileSize, NULL, SymLinkPath)) 149 { 150 if (TempExt2FileInfo.FileBlockList != NULL) 151 { 152 FrLdrTempFree(TempExt2FileInfo.FileBlockList, TAG_EXT_BLOCK_LIST); 153 } 154 155 return NULL; 156 } 157 158 TRACE("Symbolic link path = %s\n", SymLinkPath); 159 160 // Get the full path 161 if (SymLinkPath[0] == '/' || SymLinkPath[0] == '\\') 162 { 163 // Symbolic link is an absolute path 164 // So copy it to FullPath, but skip over 165 // the '/' char at the beginning 166 strcpy(FullPath, &SymLinkPath[1]); 167 } 168 else 169 { 170 // Symbolic link is a relative path 171 // Copy the first part of the path 172 strcpy(FullPath, FileName); 173 174 // Remove the last part of the path 175 for (Index=strlen(FullPath); Index>0; ) 176 { 177 Index--; 178 if (FullPath[Index] == '/' || FullPath[Index] == '\\') 179 { 180 break; 181 } 182 } 183 FullPath[Index] = '\0'; 184 185 // Concatenate the symbolic link 186 strcat(FullPath, Index == 0 ? "" : "/"); 187 strcat(FullPath, SymLinkPath); 188 } 189 190 TRACE("Full file path = %s\n", FullPath); 191 192 if (TempExt2FileInfo.FileBlockList != NULL) 193 { 194 FrLdrTempFree(TempExt2FileInfo.FileBlockList, TAG_EXT_BLOCK_LIST); 195 } 196 197 return Ext2OpenFile(FullPath); 198 } 199 else 200 { 201 FileHandle = FrLdrTempAlloc(sizeof(EXT2_FILE_INFO), TAG_EXT_FILE); 202 203 if (FileHandle == NULL) 204 { 205 if (TempExt2FileInfo.FileBlockList != NULL) 206 { 207 FrLdrTempFree(TempExt2FileInfo.FileBlockList, TAG_EXT_BLOCK_LIST); 208 } 209 210 return NULL; 211 } 212 213 RtlCopyMemory(FileHandle, &TempExt2FileInfo, sizeof(EXT2_FILE_INFO)); 214 215 return FileHandle; 216 } 217 } 218 219 /* 220 * Ext2LookupFile() 221 * This function searches the file system for the 222 * specified filename and fills in a EXT2_FILE_INFO structure 223 * with info describing the file, etc. returns true 224 * if the file exists or false otherwise 225 */ 226 BOOLEAN Ext2LookupFile(PCSTR FileName, PEXT2_FILE_INFO Ext2FileInfoPointer) 227 { 228 UINT32 i; 229 ULONG NumberOfPathParts; 230 CHAR PathPart[261]; 231 PVOID DirectoryBuffer; 232 ULONG DirectoryInode = EXT2_ROOT_INO; 233 EXT2_INODE InodeData; 234 EXT2_DIR_ENTRY DirectoryEntry; 235 236 TRACE("Ext2LookupFile() FileName = %s\n", FileName); 237 238 RtlZeroMemory(Ext2FileInfoPointer, sizeof(EXT2_FILE_INFO)); 239 240 // 241 // Figure out how many sub-directories we are nested in 242 // 243 NumberOfPathParts = FsGetNumPathParts(FileName); 244 245 // 246 // Loop once for each part 247 // 248 for (i=0; i<NumberOfPathParts; i++) 249 { 250 // 251 // Get first path part 252 // 253 FsGetFirstNameFromPath(PathPart, FileName); 254 255 // 256 // Advance to the next part of the path 257 // 258 for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++) 259 { 260 } 261 FileName++; 262 263 // 264 // Buffer the directory contents 265 // 266 if (!Ext2ReadDirectory(DirectoryInode, &DirectoryBuffer, &InodeData)) 267 { 268 return FALSE; 269 } 270 271 // 272 // Search for file name in directory 273 // 274 if (!Ext2SearchDirectoryBufferForFile(DirectoryBuffer, (ULONG)Ext2GetInodeFileSize(&InodeData), PathPart, &DirectoryEntry)) 275 { 276 FrLdrTempFree(DirectoryBuffer, TAG_EXT_BUFFER); 277 return FALSE; 278 } 279 280 FrLdrTempFree(DirectoryBuffer, TAG_EXT_BUFFER); 281 282 DirectoryInode = DirectoryEntry.inode; 283 } 284 285 if (!Ext2ReadInode(DirectoryInode, &InodeData)) 286 { 287 return FALSE; 288 } 289 290 if (((InodeData.mode & EXT2_S_IFMT) != EXT2_S_IFREG) && 291 ((InodeData.mode & EXT2_S_IFMT) != EXT2_S_IFLNK)) 292 { 293 FileSystemError("Inode is not a regular file or symbolic link."); 294 return FALSE; 295 } 296 297 // Set the drive number 298 Ext2FileInfoPointer->DriveNumber = Ext2DriveNumber; 299 300 // If it's a regular file or a regular symbolic link 301 // then get the block pointer list otherwise it must 302 // be a fast symbolic link which doesn't have a block list 303 if (((InodeData.mode & EXT2_S_IFMT) == EXT2_S_IFREG) || 304 ((InodeData.mode & EXT2_S_IFMT) == EXT2_S_IFLNK && InodeData.size > FAST_SYMLINK_MAX_NAME_SIZE)) 305 { 306 Ext2FileInfoPointer->FileBlockList = Ext2ReadBlockPointerList(&InodeData); 307 308 if (Ext2FileInfoPointer->FileBlockList == NULL) 309 { 310 return FALSE; 311 } 312 } 313 else 314 { 315 Ext2FileInfoPointer->FileBlockList = NULL; 316 } 317 318 Ext2FileInfoPointer->FilePointer = 0; 319 Ext2FileInfoPointer->FileSize = Ext2GetInodeFileSize(&InodeData); 320 RtlCopyMemory(&Ext2FileInfoPointer->Inode, &InodeData, sizeof(EXT2_INODE)); 321 322 return TRUE; 323 } 324 325 BOOLEAN Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry) 326 { 327 ULONG CurrentOffset; 328 PEXT2_DIR_ENTRY CurrentDirectoryEntry; 329 330 TRACE("Ext2SearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = %s\n", DirectoryBuffer, DirectorySize, FileName); 331 332 for (CurrentOffset=0; CurrentOffset<DirectorySize; ) 333 { 334 CurrentDirectoryEntry = (PEXT2_DIR_ENTRY)((ULONG_PTR)DirectoryBuffer + CurrentOffset); 335 336 if (CurrentDirectoryEntry->direntlen == 0) 337 { 338 break; 339 } 340 341 if ((CurrentDirectoryEntry->direntlen + CurrentOffset) > DirectorySize) 342 { 343 FileSystemError("Directory entry extends past end of directory file."); 344 return FALSE; 345 } 346 347 TRACE("Dumping directory entry at offset %d:\n", CurrentOffset); 348 DbgDumpBuffer(DPRINT_FILESYSTEM, CurrentDirectoryEntry, CurrentDirectoryEntry->direntlen); 349 350 if ((_strnicmp(FileName, CurrentDirectoryEntry->name, CurrentDirectoryEntry->namelen) == 0) && 351 (strlen(FileName) == CurrentDirectoryEntry->namelen)) 352 { 353 RtlCopyMemory(DirectoryEntry, CurrentDirectoryEntry, sizeof(EXT2_DIR_ENTRY)); 354 355 TRACE("EXT2 Directory Entry:\n"); 356 TRACE("inode = %d\n", DirectoryEntry->inode); 357 TRACE("direntlen = %d\n", DirectoryEntry->direntlen); 358 TRACE("namelen = %d\n", DirectoryEntry->namelen); 359 TRACE("filetype = %d\n", DirectoryEntry->filetype); 360 TRACE("name = "); 361 for (CurrentOffset=0; CurrentOffset<DirectoryEntry->namelen; CurrentOffset++) 362 { 363 TRACE("%c", DirectoryEntry->name[CurrentOffset]); 364 } 365 TRACE("\n"); 366 367 return TRUE; 368 } 369 370 CurrentOffset += CurrentDirectoryEntry->direntlen; 371 } 372 373 return FALSE; 374 } 375 376 /* 377 * Ext2ReadFileBig() 378 * Reads BytesToRead from open file and 379 * returns the number of bytes read in BytesRead 380 */ 381 BOOLEAN Ext2ReadFileBig(PEXT2_FILE_INFO Ext2FileInfo, ULONGLONG BytesToRead, ULONGLONG* BytesRead, PVOID Buffer) 382 { 383 ULONG BlockNumber; 384 ULONG BlockNumberIndex; 385 ULONG OffsetInBlock; 386 ULONG LengthInBlock; 387 ULONG NumberOfBlocks; 388 389 TRACE("Ext2ReadFileBig() BytesToRead = %d Buffer = 0x%x\n", (ULONG)BytesToRead, Buffer); 390 391 if (BytesRead != NULL) 392 { 393 *BytesRead = 0; 394 } 395 396 // Make sure we have the block pointer list if we need it 397 if (Ext2FileInfo->FileBlockList == NULL) 398 { 399 // Block pointer list is NULL 400 // so this better be a fast symbolic link or else 401 if (((Ext2FileInfo->Inode.mode & EXT2_S_IFMT) != EXT2_S_IFLNK) || 402 (Ext2FileInfo->FileSize > FAST_SYMLINK_MAX_NAME_SIZE)) 403 { 404 FileSystemError("Block pointer list is NULL and file is not a fast symbolic link."); 405 return FALSE; 406 } 407 } 408 409 // 410 // If they are trying to read past the 411 // end of the file then return success 412 // with BytesRead == 0 413 // 414 if (Ext2FileInfo->FilePointer >= Ext2FileInfo->FileSize) 415 { 416 return TRUE; 417 } 418 419 // 420 // If they are trying to read more than there is to read 421 // then adjust the amount to read 422 // 423 if ((Ext2FileInfo->FilePointer + BytesToRead) > Ext2FileInfo->FileSize) 424 { 425 BytesToRead = (Ext2FileInfo->FileSize - Ext2FileInfo->FilePointer); 426 } 427 428 // Check if this is a fast symbolic link 429 // if so then the read is easy 430 if (((Ext2FileInfo->Inode.mode & EXT2_S_IFMT) == EXT2_S_IFLNK) && 431 (Ext2FileInfo->FileSize <= FAST_SYMLINK_MAX_NAME_SIZE)) 432 { 433 TRACE("Reading fast symbolic link data\n"); 434 435 // Copy the data from the link 436 RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Ext2FileInfo->FilePointer + Ext2FileInfo->Inode.symlink), (ULONG)BytesToRead); 437 438 if (BytesRead != NULL) 439 { 440 *BytesRead = BytesToRead; 441 } 442 443 return TRUE; 444 } 445 446 // 447 // Ok, now we have to perform at most 3 calculations 448 // I'll draw you a picture (using nifty ASCII art): 449 // 450 // CurrentFilePointer -+ 451 // | 452 // +----------------+ 453 // | 454 // +-----------+-----------+-----------+-----------+ 455 // | Block 1 | Block 2 | Block 3 | Block 4 | 456 // +-----------+-----------+-----------+-----------+ 457 // | | 458 // +---------------+--------------------+ 459 // | 460 // BytesToRead -------+ 461 // 462 // 1 - The first calculation (and read) will align 463 // the file pointer with the next block. 464 // boundary (if we are supposed to read that much) 465 // 2 - The next calculation (and read) will read 466 // in all the full blocks that the requested 467 // amount of data would cover (in this case 468 // blocks 2 & 3). 469 // 3 - The last calculation (and read) would read 470 // in the remainder of the data requested out of 471 // the last block. 472 // 473 474 // 475 // Only do the first read if we 476 // aren't aligned on a block boundary 477 // 478 if (Ext2FileInfo->FilePointer % Ext2BlockSizeInBytes) 479 { 480 // 481 // Do the math for our first read 482 // 483 BlockNumberIndex = (ULONG)(Ext2FileInfo->FilePointer / Ext2BlockSizeInBytes); 484 BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex]; 485 OffsetInBlock = (Ext2FileInfo->FilePointer % Ext2BlockSizeInBytes); 486 LengthInBlock = (ULONG)((BytesToRead > (Ext2BlockSizeInBytes - OffsetInBlock)) ? (Ext2BlockSizeInBytes - OffsetInBlock) : BytesToRead); 487 488 // 489 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer 490 // 491 if (!Ext2ReadPartialBlock(BlockNumber, OffsetInBlock, LengthInBlock, Buffer)) 492 { 493 return FALSE; 494 } 495 if (BytesRead != NULL) 496 { 497 *BytesRead += LengthInBlock; 498 } 499 BytesToRead -= LengthInBlock; 500 Ext2FileInfo->FilePointer += LengthInBlock; 501 Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInBlock); 502 } 503 504 // 505 // Do the math for our second read (if any data left) 506 // 507 if (BytesToRead > 0) 508 { 509 // 510 // Determine how many full clusters we need to read 511 // 512 NumberOfBlocks = (ULONG)(BytesToRead / Ext2BlockSizeInBytes); 513 514 while (NumberOfBlocks > 0) 515 { 516 BlockNumberIndex = (ULONG)(Ext2FileInfo->FilePointer / Ext2BlockSizeInBytes); 517 BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex]; 518 519 // 520 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer 521 // 522 if (!Ext2ReadBlock(BlockNumber, Buffer)) 523 { 524 return FALSE; 525 } 526 if (BytesRead != NULL) 527 { 528 *BytesRead += Ext2BlockSizeInBytes; 529 } 530 BytesToRead -= Ext2BlockSizeInBytes; 531 Ext2FileInfo->FilePointer += Ext2BlockSizeInBytes; 532 Buffer = (PVOID)((ULONG_PTR)Buffer + Ext2BlockSizeInBytes); 533 NumberOfBlocks--; 534 } 535 } 536 537 // 538 // Do the math for our third read (if any data left) 539 // 540 if (BytesToRead > 0) 541 { 542 BlockNumberIndex = (ULONG)(Ext2FileInfo->FilePointer / Ext2BlockSizeInBytes); 543 BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex]; 544 545 // 546 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer 547 // 548 if (!Ext2ReadPartialBlock(BlockNumber, 0, (ULONG)BytesToRead, Buffer)) 549 { 550 return FALSE; 551 } 552 if (BytesRead != NULL) 553 { 554 *BytesRead += BytesToRead; 555 } 556 Ext2FileInfo->FilePointer += BytesToRead; 557 BytesToRead -= BytesToRead; 558 Buffer = (PVOID)((ULONG_PTR)Buffer + (ULONG_PTR)BytesToRead); 559 } 560 561 return TRUE; 562 } 563 564 BOOLEAN Ext2ReadVolumeSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer) 565 { 566 //GEOMETRY DiskGeometry; 567 //BOOLEAN ReturnValue; 568 //if (!DiskGetDriveGeometry(DriveNumber, &DiskGeometry)) 569 //{ 570 // return FALSE; 571 //} 572 //ReturnValue = MachDiskReadLogicalSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, DiskReadBuffer); 573 //RtlCopyMemory(Buffer, DiskReadBuffer, SectorCount * DiskGeometry.BytesPerSector); 574 //return ReturnValue; 575 576 return CacheReadDiskSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, Buffer); 577 } 578 579 BOOLEAN Ext2ReadSuperBlock(VOID) 580 { 581 582 TRACE("Ext2ReadSuperBlock()\n"); 583 584 // 585 // Free any memory previously allocated 586 // 587 if (Ext2SuperBlock != NULL) 588 { 589 FrLdrTempFree(Ext2SuperBlock, TAG_EXT_SUPER_BLOCK); 590 591 Ext2SuperBlock = NULL; 592 } 593 594 // 595 // Now allocate the memory to hold the super block 596 // 597 Ext2SuperBlock = (PEXT2_SUPER_BLOCK)FrLdrTempAlloc(1024, TAG_EXT_SUPER_BLOCK); 598 599 // 600 // Make sure we got the memory 601 // 602 if (Ext2SuperBlock == NULL) 603 { 604 FileSystemError("Out of memory."); 605 return FALSE; 606 } 607 608 // Now try to read the super block 609 // If this fails then abort 610 if (!MachDiskReadLogicalSectors(Ext2DriveNumber, Ext2VolumeStartSector, 8, DiskReadBuffer)) 611 { 612 return FALSE; 613 } 614 RtlCopyMemory(Ext2SuperBlock, ((PUCHAR)DiskReadBuffer + 1024), 1024); 615 616 TRACE("Dumping super block:\n"); 617 TRACE("total_inodes: %d\n", Ext2SuperBlock->total_inodes); 618 TRACE("total_blocks: %d\n", Ext2SuperBlock->total_blocks); 619 TRACE("reserved_blocks: %d\n", Ext2SuperBlock->reserved_blocks); 620 TRACE("free_blocks: %d\n", Ext2SuperBlock->free_blocks); 621 TRACE("free_inodes: %d\n", Ext2SuperBlock->free_inodes); 622 TRACE("first_data_block: %d\n", Ext2SuperBlock->first_data_block); 623 TRACE("log2_block_size: %d\n", Ext2SuperBlock->log2_block_size); 624 TRACE("log2_fragment_size: %d\n", Ext2SuperBlock->log2_fragment_size); 625 TRACE("blocks_per_group: %d\n", Ext2SuperBlock->blocks_per_group); 626 TRACE("fragments_per_group: %d\n", Ext2SuperBlock->fragments_per_group); 627 TRACE("inodes_per_group: %d\n", Ext2SuperBlock->inodes_per_group); 628 TRACE("mtime: %d\n", Ext2SuperBlock->mtime); 629 TRACE("utime: %d\n", Ext2SuperBlock->utime); 630 TRACE("mnt_count: %d\n", Ext2SuperBlock->mnt_count); 631 TRACE("max_mnt_count: %d\n", Ext2SuperBlock->max_mnt_count); 632 TRACE("magic: 0x%x\n", Ext2SuperBlock->magic); 633 TRACE("fs_state: %d\n", Ext2SuperBlock->fs_state); 634 TRACE("error_handling: %d\n", Ext2SuperBlock->error_handling); 635 TRACE("minor_revision_level: %d\n", Ext2SuperBlock->minor_revision_level); 636 TRACE("lastcheck: %d\n", Ext2SuperBlock->lastcheck); 637 TRACE("checkinterval: %d\n", Ext2SuperBlock->checkinterval); 638 TRACE("creator_os: %d\n", Ext2SuperBlock->creator_os); 639 TRACE("revision_level: %d\n", Ext2SuperBlock->revision_level); 640 TRACE("uid_reserved: %d\n", Ext2SuperBlock->uid_reserved); 641 TRACE("gid_reserved: %d\n", Ext2SuperBlock->gid_reserved); 642 TRACE("first_inode: %d\n", Ext2SuperBlock->first_inode); 643 TRACE("inode_size: %d\n", Ext2SuperBlock->inode_size); 644 TRACE("block_group_number: %d\n", Ext2SuperBlock->block_group_number); 645 TRACE("feature_compatibility: 0x%x\n", Ext2SuperBlock->feature_compatibility); 646 TRACE("feature_incompat: 0x%x\n", Ext2SuperBlock->feature_incompat); 647 TRACE("feature_ro_compat: 0x%x\n", Ext2SuperBlock->feature_ro_compat); 648 TRACE("unique_id = { 0x%x, 0x%x, 0x%x, 0x%x }\n", 649 Ext2SuperBlock->unique_id[0], Ext2SuperBlock->unique_id[1], Ext2SuperBlock->unique_id[2], Ext2SuperBlock->unique_id[3]); 650 TRACE("volume_name = '%.16s'\n", Ext2SuperBlock->volume_name); 651 TRACE("last_mounted_on = '%.64s'\n", Ext2SuperBlock->last_mounted_on); 652 TRACE("compression_info = 0x%x\n", Ext2SuperBlock->compression_info); 653 654 // 655 // Check the super block magic 656 // 657 if (Ext2SuperBlock->magic != EXT2_MAGIC) 658 { 659 FileSystemError("Invalid super block magic (0xef53)"); 660 return FALSE; 661 } 662 663 // 664 // Check the revision level 665 // 666 if (Ext2SuperBlock->revision_level > EXT2_DYNAMIC_REVISION) 667 { 668 FileSystemError("FreeLoader does not understand the revision of this EXT2/EXT3 filesystem.\nPlease update FreeLoader."); 669 return FALSE; 670 } 671 672 // 673 // Check the feature set 674 // Don't need to check the compatible or read-only compatible features 675 // because we only mount the filesystem as read-only 676 // 677 if ((Ext2SuperBlock->revision_level >= EXT2_DYNAMIC_REVISION) && 678 (/*((Ext2SuperBlock->s_feature_compat & ~EXT3_FEATURE_COMPAT_SUPP) != 0) ||*/ 679 /*((Ext2SuperBlock->s_feature_ro_compat & ~EXT3_FEATURE_RO_COMPAT_SUPP) != 0) ||*/ 680 ((Ext2SuperBlock->feature_incompat & ~EXT3_FEATURE_INCOMPAT_SUPP) != 0))) 681 { 682 FileSystemError("FreeLoader does not understand features of this EXT2/EXT3 filesystem.\nPlease update FreeLoader."); 683 return FALSE; 684 } 685 686 // Calculate the group count 687 Ext2GroupCount = (Ext2SuperBlock->total_blocks - Ext2SuperBlock->first_data_block + Ext2SuperBlock->blocks_per_group - 1) / Ext2SuperBlock->blocks_per_group; 688 TRACE("Ext2GroupCount: %d\n", Ext2GroupCount); 689 690 // Calculate the block size 691 Ext2BlockSizeInBytes = 1024 << Ext2SuperBlock->log2_block_size; 692 Ext2BlockSizeInSectors = Ext2BlockSizeInBytes / Ext2DiskGeometry.BytesPerSector; 693 TRACE("Ext2BlockSizeInBytes: %d\n", Ext2BlockSizeInBytes); 694 TRACE("Ext2BlockSizeInSectors: %d\n", Ext2BlockSizeInSectors); 695 696 // Calculate the fragment size 697 if (Ext2SuperBlock->log2_fragment_size >= 0) 698 { 699 Ext2FragmentSizeInBytes = 1024 << Ext2SuperBlock->log2_fragment_size; 700 } 701 else 702 { 703 Ext2FragmentSizeInBytes = 1024 >> -(Ext2SuperBlock->log2_fragment_size); 704 } 705 Ext2FragmentSizeInSectors = Ext2FragmentSizeInBytes / Ext2DiskGeometry.BytesPerSector; 706 TRACE("Ext2FragmentSizeInBytes: %d\n", Ext2FragmentSizeInBytes); 707 TRACE("Ext2FragmentSizeInSectors: %d\n", Ext2FragmentSizeInSectors); 708 709 // Verify that the fragment size and the block size are equal 710 if (Ext2BlockSizeInBytes != Ext2FragmentSizeInBytes) 711 { 712 FileSystemError("The fragment size must be equal to the block size."); 713 return FALSE; 714 } 715 716 // Calculate the number of inodes in one block 717 Ext2InodesPerBlock = Ext2BlockSizeInBytes / EXT2_INODE_SIZE(Ext2SuperBlock); 718 TRACE("Ext2InodesPerBlock: %d\n", Ext2InodesPerBlock); 719 720 // Calculate the number of group descriptors in one block 721 Ext2GroupDescPerBlock = EXT2_DESC_PER_BLOCK(Ext2SuperBlock); 722 TRACE("Ext2GroupDescPerBlock: %d\n", Ext2GroupDescPerBlock); 723 724 return TRUE; 725 } 726 727 BOOLEAN Ext2ReadGroupDescriptors(VOID) 728 { 729 ULONG GroupDescBlockCount; 730 ULONG BlockNumber; 731 PUCHAR CurrentGroupDescBlock; 732 733 TRACE("Ext2ReadGroupDescriptors()\n"); 734 735 // 736 // Free any memory previously allocated 737 // 738 if (Ext2GroupDescriptors != NULL) 739 { 740 FrLdrTempFree(Ext2GroupDescriptors, TAG_EXT_GROUP_DESC); 741 742 Ext2GroupDescriptors = NULL; 743 } 744 745 // 746 // Now allocate the memory to hold the group descriptors 747 // 748 GroupDescBlockCount = ROUND_UP(Ext2GroupCount, Ext2GroupDescPerBlock) / Ext2GroupDescPerBlock; 749 Ext2GroupDescriptors = (PEXT2_GROUP_DESC)FrLdrTempAlloc(GroupDescBlockCount * Ext2BlockSizeInBytes, TAG_EXT_GROUP_DESC); 750 751 // 752 // Make sure we got the memory 753 // 754 if (Ext2GroupDescriptors == NULL) 755 { 756 FileSystemError("Out of memory."); 757 return FALSE; 758 } 759 760 // Now read the group descriptors 761 CurrentGroupDescBlock = (PUCHAR)Ext2GroupDescriptors; 762 BlockNumber = Ext2SuperBlock->first_data_block + 1; 763 764 while (GroupDescBlockCount--) 765 { 766 if (!Ext2ReadBlock(BlockNumber, CurrentGroupDescBlock)) 767 { 768 return FALSE; 769 } 770 771 BlockNumber++; 772 CurrentGroupDescBlock += Ext2BlockSizeInBytes; 773 } 774 775 return TRUE; 776 } 777 778 BOOLEAN Ext2ReadDirectory(ULONG Inode, PVOID* DirectoryBuffer, PEXT2_INODE InodePointer) 779 { 780 EXT2_FILE_INFO DirectoryFileInfo; 781 782 TRACE("Ext2ReadDirectory() Inode = %d\n", Inode); 783 784 // Read the directory inode 785 if (!Ext2ReadInode(Inode, InodePointer)) 786 { 787 return FALSE; 788 } 789 790 // Make sure it is a directory inode 791 if ((InodePointer->mode & EXT2_S_IFMT) != EXT2_S_IFDIR) 792 { 793 FileSystemError("Inode is not a directory."); 794 return FALSE; 795 } 796 797 // Fill in file info struct so we can call Ext2ReadFileBig() 798 RtlZeroMemory(&DirectoryFileInfo, sizeof(EXT2_FILE_INFO)); 799 DirectoryFileInfo.DriveNumber = Ext2DriveNumber; 800 DirectoryFileInfo.FileBlockList = Ext2ReadBlockPointerList(InodePointer); 801 DirectoryFileInfo.FilePointer = 0; 802 DirectoryFileInfo.FileSize = Ext2GetInodeFileSize(InodePointer); 803 804 if (DirectoryFileInfo.FileBlockList == NULL) 805 { 806 return FALSE; 807 } 808 809 // 810 // Now allocate the memory to hold the group descriptors 811 // 812 ASSERT(DirectoryFileInfo.FileSize <= 0xFFFFFFFF); 813 *DirectoryBuffer = (PEXT2_DIR_ENTRY)FrLdrTempAlloc((ULONG)DirectoryFileInfo.FileSize, TAG_EXT_BUFFER); 814 815 // 816 // Make sure we got the memory 817 // 818 if (*DirectoryBuffer == NULL) 819 { 820 FrLdrTempFree(DirectoryFileInfo.FileBlockList, TAG_EXT_BLOCK_LIST); 821 FileSystemError("Out of memory."); 822 return FALSE; 823 } 824 825 // Now read the root directory data 826 if (!Ext2ReadFileBig(&DirectoryFileInfo, DirectoryFileInfo.FileSize, NULL, *DirectoryBuffer)) 827 { 828 FrLdrTempFree(*DirectoryBuffer, TAG_EXT_BUFFER); 829 *DirectoryBuffer = NULL; 830 FrLdrTempFree(DirectoryFileInfo.FileBlockList, TAG_EXT_BLOCK_LIST); 831 return FALSE; 832 } 833 834 FrLdrTempFree(DirectoryFileInfo.FileBlockList, TAG_EXT_BLOCK_LIST); 835 return TRUE; 836 } 837 838 BOOLEAN Ext2ReadBlock(ULONG BlockNumber, PVOID Buffer) 839 { 840 CHAR ErrorString[80]; 841 842 TRACE("Ext2ReadBlock() BlockNumber = %d Buffer = 0x%x\n", BlockNumber, Buffer); 843 844 // Make sure its a valid block 845 if (BlockNumber > Ext2SuperBlock->total_blocks) 846 { 847 sprintf(ErrorString, "Error reading block %d - block out of range.", (int) BlockNumber); 848 FileSystemError(ErrorString); 849 return FALSE; 850 } 851 852 // Check to see if this is a sparse block 853 if (BlockNumber == 0) 854 { 855 TRACE("Block is part of a sparse file. Zeroing input buffer.\n"); 856 857 RtlZeroMemory(Buffer, Ext2BlockSizeInBytes); 858 859 return TRUE; 860 } 861 862 return Ext2ReadVolumeSectors(Ext2DriveNumber, (ULONGLONG)BlockNumber * Ext2BlockSizeInSectors, Ext2BlockSizeInSectors, Buffer); 863 } 864 865 /* 866 * Ext2ReadPartialBlock() 867 * Reads part of a block into memory 868 */ 869 BOOLEAN Ext2ReadPartialBlock(ULONG BlockNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer) 870 { 871 PVOID TempBuffer; 872 873 TRACE("Ext2ReadPartialBlock() BlockNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", BlockNumber, StartingOffset, Length, Buffer); 874 875 TempBuffer = FrLdrTempAlloc(Ext2BlockSizeInBytes, TAG_EXT_BUFFER); 876 877 if (!Ext2ReadBlock(BlockNumber, TempBuffer)) 878 { 879 return FALSE; 880 } 881 882 memcpy(Buffer, ((PUCHAR)TempBuffer + StartingOffset), Length); 883 884 FrLdrTempFree(TempBuffer, TAG_EXT_BUFFER); 885 886 return TRUE; 887 } 888 889 ULONG Ext2GetGroupDescBlockNumber(ULONG Group) 890 { 891 return (((Group * sizeof(EXT2_GROUP_DESC)) / Ext2GroupDescPerBlock) + Ext2SuperBlock->first_data_block + 1); 892 } 893 894 ULONG Ext2GetGroupDescOffsetInBlock(ULONG Group) 895 { 896 return ((Group * sizeof(EXT2_GROUP_DESC)) % Ext2GroupDescPerBlock); 897 } 898 899 ULONG Ext2GetInodeGroupNumber(ULONG Inode) 900 { 901 return ((Inode - 1) / Ext2SuperBlock->inodes_per_group); 902 } 903 904 ULONG Ext2GetInodeBlockNumber(ULONG Inode) 905 { 906 return (((Inode - 1) % Ext2SuperBlock->inodes_per_group) / Ext2InodesPerBlock); 907 } 908 909 ULONG Ext2GetInodeOffsetInBlock(ULONG Inode) 910 { 911 return (((Inode - 1) % Ext2SuperBlock->inodes_per_group) % Ext2InodesPerBlock); 912 } 913 914 BOOLEAN Ext2ReadInode(ULONG Inode, PEXT2_INODE InodeBuffer) 915 { 916 ULONG InodeGroupNumber; 917 ULONG InodeBlockNumber; 918 ULONG InodeOffsetInBlock; 919 CHAR ErrorString[80]; 920 EXT2_GROUP_DESC GroupDescriptor; 921 922 TRACE("Ext2ReadInode() Inode = %d\n", Inode); 923 924 // Make sure its a valid inode 925 if ((Inode < 1) || (Inode > Ext2SuperBlock->total_inodes)) 926 { 927 sprintf(ErrorString, "Error reading inode %ld - inode out of range.", Inode); 928 FileSystemError(ErrorString); 929 return FALSE; 930 } 931 932 // Get inode group & block number and offset in block 933 InodeGroupNumber = Ext2GetInodeGroupNumber(Inode); 934 InodeBlockNumber = Ext2GetInodeBlockNumber(Inode); 935 InodeOffsetInBlock = Ext2GetInodeOffsetInBlock(Inode); 936 TRACE("InodeGroupNumber = %d\n", InodeGroupNumber); 937 TRACE("InodeBlockNumber = %d\n", InodeBlockNumber); 938 TRACE("InodeOffsetInBlock = %d\n", InodeOffsetInBlock); 939 940 // Read the group descriptor 941 if (!Ext2ReadGroupDescriptor(InodeGroupNumber, &GroupDescriptor)) 942 { 943 return FALSE; 944 } 945 946 // Add the start block of the inode table to the inode block number 947 InodeBlockNumber += GroupDescriptor.inode_table_id; 948 TRACE("InodeBlockNumber (after group desc correction) = %d\n", InodeBlockNumber); 949 950 // Read the block 951 if (!Ext2ReadPartialBlock(InodeBlockNumber, 952 (InodeOffsetInBlock * EXT2_INODE_SIZE(Ext2SuperBlock)), 953 sizeof(EXT2_INODE), 954 InodeBuffer)) 955 { 956 return FALSE; 957 } 958 959 TRACE("Dumping inode information:\n"); 960 TRACE("mode = 0x%x\n", InodeBuffer->mode); 961 TRACE("uid = %d\n", InodeBuffer->uid); 962 TRACE("size = %d\n", InodeBuffer->size); 963 TRACE("atime = %d\n", InodeBuffer->atime); 964 TRACE("ctime = %d\n", InodeBuffer->ctime); 965 TRACE("mtime = %d\n", InodeBuffer->mtime); 966 TRACE("dtime = %d\n", InodeBuffer->dtime); 967 TRACE("gid = %d\n", InodeBuffer->gid); 968 TRACE("nlinks = %d\n", InodeBuffer->nlinks); 969 TRACE("blockcnt = %d\n", InodeBuffer->blockcnt); 970 TRACE("flags = 0x%x\n", InodeBuffer->flags); 971 TRACE("osd1 = 0x%x\n", InodeBuffer->osd1); 972 TRACE("dir_blocks = { %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u }\n", 973 InodeBuffer->blocks.dir_blocks[0], InodeBuffer->blocks.dir_blocks[1], InodeBuffer->blocks.dir_blocks[ 2], InodeBuffer->blocks.dir_blocks[ 3], 974 InodeBuffer->blocks.dir_blocks[4], InodeBuffer->blocks.dir_blocks[5], InodeBuffer->blocks.dir_blocks[ 6], InodeBuffer->blocks.dir_blocks[ 7], 975 InodeBuffer->blocks.dir_blocks[8], InodeBuffer->blocks.dir_blocks[9], InodeBuffer->blocks.dir_blocks[10], InodeBuffer->blocks.dir_blocks[11]); 976 TRACE("indir_block = %u\n", InodeBuffer->blocks.indir_block); 977 TRACE("double_indir_block = %u\n", InodeBuffer->blocks.double_indir_block); 978 TRACE("tripple_indir_block = %u\n", InodeBuffer->blocks.tripple_indir_block); 979 TRACE("version = %d\n", InodeBuffer->version); 980 TRACE("acl = %d\n", InodeBuffer->acl); 981 TRACE("dir_acl = %d\n", InodeBuffer->dir_acl); 982 TRACE("fragment_addr = %d\n", InodeBuffer->fragment_addr); 983 TRACE("osd2 = { %d, %d, %d }\n", 984 InodeBuffer->osd2[0], InodeBuffer->osd2[1], InodeBuffer->osd2[2]); 985 986 return TRUE; 987 } 988 989 BOOLEAN Ext2ReadGroupDescriptor(ULONG Group, PEXT2_GROUP_DESC GroupBuffer) 990 { 991 TRACE("Ext2ReadGroupDescriptor()\n"); 992 993 /*if (!Ext2ReadBlock(Ext2GetGroupDescBlockNumber(Group), (PVOID)FILESYSBUFFER)) 994 { 995 return FALSE; 996 } 997 998 RtlCopyMemory(GroupBuffer, (PVOID)(FILESYSBUFFER + Ext2GetGroupDescOffsetInBlock(Group)), sizeof(EXT2_GROUP_DESC));*/ 999 1000 RtlCopyMemory(GroupBuffer, &Ext2GroupDescriptors[Group], sizeof(EXT2_GROUP_DESC)); 1001 1002 TRACE("Dumping group descriptor:\n"); 1003 TRACE("block_id = %d\n", GroupBuffer->block_id); 1004 TRACE("inode_id = %d\n", GroupBuffer->inode_id); 1005 TRACE("inode_table_id = %d\n", GroupBuffer->inode_table_id); 1006 TRACE("free_blocks = %d\n", GroupBuffer->free_blocks); 1007 TRACE("free_inodes = %d\n", GroupBuffer->free_inodes); 1008 TRACE("used_dirs = %d\n", GroupBuffer->used_dirs); 1009 1010 return TRUE; 1011 } 1012 1013 ULONG* Ext2ReadBlockPointerList(PEXT2_INODE Inode) 1014 { 1015 ULONGLONG FileSize; 1016 ULONG BlockCount; 1017 ULONG* BlockList; 1018 ULONG CurrentBlockInList; 1019 ULONG CurrentBlock; 1020 1021 TRACE("Ext2ReadBlockPointerList()\n"); 1022 1023 // Get the number of blocks this file occupies 1024 // I would just use Inode->i_blocks but it 1025 // doesn't seem to be the number of blocks 1026 // the file size corresponds to, but instead 1027 // it is much bigger. 1028 //BlockCount = Inode->i_blocks; 1029 FileSize = Ext2GetInodeFileSize(Inode); 1030 FileSize = ROUND_UP(FileSize, Ext2BlockSizeInBytes); 1031 BlockCount = (ULONG)(FileSize / Ext2BlockSizeInBytes); 1032 1033 // Allocate the memory for the block list 1034 BlockList = FrLdrTempAlloc(BlockCount * sizeof(ULONG), TAG_EXT_BLOCK_LIST); 1035 if (BlockList == NULL) 1036 { 1037 return NULL; 1038 } 1039 1040 RtlZeroMemory(BlockList, BlockCount * sizeof(ULONG)); 1041 1042 // Copy the direct block pointers 1043 for (CurrentBlockInList = CurrentBlock = 0; 1044 CurrentBlockInList < BlockCount && CurrentBlock < INDIRECT_BLOCKS; 1045 CurrentBlock++, CurrentBlockInList++) 1046 { 1047 BlockList[CurrentBlockInList] = Inode->blocks.dir_blocks[CurrentBlock]; 1048 } 1049 1050 // Copy the indirect block pointers 1051 if (CurrentBlockInList < BlockCount) 1052 { 1053 if (!Ext2CopyIndirectBlockPointers(BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.indir_block)) 1054 { 1055 FrLdrTempFree(BlockList, TAG_EXT_BLOCK_LIST); 1056 return NULL; 1057 } 1058 } 1059 1060 // Copy the double indirect block pointers 1061 if (CurrentBlockInList < BlockCount) 1062 { 1063 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.double_indir_block)) 1064 { 1065 FrLdrTempFree(BlockList, TAG_EXT_BLOCK_LIST); 1066 return NULL; 1067 } 1068 } 1069 1070 // Copy the triple indirect block pointers 1071 if (CurrentBlockInList < BlockCount) 1072 { 1073 if (!Ext2CopyTripleIndirectBlockPointers(BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.tripple_indir_block)) 1074 { 1075 FrLdrTempFree(BlockList, TAG_EXT_BLOCK_LIST); 1076 return NULL; 1077 } 1078 } 1079 1080 return BlockList; 1081 } 1082 1083 ULONGLONG Ext2GetInodeFileSize(PEXT2_INODE Inode) 1084 { 1085 if ((Inode->mode & EXT2_S_IFMT) == EXT2_S_IFDIR) 1086 { 1087 return (ULONGLONG)(Inode->size); 1088 } 1089 else 1090 { 1091 return ((ULONGLONG)(Inode->size) | ((ULONGLONG)(Inode->dir_acl) << 32)); 1092 } 1093 } 1094 1095 BOOLEAN Ext2CopyIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock) 1096 { 1097 ULONG* BlockBuffer; 1098 ULONG CurrentBlock; 1099 ULONG BlockPointersPerBlock; 1100 1101 TRACE("Ext2CopyIndirectBlockPointers() BlockCount = %d\n", BlockCount); 1102 1103 BlockPointersPerBlock = Ext2BlockSizeInBytes / sizeof(ULONG); 1104 1105 BlockBuffer = FrLdrTempAlloc(Ext2BlockSizeInBytes, TAG_EXT_BUFFER); 1106 if (!BlockBuffer) 1107 { 1108 return FALSE; 1109 } 1110 1111 if (!Ext2ReadBlock(IndirectBlock, BlockBuffer)) 1112 { 1113 return FALSE; 1114 } 1115 1116 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++) 1117 { 1118 BlockList[(*CurrentBlockInList)] = BlockBuffer[CurrentBlock]; 1119 (*CurrentBlockInList)++; 1120 } 1121 1122 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER); 1123 1124 return TRUE; 1125 } 1126 1127 BOOLEAN Ext2CopyDoubleIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock) 1128 { 1129 ULONG* BlockBuffer; 1130 ULONG CurrentBlock; 1131 ULONG BlockPointersPerBlock; 1132 1133 TRACE("Ext2CopyDoubleIndirectBlockPointers() BlockCount = %d\n", BlockCount); 1134 1135 BlockPointersPerBlock = Ext2BlockSizeInBytes / sizeof(ULONG); 1136 1137 BlockBuffer = (ULONG*)FrLdrTempAlloc(Ext2BlockSizeInBytes, TAG_EXT_BUFFER); 1138 if (BlockBuffer == NULL) 1139 { 1140 return FALSE; 1141 } 1142 1143 if (!Ext2ReadBlock(DoubleIndirectBlock, BlockBuffer)) 1144 { 1145 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER); 1146 return FALSE; 1147 } 1148 1149 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++) 1150 { 1151 if (!Ext2CopyIndirectBlockPointers(BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock])) 1152 { 1153 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER); 1154 return FALSE; 1155 } 1156 } 1157 1158 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER); 1159 return TRUE; 1160 } 1161 1162 BOOLEAN Ext2CopyTripleIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock) 1163 { 1164 ULONG* BlockBuffer; 1165 ULONG CurrentBlock; 1166 ULONG BlockPointersPerBlock; 1167 1168 TRACE("Ext2CopyTripleIndirectBlockPointers() BlockCount = %d\n", BlockCount); 1169 1170 BlockPointersPerBlock = Ext2BlockSizeInBytes / sizeof(ULONG); 1171 1172 BlockBuffer = (ULONG*)FrLdrTempAlloc(Ext2BlockSizeInBytes, TAG_EXT_BUFFER); 1173 if (BlockBuffer == NULL) 1174 { 1175 return FALSE; 1176 } 1177 1178 if (!Ext2ReadBlock(TripleIndirectBlock, BlockBuffer)) 1179 { 1180 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER); 1181 return FALSE; 1182 } 1183 1184 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++) 1185 { 1186 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock])) 1187 { 1188 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER); 1189 return FALSE; 1190 } 1191 } 1192 1193 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER); 1194 return TRUE; 1195 } 1196 1197 ARC_STATUS Ext2Close(ULONG FileId) 1198 { 1199 PEXT2_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); 1200 1201 FrLdrTempFree(FileHandle, TAG_EXT_FILE); 1202 1203 return ESUCCESS; 1204 } 1205 1206 ARC_STATUS Ext2GetFileInformation(ULONG FileId, FILEINFORMATION* Information) 1207 { 1208 PEXT2_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); 1209 1210 RtlZeroMemory(Information, sizeof(FILEINFORMATION)); 1211 Information->EndingAddress.QuadPart = FileHandle->FileSize; 1212 Information->CurrentAddress.QuadPart = FileHandle->FilePointer; 1213 1214 TRACE("Ext2GetFileInformation() FileSize = %d\n", 1215 Information->EndingAddress.LowPart); 1216 TRACE("Ext2GetFileInformation() FilePointer = %d\n", 1217 Information->CurrentAddress.LowPart); 1218 1219 return ESUCCESS; 1220 } 1221 1222 ARC_STATUS Ext2Open(CHAR* Path, OPENMODE OpenMode, ULONG* FileId) 1223 { 1224 PEXT2_FILE_INFO FileHandle; 1225 //ULONG DeviceId; 1226 1227 if (OpenMode != OpenReadOnly) 1228 return EACCES; 1229 1230 //DeviceId = FsGetDeviceId(*FileId); 1231 1232 TRACE("Ext2Open() FileName = %s\n", Path); 1233 1234 // 1235 // Call old open method 1236 // 1237 FileHandle = Ext2OpenFile(Path); 1238 1239 // 1240 // Check for error 1241 // 1242 if (!FileHandle) 1243 return ENOENT; 1244 1245 // 1246 // Success. Remember the handle 1247 // 1248 FsSetDeviceSpecific(*FileId, FileHandle); 1249 return ESUCCESS; 1250 } 1251 1252 ARC_STATUS Ext2Read(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count) 1253 { 1254 PEXT2_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); 1255 ULONGLONG BytesReadBig; 1256 BOOLEAN Success; 1257 1258 // 1259 // Read data 1260 // 1261 Success = Ext2ReadFileBig(FileHandle, N, &BytesReadBig, Buffer); 1262 *Count = (ULONG)BytesReadBig; 1263 1264 // 1265 // Check for success 1266 // 1267 if (Success) 1268 return ESUCCESS; 1269 else 1270 return EIO; 1271 } 1272 1273 ARC_STATUS Ext2Seek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode) 1274 { 1275 PEXT2_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); 1276 1277 TRACE("Ext2Seek() NewFilePointer = %lu\n", Position->LowPart); 1278 1279 if (SeekMode != SeekAbsolute) 1280 return EINVAL; 1281 if (Position->HighPart != 0) 1282 return EINVAL; 1283 if (Position->LowPart >= FileHandle->FileSize) 1284 return EINVAL; 1285 1286 FileHandle->FilePointer = Position->LowPart; 1287 return ESUCCESS; 1288 } 1289 1290 const DEVVTBL Ext2FuncTable = 1291 { 1292 Ext2Close, 1293 Ext2GetFileInformation, 1294 Ext2Open, 1295 Ext2Read, 1296 Ext2Seek, 1297 L"ext2fs", 1298 }; 1299 1300 const DEVVTBL* Ext2Mount(ULONG DeviceId) 1301 { 1302 EXT2_SUPER_BLOCK SuperBlock; 1303 LARGE_INTEGER Position; 1304 ULONG Count; 1305 ARC_STATUS Status; 1306 1307 // 1308 // Read the SuperBlock 1309 // 1310 Position.HighPart = 0; 1311 Position.LowPart = 2 * 512; 1312 Status = ArcSeek(DeviceId, &Position, SeekAbsolute); 1313 if (Status != ESUCCESS) 1314 return NULL; 1315 Status = ArcRead(DeviceId, &SuperBlock, sizeof(SuperBlock), &Count); 1316 if (Status != ESUCCESS || Count != sizeof(SuperBlock)) 1317 return NULL; 1318 1319 // 1320 // Check if SuperBlock is valid. If yes, return Ext2 function table 1321 // 1322 if (SuperBlock.magic == EXT2_MAGIC) 1323 { 1324 // 1325 // Compatibility hack as long as FS is not using underlying device DeviceId 1326 // 1327 UCHAR DriveNumber; 1328 ULONGLONG StartSector; 1329 ULONGLONG SectorCount; 1330 int Type; 1331 if (!DiskGetBootVolume(&DriveNumber, &StartSector, &SectorCount, &Type)) 1332 return NULL; 1333 Ext2OpenVolume(DriveNumber, StartSector, SectorCount); 1334 return &Ext2FuncTable; 1335 } 1336 else 1337 return NULL; 1338 } 1339 1340 #endif 1341 1342