Home | History | Annotate | Download | only in Host
      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