1 /* 2 * COPYRIGHT: See COPYING.ARM in the top level directory 3 * PROJECT: ReactOS UEFI Boot Library 4 * FILE: boot/environ/lib/io/file.c 5 * PURPOSE: Boot Library File Management Routines 6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "bl.h" 12 13 /* DATA VARIABLES ************************************************************/ 14 15 PVOID* FileTable; 16 ULONG FileEntries; 17 18 LIST_ENTRY RegisteredFileSystems; 19 BL_FILE_SYSTEM_REGISTRATION_TABLE FatRegisterFunctionTable = 20 { 21 FatInitialize, 22 NULL, 23 FatMount, 24 NULL 25 }; 26 BL_FILE_SYSTEM_REGISTRATION_TABLE EtfsRegisterFunctionTable = 27 { 28 EtfsInitialize, 29 NULL, 30 EtfsMount, 31 NULL 32 }; 33 34 extern ULONG DmTableEntries; 35 extern PVOID* DmDeviceTable; 36 37 /* FUNCTIONS *****************************************************************/ 38 39 PWCHAR 40 FileIoCopyParentDirectoryPath ( 41 _In_ PWCHAR FilePath 42 ) 43 { 44 SIZE_T PathSize, PathSizeWithNull; 45 PWCHAR Backslash, ParentCopy; 46 47 PathSize = wcslen(FilePath) * sizeof(WCHAR); 48 49 PathSizeWithNull = PathSize + sizeof(UNICODE_NULL); 50 if (PathSizeWithNull < PathSize) 51 { 52 return NULL; 53 } 54 55 ParentCopy = BlMmAllocateHeap(PathSizeWithNull); 56 if (!ParentCopy) 57 { 58 return NULL; 59 } 60 wcsncpy(ParentCopy, FilePath, PathSizeWithNull / sizeof(WCHAR)); 61 62 Backslash = wcsrchr(ParentCopy, '\\'); 63 if (!Backslash) 64 { 65 BlMmFreeHeap(ParentCopy); 66 return NULL; 67 } 68 69 if (Backslash == ParentCopy) 70 { 71 ++Backslash; 72 } 73 74 *Backslash = UNICODE_NULL; 75 return ParentCopy; 76 } 77 78 PWCHAR 79 FileIoCopyFileName ( 80 _In_ PWCHAR FilePath 81 ) 82 { 83 PWCHAR Separator, FileCopy; 84 SIZE_T PathSize; 85 86 Separator = wcsrchr(FilePath, '\\'); 87 if (!Separator) 88 { 89 return NULL; 90 } 91 92 PathSize = wcslen(Separator) * sizeof(WCHAR); 93 94 FileCopy = BlMmAllocateHeap(PathSize); 95 if (!FileCopy) 96 { 97 return NULL; 98 } 99 100 wcsncpy(FileCopy, Separator + 1, PathSize / sizeof(WCHAR)); 101 return FileCopy; 102 } 103 104 BOOLEAN 105 FileTableCompareWithSubsetAttributes ( 106 _In_ PVOID Entry, 107 _In_ PVOID Argument1, 108 _In_ PVOID Argument2, 109 _In_ PVOID Argument3, 110 _In_ PVOID Argument4 111 ) 112 { 113 PBL_FILE_ENTRY FileEntry = (PBL_FILE_ENTRY)Entry; 114 ULONG DeviceId = *(PULONG)Argument1; 115 PWCHAR FilePath = (PWCHAR)Argument2; 116 ULONG Flags = *(PULONG)Argument3; 117 ULONG Unknown = *(PULONG)Argument4; 118 BOOLEAN Found; 119 120 Found = FALSE; 121 122 if ((FileEntry->DeviceId == DeviceId) && 123 !(_wcsicmp(FileEntry->FilePath, FilePath)) && 124 (FileEntry->Unknown == Unknown)) 125 { 126 if ((!(Flags & 1) || (FileEntry->Flags & 2)) && (!(Flags & 2) || (FileEntry->Flags & 4))) 127 { 128 if ((!(Flags & 4) || (FileEntry->Flags & 0x10000)) && ((Flags & 4) || !(FileEntry->Flags & 0x10000))) 129 { 130 Found = TRUE; 131 } 132 } 133 } 134 return Found; 135 } 136 137 BOOLEAN 138 FileTableCompareWithSameAttributes ( 139 _In_ PVOID Entry, 140 _In_ PVOID Argument1, 141 _In_ PVOID Argument2, 142 _In_ PVOID Argument3, 143 _In_ PVOID Argument4 144 ) 145 { 146 PBL_FILE_ENTRY FileEntry = (PBL_FILE_ENTRY)Entry; 147 ULONG DeviceId = *(PULONG)Argument1; 148 PWCHAR FilePath = (PWCHAR)Argument2; 149 ULONG Flags = *(PULONG)Argument3; 150 ULONG Unknown = *(PULONG)Argument4; 151 BOOLEAN Found; 152 153 Found = FALSE; 154 155 if ((FileEntry->DeviceId == DeviceId) && 156 !(_wcsicmp(FileEntry->FilePath, FilePath)) && 157 (FileEntry->Unknown == Unknown)) 158 { 159 if ((!(Flags & 1) || (FileEntry->Flags & 2)) && ((Flags & 1) || !(FileEntry->Flags & 2)) && (!(Flags & 2) || (FileEntry->Flags & 4)) && ((Flags & 2) || !(FileEntry->Flags & 4))) 160 { 161 if ((!(Flags & 4) || (FileEntry->Flags & 0x10000)) && ((Flags & 4) || !(FileEntry->Flags & 0x10000))) 162 { 163 Found = TRUE; 164 } 165 } 166 } 167 return Found; 168 } 169 170 NTSTATUS 171 FileTableDestroyEntry ( 172 _In_ PBL_FILE_ENTRY FileEntry, 173 _In_ ULONG Index 174 ) 175 { 176 ULONG DeviceId; 177 PBL_DEVICE_ENTRY DeviceEntry; 178 NTSTATUS Status; 179 180 DeviceId = FileEntry->DeviceId; 181 if (DmTableEntries > DeviceId) 182 { 183 DeviceEntry = DmDeviceTable[DeviceId]; 184 if (DeviceEntry) 185 { 186 --DeviceEntry->ReferenceCount; 187 } 188 } 189 190 Status = FileEntry->Callbacks.Close(FileEntry); 191 192 BlMmFreeHeap(FileEntry); 193 194 FileTable[Index] = NULL; 195 return Status; 196 } 197 198 #define BL_FILE_PURGE_LIMIT 512 199 200 NTSTATUS 201 FileTablePurgeEntry ( 202 _In_ PVOID Entry 203 ) 204 { 205 PBL_FILE_ENTRY FileEntry = (PBL_FILE_ENTRY)Entry; 206 207 /* Don't purge opened files, or if there's less than 512 files cached */ 208 if (((FileEntry->Flags & BL_FILE_ENTRY_OPENED) || 209 (FileEntry->Flags & 0x10000)) && 210 (FileEntries < BL_FILE_PURGE_LIMIT)) 211 { 212 return STATUS_UNSUCCESSFUL; 213 } 214 215 /* Purge the entry otherwise */ 216 return FileTableDestroyEntry(FileEntry, FileEntry->FileId); 217 } 218 219 NTSTATUS 220 BlFileClose ( 221 _In_ ULONG FileId 222 ) 223 { 224 PBL_FILE_ENTRY FileEntry; 225 226 /* Validate the file ID */ 227 if (FileEntries <= FileId) 228 { 229 return STATUS_INVALID_PARAMETER; 230 } 231 232 /* Make sure a file entry actually exists */ 233 FileEntry = FileTable[FileId]; 234 if (!FileEntry) 235 { 236 return STATUS_INVALID_PARAMETER; 237 } 238 239 /* And that it's actually open */ 240 if (!(FileEntry->Flags & BL_FILE_ENTRY_OPENED)) 241 { 242 return STATUS_INVALID_PARAMETER; 243 } 244 245 /* Drop a reference, check if this was the last one */ 246 --FileEntry->ReferenceCount; 247 if (!FileEntry->ReferenceCount) 248 { 249 /* File is no longer open */ 250 FileEntry->Flags &= ~BL_FILE_ENTRY_OPENED; 251 } 252 253 /* All good */ 254 return STATUS_SUCCESS; 255 } 256 257 NTSTATUS 258 FileIoOpen ( 259 _In_ ULONG DeviceId, 260 _In_ PWCHAR FileName, 261 _In_ ULONG Flags, 262 _In_ ULONG Unknown, 263 _In_ PBL_TBL_LOOKUP_ROUTINE CompareRoutine, 264 _Out_opt_ PBL_FILE_ENTRY *NewFileEntry 265 ) 266 { 267 PWCHAR FileNameCopy, ParentFileName; 268 NTSTATUS Status; 269 PBL_DEVICE_ENTRY DeviceEntry; 270 PBL_FILE_SYSTEM_ENTRY FileSystem; 271 ULONG FileId, CheckFlags; 272 PBL_FILE_ENTRY DirectoryEntry, FileEntry; 273 PLIST_ENTRY NextEntry, ListHead; 274 275 /* Preinitialize variables for failure */ 276 DirectoryEntry = NULL; 277 FileNameCopy = NULL; 278 ParentFileName = NULL; 279 Status = STATUS_SUCCESS; 280 281 /* Bail out if the device ID is invalid */ 282 if (DmTableEntries <= DeviceId) 283 { 284 return STATUS_ACCESS_DENIED; 285 } 286 287 /* Bail out if there's no device entry */ 288 DeviceEntry = DmDeviceTable[DeviceId]; 289 if (!DeviceEntry) 290 { 291 return STATUS_ACCESS_DENIED; 292 } 293 294 /* Read access is always required for touching the device */ 295 CheckFlags = Flags | BL_FILE_READ_ACCESS; 296 297 /* Check if the device is granting us read access */ 298 if ((CheckFlags & BL_FILE_READ_ACCESS) && 299 (!(DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED) || 300 !(DeviceEntry->Flags & BL_DEVICE_ENTRY_READ_ACCESS))) 301 { 302 EfiPrintf(L"Access denied\r\n"); 303 return STATUS_ACCESS_DENIED; 304 } 305 306 /* Check if the device is granting us write access */ 307 if ((CheckFlags & BL_FILE_WRITE_ACCESS) && 308 (!(DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED) || 309 !(DeviceEntry->Flags & BL_DEVICE_ENTRY_WRITE_ACCESS))) 310 { 311 EfiPrintf(L"Access denied2\r\n"); 312 return STATUS_ACCESS_DENIED; 313 } 314 315 /* Check if we already have this file open */ 316 FileEntry = (PBL_FILE_ENTRY )BlTblFindEntry(FileTable, 317 FileEntries, 318 &FileId, 319 CompareRoutine, 320 &DeviceId, 321 FileName, 322 &Flags, 323 &Unknown); 324 if (FileEntry) 325 { 326 goto FileOpened; 327 } 328 329 /* Check if we are opening the root drive or an actual file/directory */ 330 if ((*FileName != OBJ_NAME_PATH_SEPARATOR) || (FileName[1])) 331 { 332 /* Get the name of the directory */ 333 ParentFileName = FileIoCopyParentDirectoryPath(FileName); 334 if (!ParentFileName) 335 { 336 Status = STATUS_NO_MEMORY; 337 goto Quickie; 338 } 339 340 /* Open it */ 341 Status = FileIoOpen(DeviceId, 342 ParentFileName, 343 BL_FILE_READ_ACCESS | BL_DIRECTORY_ACCESS, 344 Unknown, 345 FileTableCompareWithSubsetAttributes, 346 &DirectoryEntry); 347 if (!NT_SUCCESS(Status)) 348 { 349 goto Quickie; 350 } 351 352 /* Now get the the file name itself */ 353 FileNameCopy = FileIoCopyFileName(FileName); 354 if (!FileNameCopy) 355 { 356 Status = STATUS_NO_MEMORY; 357 goto Quickie; 358 } 359 360 /* Open it */ 361 Status = DirectoryEntry->Callbacks.Open(DirectoryEntry, 362 FileNameCopy, 363 Flags, 364 &FileEntry); 365 } 366 else 367 { 368 /* We're opening the root, scan through all the file systems */ 369 Status = STATUS_UNSUCCESSFUL; 370 ListHead = &RegisteredFileSystems; 371 NextEntry = ListHead->Flink; 372 while (NextEntry != ListHead) 373 { 374 /* Try to mount this one */ 375 FileSystem = CONTAINING_RECORD(NextEntry, BL_FILE_SYSTEM_ENTRY, ListEntry); 376 Status = FileSystem->MountCallback(DeviceId, Unknown, &FileEntry); 377 if (NT_SUCCESS(Status)) 378 { 379 /* Mount successful */ 380 break; 381 } 382 383 /* Try the next file system */ 384 NextEntry = NextEntry->Flink; 385 } 386 387 /* Nothing to free on this path */ 388 FileNameCopy = NULL; 389 } 390 391 /* Handle failure */ 392 if (!NT_SUCCESS(Status)) 393 { 394 EfiPrintf(L"Could not open file!: %lx\r\n", Status); 395 goto Quickie; 396 } 397 398 /* Save the unknown */ 399 FileEntry->Unknown = Unknown; 400 401 /* Convert open flags into entry flags */ 402 if (Flags & BL_FILE_READ_ACCESS) 403 { 404 FileEntry->Flags |= BL_FILE_ENTRY_READ_ACCESS; 405 } 406 if (Flags & BL_FILE_WRITE_ACCESS) 407 { 408 FileEntry->Flags |= BL_FILE_ENTRY_WRITE_ACCESS; 409 } 410 411 /* Save the file into the file table */ 412 Status = BlTblSetEntry(&FileTable, 413 &FileEntries, 414 (PVOID)FileEntry, 415 &FileId, 416 FileTablePurgeEntry); 417 if (!NT_SUCCESS(Status)) 418 { 419 /* Close it if that failed */ 420 FileEntry->Callbacks.Close(FileEntry); 421 goto Quickie; 422 } 423 424 /* Add a reference on the device, and save our file ID */ 425 ++DeviceEntry->ReferenceCount; 426 Status = STATUS_SUCCESS; 427 FileEntry->FileId = FileId; 428 429 FileOpened: 430 /* Add a reference to the file entry, and see if this is the first one */ 431 if (++FileEntry->ReferenceCount == 1) 432 { 433 /* Reset unknowns */ 434 FileEntry->TotalBytesRead = 0; 435 FileEntry->Unknown2 = 0; 436 } 437 438 /* Set the file as opened */ 439 FileEntry->Flags |= BL_FILE_ENTRY_OPENED; 440 441 /* Not sure what this flag does */ 442 if (Flags & BL_UNKNOWN_ACCESS) 443 { 444 FileEntry->Flags |= BL_FILE_ENTRY_UNKNOWN_ACCESS; 445 } 446 447 /* If the caller wanted the entry back, return it */ 448 if (NewFileEntry) 449 { 450 *NewFileEntry = FileEntry; 451 } 452 453 Quickie: 454 /* Close the parent */ 455 if (DirectoryEntry) 456 { 457 BlFileClose(DirectoryEntry->FileId); 458 } 459 460 /* Free the parent name copy */ 461 if (ParentFileName) 462 { 463 BlMmFreeHeap(ParentFileName); 464 } 465 466 /* Free the file name copy */ 467 if (FileNameCopy) 468 { 469 BlMmFreeHeap(FileNameCopy); 470 } 471 472 /* Return back to caller */ 473 return Status; 474 } 475 476 NTSTATUS 477 BlFileOpen ( 478 _In_ ULONG DeviceId, 479 _In_ PWCHAR FileName, 480 _In_ ULONG Flags, 481 _Out_ PULONG FileId 482 ) 483 { 484 NTSTATUS Status; 485 PBL_FILE_ENTRY FileEntry; 486 BL_DEVICE_INFORMATION DeviceInformation; 487 488 /* Make sure we have a valid file name, access flags and parameters */ 489 if (!(FileName) || 490 (*FileName != OBJ_NAME_PATH_SEPARATOR) || 491 !(FileId) || 492 !(Flags & (BL_FILE_READ_ACCESS | BL_FILE_WRITE_ACCESS))) 493 { 494 EfiPrintf(L"Invalid file options\r\n"); 495 return STATUS_INVALID_PARAMETER; 496 } 497 498 /* Get information on the underlying device */ 499 Status = BlDeviceGetInformation(DeviceId, &DeviceInformation); 500 if (!NT_SUCCESS(Status)) 501 { 502 EfiPrintf(L"Get device info failed: %lx\r\n", Status); 503 return Status; 504 } 505 506 /* Make sure it's a device that can host files */ 507 if ((DeviceInformation.DeviceType != DiskDevice) && 508 (DeviceInformation.DeviceType != LegacyPartitionDevice) && 509 (DeviceInformation.DeviceType != UdpDevice)) 510 { 511 EfiPrintf(L"Invalid device type\r\n"); 512 return STATUS_INVALID_PARAMETER; 513 } 514 515 /* Open a file on this device, creating one if needed */ 516 Status = FileIoOpen(DeviceId, 517 FileName, 518 Flags, 519 0, 520 FileTableCompareWithSameAttributes, 521 &FileEntry); 522 if (NT_SUCCESS(Status)) 523 { 524 /* Return the file ID back to the caller */ 525 *FileId = FileEntry->FileId; 526 } 527 528 /* All good */ 529 return Status; 530 } 531 532 NTSTATUS 533 BlFileSetInformation ( 534 _In_ ULONG FileId, 535 _Out_ PBL_FILE_INFORMATION FileInfo 536 ) 537 { 538 PBL_FILE_ENTRY FileEntry; 539 540 /* Make sure caller passed this in */ 541 if (!FileInfo) 542 { 543 return STATUS_INVALID_PARAMETER; 544 } 545 546 /* Validate file ID */ 547 if (FileId > FileEntries) 548 { 549 return STATUS_INVALID_PARAMETER; 550 } 551 552 /* Make sure an opened file exits with this ID */ 553 FileEntry = FileTable[FileId]; 554 if (!(FileEntry) || !(FileEntry->Flags & BL_FILE_ENTRY_OPENED)) 555 { 556 return STATUS_INVALID_PARAMETER; 557 } 558 559 /* Do the I/O operation */ 560 return FileEntry->Callbacks.SetInfo(FileEntry, FileInfo); 561 } 562 563 NTSTATUS 564 BlFileGetInformation ( 565 _In_ ULONG FileId, 566 _In_ PBL_FILE_INFORMATION FileInfo 567 ) 568 { 569 PBL_FILE_ENTRY FileEntry; 570 571 /* Make sure caller passed this in */ 572 if (!FileInfo) 573 { 574 return STATUS_INVALID_PARAMETER; 575 } 576 577 /* Validate file ID */ 578 if (FileId > FileEntries) 579 { 580 return STATUS_INVALID_PARAMETER; 581 } 582 583 /* Make sure an opened file exits with this ID */ 584 FileEntry = FileTable[FileId]; 585 if (!(FileEntry) || !(FileEntry->Flags & BL_FILE_ENTRY_OPENED)) 586 { 587 return STATUS_INVALID_PARAMETER; 588 } 589 590 /* Do the I/O operation */ 591 return FileEntry->Callbacks.GetInfo(FileEntry, FileInfo); 592 } 593 594 NTSTATUS 595 FileInformationCheck ( 596 _In_ PBL_FILE_INFORMATION FileInformation, 597 _In_ BOOLEAN Write, 598 _In_opt_ PULONG InputSize, 599 _In_opt_ PULONG BytesReturned, 600 _Out_opt_ PULONG RequiredSize 601 ) 602 { 603 NTSTATUS Status; 604 ULONG Size; 605 606 /* Initialize variables */ 607 Status = STATUS_SUCCESS; 608 Size = 0; 609 610 /* Make sure we didn't overshoot */ 611 if (FileInformation->Offset > FileInformation->Size) 612 { 613 /* Bail out */ 614 Status = STATUS_INVALID_PARAMETER; 615 goto Quickie; 616 } 617 618 /* Compute the appropriate 32-bit size of this read, based on file size */ 619 Size = ULONG_MAX; 620 if ((FileInformation->Size - FileInformation->Offset) <= ULONG_MAX) 621 { 622 Size = (ULONG)(FileInformation->Size) - (ULONG)(FileInformation->Offset); 623 } 624 625 /* Check if the caller has an input buffer */ 626 if (InputSize) 627 { 628 /* Is the size bigger than what the caller can handle? */ 629 if (Size >= *InputSize) 630 { 631 /* Yes, so cap it at the size of the caller's buffer */ 632 Size = *InputSize; 633 } 634 else if (!(BytesReturned) || (Write)) 635 { 636 /* Caller's input buffer is too smaller is fatal for writes */ 637 Status = STATUS_INVALID_PARAMETER; 638 goto Quickie; 639 } 640 } 641 642 Quickie: 643 /* Does the caller want to know how big to make their buffer? */ 644 if (RequiredSize) 645 { 646 /* Let them know*/ 647 *RequiredSize = Size; 648 } 649 650 /* Return final status */ 651 return Status; 652 } 653 654 NTSTATUS 655 BlFileReadEx ( 656 _In_ ULONG FileId, 657 _Out_ PVOID Buffer, 658 _In_ ULONG Size, 659 _Out_ PULONG BytesReturned, 660 _In_ ULONG Flags 661 ) 662 { 663 PBL_FILE_ENTRY FileEntry; 664 NTSTATUS Status; 665 ULONG OldUnknown, RequiredSize; 666 BOOLEAN ChangedUnknown; 667 BL_DEVICE_INFORMATION DeviceInfo; 668 BL_FILE_INFORMATION fileInfo; 669 670 /* Initialize variables */ 671 RtlZeroMemory(&DeviceInfo, sizeof(DeviceInfo)); 672 OldUnknown = 0; 673 ChangedUnknown = FALSE; 674 675 /* Bail out if there's no buffer */ 676 if (!Buffer) 677 { 678 return STATUS_INVALID_PARAMETER; 679 } 680 681 /* Bail out of the file ID is invalid */ 682 if (FileId > FileEntries) 683 { 684 return STATUS_INVALID_PARAMETER; 685 } 686 687 /* Bail out if there's no file opened for read access */ 688 FileEntry = FileTable[FileId]; 689 if (!(FileEntry) || 690 !(FileEntry->Flags & (BL_FILE_ENTRY_OPENED | BL_FILE_ENTRY_READ_ACCESS))) 691 { 692 return STATUS_INVALID_PARAMETER; 693 } 694 695 /* Bail out if we can't read the file's information */ 696 Status = BlFileGetInformation(FileId, &fileInfo); 697 if (!NT_SUCCESS(Status)) 698 { 699 return Status; 700 } 701 702 /* Ensure the read attempt is valid, and fix up the size if needed */ 703 RequiredSize = Size; 704 Status = FileInformationCheck(&fileInfo, 705 FALSE, 706 &RequiredSize, 707 BytesReturned, 708 &RequiredSize); 709 if (!NT_SUCCESS(Status)) 710 { 711 /* Invalid or illegal read attempt */ 712 return Status; 713 } 714 715 /* Is there anything left to read after all? */ 716 if (RequiredSize) 717 { 718 /* Check if flags 2 or 4 are set */ 719 if ((Flags & 2) || (Flags & 4)) 720 { 721 /* Check if this is a disk or partition device */ 722 BlDeviceGetInformation(FileEntry->DeviceId, &DeviceInfo); 723 if ((DeviceInfo.DeviceType == DiskDevice) || 724 (DeviceInfo.DeviceType == LegacyPartitionDevice)) 725 { 726 /* Check if request flags are incompatible with device flags */ 727 if ((!(DeviceInfo.BlockDeviceInfo.Unknown & 1) && (Flags & 2)) || 728 (!(DeviceInfo.BlockDeviceInfo.Unknown & 2) && (Flags & 4))) 729 { 730 /* We're going to change the device flags */ 731 ChangedUnknown = TRUE; 732 733 /* Set unknown flag 1 for request flag 2 */ 734 if (Flags & 2) 735 { 736 DeviceInfo.BlockDeviceInfo.Unknown |= 1; 737 } 738 739 /* Set unknown flag 2 for request flag 4 */ 740 if (Flags & 4) 741 { 742 DeviceInfo.BlockDeviceInfo.Unknown |= 2; 743 } 744 745 /* Save the new device flags */ 746 BlDeviceSetInformation(FileEntry->DeviceId, &DeviceInfo); 747 } 748 } 749 } 750 751 /* Issue the read to the underlying file system */ 752 Status = FileEntry->Callbacks.Read(FileEntry, 753 Buffer, 754 RequiredSize, 755 BytesReturned); 756 if (!NT_SUCCESS(Status)) 757 { 758 /* Don't update the bytes read on failure */ 759 RequiredSize = 0; 760 } 761 } 762 else 763 { 764 /* There's nothing to do, return success and 0 bytes */ 765 Status = STATUS_SUCCESS; 766 if (BytesReturned) 767 { 768 *BytesReturned = 0; 769 } 770 } 771 772 /* Increment the number of bytes read */ 773 FileEntry->TotalBytesRead += RequiredSize; 774 775 /* Check if the unknown flag on the device was changed during this routine */ 776 if (ChangedUnknown) 777 { 778 /* Reset it back to its original value */ 779 DeviceInfo.BlockDeviceInfo.Unknown = OldUnknown; 780 BlDeviceSetInformation(FileEntry->DeviceId, &DeviceInfo); 781 } 782 783 /* Return the final status */ 784 return Status; 785 } 786 787 NTSTATUS 788 BlFileReadAtOffsetEx ( 789 _In_ ULONG FileId, 790 _In_ ULONG Size, 791 _In_ ULONGLONG ByteOffset, 792 _In_ PVOID Buffer, 793 _Out_ PULONG BytesReturned, 794 _In_ ULONG Flags 795 ) 796 { 797 NTSTATUS Status; 798 BL_FILE_INFORMATION FileInfo; 799 ULONG RequiredSize; 800 ULONGLONG FileOffset; 801 802 /* Get information on the specified file */ 803 Status = BlFileGetInformation(FileId, &FileInfo); 804 if (!NT_SUCCESS(Status)) 805 { 806 return Status; 807 } 808 809 /* Save the current offset, and overwrite it with the one we want */ 810 FileOffset = FileInfo.Offset; 811 FileInfo.Offset = ByteOffset; 812 813 /* Check the validity of the read and the actual size to read */ 814 RequiredSize = Size; 815 Status = FileInformationCheck(&FileInfo, 816 FALSE, 817 &RequiredSize, 818 BytesReturned, 819 &RequiredSize); 820 if (!NT_SUCCESS(Status)) 821 { 822 /* Bail out if the read is invalid */ 823 EfiPrintf(L"File info check failure: %lx\r\n", Status); 824 return Status; 825 } 826 827 /* Check if the offset we're requesting is not the current offset */ 828 if (FileInfo.Offset != FileOffset) 829 { 830 /* Set the new offset to use */ 831 Status = BlFileSetInformation(FileId, &FileInfo); 832 if (!NT_SUCCESS(Status)) 833 { 834 /* Can't do much if that failed */ 835 return Status; 836 } 837 } 838 839 /* Do the read at the required offset now */ 840 Status = BlFileReadEx(FileId, 841 Buffer, 842 RequiredSize, 843 BytesReturned, 844 Flags); 845 if (!NT_SUCCESS(Status)) 846 { 847 /* The read failed -- had we modified the offset? */ 848 if (FileInfo.Offset != FileOffset) 849 { 850 /* Restore the offset back to its original value */ 851 FileInfo.Offset = FileOffset; 852 BlFileSetInformation(FileId, &FileInfo); 853 } 854 } 855 856 /* Return the status of the read */ 857 return Status; 858 } 859 860 NTSTATUS 861 BlpFileRegisterFileSystem ( 862 _In_ PBL_FS_INIT_CALLBACK InitCallback, 863 _In_ PBL_FS_DESTROY_CALLBACK DestroyCallback, 864 _In_ PBL_FS_MOUNT_CALLBACK MountCallback, 865 _In_ PBL_FS_PURGE_CALLBACK PurgeCallback, 866 _In_ ULONG Flags 867 ) 868 { 869 PBL_FILE_SYSTEM_ENTRY FsEntry; 870 NTSTATUS Status; 871 872 /* Allocate an entry */ 873 FsEntry = BlMmAllocateHeap(sizeof(*FsEntry)); 874 if (!FsEntry) 875 { 876 return STATUS_NO_MEMORY; 877 } 878 879 /* Initialize the file system */ 880 Status = InitCallback(); 881 if (!NT_SUCCESS(Status)) 882 { 883 BlMmFreeHeap(FsEntry); 884 return Status; 885 } 886 887 /* Register the callbacks */ 888 FsEntry->MountCallback = MountCallback; 889 FsEntry->DestroyCallback = DestroyCallback; 890 FsEntry->InitCallback = InitCallback; 891 FsEntry->PurgeCallback = PurgeCallback; 892 893 /* Insert in the right location in the list */ 894 if (Flags & BL_FS_REGISTER_AT_HEAD_FLAG) 895 { 896 InsertHeadList(&RegisteredFileSystems, &FsEntry->ListEntry); 897 } 898 else 899 { 900 InsertTailList(&RegisteredFileSystems, &FsEntry->ListEntry); 901 } 902 903 /* Return */ 904 return STATUS_SUCCESS; 905 } 906 907 NTSTATUS 908 BlpFileInitialize ( 909 VOID 910 ) 911 { 912 NTSTATUS Status; 913 914 /* Allocate the file table */ 915 FileEntries = 16; 916 FileTable = BlMmAllocateHeap(sizeof(PBL_FILE_ENTRY) * FileEntries); 917 if (!FileTable) 918 { 919 return STATUS_INVALID_PARAMETER; 920 } 921 922 /* Initialize it */ 923 RtlZeroMemory(FileTable, sizeof(PBL_FILE_ENTRY) * FileEntries); 924 InitializeListHead(&RegisteredFileSystems); 925 926 #if 0 927 /* Initialize the network file system */ 928 Status = BlpFileRegisterFileSystem(NetRegisterFunctionTable.Init, 929 NetRegisterFunctionTable.Destroy, 930 NetRegisterFunctionTable.Mount, 931 NetRegisterFunctionTable.Purge, 932 1); 933 if (NT_SUCCESS(Status)) 934 { 935 /* Initialize NTFS */ 936 Status = BlpFileRegisterFileSystem(NtfsRegisterFunctionTable.Init, 937 NtfsRegisterFunctionTable.Destroy, 938 NtfsRegisterFunctionTable.Mount, 939 NtfsRegisterFunctionTable.Purge, 940 0); 941 } 942 943 if (NT_SUCCESS(Status)) 944 #endif 945 { 946 /* Initialize FAT */ 947 Status = BlpFileRegisterFileSystem(FatRegisterFunctionTable.Init, 948 FatRegisterFunctionTable.Destroy, 949 FatRegisterFunctionTable.Mount, 950 FatRegisterFunctionTable.Purge, 951 0); 952 } 953 954 #if 0 955 if (NT_SUCCESS(Status)) 956 { 957 /* Initialize EXFAT (FatPlus) */ 958 Status = BlpFileRegisterFileSystem(FppRegisterFunctionTable.Init, 959 FppRegisterFunctionTable.Destroy, 960 FppRegisterFunctionTable.Mount, 961 FppRegisterFunctionTable.Purge, 962 0); 963 } 964 965 if (NT_SUCCESS(Status)) 966 { 967 /* Initialize WIM */ 968 Status = BlpFileRegisterFileSystem(WimRegisterFunctionTable.Init, 969 WimRegisterFunctionTable.Destroy, 970 WimRegisterFunctionTable.Mount, 971 WimRegisterFunctionTable.Purge, 972 0); 973 } 974 975 if (NT_SUCCESS(Status)) 976 { 977 /* Initialize UDFS */ 978 Status = BlpFileRegisterFileSystem(UdfsRegisterFunctionTable.Init, 979 UdfsRegisterFunctionTable.Destroy, 980 UdfsRegisterFunctionTable.Mount, 981 UdfsRegisterFunctionTable.Purge, 982 0); 983 } 984 #endif 985 if (NT_SUCCESS(Status)) 986 { 987 /* Initialize El-Torito CDFS */ 988 Status = BlpFileRegisterFileSystem(EtfsRegisterFunctionTable.Init, 989 EtfsRegisterFunctionTable.Destroy, 990 EtfsRegisterFunctionTable.Mount, 991 EtfsRegisterFunctionTable.Purge, 992 0); 993 } 994 995 /* Destroy the file manager if any of the file systems didn't initialize */ 996 if (!NT_SUCCESS(Status)) 997 { 998 if (FileTable) 999 { 1000 //BlpFileDestroy(); 1001 } 1002 } 1003 return Status; 1004 } 1005