1 /* 2 * COPYRIGHT: See COPYING.ARM in the top level directory 3 * PROJECT: ReactOS UEFI Boot Library 4 * FILE: boot/environ/lib/io/etfs.c 5 * PURPOSE: Boot Library El Torito File System Management Routines 6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <bl.h> 12 #include <cdfs/cd.h> 13 typedef struct _RAW_ET_VD 14 { 15 UCHAR BootIndicator; 16 UCHAR StandardId[5]; 17 UCHAR Version; 18 UCHAR SystemId[32]; 19 UCHAR Reserved[32]; 20 ULONG BootCatalogOffset; 21 UCHAR Padding[1973]; 22 } RAW_ET_VD, *PRAW_ET_VD; 23 24 /* DATA VARIABLES ************************************************************/ 25 26 typedef struct _BL_ETFS_DEVICE 27 { 28 ULONG RootDirOffset; 29 ULONG RootDirSize; 30 ULONG BlockSize; 31 ULONG VolumeSize; 32 BOOLEAN IsIso; 33 PUCHAR MemoryBlock; 34 ULONG Offset; 35 } BL_ETFS_DEVICE, *PBL_ETFS_DEVICE; 36 37 typedef struct _BL_ETFS_FILE 38 { 39 ULONG DiskOffset; 40 ULONG DirOffset; 41 ULONG DirEntOffset; 42 43 BL_FILE_INFORMATION; 44 45 ULONG DeviceId; 46 } BL_ETFS_FILE, *PBL_ETFS_FILE; 47 48 ULONG EtfsDeviceTableEntries; 49 PVOID* EtfsDeviceTable; 50 51 NTSTATUS 52 EtfsOpen ( 53 _In_ PBL_FILE_ENTRY Directory, 54 _In_ PWCHAR FileName, 55 _In_ ULONG Flags, 56 _Out_ PBL_FILE_ENTRY *FileEntry 57 ); 58 59 NTSTATUS 60 EtfsGetInformation ( 61 _In_ PBL_FILE_ENTRY FileEntry, 62 _Out_ PBL_FILE_INFORMATION FileInfo 63 ); 64 65 NTSTATUS 66 EtfsSetInformation ( 67 _In_ PBL_FILE_ENTRY FileEntry, 68 _In_ PBL_FILE_INFORMATION FileInfo 69 ); 70 71 NTSTATUS 72 EtfsRead ( 73 _In_ PBL_FILE_ENTRY FileEntry, 74 _In_ PVOID Buffer, 75 _In_ ULONG Size, 76 _Out_opt_ PULONG BytesReturned 77 ); 78 79 BL_FILE_CALLBACKS EtfsFunctionTable = 80 { 81 EtfsOpen, 82 NULL, 83 EtfsRead, 84 NULL, 85 NULL, 86 EtfsGetInformation, 87 EtfsSetInformation 88 }; 89 90 /* FUNCTIONS *****************************************************************/ 91 92 VOID 93 EtfspGetDirectoryInfo ( 94 _In_ PBL_ETFS_DEVICE EtfsDevice, 95 _In_ PRAW_DIR_REC DirEntry, 96 _Out_ PULONG FileOffset, 97 _Out_ PULONG FileSize, 98 _Out_opt_ PBOOLEAN IsDirectory 99 ) 100 { 101 ULONG SectorOffset; 102 BOOLEAN IsDir; 103 104 *FileOffset = *(PULONG)DirEntry->FileLoc * EtfsDevice->BlockSize; 105 *FileOffset += (DirEntry->XarLen * EtfsDevice->BlockSize); 106 107 SectorOffset = ALIGN_DOWN_BY(*FileOffset, CD_SECTOR_SIZE); 108 109 *FileSize = *(PULONG)DirEntry->DataLen; 110 111 IsDir = DE_FILE_FLAGS(EtfsDevice->IsIso, DirEntry) & ISO_ATTR_DIRECTORY; 112 if (IsDir) 113 { 114 *FileSize += ALIGN_UP_BY(SectorOffset, CD_SECTOR_SIZE) - SectorOffset; 115 } 116 117 if (IsDirectory) 118 { 119 *IsDirectory = IsDir; 120 } 121 } 122 123 USHORT 124 EtfspGetDirentNameLength ( 125 _In_ PRAW_DIR_REC DirEntry 126 ) 127 { 128 USHORT Length, RealLength; 129 PUCHAR Pos; 130 131 RealLength = Length = DirEntry->FileIdLen; 132 for (Pos = DirEntry->FileId + Length - 1; Length; --Pos) 133 { 134 --Length; 135 136 if (*Pos == ';') 137 { 138 RealLength = Length; 139 break; 140 } 141 } 142 143 Length = RealLength; 144 for (Pos = DirEntry->FileId + Length - 1; Length; --Pos) 145 { 146 --Length; 147 148 if (*Pos != '.') 149 { 150 break; 151 } 152 153 RealLength = Length; 154 } 155 156 return RealLength; 157 } 158 159 LONG 160 EtfspCompareNames ( 161 __in PSTRING Name1, 162 __in PUNICODE_STRING Name2 163 ) 164 { 165 ULONG i, l1, l2, l; 166 167 l1 = Name1->Length; 168 l2 = Name2->Length / sizeof(WCHAR); 169 l = min(l1, l2); 170 171 for (i = 0; i < l; i++) 172 { 173 if (toupper(Name1->Buffer[i]) != toupper(Name2->Buffer[i])) 174 { 175 return toupper(Name1->Buffer[i]) - toupper(Name2->Buffer[i]); 176 } 177 } 178 179 if (l2 <= l1) 180 { 181 return l2 < l1; 182 } 183 else 184 { 185 return -1; 186 } 187 } 188 189 BOOLEAN 190 EtfspFileMatch ( 191 _In_ PRAW_DIR_REC DirEntry, 192 _In_ PUNICODE_STRING FileName 193 ) 194 { 195 BOOLEAN Match; 196 USHORT Length; 197 ANSI_STRING DirName; 198 199 if ((DirEntry->FileIdLen != 1) || 200 ((DirEntry->FileId[0] != 0) && (DirEntry->FileId[0] != 1))) 201 { 202 Length = EtfspGetDirentNameLength(DirEntry); 203 DirName.Length = Length; 204 DirName.MaximumLength = Length; 205 DirName.Buffer = (PCHAR)DirEntry->FileId; 206 207 Match = EtfspCompareNames(&DirName, FileName); 208 } 209 else 210 { 211 Match = -1; 212 } 213 return Match; 214 } 215 216 NTSTATUS 217 EtfspGetDirent ( 218 _In_ PBL_FILE_ENTRY DirectoryEntry, 219 _Out_ PRAW_DIR_REC *DirEntry, 220 _Inout_ PULONG DirentOffset 221 ) 222 { 223 PBL_ETFS_FILE EtfsFile; 224 ULONG FileOffset, DirectoryOffset, AlignedOffset, RemainderOffset; 225 ULONG DeviceId, ReadSize, DirLen; 226 PBL_ETFS_DEVICE EtfsDevice; 227 BOOLEAN NeedRead, IsMulti; 228 NTSTATUS result; 229 PRAW_DIR_REC DirEnt; 230 PUCHAR MemoryBlock; 231 232 EtfsFile = DirectoryEntry->FsSpecificData; 233 DeviceId = EtfsFile->DeviceId; 234 FileOffset = EtfsFile->DiskOffset; 235 EtfsDevice = EtfsDeviceTable[DeviceId]; 236 237 DirectoryOffset = *DirentOffset; 238 MemoryBlock = EtfsDevice->MemoryBlock; 239 240 IsMulti = 0; 241 242 AlignedOffset = (FileOffset + *DirentOffset) & ~CD_SECTOR_SIZE; 243 RemainderOffset = *DirentOffset + FileOffset - AlignedOffset; 244 245 ReadSize = 2048 - RemainderOffset; 246 NeedRead = AlignedOffset == EtfsDevice->Offset ? 0 : 1; 247 248 ReadAgain: 249 if (DirectoryOffset >= EtfsFile->Size) 250 { 251 return STATUS_NO_SUCH_FILE; 252 } 253 254 while (ReadSize < MIN_DIR_REC_SIZE) 255 { 256 DirectoryOffset += ReadSize; 257 AlignedOffset += 2048; 258 ReadSize = 2048; 259 RemainderOffset = 0; 260 NeedRead = 1; 261 if (DirectoryOffset >= EtfsFile->Size) 262 { 263 return STATUS_NO_SUCH_FILE; 264 } 265 } 266 267 if (NeedRead) 268 { 269 result = BlDeviceReadAtOffset(DirectoryEntry->DeviceId, 270 CD_SECTOR_SIZE, 271 AlignedOffset, 272 MemoryBlock, 273 NULL); 274 if (!NT_SUCCESS(result)) 275 { 276 EfiPrintf(L"Device read failed %lx\r\n", result); 277 return result; 278 } 279 280 NeedRead = FALSE; 281 EtfsDevice->Offset = AlignedOffset; 282 } 283 284 if (!*(MemoryBlock + RemainderOffset)) 285 { 286 AlignedOffset += 2048; 287 NeedRead = TRUE; 288 289 RemainderOffset = 0; 290 DirectoryOffset += ReadSize; 291 ReadSize = 2048; 292 goto ReadAgain; 293 } 294 295 DirEnt = (PRAW_DIR_REC)(MemoryBlock + RemainderOffset); 296 DirLen = DirEnt->DirLen; 297 if (DirLen > ReadSize) 298 { 299 EfiPrintf(L"Dir won't fit %lx %lx\r\n", DirLen, ReadSize); 300 return STATUS_NO_SUCH_FILE; 301 } 302 303 if (IsMulti) 304 { 305 if (!(DE_FILE_FLAGS(EtfsDevice->IsIso, DirEnt) & ISO_ATTR_MULTI)) 306 { 307 IsMulti = TRUE; 308 } 309 } 310 else if (DE_FILE_FLAGS(EtfsDevice->IsIso, DirEnt) & ISO_ATTR_MULTI) 311 { 312 IsMulti = TRUE; 313 } 314 else 315 { 316 if ((DirEnt->FileIdLen != 1) || 317 ((DirEnt->FileId[0] != 0) && (DirEnt->FileId[0] != 1))) 318 { 319 goto Quickie; 320 } 321 } 322 323 RemainderOffset += DirLen; 324 DirectoryOffset += DirLen; 325 ReadSize -= DirLen; 326 goto ReadAgain; 327 328 Quickie: 329 *DirEntry = DirEnt; 330 *DirentOffset = DirectoryOffset; 331 return STATUS_SUCCESS; 332 } 333 334 NTSTATUS 335 EtfspSearchForDirent ( 336 _In_ PBL_FILE_ENTRY DirectoryEntry, 337 _In_ PWCHAR FileName, 338 _Out_ PRAW_DIR_REC *DirEntry, 339 _Out_ PULONG DirentOffset 340 ) 341 { 342 UNICODE_STRING Name; 343 ULONG NextOffset; 344 PRAW_DIR_REC DirEnt; 345 NTSTATUS Status; 346 347 RtlInitUnicodeString(&Name, FileName); 348 for (NextOffset = *DirentOffset; 349 ; 350 NextOffset = NextOffset + DirEnt->DirLen) 351 { 352 Status = EtfspGetDirent(DirectoryEntry, &DirEnt, &NextOffset); 353 if (!NT_SUCCESS(Status)) 354 { 355 return STATUS_NO_SUCH_FILE; 356 } 357 358 if (!EtfspFileMatch(DirEnt, &Name)) 359 { 360 break; 361 } 362 } 363 364 *DirEntry = DirEnt; 365 *DirentOffset = NextOffset; 366 return 0; 367 } 368 369 NTSTATUS 370 EtfspCachedSearchForDirent ( 371 _In_ PBL_FILE_ENTRY DirectoryEntry, 372 _In_ PWCHAR FileName, 373 _Out_ PRAW_DIR_REC *DirEntry, 374 _Out_ PULONG DirOffset, 375 _In_ BOOLEAN KeepOffset 376 ) 377 { 378 PBL_ETFS_FILE EtfsFile; 379 PBL_ETFS_DEVICE EtfsDevice; 380 NTSTATUS Status; 381 ULONG DirentOffset; 382 PRAW_DIR_REC Dirent; 383 UNICODE_STRING Name; 384 385 EtfsFile = DirectoryEntry->FsSpecificData; 386 EtfsDevice = EtfsDeviceTable[EtfsFile->DeviceId]; 387 RtlInitUnicodeString(&Name, FileName); 388 DirentOffset = EtfsFile->DirEntOffset; 389 390 if ((KeepOffset) || 391 (ALIGN_DOWN_BY((DirentOffset + EtfsFile->DiskOffset), CD_SECTOR_SIZE) == 392 EtfsDevice->Offset)) 393 { 394 Status = EtfspGetDirent(DirectoryEntry, &Dirent, &DirentOffset); 395 if (NT_SUCCESS(Status)) 396 { 397 if (!EtfspFileMatch(Dirent, &Name)) 398 { 399 *DirEntry = Dirent; 400 *DirOffset = DirentOffset; 401 return STATUS_SUCCESS; 402 } 403 } 404 else 405 { 406 DirentOffset = 0; 407 } 408 } 409 else 410 { 411 DirentOffset = 0; 412 } 413 414 Status = EtfspSearchForDirent(DirectoryEntry, 415 FileName, 416 DirEntry, 417 &DirentOffset); 418 if (!(NT_SUCCESS(Status)) && (DirentOffset)) 419 { 420 DirentOffset = 0; 421 Status = EtfspSearchForDirent(DirectoryEntry, 422 FileName, 423 DirEntry, 424 &DirentOffset); 425 } 426 427 if (NT_SUCCESS(Status)) 428 { 429 *DirOffset = DirentOffset; 430 } 431 432 return Status; 433 } 434 435 NTSTATUS 436 EtfsRead ( 437 _In_ PBL_FILE_ENTRY FileEntry, 438 _In_ PVOID Buffer, 439 _In_ ULONG Size, 440 _Out_opt_ PULONG BytesReturned 441 ) 442 { 443 ULONG BytesRead; 444 PBL_ETFS_FILE EtfsFile; 445 NTSTATUS Status; 446 447 /* Assume failure for now */ 448 BytesRead = 0; 449 450 /* Make sure that the read is within the file's boundaries */ 451 EtfsFile = FileEntry->FsSpecificData; 452 if ((Size + EtfsFile->Offset) > EtfsFile->Size) 453 { 454 /* Bail out otherwise */ 455 Status = STATUS_INVALID_PARAMETER; 456 } 457 else 458 { 459 /* Read the offset that matches this file's offset, on the disk */ 460 Status = BlDeviceReadAtOffset(FileEntry->DeviceId, 461 Size, 462 EtfsFile->Offset + EtfsFile->DiskOffset, 463 Buffer, 464 &BytesRead); 465 if (NT_SUCCESS(Status)) 466 { 467 /* Update the file offset and return the size as having been read */ 468 EtfsFile->Offset += Size; 469 BytesRead = Size; 470 } 471 } 472 473 /* Check if caller wanted to know how many bytes were read */ 474 if (BytesReturned) 475 { 476 /* Return the value */ 477 *BytesReturned = BytesRead; 478 } 479 480 /* All done */ 481 return Status; 482 } 483 484 NTSTATUS 485 EtfsSetInformation ( 486 _In_ PBL_FILE_ENTRY FileEntry, 487 _In_ PBL_FILE_INFORMATION FileInfo 488 ) 489 { 490 PBL_ETFS_FILE EtfsFile; 491 BL_FILE_INFORMATION LocalFileInfo; 492 493 /* Get the underlying ETFS file data structure */ 494 EtfsFile = (PBL_ETFS_FILE)FileEntry->FsSpecificData; 495 496 /* Make a copy of the incoming attributes, but ignore the new offset */ 497 LocalFileInfo = *FileInfo; 498 LocalFileInfo.Offset = EtfsFile->Offset; 499 500 /* Check if these match exactly the current file */ 501 if (!RtlEqualMemory(&LocalFileInfo, &EtfsFile->Size, sizeof(*FileInfo))) 502 { 503 /* Nope -- which means caller is trying to change an immutable */ 504 EfiPrintf(L"Incorrect information change\r\n"); 505 return STATUS_INVALID_PARAMETER; 506 } 507 508 /* Is the offset past the end of the file? */ 509 if (FileInfo->Offset >= EtfsFile->Size) 510 { 511 /* Don't allow EOF */ 512 EfiPrintf(L"Offset too large: %lx vs %lx\r\n", FileInfo->Offset, EtfsFile->Size); 513 return STATUS_INVALID_PARAMETER; 514 } 515 516 /* Update the offset */ 517 EtfsFile->Offset = FileInfo->Offset; 518 return STATUS_SUCCESS; 519 } 520 521 NTSTATUS 522 EtfsGetInformation ( 523 _In_ PBL_FILE_ENTRY FileEntry, 524 _Out_ PBL_FILE_INFORMATION FileInfo 525 ) 526 { 527 PBL_ETFS_FILE EtfsFile; 528 529 /* Get the underlying ETFS file data structure */ 530 EtfsFile = (PBL_ETFS_FILE)FileEntry->FsSpecificData; 531 532 /* Copy the cached information structure within it */ 533 RtlCopyMemory(FileInfo, &EtfsFile->Size, sizeof(*FileInfo)); 534 return STATUS_SUCCESS; 535 } 536 537 NTSTATUS 538 EtfsOpen ( 539 _In_ PBL_FILE_ENTRY Directory, 540 _In_ PWCHAR FileName, 541 _In_ ULONG Flags, 542 _Out_ PBL_FILE_ENTRY *FileEntry 543 ) 544 { 545 PBL_ETFS_DEVICE EtfsDevice; 546 NTSTATUS Status; 547 PBL_FILE_ENTRY NewFile; 548 PWCHAR FilePath, FormatString; 549 PBL_ETFS_FILE EtfsFile; 550 ULONG DeviceId, FileSize, DirOffset, FileOffset; 551 SIZE_T Size; 552 PRAW_DIR_REC DirEntry; 553 BOOLEAN IsDirectory; 554 555 EtfsFile = Directory->FsSpecificData; 556 DeviceId = EtfsFile->DeviceId; 557 EtfsDevice = EtfsDeviceTable[DeviceId]; 558 559 /* Find the given file (or directory) in the given directory */ 560 Status = EtfspCachedSearchForDirent(Directory, 561 FileName, 562 &DirEntry, 563 &DirOffset, 564 FALSE); 565 if (!NT_SUCCESS(Status)) 566 { 567 return Status; 568 } 569 570 /* Find out information about the file (or directory) we found */ 571 EtfspGetDirectoryInfo(EtfsDevice, 572 DirEntry, 573 &FileOffset, 574 &FileSize, 575 &IsDirectory); 576 577 /* Allocate a file entry */ 578 NewFile = BlMmAllocateHeap(sizeof(*NewFile)); 579 if (!NewFile) 580 { 581 return STATUS_NO_MEMORY; 582 } 583 584 /* Zero it out */ 585 RtlZeroMemory(NewFile, sizeof(*NewFile)); 586 587 /* Figure out the size of the path and filename plus a slash and NUL */ 588 Size = wcslen(Directory->FilePath) + wcslen(FileName) + 2; 589 FilePath = BlMmAllocateHeap(Size * sizeof(WCHAR)); 590 if (!FilePath) 591 { 592 Status = STATUS_NO_MEMORY; 593 goto Quickie; 594 } 595 596 /* Allocate an ETFS file entry */ 597 EtfsFile = (PBL_ETFS_FILE)BlMmAllocateHeap(sizeof(*EtfsFile)); 598 if (!EtfsFile) 599 { 600 Status = STATUS_NO_MEMORY; 601 goto Quickie; 602 } 603 604 /* Zero it out */ 605 RtlZeroMemory(EtfsFile, sizeof(*EtfsFile)); 606 607 /* Capture the device ID of the directory */ 608 NewFile->DeviceId = Directory->DeviceId; 609 610 /* Check if this is the root or a filename\directory under */ 611 FormatString = L"%ls%ls"; 612 if (Directory->FilePath[1]) 613 { 614 FormatString = L"%ls\\%ls"; 615 } 616 617 /* Combine the paths, and save the final path in the file entry */ 618 _snwprintf(FilePath, Size, FormatString, Directory->FilePath, FileName); 619 NewFile->FilePath = FilePath; 620 621 /* Copy the ETFS function callbacks into the file netry */ 622 RtlCopyMemory(&NewFile->Callbacks, 623 &EtfsFunctionTable, 624 sizeof(NewFile->Callbacks)); 625 626 /* Fill out the rest of the details */ 627 EtfsFile->DiskOffset = FileOffset; 628 EtfsFile->DirOffset = DirOffset; 629 EtfsFile->Size = FileSize; 630 EtfsFile->DeviceId = DeviceId; 631 632 /* Check if this is a directory */ 633 if (IsDirectory) 634 { 635 EtfsFile->Flags |= BL_ETFS_FILE_ENTRY_DIRECTORY; 636 NewFile->Flags |= BL_FILE_ENTRY_DIRECTORY; 637 } 638 639 /* Write down the name of the filesystem */ 640 EtfsFile->FsName = L"cdfs"; 641 642 /* All done, return the file entry, and save the ETFS side */ 643 NewFile->FsSpecificData = EtfsFile; 644 *FileEntry = NewFile; 645 return Status; 646 647 Quickie: 648 /* Failure path -- free the file path if we had one */ 649 if (NewFile->FilePath) 650 { 651 BlMmFreeHeap(NewFile->FilePath); 652 } 653 654 /* Free the ETFS file entry if we had one */ 655 if (NewFile->FsSpecificData) 656 { 657 BlMmFreeHeap(NewFile->FsSpecificData); 658 } 659 660 /* Free the file entry itself, and return the error code */ 661 BlMmFreeHeap(NewFile); 662 return Status; 663 } 664 665 NTSTATUS 666 EtfspCheckCdfs ( 667 _In_ PBL_ETFS_DEVICE EtfsDevice, 668 _In_ ULONG DeviceId, 669 _Out_ PRAW_ISO_VD *VolumeDescriptor, 670 _Out_ PBOOLEAN VolumeIsIso 671 ) 672 { 673 EfiPrintf(L"Raw Cdfs not implemented\r\n"); 674 return STATUS_NOT_IMPLEMENTED; 675 } 676 677 NTSTATUS 678 EtfspCheckEtfs ( 679 _In_ PBL_ETFS_DEVICE EtfsDevice, 680 _In_ ULONG DeviceId, 681 _Out_ PRAW_ISO_VD *VolumeDescriptor, 682 _Out_ PBOOLEAN VolumeIsIso 683 ) 684 { 685 PRAW_ISO_VD IsoVd; 686 PRAW_ET_VD EtVd; 687 NTSTATUS Status; 688 BOOLEAN IsIso; 689 BL_DEVICE_INFORMATION DeviceInformation; 690 ULONG Unknown, BytesRead; 691 ANSI_STRING CompareString, String; 692 693 /* Save our static buffer pointer */ 694 IsoVd = (PRAW_ISO_VD)EtfsDevice->MemoryBlock; 695 EtVd = (PRAW_ET_VD)IsoVd; 696 697 /* First, read the El Torito Volume Descriptor */ 698 BlDeviceGetInformation(DeviceId, &DeviceInformation); 699 Unknown = DeviceInformation.BlockDeviceInfo.Unknown; 700 DeviceInformation.BlockDeviceInfo.Unknown |= 1; 701 BlDeviceSetInformation(DeviceId, &DeviceInformation); 702 Status = BlDeviceReadAtOffset(DeviceId, 703 CD_SECTOR_SIZE, 704 (FIRST_VD_SECTOR + 1) * CD_SECTOR_SIZE, 705 EtfsDevice->MemoryBlock, 706 &BytesRead); 707 DeviceInformation.BlockDeviceInfo.Unknown = Unknown; 708 BlDeviceSetInformation(DeviceId, &DeviceInformation); 709 if (!NT_SUCCESS(Status)) 710 { 711 EfiPrintf(L" read failed\r\n"); 712 return Status; 713 } 714 715 /* Remember that's where we last read */ 716 EtfsDevice->Offset = (FIRST_VD_SECTOR + 1) * CD_SECTOR_SIZE; 717 718 /* Check if it's EL TORITO! */ 719 RtlInitString(&String, "EL TORITO SPECIFICATION"); 720 CompareString.Buffer = (PCHAR)EtVd->SystemId; 721 CompareString.Length = 23; 722 CompareString.MaximumLength = 23; 723 if (!RtlEqualString(&CompareString, &String, TRUE)) 724 { 725 return STATUS_UNSUCCESSFUL; 726 } 727 728 /* Check the version and boot indicator */ 729 if ((EtVd->Version != 1) || (EtVd->BootIndicator)) 730 { 731 return STATUS_UNSUCCESSFUL; 732 } 733 734 /* Check if it has the CD0001 identifier */ 735 RtlInitString(&String, ISO_VOL_ID); 736 CompareString.Buffer = (PCHAR)EtVd->StandardId; 737 CompareString.Length = 5; 738 CompareString.MaximumLength = 5; 739 if (!RtlEqualString(&CompareString, &String, TRUE)) 740 { 741 return STATUS_UNSUCCESSFUL; 742 } 743 744 /* Step two, we now want to read the ISO Volume Descriptor */ 745 DeviceInformation.BlockDeviceInfo.Unknown |= 1u; 746 BlDeviceSetInformation(DeviceId, &DeviceInformation); 747 Status = BlDeviceReadAtOffset(DeviceId, 748 CD_SECTOR_SIZE, 749 FIRST_VD_SECTOR * CD_SECTOR_SIZE, 750 EtfsDevice->MemoryBlock, 751 &BytesRead); 752 DeviceInformation.BlockDeviceInfo.Unknown = Unknown; 753 BlDeviceSetInformation(DeviceId, &DeviceInformation); 754 if (!NT_SUCCESS(Status)) 755 { 756 return Status; 757 } 758 759 /* Remember where we left off */ 760 EtfsDevice->Offset = FIRST_VD_SECTOR * CD_SECTOR_SIZE; 761 762 /* This should also say CD0001 */ 763 CompareString.Buffer = (PCHAR)IsoVd->StandardId; 764 CompareString.Length = 5; 765 CompareString.MaximumLength = 5; 766 IsIso = RtlEqualString(&CompareString, &String, TRUE); 767 if (!IsIso) 768 { 769 return STATUS_UNSUCCESSFUL; 770 } 771 772 /* And should be a version we support */ 773 if ((IsoVd->Version != VERSION_1) || (IsoVd->DescType != VD_PRIMARY)) 774 { 775 return STATUS_UNSUCCESSFUL; 776 } 777 778 /* Return back to the caller */ 779 *VolumeDescriptor = IsoVd; 780 *VolumeIsIso = IsIso; 781 return STATUS_SUCCESS; 782 } 783 784 NTSTATUS 785 EtfspDeviceContextDestroy ( 786 _In_ PBL_ETFS_DEVICE EtfsDevice 787 ) 788 { 789 if (EtfsDevice->MemoryBlock) 790 { 791 BlMmFreeHeap(EtfsDevice->MemoryBlock); 792 } 793 794 BlMmFreeHeap(EtfsDevice); 795 796 return STATUS_SUCCESS; 797 } 798 799 NTSTATUS 800 EtfspCreateContext ( 801 _In_ ULONG DeviceId, 802 _Out_ PBL_ETFS_DEVICE *EtfsDevice 803 ) 804 { 805 PBL_ETFS_DEVICE NewContext; 806 PVOID MemoryBlock; 807 NTSTATUS Status; 808 BOOLEAN IsIso; 809 PRAW_ISO_VD RawVd; 810 811 NewContext = (PBL_ETFS_DEVICE)BlMmAllocateHeap(sizeof(*NewContext)); 812 if (!NewContext) 813 { 814 return STATUS_NO_MEMORY; 815 } 816 RtlZeroMemory(NewContext, sizeof(*NewContext)); 817 818 MemoryBlock = BlMmAllocateHeap(CD_SECTOR_SIZE); 819 NewContext->MemoryBlock = MemoryBlock; 820 if (!MemoryBlock) 821 { 822 Status = STATUS_NO_MEMORY; 823 goto Quickie; 824 } 825 826 Status = EtfspCheckEtfs(NewContext, DeviceId, &RawVd, &IsIso); 827 if (!NT_SUCCESS(Status)) 828 { 829 EfiPrintf(L"Drive not EDFS. Checking for CDFS: %lx\r\n"); 830 Status = EtfspCheckCdfs(NewContext, DeviceId, &RawVd, &IsIso); 831 } 832 833 if (!NT_SUCCESS(Status)) 834 { 835 EfiPrintf(L"Drive not CDFS. Failing: %lx\r\n"); 836 goto Quickie; 837 } 838 839 NewContext->IsIso = IsIso; 840 NewContext->BlockSize = RVD_LB_SIZE(RawVd, IsIso); 841 NewContext->VolumeSize = RVD_VOL_SIZE(RawVd, IsIso); 842 843 EtfspGetDirectoryInfo(NewContext, 844 (PRAW_DIR_REC)RVD_ROOT_DE(RawVd, IsIso), 845 &NewContext->RootDirOffset, 846 &NewContext->RootDirSize, 847 0); 848 Status = STATUS_SUCCESS; 849 850 Quickie: 851 if (!NT_SUCCESS(Status)) 852 { 853 EtfspDeviceContextDestroy(NewContext); 854 NewContext = NULL; 855 } 856 857 *EtfsDevice = NewContext; 858 return Status; 859 } 860 861 NTSTATUS 862 EtfspDeviceTableDestroyEntry ( 863 _In_ PBL_ETFS_DEVICE EtfsDevice, 864 _In_ ULONG Index 865 ) 866 { 867 EtfspDeviceContextDestroy(EtfsDevice); 868 EtfsDeviceTable[Index] = NULL; 869 870 return STATUS_SUCCESS; 871 } 872 873 NTSTATUS 874 EtfsMount ( 875 _In_ ULONG DeviceId, 876 _In_ ULONG Unknown, 877 _Out_ PBL_FILE_ENTRY* FileEntry 878 ) 879 { 880 PBL_ETFS_DEVICE EtfsDevice = NULL; 881 PBL_FILE_ENTRY RootEntry; 882 NTSTATUS Status; 883 PBL_ETFS_FILE EtfsFile; 884 885 EfiPrintf(L"Trying to mount as ETFS...\r\n"); 886 887 Status = EtfspCreateContext(DeviceId, &EtfsDevice); 888 if (!NT_SUCCESS(Status)) 889 { 890 EfiPrintf(L"ETFS context failed: %lx\r\n"); 891 return Status; 892 } 893 894 Status = BlTblSetEntry(&EtfsDeviceTable, 895 &EtfsDeviceTableEntries, 896 EtfsDevice, 897 &DeviceId, 898 TblDoNotPurgeEntry); 899 if (!NT_SUCCESS(Status)) 900 { 901 EtfspDeviceContextDestroy(EtfsDevice); 902 return Status; 903 } 904 905 RootEntry = BlMmAllocateHeap(sizeof(*RootEntry)); 906 if (!RootEntry) 907 { 908 Status = STATUS_NO_MEMORY; 909 goto Quickie; 910 } 911 912 RtlZeroMemory(RootEntry, sizeof(*RootEntry)); 913 914 RootEntry->FilePath = BlMmAllocateHeap(4); 915 if (!RootEntry->FilePath) 916 { 917 Status = STATUS_NO_MEMORY; 918 goto Quickie; 919 } 920 921 wcsncpy(RootEntry->FilePath, L"\\", 1); 922 923 RootEntry->DeviceId = DeviceId; 924 RtlCopyMemory(&RootEntry->Callbacks, 925 &EtfsFunctionTable, 926 sizeof(RootEntry->Callbacks)); 927 928 EtfsFile = (PBL_ETFS_FILE)BlMmAllocateHeap(sizeof(*EtfsFile)); 929 if (!EtfsFile) 930 { 931 Status = STATUS_NO_MEMORY; 932 goto Quickie; 933 } 934 935 RootEntry->Flags |= 0x10000; 936 937 RtlZeroMemory(EtfsFile, sizeof(*EtfsFile)); 938 RootEntry->FsSpecificData = EtfsFile; 939 EtfsFile->DeviceId = DeviceId; 940 EtfsFile->Flags |= 1; 941 EtfsFile->DiskOffset = EtfsDevice->RootDirOffset; 942 EtfsFile->DirOffset = 0; 943 EtfsFile->Size = EtfsDevice->RootDirSize; 944 EtfsFile->FsName = L"cdfs"; 945 *FileEntry = RootEntry; 946 947 return STATUS_SUCCESS; 948 949 Quickie: 950 if (RootEntry->FilePath) 951 { 952 BlMmFreeHeap(RootEntry->FilePath); 953 } 954 if (RootEntry->FsSpecificData) 955 { 956 BlMmFreeHeap(RootEntry->FsSpecificData); 957 } 958 if (RootEntry) 959 { 960 BlMmFreeHeap(RootEntry); 961 } 962 963 EtfspDeviceTableDestroyEntry(EtfsDevice, DeviceId); 964 965 return Status; 966 } 967 968 NTSTATUS 969 EtfsInitialize ( 970 VOID 971 ) 972 { 973 NTSTATUS Status; 974 975 /* Allocate the device table with 2 entries*/ 976 EtfsDeviceTableEntries = 2; 977 EtfsDeviceTable = BlMmAllocateHeap(sizeof(PBL_FILE_ENTRY) * 978 EtfsDeviceTableEntries); 979 if (EtfsDeviceTable) 980 { 981 /* Zero it out */ 982 RtlZeroMemory(EtfsDeviceTable, 983 sizeof(PBL_FILE_ENTRY) * EtfsDeviceTableEntries); 984 Status = STATUS_SUCCESS; 985 } 986 else 987 { 988 /* No memory, fail */ 989 Status = STATUS_NO_MEMORY; 990 } 991 992 /* Return back to caller */ 993 return Status; 994 } 995 996