1 /*++ @file 2 POSIX Pthreads to emulate APs and implement threads 3 4 Copyright (c) 2011, Apple Inc. All rights reserved. 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 14 **/ 15 16 #include "Host.h" 17 18 19 #define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 's') 20 21 typedef struct { 22 UINTN Signature; 23 EMU_IO_THUNK_PROTOCOL *Thunk; 24 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFileSystem; 25 CHAR8 *FilePath; 26 CHAR16 *VolumeLabel; 27 BOOLEAN FileHandlesOpen; 28 } EMU_SIMPLE_FILE_SYSTEM_PRIVATE; 29 30 #define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \ 31 CR (a, \ 32 EMU_SIMPLE_FILE_SYSTEM_PRIVATE, \ 33 SimpleFileSystem, \ 34 EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \ 35 ) 36 37 38 #define EMU_EFI_FILE_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 'i') 39 40 typedef struct { 41 UINTN Signature; 42 EMU_IO_THUNK_PROTOCOL *Thunk; 43 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; 44 EFI_FILE_PROTOCOL EfiFile; 45 int fd; 46 DIR *Dir; 47 BOOLEAN IsRootDirectory; 48 BOOLEAN IsDirectoryPath; 49 BOOLEAN IsOpenedByRead; 50 char *FileName; 51 struct dirent *Dirent; 52 } EMU_EFI_FILE_PRIVATE; 53 54 #define EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \ 55 CR (a, \ 56 EMU_EFI_FILE_PRIVATE, \ 57 EfiFile, \ 58 EMU_EFI_FILE_PRIVATE_SIGNATURE \ 59 ) 60 61 EFI_STATUS 62 PosixFileGetInfo ( 63 IN EFI_FILE_PROTOCOL *This, 64 IN EFI_GUID *InformationType, 65 IN OUT UINTN *BufferSize, 66 OUT VOID *Buffer 67 ); 68 69 EFI_STATUS 70 PosixFileSetInfo ( 71 IN EFI_FILE_PROTOCOL *This, 72 IN EFI_GUID *InformationType, 73 IN UINTN BufferSize, 74 IN VOID *Buffer 75 ); 76 77 78 EFI_FILE_PROTOCOL gPosixFileProtocol = { 79 EFI_FILE_REVISION, 80 GasketPosixFileOpen, 81 GasketPosixFileCLose, 82 GasketPosixFileDelete, 83 GasketPosixFileRead, 84 GasketPosixFileWrite, 85 GasketPosixFileGetPossition, 86 GasketPosixFileSetPossition, 87 GasketPosixFileGetInfo, 88 GasketPosixFileSetInfo, 89 GasketPosixFileFlush 90 }; 91 92 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gPosixFileSystemProtocol = { 93 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION, 94 GasketPosixOpenVolume, 95 }; 96 97 98 /** 99 Open the root directory on a volume. 100 101 @param This Protocol instance pointer. 102 @param Root Returns an Open file handle for the root directory 103 104 @retval EFI_SUCCESS The device was opened. 105 @retval EFI_UNSUPPORTED This volume does not support the file system. 106 @retval EFI_NO_MEDIA The device has no media. 107 @retval EFI_DEVICE_ERROR The device reported an error. 108 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 109 @retval EFI_ACCESS_DENIED The service denied access to the file. 110 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. 111 112 **/ 113 EFI_STATUS 114 PosixOpenVolume ( 115 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, 116 OUT EFI_FILE_PROTOCOL **Root 117 ) 118 { 119 EFI_STATUS Status; 120 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private; 121 EMU_EFI_FILE_PRIVATE *PrivateFile; 122 123 Private = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This); 124 125 Status = EFI_OUT_OF_RESOURCES; 126 PrivateFile = malloc (sizeof (EMU_EFI_FILE_PRIVATE)); 127 if (PrivateFile == NULL) { 128 goto Done; 129 } 130 131 PrivateFile->FileName = malloc (AsciiStrSize (Private->FilePath)); 132 if (PrivateFile->FileName == NULL) { 133 goto Done; 134 } 135 AsciiStrCpy (PrivateFile->FileName, Private->FilePath); 136 137 PrivateFile->Signature = EMU_EFI_FILE_PRIVATE_SIGNATURE; 138 PrivateFile->Thunk = Private->Thunk; 139 PrivateFile->SimpleFileSystem = This; 140 PrivateFile->IsRootDirectory = TRUE; 141 PrivateFile->IsDirectoryPath = TRUE; 142 PrivateFile->IsOpenedByRead = TRUE; 143 144 CopyMem (&PrivateFile->EfiFile, &gPosixFileProtocol, sizeof (EFI_FILE_PROTOCOL)); 145 146 PrivateFile->fd = -1; 147 PrivateFile->Dir = NULL; 148 PrivateFile->Dirent = NULL; 149 150 *Root = &PrivateFile->EfiFile; 151 152 PrivateFile->Dir = opendir (PrivateFile->FileName); 153 if (PrivateFile->Dir == NULL) { 154 Status = EFI_ACCESS_DENIED; 155 } else { 156 Status = EFI_SUCCESS; 157 } 158 159 Done: 160 if (EFI_ERROR (Status)) { 161 if (PrivateFile != NULL) { 162 if (PrivateFile->FileName != NULL) { 163 free (PrivateFile->FileName); 164 } 165 166 free (PrivateFile); 167 } 168 169 *Root = NULL; 170 } 171 172 return Status; 173 } 174 175 176 EFI_STATUS 177 ErrnoToEfiStatus () 178 { 179 switch (errno) { 180 case EACCES: 181 return EFI_ACCESS_DENIED; 182 183 case EDQUOT: 184 case ENOSPC: 185 return EFI_VOLUME_FULL; 186 187 default: 188 return EFI_DEVICE_ERROR; 189 } 190 } 191 192 VOID 193 CutPrefix ( 194 IN CHAR8 *Str, 195 IN UINTN Count 196 ) 197 { 198 CHAR8 *Pointer; 199 200 if (AsciiStrLen (Str) < Count) { 201 ASSERT (0); 202 } 203 204 for (Pointer = Str; *(Pointer + Count); Pointer++) { 205 *Pointer = *(Pointer + Count); 206 } 207 208 *Pointer = *(Pointer + Count); 209 } 210 211 212 VOID 213 PosixSystemTimeToEfiTime ( 214 IN time_t SystemTime, 215 OUT EFI_TIME *Time 216 ) 217 { 218 struct tm *tm; 219 220 tm = gmtime (&SystemTime); 221 Time->Year = tm->tm_year; 222 Time->Month = tm->tm_mon + 1; 223 Time->Day = tm->tm_mday; 224 Time->Hour = tm->tm_hour; 225 Time->Minute = tm->tm_min; 226 Time->Second = tm->tm_sec; 227 Time->Nanosecond = 0; 228 229 Time->TimeZone = timezone; 230 Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0) | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0); 231 } 232 233 234 EFI_STATUS 235 UnixSimpleFileSystemFileInfo ( 236 EMU_EFI_FILE_PRIVATE *PrivateFile, 237 IN CHAR8 *FileName, 238 IN OUT UINTN *BufferSize, 239 OUT VOID *Buffer 240 ) 241 { 242 EFI_STATUS Status; 243 UINTN Size; 244 UINTN NameSize; 245 UINTN ResultSize; 246 EFI_FILE_INFO *Info; 247 CHAR8 *RealFileName; 248 CHAR8 *TempPointer; 249 CHAR16 *BufferFileName; 250 struct stat buf; 251 252 if (FileName != NULL) { 253 RealFileName = FileName; 254 } else if (PrivateFile->IsRootDirectory) { 255 RealFileName = ""; 256 } else { 257 RealFileName = PrivateFile->FileName; 258 } 259 260 TempPointer = RealFileName; 261 while (*TempPointer) { 262 if (*TempPointer == '/') { 263 RealFileName = TempPointer + 1; 264 } 265 266 TempPointer++; 267 } 268 269 Size = SIZE_OF_EFI_FILE_INFO; 270 NameSize = AsciiStrSize (RealFileName) * 2; 271 ResultSize = Size + NameSize; 272 273 if (*BufferSize < ResultSize) { 274 *BufferSize = ResultSize; 275 return EFI_BUFFER_TOO_SMALL; 276 } 277 if (stat (FileName == NULL ? PrivateFile->FileName : FileName, &buf) < 0) { 278 return EFI_DEVICE_ERROR; 279 } 280 281 Status = EFI_SUCCESS; 282 283 Info = Buffer; 284 ZeroMem (Info, ResultSize); 285 286 Info->Size = ResultSize; 287 Info->FileSize = buf.st_size; 288 Info->PhysicalSize = MultU64x32 (buf.st_blocks, buf.st_blksize); 289 290 PosixSystemTimeToEfiTime (buf.st_ctime, &Info->CreateTime); 291 PosixSystemTimeToEfiTime (buf.st_atime, &Info->LastAccessTime); 292 PosixSystemTimeToEfiTime (buf.st_mtime, &Info->ModificationTime); 293 294 if (!(buf.st_mode & S_IWUSR)) { 295 Info->Attribute |= EFI_FILE_READ_ONLY; 296 } 297 298 if (S_ISDIR(buf.st_mode)) { 299 Info->Attribute |= EFI_FILE_DIRECTORY; 300 } 301 302 303 BufferFileName = (CHAR16 *)((CHAR8 *) Buffer + Size); 304 while (*RealFileName) { 305 *BufferFileName++ = *RealFileName++; 306 } 307 *BufferFileName = 0; 308 309 *BufferSize = ResultSize; 310 return Status; 311 } 312 313 BOOLEAN 314 IsZero ( 315 IN VOID *Buffer, 316 IN UINTN Length 317 ) 318 { 319 if (Buffer == NULL || Length == 0) { 320 return FALSE; 321 } 322 323 if (*(UINT8 *) Buffer != 0) { 324 return FALSE; 325 } 326 327 if (Length > 1) { 328 if (!CompareMem (Buffer, (UINT8 *) Buffer + 1, Length - 1)) { 329 return FALSE; 330 } 331 } 332 333 return TRUE; 334 } 335 336 337 338 /** 339 Opens a new file relative to the source file's location. 340 341 @param This The protocol instance pointer. 342 @param NewHandle Returns File Handle for FileName. 343 @param FileName Null terminated string. "\", ".", and ".." are supported. 344 @param OpenMode Open mode for file. 345 @param Attributes Only used for EFI_FILE_MODE_CREATE. 346 347 @retval EFI_SUCCESS The device was opened. 348 @retval EFI_NOT_FOUND The specified file could not be found on the device. 349 @retval EFI_NO_MEDIA The device has no media. 350 @retval EFI_MEDIA_CHANGED The media has changed. 351 @retval EFI_DEVICE_ERROR The device reported an error. 352 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 353 @retval EFI_ACCESS_DENIED The service denied access to the file. 354 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. 355 @retval EFI_VOLUME_FULL The volume is full. 356 357 **/ 358 EFI_STATUS 359 PosixFileOpen ( 360 IN EFI_FILE_PROTOCOL *This, 361 OUT EFI_FILE_PROTOCOL **NewHandle, 362 IN CHAR16 *FileName, 363 IN UINT64 OpenMode, 364 IN UINT64 Attributes 365 ) 366 { 367 EFI_FILE_PROTOCOL *Root; 368 EMU_EFI_FILE_PRIVATE *PrivateFile; 369 EMU_EFI_FILE_PRIVATE *NewPrivateFile; 370 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; 371 EFI_STATUS Status; 372 CHAR16 *Src; 373 char *Dst; 374 CHAR8 *RealFileName; 375 char *ParseFileName; 376 char *GuardPointer; 377 CHAR8 TempChar; 378 UINTN Count; 379 BOOLEAN TrailingDash; 380 BOOLEAN LoopFinish; 381 UINTN InfoSize; 382 EFI_FILE_INFO *Info; 383 struct stat finfo; 384 int res; 385 386 387 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); 388 PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); 389 NewPrivateFile = NULL; 390 Status = EFI_OUT_OF_RESOURCES; 391 392 // 393 // BUGBUG: assume an open of root 394 // if current location, return current data 395 // 396 TrailingDash = FALSE; 397 if ((StrCmp (FileName, L"\\") == 0) || 398 (StrCmp (FileName, L".") == 0 && PrivateFile->IsRootDirectory)) { 399 OpenRoot: 400 Status = PosixOpenVolume (PrivateFile->SimpleFileSystem, &Root); 401 NewPrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (Root); 402 goto Done; 403 } 404 405 if (FileName[StrLen (FileName) - 1] == L'\\') { 406 TrailingDash = TRUE; 407 FileName[StrLen (FileName) - 1] = 0; 408 } 409 410 // 411 // Attempt to open the file 412 // 413 NewPrivateFile = malloc (sizeof (EMU_EFI_FILE_PRIVATE)); 414 if (NewPrivateFile == NULL) { 415 goto Done; 416 } 417 418 CopyMem (NewPrivateFile, PrivateFile, sizeof (EMU_EFI_FILE_PRIVATE)); 419 420 NewPrivateFile->FileName = malloc (AsciiStrSize (PrivateFile->FileName) + 1 + StrLen (FileName) + 1); 421 if (NewPrivateFile->FileName == NULL) { 422 goto Done; 423 } 424 425 if (*FileName == L'\\') { 426 AsciiStrCpy (NewPrivateFile->FileName, PrivateRoot->FilePath); 427 // Skip first '\'. 428 Src = FileName + 1; 429 } else { 430 AsciiStrCpy (NewPrivateFile->FileName, PrivateFile->FileName); 431 Src = FileName; 432 } 433 Dst = NewPrivateFile->FileName + AsciiStrLen (NewPrivateFile->FileName); 434 GuardPointer = NewPrivateFile->FileName + AsciiStrLen (PrivateRoot->FilePath); 435 *Dst++ = '/'; 436 // Convert unicode to ascii and '\' to '/' 437 while (*Src) { 438 if (*Src == '\\') { 439 *Dst++ = '/'; 440 } else { 441 *Dst++ = *Src; 442 } 443 Src++; 444 } 445 *Dst = 0; 446 447 448 // 449 // Get rid of . and .., except leading . or .. 450 // 451 452 // 453 // GuardPointer protect simplefilesystem root path not be destroyed 454 // 455 456 LoopFinish = FALSE; 457 while (!LoopFinish) { 458 LoopFinish = TRUE; 459 460 for (ParseFileName = GuardPointer; *ParseFileName; ParseFileName++) { 461 if (*ParseFileName == '.' && 462 (*(ParseFileName + 1) == 0 || *(ParseFileName + 1) == '/') && 463 *(ParseFileName - 1) == '/' 464 ) { 465 466 // 467 // cut /. 468 // 469 CutPrefix (ParseFileName - 1, 2); 470 LoopFinish = FALSE; 471 break; 472 } 473 474 if (*ParseFileName == '.' && 475 *(ParseFileName + 1) == '.' && 476 (*(ParseFileName + 2) == 0 || *(ParseFileName + 2) == '/') && 477 *(ParseFileName - 1) == '/' 478 ) { 479 480 ParseFileName--; 481 Count = 3; 482 483 while (ParseFileName != GuardPointer) { 484 ParseFileName--; 485 Count++; 486 if (*ParseFileName == '/') { 487 break; 488 } 489 } 490 491 // 492 // cut /.. and its left directory 493 // 494 CutPrefix (ParseFileName, Count); 495 LoopFinish = FALSE; 496 break; 497 } 498 } 499 } 500 501 if (AsciiStrCmp (NewPrivateFile->FileName, PrivateRoot->FilePath) == 0) { 502 NewPrivateFile->IsRootDirectory = TRUE; 503 free (NewPrivateFile->FileName); 504 free (NewPrivateFile); 505 goto OpenRoot; 506 } 507 508 RealFileName = NewPrivateFile->FileName + AsciiStrLen(NewPrivateFile->FileName) - 1; 509 while (RealFileName > NewPrivateFile->FileName && *RealFileName != '/') { 510 RealFileName--; 511 } 512 513 TempChar = *(RealFileName - 1); 514 *(RealFileName - 1) = 0; 515 *(RealFileName - 1) = TempChar; 516 517 518 // 519 // Test whether file or directory 520 // 521 NewPrivateFile->IsRootDirectory = FALSE; 522 NewPrivateFile->fd = -1; 523 NewPrivateFile->Dir = NULL; 524 if (OpenMode & EFI_FILE_MODE_CREATE) { 525 if (Attributes & EFI_FILE_DIRECTORY) { 526 NewPrivateFile->IsDirectoryPath = TRUE; 527 } else { 528 NewPrivateFile->IsDirectoryPath = FALSE; 529 } 530 } else { 531 res = stat (NewPrivateFile->FileName, &finfo); 532 if (res == 0 && S_ISDIR(finfo.st_mode)) { 533 NewPrivateFile->IsDirectoryPath = TRUE; 534 } else { 535 NewPrivateFile->IsDirectoryPath = FALSE; 536 } 537 } 538 539 if (OpenMode & EFI_FILE_MODE_WRITE) { 540 NewPrivateFile->IsOpenedByRead = FALSE; 541 } else { 542 NewPrivateFile->IsOpenedByRead = TRUE; 543 } 544 545 Status = EFI_SUCCESS; 546 547 // 548 // deal with directory 549 // 550 if (NewPrivateFile->IsDirectoryPath) { 551 if ((OpenMode & EFI_FILE_MODE_CREATE)) { 552 // 553 // Create a directory 554 // 555 if (mkdir (NewPrivateFile->FileName, 0777) != 0) { 556 if (errno != EEXIST) { 557 //free (TempFileName); 558 Status = EFI_ACCESS_DENIED; 559 goto Done; 560 } 561 } 562 } 563 564 NewPrivateFile->Dir = opendir (NewPrivateFile->FileName); 565 if (NewPrivateFile->Dir == NULL) { 566 if (errno == EACCES) { 567 Status = EFI_ACCESS_DENIED; 568 } else { 569 Status = EFI_NOT_FOUND; 570 } 571 572 goto Done; 573 } 574 575 } else { 576 // 577 // deal with file 578 // 579 NewPrivateFile->fd = open ( 580 NewPrivateFile->FileName, 581 ((OpenMode & EFI_FILE_MODE_CREATE) ? O_CREAT : 0) | (NewPrivateFile->IsOpenedByRead ? O_RDONLY : O_RDWR), 582 0666 583 ); 584 if (NewPrivateFile->fd < 0) { 585 if (errno == ENOENT) { 586 Status = EFI_NOT_FOUND; 587 } else { 588 Status = EFI_ACCESS_DENIED; 589 } 590 } 591 } 592 593 if ((OpenMode & EFI_FILE_MODE_CREATE) && Status == EFI_SUCCESS) { 594 // 595 // Set the attribute 596 // 597 InfoSize = 0; 598 Info = NULL; 599 Status = PosixFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info); 600 if (Status != EFI_BUFFER_TOO_SMALL) { 601 Status = EFI_DEVICE_ERROR; 602 goto Done; 603 } 604 605 Info = malloc (InfoSize); 606 if (Info == NULL) { 607 goto Done; 608 } 609 610 Status = PosixFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info); 611 if (EFI_ERROR (Status)) { 612 goto Done; 613 } 614 615 Info->Attribute = Attributes; 616 PosixFileSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info); 617 618 free (Info); 619 } 620 621 Done: ; 622 if (TrailingDash) { 623 FileName[StrLen (FileName) + 1] = 0; 624 FileName[StrLen (FileName)] = L'\\'; 625 } 626 627 if (EFI_ERROR (Status)) { 628 if (NewPrivateFile) { 629 if (NewPrivateFile->FileName) { 630 free (NewPrivateFile->FileName); 631 } 632 633 free (NewPrivateFile); 634 } 635 } else { 636 *NewHandle = &NewPrivateFile->EfiFile; 637 } 638 639 return Status; 640 } 641 642 643 644 /** 645 Close the file handle 646 647 @param This Protocol instance pointer. 648 649 @retval EFI_SUCCESS The device was opened. 650 651 **/ 652 EFI_STATUS 653 PosixFileCLose ( 654 IN EFI_FILE_PROTOCOL *This 655 ) 656 { 657 EMU_EFI_FILE_PRIVATE *PrivateFile; 658 659 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); 660 661 if (PrivateFile->fd >= 0) { 662 close (PrivateFile->fd); 663 } 664 if (PrivateFile->Dir != NULL) { 665 closedir (PrivateFile->Dir); 666 } 667 668 PrivateFile->fd = -1; 669 PrivateFile->Dir = NULL; 670 671 if (PrivateFile->FileName) { 672 free (PrivateFile->FileName); 673 } 674 675 free (PrivateFile); 676 677 return EFI_SUCCESS; 678 } 679 680 681 /** 682 Close and delete the file handle. 683 684 @param This Protocol instance pointer. 685 686 @retval EFI_SUCCESS The device was opened. 687 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted. 688 689 **/ 690 EFI_STATUS 691 PosixFileDelete ( 692 IN EFI_FILE_PROTOCOL *This 693 ) 694 { 695 EFI_STATUS Status; 696 EMU_EFI_FILE_PRIVATE *PrivateFile; 697 698 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); 699 Status = EFI_WARN_DELETE_FAILURE; 700 701 if (PrivateFile->IsDirectoryPath) { 702 if (PrivateFile->Dir != NULL) { 703 closedir (PrivateFile->Dir); 704 PrivateFile->Dir = NULL; 705 } 706 707 if (rmdir (PrivateFile->FileName) == 0) { 708 Status = EFI_SUCCESS; 709 } 710 } else { 711 close (PrivateFile->fd); 712 PrivateFile->fd = -1; 713 714 if (!PrivateFile->IsOpenedByRead) { 715 if (!unlink (PrivateFile->FileName)) { 716 Status = EFI_SUCCESS; 717 } 718 } 719 } 720 721 free (PrivateFile->FileName); 722 free (PrivateFile); 723 724 return Status; 725 } 726 727 728 /** 729 Read data from the file. 730 731 @param This Protocol instance pointer. 732 @param BufferSize On input size of buffer, on output amount of data in buffer. 733 @param Buffer The buffer in which data is read. 734 735 @retval EFI_SUCCESS Data was read. 736 @retval EFI_NO_MEDIA The device has no media. 737 @retval EFI_DEVICE_ERROR The device reported an error. 738 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 739 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size. 740 741 **/ 742 EFI_STATUS 743 PosixFileRead ( 744 IN EFI_FILE_PROTOCOL *This, 745 IN OUT UINTN *BufferSize, 746 OUT VOID *Buffer 747 ) 748 { 749 EMU_EFI_FILE_PRIVATE *PrivateFile; 750 EFI_STATUS Status; 751 int Res; 752 UINTN Size; 753 UINTN NameSize; 754 UINTN ResultSize; 755 CHAR8 *FullFileName; 756 757 758 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); 759 760 if (!PrivateFile->IsDirectoryPath) { 761 if (PrivateFile->fd < 0) { 762 Status = EFI_DEVICE_ERROR; 763 goto Done; 764 } 765 766 Res = read (PrivateFile->fd, Buffer, *BufferSize); 767 if (Res < 0) { 768 Status = EFI_DEVICE_ERROR; 769 goto Done; 770 } 771 *BufferSize = Res; 772 Status = EFI_SUCCESS; 773 goto Done; 774 } 775 776 // 777 // Read on a directory. 778 // 779 if (PrivateFile->Dir == NULL) { 780 Status = EFI_DEVICE_ERROR; 781 goto Done; 782 } 783 784 if (PrivateFile->Dirent == NULL) { 785 PrivateFile->Dirent = readdir (PrivateFile->Dir); 786 if (PrivateFile->Dirent == NULL) { 787 *BufferSize = 0; 788 Status = EFI_SUCCESS; 789 goto Done; 790 } 791 } 792 793 Size = SIZE_OF_EFI_FILE_INFO; 794 NameSize = AsciiStrLen (PrivateFile->Dirent->d_name) + 1; 795 ResultSize = Size + 2 * NameSize; 796 797 if (*BufferSize < ResultSize) { 798 *BufferSize = ResultSize; 799 Status = EFI_BUFFER_TOO_SMALL; 800 goto Done; 801 } 802 Status = EFI_SUCCESS; 803 804 *BufferSize = ResultSize; 805 806 FullFileName = malloc (AsciiStrLen(PrivateFile->FileName) + 1 + NameSize); 807 if (FullFileName == NULL) { 808 Status = EFI_OUT_OF_RESOURCES; 809 goto Done; 810 } 811 812 AsciiStrCpy (FullFileName, PrivateFile->FileName); 813 AsciiStrCat (FullFileName, "/"); 814 AsciiStrCat (FullFileName, PrivateFile->Dirent->d_name); 815 Status = UnixSimpleFileSystemFileInfo ( 816 PrivateFile, 817 FullFileName, 818 BufferSize, 819 Buffer 820 ); 821 free (FullFileName); 822 823 PrivateFile->Dirent = NULL; 824 825 Done: 826 return Status; 827 } 828 829 830 831 /** 832 Write data to a file. 833 834 @param This Protocol instance pointer. 835 @param BufferSize On input size of buffer, on output amount of data in buffer. 836 @param Buffer The buffer in which data to write. 837 838 @retval EFI_SUCCESS Data was written. 839 @retval EFI_UNSUPPORTED Writes to Open directory are not supported. 840 @retval EFI_NO_MEDIA The device has no media. 841 @retval EFI_DEVICE_ERROR The device reported an error. 842 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file. 843 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 844 @retval EFI_WRITE_PROTECTED The device is write protected. 845 @retval EFI_ACCESS_DENIED The file was open for read only. 846 @retval EFI_VOLUME_FULL The volume is full. 847 848 **/ 849 EFI_STATUS 850 PosixFileWrite ( 851 IN EFI_FILE_PROTOCOL *This, 852 IN OUT UINTN *BufferSize, 853 IN VOID *Buffer 854 ) 855 { 856 EMU_EFI_FILE_PRIVATE *PrivateFile; 857 int Res; 858 859 860 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); 861 862 if (PrivateFile->fd < 0) { 863 return EFI_DEVICE_ERROR; 864 } 865 866 if (PrivateFile->IsDirectoryPath) { 867 return EFI_UNSUPPORTED; 868 } 869 870 if (PrivateFile->IsOpenedByRead) { 871 return EFI_ACCESS_DENIED; 872 } 873 874 Res = write (PrivateFile->fd, Buffer, *BufferSize); 875 if (Res == (UINTN)-1) { 876 return ErrnoToEfiStatus (); 877 } 878 879 *BufferSize = Res; 880 return EFI_SUCCESS; 881 } 882 883 884 885 /** 886 Set a files current position 887 888 @param This Protocol instance pointer. 889 @param Position Byte position from the start of the file. 890 891 @retval EFI_SUCCESS Data was written. 892 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open. 893 894 **/ 895 EFI_STATUS 896 PosixFileSetPossition ( 897 IN EFI_FILE_PROTOCOL *This, 898 IN UINT64 Position 899 ) 900 { 901 EMU_EFI_FILE_PRIVATE *PrivateFile; 902 off_t Pos; 903 904 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); 905 906 if (PrivateFile->IsDirectoryPath) { 907 if (Position != 0) { 908 return EFI_UNSUPPORTED; 909 } 910 911 if (PrivateFile->Dir == NULL) { 912 return EFI_DEVICE_ERROR; 913 } 914 rewinddir (PrivateFile->Dir); 915 return EFI_SUCCESS; 916 } else { 917 if (Position == (UINT64) -1) { 918 Pos = lseek (PrivateFile->fd, 0, SEEK_END); 919 } else { 920 Pos = lseek (PrivateFile->fd, Position, SEEK_SET); 921 } 922 if (Pos == (off_t)-1) { 923 return ErrnoToEfiStatus (); 924 } 925 return EFI_SUCCESS; 926 } 927 } 928 929 930 931 /** 932 Get a file's current position 933 934 @param This Protocol instance pointer. 935 @param Position Byte position from the start of the file. 936 937 @retval EFI_SUCCESS Data was written. 938 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.. 939 940 **/ 941 EFI_STATUS 942 PosixFileGetPossition ( 943 IN EFI_FILE_PROTOCOL *This, 944 OUT UINT64 *Position 945 ) 946 { 947 EFI_STATUS Status; 948 EMU_EFI_FILE_PRIVATE *PrivateFile; 949 950 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); 951 952 if (PrivateFile->IsDirectoryPath) { 953 Status = EFI_UNSUPPORTED; 954 } else { 955 *Position = (UINT64)lseek (PrivateFile->fd, 0, SEEK_CUR); 956 Status = (*Position == (UINT64) -1) ? ErrnoToEfiStatus () : EFI_SUCCESS; 957 } 958 959 return Status; 960 } 961 962 963 /** 964 Get information about a file. 965 966 @param This Protocol instance pointer. 967 @param InformationType Type of information to return in Buffer. 968 @param BufferSize On input size of buffer, on output amount of data in buffer. 969 @param Buffer The buffer to return data. 970 971 @retval EFI_SUCCESS Data was returned. 972 @retval EFI_UNSUPPORTED InformationType is not supported. 973 @retval EFI_NO_MEDIA The device has no media. 974 @retval EFI_DEVICE_ERROR The device reported an error. 975 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 976 @retval EFI_WRITE_PROTECTED The device is write protected. 977 @retval EFI_ACCESS_DENIED The file was open for read only. 978 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize. 979 980 **/ 981 EFI_STATUS 982 PosixFileGetInfo ( 983 IN EFI_FILE_PROTOCOL *This, 984 IN EFI_GUID *InformationType, 985 IN OUT UINTN *BufferSize, 986 OUT VOID *Buffer 987 ) 988 { 989 EFI_STATUS Status; 990 EMU_EFI_FILE_PRIVATE *PrivateFile; 991 EFI_FILE_SYSTEM_INFO *FileSystemInfoBuffer; 992 int UnixStatus; 993 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; 994 struct statfs buf; 995 996 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); 997 PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); 998 999 Status = EFI_SUCCESS; 1000 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { 1001 Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, BufferSize, Buffer); 1002 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { 1003 if (*BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) { 1004 *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); 1005 return EFI_BUFFER_TOO_SMALL; 1006 } 1007 1008 UnixStatus = statfs (PrivateFile->FileName, &buf); 1009 if (UnixStatus < 0) { 1010 return EFI_DEVICE_ERROR; 1011 } 1012 1013 FileSystemInfoBuffer = (EFI_FILE_SYSTEM_INFO *) Buffer; 1014 FileSystemInfoBuffer->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); 1015 FileSystemInfoBuffer->ReadOnly = FALSE; 1016 1017 // 1018 // Succeeded 1019 // 1020 FileSystemInfoBuffer->VolumeSize = MultU64x32 (buf.f_blocks, buf.f_bsize); 1021 FileSystemInfoBuffer->FreeSpace = MultU64x32 (buf.f_bavail, buf.f_bsize); 1022 FileSystemInfoBuffer->BlockSize = buf.f_bsize; 1023 1024 1025 StrCpy ((CHAR16 *) FileSystemInfoBuffer->VolumeLabel, PrivateRoot->VolumeLabel); 1026 *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); 1027 1028 } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { 1029 if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) { 1030 *BufferSize = StrSize (PrivateRoot->VolumeLabel); 1031 return EFI_BUFFER_TOO_SMALL; 1032 } 1033 1034 StrCpy ((CHAR16 *) Buffer, PrivateRoot->VolumeLabel); 1035 *BufferSize = StrSize (PrivateRoot->VolumeLabel); 1036 1037 } 1038 1039 return Status; 1040 } 1041 1042 1043 /** 1044 Set information about a file 1045 1046 @param File Protocol instance pointer. 1047 @param InformationType Type of information in Buffer. 1048 @param BufferSize Size of buffer. 1049 @param Buffer The data to write. 1050 1051 @retval EFI_SUCCESS Data was returned. 1052 @retval EFI_UNSUPPORTED InformationType is not supported. 1053 @retval EFI_NO_MEDIA The device has no media. 1054 @retval EFI_DEVICE_ERROR The device reported an error. 1055 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 1056 @retval EFI_WRITE_PROTECTED The device is write protected. 1057 @retval EFI_ACCESS_DENIED The file was open for read only. 1058 1059 **/ 1060 EFI_STATUS 1061 PosixFileSetInfo ( 1062 IN EFI_FILE_PROTOCOL *This, 1063 IN EFI_GUID *InformationType, 1064 IN UINTN BufferSize, 1065 IN VOID *Buffer 1066 ) 1067 { 1068 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; 1069 EMU_EFI_FILE_PRIVATE *PrivateFile; 1070 EFI_FILE_INFO *OldFileInfo; 1071 EFI_FILE_INFO *NewFileInfo; 1072 EFI_STATUS Status; 1073 UINTN OldInfoSize; 1074 mode_t NewAttr; 1075 struct stat OldAttr; 1076 CHAR8 *OldFileName; 1077 CHAR8 *NewFileName; 1078 CHAR8 *CharPointer; 1079 BOOLEAN AttrChangeFlag; 1080 BOOLEAN NameChangeFlag; 1081 BOOLEAN SizeChangeFlag; 1082 BOOLEAN TimeChangeFlag; 1083 struct tm NewLastAccessSystemTime; 1084 struct tm NewLastWriteSystemTime; 1085 EFI_FILE_SYSTEM_INFO *NewFileSystemInfo; 1086 CHAR8 *AsciiFilePtr; 1087 CHAR16 *UnicodeFilePtr; 1088 int UnixStatus; 1089 struct utimbuf Utime; 1090 1091 1092 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); 1093 PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); 1094 errno = 0; 1095 Status = EFI_UNSUPPORTED; 1096 OldFileInfo = NewFileInfo = NULL; 1097 OldFileName = NewFileName = NULL; 1098 AttrChangeFlag = NameChangeFlag = SizeChangeFlag = TimeChangeFlag = FALSE; 1099 1100 // 1101 // Set file system information. 1102 // 1103 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { 1104 if (BufferSize < (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel))) { 1105 Status = EFI_BAD_BUFFER_SIZE; 1106 goto Done; 1107 } 1108 1109 NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *) Buffer; 1110 1111 free (PrivateRoot->VolumeLabel); 1112 1113 PrivateRoot->VolumeLabel = malloc (StrSize (NewFileSystemInfo->VolumeLabel)); 1114 if (PrivateRoot->VolumeLabel == NULL) { 1115 goto Done; 1116 } 1117 1118 StrCpy (PrivateRoot->VolumeLabel, NewFileSystemInfo->VolumeLabel); 1119 1120 Status = EFI_SUCCESS; 1121 goto Done; 1122 } 1123 1124 // 1125 // Set volume label information. 1126 // 1127 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { 1128 if (BufferSize < StrSize (PrivateRoot->VolumeLabel)) { 1129 Status = EFI_BAD_BUFFER_SIZE; 1130 goto Done; 1131 } 1132 1133 StrCpy (PrivateRoot->VolumeLabel, (CHAR16 *) Buffer); 1134 1135 Status = EFI_SUCCESS; 1136 goto Done; 1137 } 1138 1139 if (!CompareGuid (InformationType, &gEfiFileInfoGuid)) { 1140 Status = EFI_UNSUPPORTED; 1141 goto Done; 1142 } 1143 1144 if (BufferSize < SIZE_OF_EFI_FILE_INFO) { 1145 Status = EFI_BAD_BUFFER_SIZE; 1146 goto Done; 1147 } 1148 1149 // 1150 // Set file/directory information. 1151 // 1152 1153 // 1154 // Check for invalid set file information parameters. 1155 // 1156 NewFileInfo = (EFI_FILE_INFO *) Buffer; 1157 if (NewFileInfo->Size <= sizeof (EFI_FILE_INFO) || 1158 (NewFileInfo->Attribute &~(EFI_FILE_VALID_ATTR)) || 1159 (sizeof (UINTN) == 4 && NewFileInfo->Size > 0xFFFFFFFF) 1160 ) { 1161 Status = EFI_INVALID_PARAMETER; 1162 goto Done; 1163 } 1164 1165 // 1166 // Get current file information so we can determine what kind 1167 // of change request this is. 1168 // 1169 OldInfoSize = 0; 1170 Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, NULL); 1171 if (Status != EFI_BUFFER_TOO_SMALL) { 1172 Status = EFI_DEVICE_ERROR; 1173 goto Done; 1174 } 1175 1176 OldFileInfo = malloc (OldInfoSize); 1177 if (OldFileInfo == NULL) { 1178 goto Done; 1179 } 1180 1181 Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, OldFileInfo); 1182 if (EFI_ERROR (Status)) { 1183 goto Done; 1184 } 1185 1186 OldFileName = malloc (AsciiStrSize (PrivateFile->FileName)); 1187 if (OldFileInfo == NULL) { 1188 goto Done; 1189 } 1190 1191 AsciiStrCpy (OldFileName, PrivateFile->FileName); 1192 1193 // 1194 // Make full pathname from new filename and rootpath. 1195 // 1196 if (NewFileInfo->FileName[0] == '\\') { 1197 NewFileName = malloc (AsciiStrLen (PrivateRoot->FilePath) + 1 + StrLen (NewFileInfo->FileName) + 1); 1198 if (NewFileName == NULL) { 1199 goto Done; 1200 } 1201 1202 AsciiStrCpy (NewFileName, PrivateRoot->FilePath); 1203 AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName); 1204 UnicodeFilePtr = NewFileInfo->FileName + 1; 1205 *AsciiFilePtr++ ='/'; 1206 } else { 1207 NewFileName = malloc (AsciiStrLen (PrivateFile->FileName) + 2 + StrLen (NewFileInfo->FileName) + 1); 1208 if (NewFileName == NULL) { 1209 goto Done; 1210 } 1211 1212 AsciiStrCpy (NewFileName, PrivateRoot->FilePath); 1213 AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName); 1214 if ((AsciiFilePtr[-1] != '/') && (NewFileInfo->FileName[0] != '/')) { 1215 // make sure there is a / between Root FilePath and NewFileInfo Filename 1216 AsciiFilePtr[0] = '/'; 1217 AsciiFilePtr[1] = '\0'; 1218 AsciiFilePtr++; 1219 } 1220 UnicodeFilePtr = NewFileInfo->FileName; 1221 } 1222 // Convert to ascii. 1223 while (*UnicodeFilePtr) { 1224 *AsciiFilePtr++ = *UnicodeFilePtr++; 1225 } 1226 *AsciiFilePtr = 0; 1227 1228 // 1229 // Is there an attribute change request? 1230 // 1231 if (NewFileInfo->Attribute != OldFileInfo->Attribute) { 1232 if ((NewFileInfo->Attribute & EFI_FILE_DIRECTORY) != (OldFileInfo->Attribute & EFI_FILE_DIRECTORY)) { 1233 Status = EFI_INVALID_PARAMETER; 1234 goto Done; 1235 } 1236 1237 AttrChangeFlag = TRUE; 1238 } 1239 1240 // 1241 // Is there a name change request? 1242 // bugbug: - Should really use EFI_UNICODE_COLLATION_PROTOCOL 1243 // 1244 if (StrCmp (NewFileInfo->FileName, OldFileInfo->FileName)) { 1245 NameChangeFlag = TRUE; 1246 } 1247 1248 // 1249 // Is there a size change request? 1250 // 1251 if (NewFileInfo->FileSize != OldFileInfo->FileSize) { 1252 SizeChangeFlag = TRUE; 1253 } 1254 1255 // 1256 // Is there a time stamp change request? 1257 // 1258 if (!IsZero (&NewFileInfo->CreateTime, sizeof (EFI_TIME)) && 1259 CompareMem (&NewFileInfo->CreateTime, &OldFileInfo->CreateTime, sizeof (EFI_TIME)) 1260 ) { 1261 TimeChangeFlag = TRUE; 1262 } else if (!IsZero (&NewFileInfo->LastAccessTime, sizeof (EFI_TIME)) && 1263 CompareMem (&NewFileInfo->LastAccessTime, &OldFileInfo->LastAccessTime, sizeof (EFI_TIME)) 1264 ) { 1265 TimeChangeFlag = TRUE; 1266 } else if (!IsZero (&NewFileInfo->ModificationTime, sizeof (EFI_TIME)) && 1267 CompareMem (&NewFileInfo->ModificationTime, &OldFileInfo->ModificationTime, sizeof (EFI_TIME)) 1268 ) { 1269 TimeChangeFlag = TRUE; 1270 } 1271 1272 // 1273 // All done if there are no change requests being made. 1274 // 1275 if (!(AttrChangeFlag || NameChangeFlag || SizeChangeFlag || TimeChangeFlag)) { 1276 Status = EFI_SUCCESS; 1277 goto Done; 1278 } 1279 1280 // 1281 // Set file or directory information. 1282 // 1283 if (stat (OldFileName, &OldAttr) != 0) { 1284 Status = ErrnoToEfiStatus (); 1285 goto Done; 1286 } 1287 1288 // 1289 // Name change. 1290 // 1291 if (NameChangeFlag) { 1292 // 1293 // Close the handles first 1294 // 1295 if (PrivateFile->IsOpenedByRead) { 1296 Status = EFI_ACCESS_DENIED; 1297 goto Done; 1298 } 1299 1300 for (CharPointer = NewFileName; *CharPointer != 0 && *CharPointer != L'/'; CharPointer++) { 1301 } 1302 1303 if (*CharPointer != 0) { 1304 Status = EFI_ACCESS_DENIED; 1305 goto Done; 1306 } 1307 1308 UnixStatus = rename (OldFileName, NewFileName); 1309 if (UnixStatus == 0) { 1310 // 1311 // modify file name 1312 // 1313 free (PrivateFile->FileName); 1314 1315 PrivateFile->FileName = malloc (AsciiStrSize (NewFileName)); 1316 if (PrivateFile->FileName == NULL) { 1317 goto Done; 1318 } 1319 1320 AsciiStrCpy (PrivateFile->FileName, NewFileName); 1321 } else { 1322 Status = EFI_DEVICE_ERROR; 1323 goto Done; 1324 } 1325 } 1326 1327 // 1328 // Size change 1329 // 1330 if (SizeChangeFlag) { 1331 if (PrivateFile->IsDirectoryPath) { 1332 Status = EFI_UNSUPPORTED; 1333 goto Done; 1334 } 1335 1336 if (PrivateFile->IsOpenedByRead || OldFileInfo->Attribute & EFI_FILE_READ_ONLY) { 1337 Status = EFI_ACCESS_DENIED; 1338 goto Done; 1339 } 1340 1341 if (ftruncate (PrivateFile->fd, NewFileInfo->FileSize) != 0) { 1342 Status = ErrnoToEfiStatus (); 1343 goto Done; 1344 } 1345 1346 } 1347 1348 // 1349 // Time change 1350 // 1351 if (TimeChangeFlag) { 1352 NewLastAccessSystemTime.tm_year = NewFileInfo->LastAccessTime.Year; 1353 NewLastAccessSystemTime.tm_mon = NewFileInfo->LastAccessTime.Month; 1354 NewLastAccessSystemTime.tm_mday = NewFileInfo->LastAccessTime.Day; 1355 NewLastAccessSystemTime.tm_hour = NewFileInfo->LastAccessTime.Hour; 1356 NewLastAccessSystemTime.tm_min = NewFileInfo->LastAccessTime.Minute; 1357 NewLastAccessSystemTime.tm_sec = NewFileInfo->LastAccessTime.Second; 1358 NewLastAccessSystemTime.tm_isdst = 0; 1359 1360 Utime.actime = mktime (&NewLastAccessSystemTime); 1361 1362 NewLastWriteSystemTime.tm_year = NewFileInfo->ModificationTime.Year; 1363 NewLastWriteSystemTime.tm_mon = NewFileInfo->ModificationTime.Month; 1364 NewLastWriteSystemTime.tm_mday = NewFileInfo->ModificationTime.Day; 1365 NewLastWriteSystemTime.tm_hour = NewFileInfo->ModificationTime.Hour; 1366 NewLastWriteSystemTime.tm_min = NewFileInfo->ModificationTime.Minute; 1367 NewLastWriteSystemTime.tm_sec = NewFileInfo->ModificationTime.Second; 1368 NewLastWriteSystemTime.tm_isdst = 0; 1369 1370 Utime.modtime = mktime (&NewLastWriteSystemTime); 1371 1372 if (Utime.actime == (time_t)-1 || Utime.modtime == (time_t)-1) { 1373 goto Done; 1374 } 1375 1376 if (utime (PrivateFile->FileName, &Utime) == -1) { 1377 Status = ErrnoToEfiStatus (); 1378 goto Done; 1379 } 1380 } 1381 1382 // 1383 // No matter about AttrChangeFlag, Attribute must be set. 1384 // Because operation before may cause attribute change. 1385 // 1386 NewAttr = OldAttr.st_mode; 1387 1388 if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) { 1389 NewAttr &= ~(S_IRUSR | S_IRGRP | S_IROTH); 1390 } else { 1391 NewAttr |= S_IRUSR; 1392 } 1393 1394 if (chmod (NewFileName, NewAttr) != 0) { 1395 Status = ErrnoToEfiStatus (); 1396 } 1397 1398 Done: 1399 if (OldFileInfo != NULL) { 1400 free (OldFileInfo); 1401 } 1402 1403 if (OldFileName != NULL) { 1404 free (OldFileName); 1405 } 1406 1407 if (NewFileName != NULL) { 1408 free (NewFileName); 1409 } 1410 1411 return Status; 1412 } 1413 1414 1415 /** 1416 Flush data back for the file handle. 1417 1418 @param This Protocol instance pointer. 1419 1420 @retval EFI_SUCCESS Data was written. 1421 @retval EFI_UNSUPPORTED Writes to Open directory are not supported. 1422 @retval EFI_NO_MEDIA The device has no media. 1423 @retval EFI_DEVICE_ERROR The device reported an error. 1424 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 1425 @retval EFI_WRITE_PROTECTED The device is write protected. 1426 @retval EFI_ACCESS_DENIED The file was open for read only. 1427 @retval EFI_VOLUME_FULL The volume is full. 1428 1429 **/ 1430 EFI_STATUS 1431 PosixFileFlush ( 1432 IN EFI_FILE_PROTOCOL *This 1433 ) 1434 { 1435 EMU_EFI_FILE_PRIVATE *PrivateFile; 1436 1437 1438 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); 1439 1440 if (PrivateFile->IsDirectoryPath) { 1441 return EFI_UNSUPPORTED; 1442 } 1443 1444 if (PrivateFile->IsOpenedByRead) { 1445 return EFI_ACCESS_DENIED; 1446 } 1447 1448 if (PrivateFile->fd < 0) { 1449 return EFI_DEVICE_ERROR; 1450 } 1451 1452 if (fsync (PrivateFile->fd) != 0) { 1453 return ErrnoToEfiStatus (); 1454 } 1455 1456 return EFI_SUCCESS; 1457 } 1458 1459 1460 1461 EFI_STATUS 1462 PosixFileSystmeThunkOpen ( 1463 IN EMU_IO_THUNK_PROTOCOL *This 1464 ) 1465 { 1466 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private; 1467 UINTN i; 1468 1469 if (This->Private != NULL) { 1470 return EFI_ALREADY_STARTED; 1471 } 1472 1473 if (!CompareGuid (This->Protocol, &gEfiSimpleFileSystemProtocolGuid)) { 1474 return EFI_UNSUPPORTED; 1475 } 1476 1477 Private = malloc (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE)); 1478 if (Private == NULL) { 1479 return EFI_OUT_OF_RESOURCES; 1480 } 1481 1482 Private->FilePath = malloc (StrLen (This->ConfigString) + 1); 1483 if (Private->FilePath == NULL) { 1484 free (Private); 1485 return EFI_OUT_OF_RESOURCES; 1486 } 1487 1488 // Convert Unicode to Ascii 1489 for (i = 0; This->ConfigString[i] != 0; i++) { 1490 Private->FilePath[i] = This->ConfigString[i]; 1491 } 1492 Private->FilePath[i] = 0; 1493 1494 1495 Private->VolumeLabel = malloc (StrSize (L"EFI_EMULATED")); 1496 if (Private->VolumeLabel == NULL) { 1497 free (Private->FilePath); 1498 free (Private); 1499 return EFI_OUT_OF_RESOURCES; 1500 } 1501 StrCpy (Private->VolumeLabel, L"EFI_EMULATED"); 1502 1503 Private->Signature = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE; 1504 Private->Thunk = This; 1505 CopyMem (&Private->SimpleFileSystem, &gPosixFileSystemProtocol, sizeof (Private->SimpleFileSystem)); 1506 Private->FileHandlesOpen = FALSE; 1507 1508 This->Interface = &Private->SimpleFileSystem; 1509 This->Private = Private; 1510 return EFI_SUCCESS; 1511 } 1512 1513 1514 EFI_STATUS 1515 PosixFileSystmeThunkClose ( 1516 IN EMU_IO_THUNK_PROTOCOL *This 1517 ) 1518 { 1519 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private; 1520 1521 if (!CompareGuid (This->Protocol, &gEfiSimpleFileSystemProtocolGuid)) { 1522 return EFI_UNSUPPORTED; 1523 } 1524 1525 Private = This->Private; 1526 1527 if (Private->FileHandlesOpen) { 1528 // 1529 // Close only supported if all the EFI_FILE_HANDLEs have been closed. 1530 // 1531 return EFI_NOT_READY; 1532 } 1533 1534 if (This->Private != NULL) { 1535 if (Private->VolumeLabel != NULL) { 1536 free (Private->VolumeLabel); 1537 } 1538 free (This->Private); 1539 This->Private = NULL; 1540 } 1541 1542 return EFI_SUCCESS; 1543 } 1544 1545 1546 EMU_IO_THUNK_PROTOCOL gPosixFileSystemThunkIo = { 1547 &gEfiSimpleFileSystemProtocolGuid, 1548 NULL, 1549 NULL, 1550 0, 1551 GasketPosixFileSystmeThunkOpen, 1552 GasketPosixFileSystmeThunkClose, 1553 NULL 1554 }; 1555 1556 1557