1 /** @file 2 Handle operations in files and directories from UDF/ECMA-167 file systems. 3 4 Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com> 5 Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> 6 7 SPDX-License-Identifier: BSD-2-Clause-Patent 8 **/ 9 10 #include "Udf.h" 11 12 EFI_FILE_PROTOCOL gUdfFileIoOps = { 13 EFI_FILE_PROTOCOL_REVISION, 14 UdfOpen, 15 UdfClose, 16 UdfDelete, 17 UdfRead, 18 UdfWrite, 19 UdfGetPosition, 20 UdfSetPosition, 21 UdfGetInfo, 22 UdfSetInfo, 23 UdfFlush, 24 NULL, 25 NULL, 26 NULL, 27 NULL 28 }; 29 30 #define _ROOT_FILE(_PrivData) (_PrivData)->Root 31 #define _PARENT_FILE(_PrivData) \ 32 ((_PrivData)->IsRootDirectory ? (_PrivData)->Root : &(_PrivData)->File) 33 #define _FILE(_PrivData) _PARENT_FILE(_PrivData) 34 35 /** 36 Open the root directory on a volume. 37 38 @param This Protocol instance pointer. 39 @param Root Returns an Open file handle for the root directory 40 41 @retval EFI_SUCCESS The device was opened. 42 @retval EFI_UNSUPPORTED This volume does not support the file system. 43 @retval EFI_NO_MEDIA The device has no media. 44 @retval EFI_DEVICE_ERROR The device reported an error. 45 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 46 @retval EFI_ACCESS_DENIED The service denied access to the file. 47 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of 48 resources. 49 50 **/ 51 EFI_STATUS 52 EFIAPI 53 UdfOpenVolume ( 54 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, 55 OUT EFI_FILE_PROTOCOL **Root 56 ) 57 { 58 EFI_TPL OldTpl; 59 EFI_STATUS Status; 60 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; 61 PRIVATE_UDF_FILE_DATA *PrivFileData; 62 63 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 64 65 if (This == NULL || Root == NULL) { 66 Status = EFI_INVALID_PARAMETER; 67 goto Error_Invalid_Params; 68 } 69 70 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (This); 71 72 if (PrivFsData->OpenFiles == 0) { 73 // 74 // There is no more open files. Read volume information again since it was 75 // cleaned up on the last UdfClose() call. 76 // 77 Status = ReadUdfVolumeInformation ( 78 PrivFsData->BlockIo, 79 PrivFsData->DiskIo, 80 &PrivFsData->Volume 81 ); 82 if (EFI_ERROR (Status)) { 83 goto Error_Read_Udf_Volume; 84 } 85 } 86 87 CleanupFileInformation (&PrivFsData->Root); 88 89 // 90 // Find root directory file. 91 // 92 Status = FindRootDirectory ( 93 PrivFsData->BlockIo, 94 PrivFsData->DiskIo, 95 &PrivFsData->Volume, 96 &PrivFsData->Root 97 ); 98 if (EFI_ERROR (Status)) { 99 goto Error_Find_Root_Dir; 100 } 101 102 PrivFileData = 103 (PRIVATE_UDF_FILE_DATA *) AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA)); 104 if (PrivFileData == NULL) { 105 Status = EFI_OUT_OF_RESOURCES; 106 goto Error_Alloc_Priv_File_Data; 107 } 108 109 PrivFileData->Signature = PRIVATE_UDF_FILE_DATA_SIGNATURE; 110 PrivFileData->SimpleFs = This; 111 PrivFileData->Root = &PrivFsData->Root; 112 PrivFileData->IsRootDirectory = TRUE; 113 114 CopyMem ((VOID *)&PrivFileData->FileIo, (VOID *)&gUdfFileIoOps, 115 sizeof (EFI_FILE_PROTOCOL)); 116 117 *Root = &PrivFileData->FileIo; 118 119 PrivFsData->OpenFiles++; 120 121 gBS->RestoreTPL (OldTpl); 122 123 return EFI_SUCCESS; 124 125 Error_Alloc_Priv_File_Data: 126 CleanupFileInformation (&PrivFsData->Root); 127 128 Error_Find_Root_Dir: 129 130 Error_Read_Udf_Volume: 131 Error_Invalid_Params: 132 gBS->RestoreTPL (OldTpl); 133 134 return Status; 135 } 136 137 /** 138 Opens a new file relative to the source file's location. 139 140 @param This The protocol instance pointer. 141 @param NewHandle Returns File Handle for FileName. 142 @param FileName Null terminated string. "\", ".", and ".." are supported. 143 @param OpenMode Open mode for file. 144 @param Attributes Only used for EFI_FILE_MODE_CREATE. 145 146 @retval EFI_SUCCESS The device was opened. 147 @retval EFI_NOT_FOUND The specified file could not be found on the 148 device. 149 @retval EFI_NO_MEDIA The device has no media. 150 @retval EFI_MEDIA_CHANGED The media has changed. 151 @retval EFI_DEVICE_ERROR The device reported an error. 152 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 153 @retval EFI_ACCESS_DENIED The service denied access to the file. 154 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of 155 resources. 156 @retval EFI_VOLUME_FULL The volume is full. 157 158 **/ 159 EFI_STATUS 160 EFIAPI 161 UdfOpen ( 162 IN EFI_FILE_PROTOCOL *This, 163 OUT EFI_FILE_PROTOCOL **NewHandle, 164 IN CHAR16 *FileName, 165 IN UINT64 OpenMode, 166 IN UINT64 Attributes 167 ) 168 { 169 EFI_TPL OldTpl; 170 EFI_STATUS Status; 171 PRIVATE_UDF_FILE_DATA *PrivFileData; 172 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; 173 CHAR16 FilePath[UDF_PATH_LENGTH]; 174 UDF_FILE_INFO File; 175 PRIVATE_UDF_FILE_DATA *NewPrivFileData; 176 CHAR16 *TempFileName; 177 178 ZeroMem (FilePath, sizeof FilePath); 179 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 180 181 if (This == NULL || NewHandle == NULL || FileName == NULL) { 182 Status = EFI_INVALID_PARAMETER; 183 goto Error_Invalid_Params; 184 } 185 186 if (OpenMode != EFI_FILE_MODE_READ) { 187 Status = EFI_WRITE_PROTECTED; 188 goto Error_Invalid_Params; 189 } 190 191 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); 192 193 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs); 194 195 // 196 // Build full path 197 // 198 if (*FileName == L'\\') { 199 StrCpyS (FilePath, UDF_PATH_LENGTH, FileName); 200 } else { 201 StrCpyS (FilePath, UDF_PATH_LENGTH, PrivFileData->AbsoluteFileName); 202 StrCatS (FilePath, UDF_PATH_LENGTH, L"\\"); 203 StrCatS (FilePath, UDF_PATH_LENGTH, FileName); 204 } 205 206 MangleFileName (FilePath); 207 if (FilePath[0] == L'\0') { 208 Status = EFI_NOT_FOUND; 209 goto Error_Bad_FileName; 210 } 211 212 Status = FindFile ( 213 PrivFsData->BlockIo, 214 PrivFsData->DiskIo, 215 &PrivFsData->Volume, 216 FilePath, 217 _ROOT_FILE (PrivFileData), 218 _PARENT_FILE (PrivFileData), 219 &_PARENT_FILE(PrivFileData)->FileIdentifierDesc->Icb, 220 &File 221 ); 222 if (EFI_ERROR (Status)) { 223 goto Error_Find_File; 224 } 225 226 NewPrivFileData = 227 (PRIVATE_UDF_FILE_DATA *)AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA)); 228 if (NewPrivFileData == NULL) { 229 Status = EFI_OUT_OF_RESOURCES; 230 goto Error_Alloc_New_Priv_File_Data; 231 } 232 233 CopyMem ((VOID *)NewPrivFileData, (VOID *)PrivFileData, 234 sizeof (PRIVATE_UDF_FILE_DATA)); 235 CopyMem ((VOID *)&NewPrivFileData->File, &File, sizeof (UDF_FILE_INFO)); 236 237 NewPrivFileData->IsRootDirectory = FALSE; 238 239 StrCpyS (NewPrivFileData->AbsoluteFileName, UDF_PATH_LENGTH, FilePath); 240 FileName = NewPrivFileData->AbsoluteFileName; 241 242 while ((TempFileName = StrStr (FileName, L"\\")) != NULL) { 243 FileName = TempFileName + 1; 244 } 245 246 StrCpyS (NewPrivFileData->FileName, UDF_FILENAME_LENGTH, FileName); 247 248 Status = GetFileSize ( 249 PrivFsData->BlockIo, 250 PrivFsData->DiskIo, 251 &PrivFsData->Volume, 252 &NewPrivFileData->File, 253 &NewPrivFileData->FileSize 254 ); 255 if (EFI_ERROR (Status)) { 256 DEBUG (( 257 DEBUG_ERROR, 258 "%a: GetFileSize() fails with status - %r.\n", 259 __FUNCTION__, Status 260 )); 261 goto Error_Get_File_Size; 262 } 263 264 NewPrivFileData->FilePosition = 0; 265 ZeroMem ((VOID *)&NewPrivFileData->ReadDirInfo, 266 sizeof (UDF_READ_DIRECTORY_INFO)); 267 268 *NewHandle = &NewPrivFileData->FileIo; 269 270 PrivFsData->OpenFiles++; 271 272 gBS->RestoreTPL (OldTpl); 273 274 return Status; 275 276 Error_Get_File_Size: 277 FreePool ((VOID *)NewPrivFileData); 278 279 Error_Alloc_New_Priv_File_Data: 280 CleanupFileInformation (&File); 281 282 Error_Find_File: 283 Error_Bad_FileName: 284 Error_Invalid_Params: 285 gBS->RestoreTPL (OldTpl); 286 287 return Status; 288 } 289 290 /** 291 Read data from the file. 292 293 @param This Protocol instance pointer. 294 @param BufferSize On input size of buffer, on output amount of data in 295 buffer. 296 @param Buffer The buffer in which data is read. 297 298 @retval EFI_SUCCESS Data was read. 299 @retval EFI_NO_MEDIA The device has no media. 300 @retval EFI_DEVICE_ERROR The device reported an error. 301 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 302 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains 303 required size. 304 305 **/ 306 EFI_STATUS 307 EFIAPI 308 UdfRead ( 309 IN EFI_FILE_PROTOCOL *This, 310 IN OUT UINTN *BufferSize, 311 OUT VOID *Buffer 312 ) 313 { 314 EFI_TPL OldTpl; 315 EFI_STATUS Status; 316 PRIVATE_UDF_FILE_DATA *PrivFileData; 317 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; 318 UDF_VOLUME_INFO *Volume; 319 UDF_FILE_INFO *Parent; 320 UDF_READ_DIRECTORY_INFO *ReadDirInfo; 321 EFI_BLOCK_IO_PROTOCOL *BlockIo; 322 EFI_DISK_IO_PROTOCOL *DiskIo; 323 UDF_FILE_INFO FoundFile; 324 UDF_FILE_IDENTIFIER_DESCRIPTOR *NewFileIdentifierDesc; 325 VOID *NewFileEntryData; 326 CHAR16 FileName[UDF_FILENAME_LENGTH]; 327 UINT64 FileSize; 328 UINT64 BufferSizeUint64; 329 330 ZeroMem (FileName, sizeof FileName); 331 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 332 333 if (This == NULL || BufferSize == NULL || (*BufferSize != 0 && 334 Buffer == NULL)) { 335 Status = EFI_INVALID_PARAMETER; 336 goto Error_Invalid_Params; 337 } 338 339 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); 340 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs); 341 342 BlockIo = PrivFsData->BlockIo; 343 DiskIo = PrivFsData->DiskIo; 344 Volume = &PrivFsData->Volume; 345 ReadDirInfo = &PrivFileData->ReadDirInfo; 346 NewFileIdentifierDesc = NULL; 347 NewFileEntryData = NULL; 348 349 Parent = _PARENT_FILE (PrivFileData); 350 351 Status = EFI_VOLUME_CORRUPTED; 352 353 if (IS_FID_NORMAL_FILE (Parent->FileIdentifierDesc)) { 354 if (PrivFileData->FilePosition > PrivFileData->FileSize) { 355 // 356 // File's position is beyond the EOF 357 // 358 Status = EFI_DEVICE_ERROR; 359 goto Error_File_Beyond_The_Eof; 360 } 361 362 if (PrivFileData->FilePosition == PrivFileData->FileSize) { 363 *BufferSize = 0; 364 Status = EFI_SUCCESS; 365 goto Done; 366 } 367 368 BufferSizeUint64 = *BufferSize; 369 370 Status = ReadFileData ( 371 BlockIo, 372 DiskIo, 373 Volume, 374 Parent, 375 PrivFileData->FileSize, 376 &PrivFileData->FilePosition, 377 Buffer, 378 &BufferSizeUint64 379 ); 380 ASSERT (BufferSizeUint64 <= MAX_UINTN); 381 *BufferSize = (UINTN)BufferSizeUint64; 382 } else if (IS_FID_DIRECTORY_FILE (Parent->FileIdentifierDesc)) { 383 if (ReadDirInfo->FidOffset == 0 && PrivFileData->FilePosition > 0) { 384 Status = EFI_DEVICE_ERROR; 385 *BufferSize = 0; 386 goto Done; 387 } 388 389 for (;;) { 390 Status = ReadDirectoryEntry ( 391 BlockIo, 392 DiskIo, 393 Volume, 394 &Parent->FileIdentifierDesc->Icb, 395 Parent->FileEntry, 396 ReadDirInfo, 397 &NewFileIdentifierDesc 398 ); 399 if (EFI_ERROR (Status)) { 400 if (Status == EFI_DEVICE_ERROR) { 401 FreePool (ReadDirInfo->DirectoryData); 402 ZeroMem ((VOID *)ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO)); 403 404 *BufferSize = 0; 405 Status = EFI_SUCCESS; 406 } 407 408 goto Done; 409 } 410 // 411 // After calling function ReadDirectoryEntry(), if 'NewFileIdentifierDesc' 412 // is NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the 413 // code reaches here, 'NewFileIdentifierDesc' must be not NULL. 414 // 415 // The ASSERT here is for addressing a false positive NULL pointer 416 // dereference issue raised from static analysis. 417 // 418 ASSERT (NewFileIdentifierDesc != NULL); 419 420 if (!IS_FID_PARENT_FILE (NewFileIdentifierDesc)) { 421 break; 422 } 423 424 FreePool ((VOID *)NewFileIdentifierDesc); 425 } 426 427 Status = FindFileEntry ( 428 BlockIo, 429 DiskIo, 430 Volume, 431 &NewFileIdentifierDesc->Icb, 432 &NewFileEntryData 433 ); 434 if (EFI_ERROR (Status)) { 435 goto Error_Find_Fe; 436 } 437 ASSERT (NewFileEntryData != NULL); 438 439 if (FE_ICB_FILE_TYPE (NewFileEntryData) == UdfFileEntrySymlink) { 440 Status = ResolveSymlink ( 441 BlockIo, 442 DiskIo, 443 Volume, 444 Parent, 445 NewFileEntryData, 446 &FoundFile 447 ); 448 if (EFI_ERROR (Status)) { 449 goto Error_Resolve_Symlink; 450 } 451 452 FreePool ((VOID *)NewFileEntryData); 453 NewFileEntryData = FoundFile.FileEntry; 454 455 Status = GetFileNameFromFid (NewFileIdentifierDesc, ARRAY_SIZE (FileName), FileName); 456 if (EFI_ERROR (Status)) { 457 FreePool ((VOID *)FoundFile.FileIdentifierDesc); 458 goto Error_Get_FileName; 459 } 460 461 FreePool ((VOID *)NewFileIdentifierDesc); 462 NewFileIdentifierDesc = FoundFile.FileIdentifierDesc; 463 } else { 464 FoundFile.FileIdentifierDesc = NewFileIdentifierDesc; 465 FoundFile.FileEntry = NewFileEntryData; 466 467 Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, ARRAY_SIZE (FileName), FileName); 468 if (EFI_ERROR (Status)) { 469 goto Error_Get_FileName; 470 } 471 } 472 473 Status = GetFileSize ( 474 BlockIo, 475 DiskIo, 476 Volume, 477 &FoundFile, 478 &FileSize 479 ); 480 if (EFI_ERROR (Status)) { 481 goto Error_Get_File_Size; 482 } 483 484 Status = SetFileInfo ( 485 &FoundFile, 486 FileSize, 487 FileName, 488 BufferSize, 489 Buffer 490 ); 491 if (EFI_ERROR (Status)) { 492 goto Error_Set_File_Info; 493 } 494 495 PrivFileData->FilePosition++; 496 Status = EFI_SUCCESS; 497 } else if (IS_FID_DELETED_FILE (Parent->FileIdentifierDesc)) { 498 // 499 // Code should never reach here. 500 // 501 ASSERT (FALSE); 502 Status = EFI_DEVICE_ERROR; 503 } 504 505 Error_Set_File_Info: 506 Error_Get_File_Size: 507 Error_Get_FileName: 508 Error_Resolve_Symlink: 509 if (NewFileEntryData != NULL) { 510 FreePool (NewFileEntryData); 511 } 512 513 Error_Find_Fe: 514 if (NewFileIdentifierDesc != NULL) { 515 FreePool ((VOID *)NewFileIdentifierDesc); 516 } 517 518 Done: 519 Error_File_Beyond_The_Eof: 520 Error_Invalid_Params: 521 gBS->RestoreTPL (OldTpl); 522 523 return Status; 524 } 525 526 /** 527 Close the file handle. 528 529 @param This Protocol instance pointer. 530 531 @retval EFI_SUCCESS The file was closed. 532 533 **/ 534 EFI_STATUS 535 EFIAPI 536 UdfClose ( 537 IN EFI_FILE_PROTOCOL *This 538 ) 539 { 540 EFI_TPL OldTpl; 541 EFI_STATUS Status; 542 PRIVATE_UDF_FILE_DATA *PrivFileData; 543 544 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 545 546 Status = EFI_SUCCESS; 547 548 if (This == NULL) { 549 Status = EFI_INVALID_PARAMETER; 550 goto Exit; 551 } 552 553 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); 554 555 if (!PrivFileData->IsRootDirectory) { 556 CleanupFileInformation (&PrivFileData->File); 557 558 if (PrivFileData->ReadDirInfo.DirectoryData != NULL) { 559 FreePool (PrivFileData->ReadDirInfo.DirectoryData); 560 } 561 } 562 563 FreePool ((VOID *)PrivFileData); 564 565 Exit: 566 gBS->RestoreTPL (OldTpl); 567 568 return Status; 569 } 570 571 /** 572 Close and delete the file handle. 573 574 @param This Protocol instance pointer. 575 576 @retval EFI_SUCCESS The file was closed and deleted. 577 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not 578 deleted. 579 580 **/ 581 EFI_STATUS 582 EFIAPI 583 UdfDelete ( 584 IN EFI_FILE_PROTOCOL *This 585 ) 586 { 587 PRIVATE_UDF_FILE_DATA *PrivFileData; 588 589 if (This == NULL) { 590 return EFI_INVALID_PARAMETER; 591 } 592 593 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); 594 595 (VOID)PrivFileData->FileIo.Close(This); 596 597 return EFI_WARN_DELETE_FAILURE; 598 } 599 600 /** 601 Write data to a file. 602 603 @param This Protocol instance pointer. 604 @param BufferSize On input size of buffer, on output amount of data in 605 buffer. 606 @param Buffer The buffer in which data to write. 607 608 @retval EFI_SUCCESS Data was written. 609 @retval EFI_UNSUPPORTED Writes to Open directory are not supported. 610 @retval EFI_NO_MEDIA The device has no media. 611 @retval EFI_DEVICE_ERROR The device reported an error. 612 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file. 613 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 614 @retval EFI_WRITE_PROTECTED The device is write protected. 615 @retval EFI_ACCESS_DENIED The file was open for read only. 616 @retval EFI_VOLUME_FULL The volume is full. 617 618 **/ 619 EFI_STATUS 620 EFIAPI 621 UdfWrite ( 622 IN EFI_FILE_PROTOCOL *This, 623 IN OUT UINTN *BufferSize, 624 IN VOID *Buffer 625 ) 626 { 627 return EFI_UNSUPPORTED; 628 } 629 630 /** 631 Get file's current position. 632 633 @param This Protocol instance pointer. 634 @param Position Byte position from the start of the file. 635 636 @retval EFI_SUCCESS Position was updated. 637 @retval EFI_UNSUPPORTED Seek request for directories is not valid. 638 639 **/ 640 EFI_STATUS 641 EFIAPI 642 UdfGetPosition ( 643 IN EFI_FILE_PROTOCOL *This, 644 OUT UINT64 *Position 645 ) 646 { 647 PRIVATE_UDF_FILE_DATA *PrivFileData; 648 649 if (This == NULL || Position == NULL) { 650 return EFI_INVALID_PARAMETER; 651 } 652 653 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); 654 655 // 656 // As per UEFI spec, if the file handle is a directory, then the current file 657 // position has no meaning and the operation is not supported. 658 // 659 if (IS_FID_DIRECTORY_FILE (PrivFileData->File.FileIdentifierDesc)) { 660 return EFI_UNSUPPORTED; 661 } 662 663 // 664 // The file is not a directory. So, return its position. 665 // 666 *Position = PrivFileData->FilePosition; 667 668 return EFI_SUCCESS; 669 } 670 671 /** 672 Set file's current position. 673 674 @param This Protocol instance pointer. 675 @param Position Byte position from the start of the file. 676 677 @retval EFI_SUCCESS Position was updated. 678 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open. 679 680 **/ 681 EFI_STATUS 682 EFIAPI 683 UdfSetPosition ( 684 IN EFI_FILE_PROTOCOL *This, 685 IN UINT64 Position 686 ) 687 { 688 EFI_STATUS Status; 689 PRIVATE_UDF_FILE_DATA *PrivFileData; 690 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc; 691 692 if (This == NULL) { 693 return EFI_INVALID_PARAMETER; 694 } 695 696 Status = EFI_UNSUPPORTED; 697 698 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); 699 700 FileIdentifierDesc = _FILE (PrivFileData)->FileIdentifierDesc; 701 ASSERT (FileIdentifierDesc != NULL); 702 if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) { 703 // 704 // If the file handle is a directory, the _only_ position that may be set is 705 // zero. This has no effect of starting the read proccess of the directory 706 // entries over. 707 // 708 if (Position == 0) { 709 PrivFileData->FilePosition = Position; 710 PrivFileData->ReadDirInfo.FidOffset = 0; 711 Status = EFI_SUCCESS; 712 } 713 } else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) { 714 // 715 // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be 716 // set to the EOF. 717 // 718 if (Position == 0xFFFFFFFFFFFFFFFF) { 719 PrivFileData->FilePosition = PrivFileData->FileSize; 720 } else { 721 PrivFileData->FilePosition = Position; 722 } 723 724 Status = EFI_SUCCESS; 725 } 726 727 return Status; 728 } 729 730 /** 731 Get information about a file. 732 733 @param This Protocol instance pointer. 734 @param InformationType Type of information to return in Buffer. 735 @param BufferSize On input size of buffer, on output amount of data in 736 buffer. 737 @param Buffer The buffer to return data. 738 739 @retval EFI_SUCCESS Data was returned. 740 @retval EFI_UNSUPPORTED InformationType is not supported. 741 @retval EFI_NO_MEDIA The device has no media. 742 @retval EFI_DEVICE_ERROR The device reported an error. 743 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 744 @retval EFI_WRITE_PROTECTED The device is write protected. 745 @retval EFI_ACCESS_DENIED The file was open for read only. 746 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in 747 BufferSize. 748 749 **/ 750 EFI_STATUS 751 EFIAPI 752 UdfGetInfo ( 753 IN EFI_FILE_PROTOCOL *This, 754 IN EFI_GUID *InformationType, 755 IN OUT UINTN *BufferSize, 756 OUT VOID *Buffer 757 ) 758 { 759 EFI_STATUS Status; 760 PRIVATE_UDF_FILE_DATA *PrivFileData; 761 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; 762 EFI_FILE_SYSTEM_INFO *FileSystemInfo; 763 UINTN FileSystemInfoLength; 764 UINT64 VolumeSize; 765 UINT64 FreeSpaceSize; 766 EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel; 767 UINTN FileSystemVolumeLabelLength; 768 CHAR16 VolumeLabel[64]; 769 770 if (This == NULL || InformationType == NULL || BufferSize == NULL || 771 (*BufferSize != 0 && Buffer == NULL)) { 772 return EFI_INVALID_PARAMETER; 773 } 774 775 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); 776 777 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs); 778 779 Status = EFI_UNSUPPORTED; 780 781 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { 782 Status = SetFileInfo ( 783 _FILE (PrivFileData), 784 PrivFileData->FileSize, 785 PrivFileData->FileName, 786 BufferSize, 787 Buffer 788 ); 789 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { 790 Status = GetVolumeLabel (&PrivFsData->Volume, ARRAY_SIZE (VolumeLabel), VolumeLabel); 791 if (EFI_ERROR (Status)) { 792 return Status; 793 } 794 795 FileSystemInfoLength = StrSize (VolumeLabel) + 796 sizeof (EFI_FILE_SYSTEM_INFO); 797 if (*BufferSize < FileSystemInfoLength) { 798 *BufferSize = FileSystemInfoLength; 799 return EFI_BUFFER_TOO_SMALL; 800 } 801 802 FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer; 803 StrCpyS ( 804 FileSystemInfo->VolumeLabel, 805 (*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_INFO) / sizeof (CHAR16), 806 VolumeLabel 807 ); 808 Status = GetVolumeSize ( 809 PrivFsData->BlockIo, 810 PrivFsData->DiskIo, 811 &PrivFsData->Volume, 812 &VolumeSize, 813 &FreeSpaceSize 814 ); 815 if (EFI_ERROR (Status)) { 816 return Status; 817 } 818 819 FileSystemInfo->Size = FileSystemInfoLength; 820 FileSystemInfo->ReadOnly = TRUE; 821 FileSystemInfo->BlockSize = 822 PrivFsData->Volume.LogicalVolDesc.LogicalBlockSize; 823 FileSystemInfo->VolumeSize = VolumeSize; 824 FileSystemInfo->FreeSpace = FreeSpaceSize; 825 826 *BufferSize = FileSystemInfoLength; 827 Status = EFI_SUCCESS; 828 } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { 829 Status = GetVolumeLabel (&PrivFsData->Volume, ARRAY_SIZE (VolumeLabel), VolumeLabel); 830 if (EFI_ERROR (Status)) { 831 return Status; 832 } 833 834 FileSystemVolumeLabelLength = StrSize (VolumeLabel) + 835 sizeof (EFI_FILE_SYSTEM_VOLUME_LABEL); 836 if (*BufferSize < FileSystemVolumeLabelLength) { 837 *BufferSize = FileSystemVolumeLabelLength; 838 return EFI_BUFFER_TOO_SMALL; 839 } 840 841 FileSystemVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer; 842 StrCpyS ( 843 FileSystemVolumeLabel->VolumeLabel, 844 (*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL) / sizeof (CHAR16), 845 VolumeLabel 846 ); 847 Status = EFI_SUCCESS; 848 } 849 850 return Status; 851 } 852 853 /** 854 Set information about a file. 855 856 @param This Protocol instance pointer. 857 @param InformationType Type of information in Buffer. 858 @param BufferSize Size of buffer. 859 @param Buffer The data to write. 860 861 @retval EFI_SUCCESS Data was set. 862 @retval EFI_UNSUPPORTED InformationType is not supported. 863 @retval EFI_NO_MEDIA The device has no media. 864 @retval EFI_DEVICE_ERROR The device reported an error. 865 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 866 @retval EFI_WRITE_PROTECTED The device is write protected. 867 @retval EFI_ACCESS_DENIED The file was open for read only. 868 869 **/ 870 EFI_STATUS 871 EFIAPI 872 UdfSetInfo ( 873 IN EFI_FILE_PROTOCOL *This, 874 IN EFI_GUID *InformationType, 875 IN UINTN BufferSize, 876 IN VOID *Buffer 877 ) 878 { 879 return EFI_WRITE_PROTECTED; 880 } 881 882 /** 883 Flush data back for the file handle. 884 885 @param This Protocol instance pointer. 886 887 @retval EFI_SUCCESS Data was flushed. 888 @retval EFI_UNSUPPORTED Writes to Open directory are not supported. 889 @retval EFI_NO_MEDIA The device has no media. 890 @retval EFI_DEVICE_ERROR The device reported an error. 891 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 892 @retval EFI_WRITE_PROTECTED The device is write protected. 893 @retval EFI_ACCESS_DENIED The file was open for read only. 894 @retval EFI_VOLUME_FULL The volume is full. 895 896 **/ 897 EFI_STATUS 898 EFIAPI 899 UdfFlush ( 900 IN EFI_FILE_PROTOCOL *This 901 ) 902 { 903 return EFI_WRITE_PROTECTED; 904 } 905