REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the EmulatorPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
		
			
				
	
	
		
			1573 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1573 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++ @file
 | |
|  POSIX Pthreads to emulate APs and implement threads
 | |
| 
 | |
| Copyright (c) 2011, Apple Inc. All rights reserved.
 | |
| Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
 | |
| SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "Host.h"
 | |
| 
 | |
| #define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE  SIGNATURE_32 ('E', 'P', 'f', 's')
 | |
| 
 | |
| typedef struct {
 | |
|   UINTN                              Signature;
 | |
|   EMU_IO_THUNK_PROTOCOL              *Thunk;
 | |
|   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL    SimpleFileSystem;
 | |
|   CHAR8                              *FilePath;
 | |
|   CHAR16                             *VolumeLabel;
 | |
|   BOOLEAN                            FileHandlesOpen;
 | |
| } EMU_SIMPLE_FILE_SYSTEM_PRIVATE;
 | |
| 
 | |
| #define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \
 | |
|   CR (a, \
 | |
|       EMU_SIMPLE_FILE_SYSTEM_PRIVATE, \
 | |
|       SimpleFileSystem, \
 | |
|       EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \
 | |
|       )
 | |
| 
 | |
| #define EMU_EFI_FILE_PRIVATE_SIGNATURE  SIGNATURE_32 ('E', 'P', 'f', 'i')
 | |
| 
 | |
| typedef struct {
 | |
|   UINTN                              Signature;
 | |
|   EMU_IO_THUNK_PROTOCOL              *Thunk;
 | |
|   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL    *SimpleFileSystem;
 | |
|   EFI_FILE_PROTOCOL                  EfiFile;
 | |
|   int                                fd;
 | |
|   DIR                                *Dir;
 | |
|   BOOLEAN                            IsRootDirectory;
 | |
|   BOOLEAN                            IsDirectoryPath;
 | |
|   BOOLEAN                            IsOpenedByRead;
 | |
|   char                               *FileName;
 | |
|   struct dirent                      *Dirent;
 | |
| } EMU_EFI_FILE_PRIVATE;
 | |
| 
 | |
| #define EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \
 | |
|   CR (a, \
 | |
|       EMU_EFI_FILE_PRIVATE, \
 | |
|       EfiFile, \
 | |
|       EMU_EFI_FILE_PRIVATE_SIGNATURE \
 | |
|       )
 | |
| 
 | |
| EFI_STATUS
 | |
| PosixFileGetInfo (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   IN EFI_GUID           *InformationType,
 | |
|   IN OUT UINTN          *BufferSize,
 | |
|   OUT VOID              *Buffer
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| PosixFileSetInfo (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   IN EFI_GUID           *InformationType,
 | |
|   IN UINTN              BufferSize,
 | |
|   IN VOID               *Buffer
 | |
|   );
 | |
| 
 | |
| EFI_FILE_PROTOCOL  gPosixFileProtocol = {
 | |
|   EFI_FILE_REVISION,
 | |
|   GasketPosixFileOpen,
 | |
|   GasketPosixFileCLose,
 | |
|   GasketPosixFileDelete,
 | |
|   GasketPosixFileRead,
 | |
|   GasketPosixFileWrite,
 | |
|   GasketPosixFileGetPossition,
 | |
|   GasketPosixFileSetPossition,
 | |
|   GasketPosixFileGetInfo,
 | |
|   GasketPosixFileSetInfo,
 | |
|   GasketPosixFileFlush
 | |
| };
 | |
| 
 | |
| EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  gPosixFileSystemProtocol = {
 | |
|   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
 | |
|   GasketPosixOpenVolume,
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Open the root directory on a volume.
 | |
| 
 | |
|   @param  This Protocol instance pointer.
 | |
|   @param  Root Returns an Open file handle for the root directory
 | |
| 
 | |
|   @retval EFI_SUCCESS          The device was opened.
 | |
|   @retval EFI_UNSUPPORTED      This volume does not support the file system.
 | |
|   @retval EFI_NO_MEDIA         The device has no media.
 | |
|   @retval EFI_DEVICE_ERROR     The device reported an error.
 | |
|   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | |
|   @retval EFI_ACCESS_DENIED    The service denied access to the file.
 | |
|   @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PosixOpenVolume (
 | |
|   IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *This,
 | |
|   OUT EFI_FILE_PROTOCOL               **Root
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   EMU_SIMPLE_FILE_SYSTEM_PRIVATE  *Private;
 | |
|   EMU_EFI_FILE_PRIVATE            *PrivateFile;
 | |
| 
 | |
|   Private = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   Status      = EFI_OUT_OF_RESOURCES;
 | |
|   PrivateFile = malloc (sizeof (EMU_EFI_FILE_PRIVATE));
 | |
|   if (PrivateFile == NULL) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   PrivateFile->FileName = malloc (AsciiStrSize (Private->FilePath));
 | |
|   if (PrivateFile->FileName == NULL) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   AsciiStrCpyS (
 | |
|     PrivateFile->FileName,
 | |
|     AsciiStrSize (Private->FilePath),
 | |
|     Private->FilePath
 | |
|     );
 | |
| 
 | |
|   PrivateFile->Signature        = EMU_EFI_FILE_PRIVATE_SIGNATURE;
 | |
|   PrivateFile->Thunk            = Private->Thunk;
 | |
|   PrivateFile->SimpleFileSystem = This;
 | |
|   PrivateFile->IsRootDirectory  = TRUE;
 | |
|   PrivateFile->IsDirectoryPath  = TRUE;
 | |
|   PrivateFile->IsOpenedByRead   = TRUE;
 | |
| 
 | |
|   CopyMem (&PrivateFile->EfiFile, &gPosixFileProtocol, sizeof (EFI_FILE_PROTOCOL));
 | |
| 
 | |
|   PrivateFile->fd     = -1;
 | |
|   PrivateFile->Dir    = NULL;
 | |
|   PrivateFile->Dirent = NULL;
 | |
| 
 | |
|   *Root = &PrivateFile->EfiFile;
 | |
| 
 | |
|   PrivateFile->Dir = opendir (PrivateFile->FileName);
 | |
|   if (PrivateFile->Dir == NULL) {
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|   } else {
 | |
|     Status = EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
| Done:
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (PrivateFile != NULL) {
 | |
|       if (PrivateFile->FileName != NULL) {
 | |
|         free (PrivateFile->FileName);
 | |
|       }
 | |
| 
 | |
|       free (PrivateFile);
 | |
|     }
 | |
| 
 | |
|     *Root = NULL;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| ErrnoToEfiStatus (
 | |
|   )
 | |
| {
 | |
|   switch (errno) {
 | |
|     case EACCES:
 | |
|       return EFI_ACCESS_DENIED;
 | |
| 
 | |
|     case EDQUOT:
 | |
|     case ENOSPC:
 | |
|       return EFI_VOLUME_FULL;
 | |
| 
 | |
|     default:
 | |
|       return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| }
 | |
| 
 | |
| VOID
 | |
| CutPrefix (
 | |
|   IN  CHAR8  *Str,
 | |
|   IN  UINTN  Count
 | |
|   )
 | |
| {
 | |
|   CHAR8  *Pointer;
 | |
| 
 | |
|   if (AsciiStrLen (Str) < Count) {
 | |
|     ASSERT (0);
 | |
|   }
 | |
| 
 | |
|   for (Pointer = Str; *(Pointer + Count); Pointer++) {
 | |
|     *Pointer = *(Pointer + Count);
 | |
|   }
 | |
| 
 | |
|   *Pointer = *(Pointer + Count);
 | |
| }
 | |
| 
 | |
| VOID
 | |
| PosixSystemTimeToEfiTime (
 | |
|   IN  time_t    SystemTime,
 | |
|   OUT EFI_TIME  *Time
 | |
|   )
 | |
| {
 | |
|   struct tm  *tm;
 | |
| 
 | |
|   tm               = gmtime (&SystemTime);
 | |
|   Time->Year       = tm->tm_year;
 | |
|   Time->Month      = tm->tm_mon + 1;
 | |
|   Time->Day        = tm->tm_mday;
 | |
|   Time->Hour       = tm->tm_hour;
 | |
|   Time->Minute     = tm->tm_min;
 | |
|   Time->Second     = tm->tm_sec;
 | |
|   Time->Nanosecond = 0;
 | |
| 
 | |
|   Time->TimeZone = timezone / 60;
 | |
|   Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0) | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0);
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| UnixSimpleFileSystemFileInfo (
 | |
|   EMU_EFI_FILE_PRIVATE  *PrivateFile,
 | |
|   IN     CHAR8          *FileName,
 | |
|   IN OUT UINTN          *BufferSize,
 | |
|   OUT    VOID           *Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS     Status;
 | |
|   UINTN          Size;
 | |
|   UINTN          NameSize;
 | |
|   UINTN          ResultSize;
 | |
|   EFI_FILE_INFO  *Info;
 | |
|   CHAR8          *RealFileName;
 | |
|   CHAR8          *TempPointer;
 | |
|   CHAR16         *BufferFileName;
 | |
|   struct stat    buf;
 | |
| 
 | |
|   if (FileName != NULL) {
 | |
|     RealFileName = FileName;
 | |
|   } else if (PrivateFile->IsRootDirectory) {
 | |
|     RealFileName = "";
 | |
|   } else {
 | |
|     RealFileName = PrivateFile->FileName;
 | |
|   }
 | |
| 
 | |
|   TempPointer = RealFileName;
 | |
|   while (*TempPointer) {
 | |
|     if (*TempPointer == '/') {
 | |
|       RealFileName = TempPointer + 1;
 | |
|     }
 | |
| 
 | |
|     TempPointer++;
 | |
|   }
 | |
| 
 | |
|   Size       = SIZE_OF_EFI_FILE_INFO;
 | |
|   NameSize   = AsciiStrSize (RealFileName) * 2;
 | |
|   ResultSize = Size + NameSize;
 | |
| 
 | |
|   if (*BufferSize < ResultSize) {
 | |
|     *BufferSize = ResultSize;
 | |
|     return EFI_BUFFER_TOO_SMALL;
 | |
|   }
 | |
| 
 | |
|   if (stat ((FileName == NULL) ? PrivateFile->FileName : FileName, &buf) < 0) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   Info = Buffer;
 | |
|   ZeroMem (Info, ResultSize);
 | |
| 
 | |
|   Info->Size         = ResultSize;
 | |
|   Info->FileSize     = buf.st_size;
 | |
|   Info->PhysicalSize = MultU64x32 (buf.st_blocks, buf.st_blksize);
 | |
| 
 | |
|   PosixSystemTimeToEfiTime (buf.st_ctime, &Info->CreateTime);
 | |
|   PosixSystemTimeToEfiTime (buf.st_atime, &Info->LastAccessTime);
 | |
|   PosixSystemTimeToEfiTime (buf.st_mtime, &Info->ModificationTime);
 | |
| 
 | |
|   if (!(buf.st_mode & S_IWUSR)) {
 | |
|     Info->Attribute |= EFI_FILE_READ_ONLY;
 | |
|   }
 | |
| 
 | |
|   if (S_ISDIR (buf.st_mode)) {
 | |
|     Info->Attribute |= EFI_FILE_DIRECTORY;
 | |
|   }
 | |
| 
 | |
|   BufferFileName = (CHAR16 *)((CHAR8 *)Buffer + Size);
 | |
|   while (*RealFileName) {
 | |
|     *BufferFileName++ = *RealFileName++;
 | |
|   }
 | |
| 
 | |
|   *BufferFileName = 0;
 | |
| 
 | |
|   *BufferSize = ResultSize;
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| BOOLEAN
 | |
| IsZero (
 | |
|   IN VOID   *Buffer,
 | |
|   IN UINTN  Length
 | |
|   )
 | |
| {
 | |
|   if ((Buffer == NULL) || (Length == 0)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (*(UINT8 *)Buffer != 0) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (Length > 1) {
 | |
|     if (!CompareMem (Buffer, (UINT8 *)Buffer + 1, Length - 1)) {
 | |
|       return FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Opens a new file relative to the source file's location.
 | |
| 
 | |
|   @param  This       The protocol instance pointer.
 | |
|   @param  NewHandle  Returns File Handle for FileName.
 | |
|   @param  FileName   Null terminated string. "\", ".", and ".." are supported.
 | |
|   @param  OpenMode   Open mode for file.
 | |
|   @param  Attributes Only used for EFI_FILE_MODE_CREATE.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The device was opened.
 | |
|   @retval EFI_NOT_FOUND        The specified file could not be found on the device.
 | |
|   @retval EFI_NO_MEDIA         The device has no media.
 | |
|   @retval EFI_MEDIA_CHANGED    The media has changed.
 | |
|   @retval EFI_DEVICE_ERROR     The device reported an error.
 | |
|   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | |
|   @retval EFI_ACCESS_DENIED    The service denied access to the file.
 | |
|   @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
 | |
|   @retval EFI_VOLUME_FULL      The volume is full.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PosixFileOpen (
 | |
|   IN EFI_FILE_PROTOCOL   *This,
 | |
|   OUT EFI_FILE_PROTOCOL  **NewHandle,
 | |
|   IN CHAR16              *FileName,
 | |
|   IN UINT64              OpenMode,
 | |
|   IN UINT64              Attributes
 | |
|   )
 | |
| {
 | |
|   EFI_FILE_PROTOCOL               *Root;
 | |
|   EMU_EFI_FILE_PRIVATE            *PrivateFile;
 | |
|   EMU_EFI_FILE_PRIVATE            *NewPrivateFile;
 | |
|   EMU_SIMPLE_FILE_SYSTEM_PRIVATE  *PrivateRoot;
 | |
|   EFI_STATUS                      Status;
 | |
|   CHAR16                          *Src;
 | |
|   char                            *Dst;
 | |
|   CHAR8                           *RealFileName;
 | |
|   char                            *ParseFileName;
 | |
|   char                            *GuardPointer;
 | |
|   CHAR8                           TempChar;
 | |
|   UINTN                           Count;
 | |
|   BOOLEAN                         TrailingDash;
 | |
|   BOOLEAN                         LoopFinish;
 | |
|   UINTN                           InfoSize;
 | |
|   EFI_FILE_INFO                   *Info;
 | |
|   struct stat                     finfo;
 | |
|   int                             res;
 | |
|   UINTN                           Size;
 | |
| 
 | |
|   PrivateFile    = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
 | |
|   PrivateRoot    = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
 | |
|   NewPrivateFile = NULL;
 | |
|   Status         = EFI_OUT_OF_RESOURCES;
 | |
| 
 | |
|   //
 | |
|   // BUGBUG: assume an open of root
 | |
|   // if current location, return current data
 | |
|   //
 | |
|   TrailingDash = FALSE;
 | |
|   if ((StrCmp (FileName, L"\\") == 0) ||
 | |
|       ((StrCmp (FileName, L".") == 0) && PrivateFile->IsRootDirectory))
 | |
|   {
 | |
| OpenRoot:
 | |
|     Status         = PosixOpenVolume (PrivateFile->SimpleFileSystem, &Root);
 | |
|     NewPrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (Root);
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   if (FileName[StrLen (FileName) - 1] == L'\\') {
 | |
|     TrailingDash                    = TRUE;
 | |
|     FileName[StrLen (FileName) - 1] = 0;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Attempt to open the file
 | |
|   //
 | |
|   NewPrivateFile = malloc (sizeof (EMU_EFI_FILE_PRIVATE));
 | |
|   if (NewPrivateFile == NULL) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   CopyMem (NewPrivateFile, PrivateFile, sizeof (EMU_EFI_FILE_PRIVATE));
 | |
| 
 | |
|   Size                     = AsciiStrSize (PrivateFile->FileName) + 1 + StrLen (FileName) + 1;
 | |
|   NewPrivateFile->FileName = malloc (Size);
 | |
|   if (NewPrivateFile->FileName == NULL) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   if (*FileName == L'\\') {
 | |
|     AsciiStrCpyS (NewPrivateFile->FileName, Size, PrivateRoot->FilePath);
 | |
|     // Skip first '\'.
 | |
|     Src = FileName + 1;
 | |
|   } else {
 | |
|     AsciiStrCpyS (NewPrivateFile->FileName, Size, PrivateFile->FileName);
 | |
|     Src = FileName;
 | |
|   }
 | |
| 
 | |
|   Dst          = NewPrivateFile->FileName + AsciiStrLen (NewPrivateFile->FileName);
 | |
|   GuardPointer = NewPrivateFile->FileName + AsciiStrLen (PrivateRoot->FilePath);
 | |
|   *Dst++       = '/';
 | |
|   // Convert unicode to ascii and '\' to '/'
 | |
|   while (*Src) {
 | |
|     if (*Src == '\\') {
 | |
|       *Dst++ = '/';
 | |
|     } else {
 | |
|       *Dst++ = *Src;
 | |
|     }
 | |
| 
 | |
|     Src++;
 | |
|   }
 | |
| 
 | |
|   *Dst = 0;
 | |
| 
 | |
|   //
 | |
|   // Get rid of . and .., except leading . or ..
 | |
|   //
 | |
| 
 | |
|   //
 | |
|   // GuardPointer protect simplefilesystem root path not be destroyed
 | |
|   //
 | |
| 
 | |
|   LoopFinish = FALSE;
 | |
|   while (!LoopFinish) {
 | |
|     LoopFinish = TRUE;
 | |
| 
 | |
|     for (ParseFileName = GuardPointer; *ParseFileName; ParseFileName++) {
 | |
|       if ((*ParseFileName == '.') &&
 | |
|           ((*(ParseFileName + 1) == 0) || (*(ParseFileName + 1) == '/')) &&
 | |
|           (*(ParseFileName - 1) == '/')
 | |
|           )
 | |
|       {
 | |
|         //
 | |
|         // cut /.
 | |
|         //
 | |
|         CutPrefix (ParseFileName - 1, 2);
 | |
|         LoopFinish = FALSE;
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       if ((*ParseFileName == '.') &&
 | |
|           (*(ParseFileName + 1) == '.') &&
 | |
|           ((*(ParseFileName + 2) == 0) || (*(ParseFileName + 2) == '/')) &&
 | |
|           (*(ParseFileName - 1) == '/')
 | |
|           )
 | |
|       {
 | |
|         ParseFileName--;
 | |
|         Count = 3;
 | |
| 
 | |
|         while (ParseFileName != GuardPointer) {
 | |
|           ParseFileName--;
 | |
|           Count++;
 | |
|           if (*ParseFileName == '/') {
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // cut /.. and its left directory
 | |
|         //
 | |
|         CutPrefix (ParseFileName, Count);
 | |
|         LoopFinish = FALSE;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (AsciiStrCmp (NewPrivateFile->FileName, PrivateRoot->FilePath) == 0) {
 | |
|     NewPrivateFile->IsRootDirectory = TRUE;
 | |
|     free (NewPrivateFile->FileName);
 | |
|     free (NewPrivateFile);
 | |
|     goto OpenRoot;
 | |
|   }
 | |
| 
 | |
|   RealFileName = NewPrivateFile->FileName + AsciiStrLen (NewPrivateFile->FileName) - 1;
 | |
|   while (RealFileName > NewPrivateFile->FileName && *RealFileName != '/') {
 | |
|     RealFileName--;
 | |
|   }
 | |
| 
 | |
|   TempChar            = *(RealFileName - 1);
 | |
|   *(RealFileName - 1) = 0;
 | |
|   *(RealFileName - 1) = TempChar;
 | |
| 
 | |
|   //
 | |
|   // Test whether file or directory
 | |
|   //
 | |
|   NewPrivateFile->IsRootDirectory = FALSE;
 | |
|   NewPrivateFile->fd              = -1;
 | |
|   NewPrivateFile->Dir             = NULL;
 | |
|   if (OpenMode & EFI_FILE_MODE_CREATE) {
 | |
|     if (Attributes & EFI_FILE_DIRECTORY) {
 | |
|       NewPrivateFile->IsDirectoryPath = TRUE;
 | |
|     } else {
 | |
|       NewPrivateFile->IsDirectoryPath = FALSE;
 | |
|     }
 | |
|   } else {
 | |
|     res = stat (NewPrivateFile->FileName, &finfo);
 | |
|     if ((res == 0) && S_ISDIR (finfo.st_mode)) {
 | |
|       NewPrivateFile->IsDirectoryPath = TRUE;
 | |
|     } else {
 | |
|       NewPrivateFile->IsDirectoryPath = FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (OpenMode & EFI_FILE_MODE_WRITE) {
 | |
|     NewPrivateFile->IsOpenedByRead = FALSE;
 | |
|   } else {
 | |
|     NewPrivateFile->IsOpenedByRead = TRUE;
 | |
|   }
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   //
 | |
|   // deal with directory
 | |
|   //
 | |
|   if (NewPrivateFile->IsDirectoryPath) {
 | |
|     if ((OpenMode & EFI_FILE_MODE_CREATE)) {
 | |
|       //
 | |
|       // Create a directory
 | |
|       //
 | |
|       if (mkdir (NewPrivateFile->FileName, 0777) != 0) {
 | |
|         if (errno != EEXIST) {
 | |
|           // free (TempFileName);
 | |
|           Status = EFI_ACCESS_DENIED;
 | |
|           goto Done;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     NewPrivateFile->Dir = opendir (NewPrivateFile->FileName);
 | |
|     if (NewPrivateFile->Dir == NULL) {
 | |
|       if (errno == EACCES) {
 | |
|         Status = EFI_ACCESS_DENIED;
 | |
|       } else {
 | |
|         Status = EFI_NOT_FOUND;
 | |
|       }
 | |
| 
 | |
|       goto Done;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // deal with file
 | |
|     //
 | |
|     NewPrivateFile->fd = open (
 | |
|                            NewPrivateFile->FileName,
 | |
|                            ((OpenMode & EFI_FILE_MODE_CREATE) ? O_CREAT : 0) | (NewPrivateFile->IsOpenedByRead ? O_RDONLY : O_RDWR),
 | |
|                            0666
 | |
|                            );
 | |
|     if (NewPrivateFile->fd < 0) {
 | |
|       if (errno == ENOENT) {
 | |
|         Status = EFI_NOT_FOUND;
 | |
|       } else {
 | |
|         Status = EFI_ACCESS_DENIED;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ((OpenMode & EFI_FILE_MODE_CREATE) && (Status == EFI_SUCCESS)) {
 | |
|     //
 | |
|     // Set the attribute
 | |
|     //
 | |
|     InfoSize = 0;
 | |
|     Info     = NULL;
 | |
|     Status   = PosixFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);
 | |
|     if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     Info = malloc (InfoSize);
 | |
|     if (Info == NULL) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     Status = PosixFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     Info->Attribute = Attributes;
 | |
|     PosixFileSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info);
 | |
| 
 | |
|     free (Info);
 | |
|   }
 | |
| 
 | |
| Done:;
 | |
|   if (TrailingDash) {
 | |
|     FileName[StrLen (FileName) + 1] = 0;
 | |
|     FileName[StrLen (FileName)]     = L'\\';
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (NewPrivateFile) {
 | |
|       if (NewPrivateFile->FileName) {
 | |
|         free (NewPrivateFile->FileName);
 | |
|       }
 | |
| 
 | |
|       free (NewPrivateFile);
 | |
|     }
 | |
|   } else {
 | |
|     *NewHandle = &NewPrivateFile->EfiFile;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Close the file handle
 | |
| 
 | |
|   @param  This          Protocol instance pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS   The device was opened.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PosixFileCLose (
 | |
|   IN EFI_FILE_PROTOCOL  *This
 | |
|   )
 | |
| {
 | |
|   EMU_EFI_FILE_PRIVATE  *PrivateFile;
 | |
| 
 | |
|   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   if (PrivateFile->fd >= 0) {
 | |
|     close (PrivateFile->fd);
 | |
|   }
 | |
| 
 | |
|   if (PrivateFile->Dir != NULL) {
 | |
|     closedir (PrivateFile->Dir);
 | |
|   }
 | |
| 
 | |
|   PrivateFile->fd  = -1;
 | |
|   PrivateFile->Dir = NULL;
 | |
| 
 | |
|   if (PrivateFile->FileName) {
 | |
|     free (PrivateFile->FileName);
 | |
|   }
 | |
| 
 | |
|   free (PrivateFile);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Close and delete the file handle.
 | |
| 
 | |
|   @param  This                     Protocol instance pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The device was opened.
 | |
|   @retval EFI_WARN_DELETE_FAILURE  The handle was closed but the file was not deleted.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PosixFileDelete (
 | |
|   IN EFI_FILE_PROTOCOL  *This
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   EMU_EFI_FILE_PRIVATE  *PrivateFile;
 | |
| 
 | |
|   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
 | |
|   Status      = EFI_WARN_DELETE_FAILURE;
 | |
| 
 | |
|   if (PrivateFile->IsDirectoryPath) {
 | |
|     if (PrivateFile->Dir != NULL) {
 | |
|       closedir (PrivateFile->Dir);
 | |
|       PrivateFile->Dir = NULL;
 | |
|     }
 | |
| 
 | |
|     if (rmdir (PrivateFile->FileName) == 0) {
 | |
|       Status = EFI_SUCCESS;
 | |
|     }
 | |
|   } else {
 | |
|     close (PrivateFile->fd);
 | |
|     PrivateFile->fd = -1;
 | |
| 
 | |
|     if (!PrivateFile->IsOpenedByRead) {
 | |
|       if (!unlink (PrivateFile->FileName)) {
 | |
|         Status = EFI_SUCCESS;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   free (PrivateFile->FileName);
 | |
|   free (PrivateFile);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Read data from the file.
 | |
| 
 | |
|   @param  This       Protocol instance pointer.
 | |
|   @param  BufferSize On input size of buffer, on output amount of data in buffer.
 | |
|   @param  Buffer     The buffer in which data is read.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Data was read.
 | |
|   @retval EFI_NO_MEDIA         The device has no media.
 | |
|   @retval EFI_DEVICE_ERROR     The device reported an error.
 | |
|   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | |
|   @retval EFI_BUFFER_TO_SMALL  BufferSize is too small. BufferSize contains required size.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PosixFileRead (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   IN OUT UINTN          *BufferSize,
 | |
|   OUT VOID              *Buffer
 | |
|   )
 | |
| {
 | |
|   EMU_EFI_FILE_PRIVATE  *PrivateFile;
 | |
|   EFI_STATUS            Status;
 | |
|   int                   Res;
 | |
|   UINTN                 Size;
 | |
|   UINTN                 NameSize;
 | |
|   UINTN                 ResultSize;
 | |
|   CHAR8                 *FullFileName;
 | |
|   UINTN                 FullFileNameSize;
 | |
| 
 | |
|   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   if (!PrivateFile->IsDirectoryPath) {
 | |
|     if (PrivateFile->fd < 0) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     Res = read (PrivateFile->fd, Buffer, *BufferSize);
 | |
|     if (Res < 0) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     *BufferSize = Res;
 | |
|     Status      = EFI_SUCCESS;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Read on a directory.
 | |
|   //
 | |
|   if (PrivateFile->Dir == NULL) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   if (PrivateFile->Dirent == NULL) {
 | |
|     PrivateFile->Dirent = readdir (PrivateFile->Dir);
 | |
|     if (PrivateFile->Dirent == NULL) {
 | |
|       *BufferSize = 0;
 | |
|       Status      = EFI_SUCCESS;
 | |
|       goto Done;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Size       = SIZE_OF_EFI_FILE_INFO;
 | |
|   NameSize   = AsciiStrLen (PrivateFile->Dirent->d_name) + 1;
 | |
|   ResultSize = Size + 2 * NameSize;
 | |
| 
 | |
|   if (*BufferSize < ResultSize) {
 | |
|     *BufferSize = ResultSize;
 | |
|     Status      = EFI_BUFFER_TOO_SMALL;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   *BufferSize = ResultSize;
 | |
| 
 | |
|   FullFileNameSize = AsciiStrLen (PrivateFile->FileName) + 1 + NameSize;
 | |
|   FullFileName     = malloc (FullFileNameSize);
 | |
|   if (FullFileName == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   AsciiStrCpyS (FullFileName, FullFileNameSize, PrivateFile->FileName);
 | |
|   AsciiStrCatS (FullFileName, FullFileNameSize, "/");
 | |
|   AsciiStrCatS (FullFileName, FullFileNameSize, PrivateFile->Dirent->d_name);
 | |
|   Status = UnixSimpleFileSystemFileInfo (
 | |
|              PrivateFile,
 | |
|              FullFileName,
 | |
|              BufferSize,
 | |
|              Buffer
 | |
|              );
 | |
|   free (FullFileName);
 | |
| 
 | |
|   PrivateFile->Dirent = NULL;
 | |
| 
 | |
| Done:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Write data to a file.
 | |
| 
 | |
|   @param  This       Protocol instance pointer.
 | |
|   @param  BufferSize On input size of buffer, on output amount of data in buffer.
 | |
|   @param  Buffer     The buffer in which data to write.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Data was written.
 | |
|   @retval EFI_UNSUPPORTED      Writes to Open directory are not supported.
 | |
|   @retval EFI_NO_MEDIA         The device has no media.
 | |
|   @retval EFI_DEVICE_ERROR     The device reported an error.
 | |
|   @retval EFI_DEVICE_ERROR     An attempt was made to write to a deleted file.
 | |
|   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | |
|   @retval EFI_WRITE_PROTECTED  The device is write protected.
 | |
|   @retval EFI_ACCESS_DENIED    The file was open for read only.
 | |
|   @retval EFI_VOLUME_FULL      The volume is full.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PosixFileWrite (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   IN OUT UINTN          *BufferSize,
 | |
|   IN VOID               *Buffer
 | |
|   )
 | |
| {
 | |
|   EMU_EFI_FILE_PRIVATE  *PrivateFile;
 | |
|   int                   Res;
 | |
| 
 | |
|   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   if (PrivateFile->fd < 0) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   if (PrivateFile->IsDirectoryPath) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if (PrivateFile->IsOpenedByRead) {
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   Res = write (PrivateFile->fd, Buffer, *BufferSize);
 | |
|   if (Res == (UINTN)-1) {
 | |
|     return ErrnoToEfiStatus ();
 | |
|   }
 | |
| 
 | |
|   *BufferSize = Res;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Set a files current position
 | |
| 
 | |
|   @param  This            Protocol instance pointer.
 | |
|   @param  Position        Byte position from the start of the file.
 | |
| 
 | |
|   @retval EFI_SUCCESS     Data was written.
 | |
|   @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PosixFileSetPossition (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   IN UINT64             Position
 | |
|   )
 | |
| {
 | |
|   EMU_EFI_FILE_PRIVATE  *PrivateFile;
 | |
|   off_t                 Pos;
 | |
| 
 | |
|   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   if (PrivateFile->IsDirectoryPath) {
 | |
|     if (Position != 0) {
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|     if (PrivateFile->Dir == NULL) {
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
| 
 | |
|     rewinddir (PrivateFile->Dir);
 | |
|     return EFI_SUCCESS;
 | |
|   } else {
 | |
|     if (Position == (UINT64)-1) {
 | |
|       Pos = lseek (PrivateFile->fd, 0, SEEK_END);
 | |
|     } else {
 | |
|       Pos = lseek (PrivateFile->fd, Position, SEEK_SET);
 | |
|     }
 | |
| 
 | |
|     if (Pos == (off_t)-1) {
 | |
|       return ErrnoToEfiStatus ();
 | |
|     }
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get a file's current position
 | |
| 
 | |
|   @param  This            Protocol instance pointer.
 | |
|   @param  Position        Byte position from the start of the file.
 | |
| 
 | |
|   @retval EFI_SUCCESS     Data was written.
 | |
|   @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PosixFileGetPossition (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   OUT UINT64            *Position
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   EMU_EFI_FILE_PRIVATE  *PrivateFile;
 | |
| 
 | |
|   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   if (PrivateFile->IsDirectoryPath) {
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|   } else {
 | |
|     *Position = (UINT64)lseek (PrivateFile->fd, 0, SEEK_CUR);
 | |
|     Status    = (*Position == (UINT64)-1) ? ErrnoToEfiStatus () : EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get information about a file.
 | |
| 
 | |
|   @param  This            Protocol instance pointer.
 | |
|   @param  InformationType Type of information to return in Buffer.
 | |
|   @param  BufferSize      On input size of buffer, on output amount of data in buffer.
 | |
|   @param  Buffer          The buffer to return data.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Data was returned.
 | |
|   @retval EFI_UNSUPPORTED      InformationType is not supported.
 | |
|   @retval EFI_NO_MEDIA         The device has no media.
 | |
|   @retval EFI_DEVICE_ERROR     The device reported an error.
 | |
|   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | |
|   @retval EFI_WRITE_PROTECTED  The device is write protected.
 | |
|   @retval EFI_ACCESS_DENIED    The file was open for read only.
 | |
|   @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PosixFileGetInfo (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   IN EFI_GUID           *InformationType,
 | |
|   IN OUT UINTN          *BufferSize,
 | |
|   OUT VOID              *Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   EMU_EFI_FILE_PRIVATE            *PrivateFile;
 | |
|   EFI_FILE_SYSTEM_INFO            *FileSystemInfoBuffer;
 | |
|   int                             UnixStatus;
 | |
|   EMU_SIMPLE_FILE_SYSTEM_PRIVATE  *PrivateRoot;
 | |
|   struct statfs                   buf;
 | |
| 
 | |
|   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
 | |
|   PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
|   if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
 | |
|     Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, BufferSize, Buffer);
 | |
|   } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
 | |
|     if (*BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) {
 | |
|       *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
 | |
|       return EFI_BUFFER_TOO_SMALL;
 | |
|     }
 | |
| 
 | |
|     UnixStatus = statfs (PrivateFile->FileName, &buf);
 | |
|     if (UnixStatus < 0) {
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
| 
 | |
|     FileSystemInfoBuffer           = (EFI_FILE_SYSTEM_INFO *)Buffer;
 | |
|     FileSystemInfoBuffer->Size     = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
 | |
|     FileSystemInfoBuffer->ReadOnly = FALSE;
 | |
| 
 | |
|     //
 | |
|     // Succeeded
 | |
|     //
 | |
|     FileSystemInfoBuffer->VolumeSize = MultU64x32 (buf.f_blocks, buf.f_bsize);
 | |
|     FileSystemInfoBuffer->FreeSpace  = MultU64x32 (buf.f_bavail, buf.f_bsize);
 | |
|     FileSystemInfoBuffer->BlockSize  = buf.f_bsize;
 | |
| 
 | |
|     StrCpyS (
 | |
|       (CHAR16 *)FileSystemInfoBuffer->VolumeLabel,
 | |
|       (*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_INFO) / sizeof (CHAR16),
 | |
|       PrivateRoot->VolumeLabel
 | |
|       );
 | |
|     *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
 | |
|   } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
 | |
|     if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) {
 | |
|       *BufferSize = StrSize (PrivateRoot->VolumeLabel);
 | |
|       return EFI_BUFFER_TOO_SMALL;
 | |
|     }
 | |
| 
 | |
|     StrCpyS (
 | |
|       (CHAR16 *)Buffer,
 | |
|       *BufferSize / sizeof (CHAR16),
 | |
|       PrivateRoot->VolumeLabel
 | |
|       );
 | |
|     *BufferSize = StrSize (PrivateRoot->VolumeLabel);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Set information about a file
 | |
| 
 | |
|   @param  File            Protocol instance pointer.
 | |
|   @param  InformationType Type of information in Buffer.
 | |
|   @param  BufferSize      Size of buffer.
 | |
|   @param  Buffer          The data to write.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Data was returned.
 | |
|   @retval EFI_UNSUPPORTED      InformationType is not supported.
 | |
|   @retval EFI_NO_MEDIA         The device has no media.
 | |
|   @retval EFI_DEVICE_ERROR     The device reported an error.
 | |
|   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | |
|   @retval EFI_WRITE_PROTECTED  The device is write protected.
 | |
|   @retval EFI_ACCESS_DENIED    The file was open for read only.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PosixFileSetInfo (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   IN EFI_GUID           *InformationType,
 | |
|   IN UINTN              BufferSize,
 | |
|   IN VOID               *Buffer
 | |
|   )
 | |
| {
 | |
|   EMU_SIMPLE_FILE_SYSTEM_PRIVATE  *PrivateRoot;
 | |
|   EMU_EFI_FILE_PRIVATE            *PrivateFile;
 | |
|   EFI_FILE_INFO                   *OldFileInfo;
 | |
|   EFI_FILE_INFO                   *NewFileInfo;
 | |
|   EFI_STATUS                      Status;
 | |
|   UINTN                           OldInfoSize;
 | |
|   mode_t                          NewAttr;
 | |
|   struct stat                     OldAttr;
 | |
|   CHAR8                           *OldFileName;
 | |
|   CHAR8                           *NewFileName;
 | |
|   CHAR8                           *CharPointer;
 | |
|   BOOLEAN                         AttrChangeFlag;
 | |
|   BOOLEAN                         NameChangeFlag;
 | |
|   BOOLEAN                         SizeChangeFlag;
 | |
|   BOOLEAN                         TimeChangeFlag;
 | |
|   struct tm                       NewLastAccessSystemTime;
 | |
|   struct tm                       NewLastWriteSystemTime;
 | |
|   EFI_FILE_SYSTEM_INFO            *NewFileSystemInfo;
 | |
|   CHAR8                           *AsciiFilePtr;
 | |
|   CHAR16                          *UnicodeFilePtr;
 | |
|   int                             UnixStatus;
 | |
|   struct utimbuf                  Utime;
 | |
|   UINTN                           Size;
 | |
| 
 | |
|   PrivateFile    = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
 | |
|   PrivateRoot    = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
 | |
|   errno          = 0;
 | |
|   Status         = EFI_UNSUPPORTED;
 | |
|   OldFileInfo    = NewFileInfo = NULL;
 | |
|   OldFileName    = NewFileName = NULL;
 | |
|   AttrChangeFlag = NameChangeFlag = SizeChangeFlag = TimeChangeFlag = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Set file system information.
 | |
|   //
 | |
|   if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
 | |
|     if (BufferSize < (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel))) {
 | |
|       Status = EFI_BAD_BUFFER_SIZE;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
 | |
| 
 | |
|     free (PrivateRoot->VolumeLabel);
 | |
| 
 | |
|     PrivateRoot->VolumeLabel = malloc (StrSize (NewFileSystemInfo->VolumeLabel));
 | |
|     if (PrivateRoot->VolumeLabel == NULL) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     StrCpyS (
 | |
|       PrivateRoot->VolumeLabel,
 | |
|       StrSize (NewFileSystemInfo->VolumeLabel) / sizeof (CHAR16),
 | |
|       NewFileSystemInfo->VolumeLabel
 | |
|       );
 | |
| 
 | |
|     Status = EFI_SUCCESS;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set volume label information.
 | |
|   //
 | |
|   if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
 | |
|     if (BufferSize < StrSize (PrivateRoot->VolumeLabel)) {
 | |
|       Status = EFI_BAD_BUFFER_SIZE;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     StrCpyS (
 | |
|       PrivateRoot->VolumeLabel,
 | |
|       StrSize (PrivateRoot->VolumeLabel) / sizeof (CHAR16),
 | |
|       (CHAR16 *)Buffer
 | |
|       );
 | |
| 
 | |
|     Status = EFI_SUCCESS;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   if (!CompareGuid (InformationType, &gEfiFileInfoGuid)) {
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize < SIZE_OF_EFI_FILE_INFO) {
 | |
|     Status = EFI_BAD_BUFFER_SIZE;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set file/directory information.
 | |
|   //
 | |
| 
 | |
|   //
 | |
|   // Check for invalid set file information parameters.
 | |
|   //
 | |
|   NewFileInfo = (EFI_FILE_INFO *)Buffer;
 | |
|   if ((NewFileInfo->Size <= sizeof (EFI_FILE_INFO)) ||
 | |
|       (NewFileInfo->Attribute &~(EFI_FILE_VALID_ATTR)) ||
 | |
|       ((sizeof (UINTN) == 4) && (NewFileInfo->Size > 0xFFFFFFFF))
 | |
|       )
 | |
|   {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get current file information so we can determine what kind
 | |
|   // of change request this is.
 | |
|   //
 | |
|   OldInfoSize = 0;
 | |
|   Status      = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, NULL);
 | |
|   if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   OldFileInfo = malloc (OldInfoSize);
 | |
|   if (OldFileInfo == NULL) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, OldFileInfo);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   OldFileName = malloc (AsciiStrSize (PrivateFile->FileName));
 | |
|   if (OldFileInfo == NULL) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   AsciiStrCpyS (
 | |
|     OldFileName,
 | |
|     AsciiStrSize (PrivateFile->FileName),
 | |
|     PrivateFile->FileName
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Make full pathname from new filename and rootpath.
 | |
|   //
 | |
|   if (NewFileInfo->FileName[0] == '\\') {
 | |
|     Size        = AsciiStrLen (PrivateRoot->FilePath) + 1 + StrLen (NewFileInfo->FileName) + 1;
 | |
|     NewFileName = malloc (Size);
 | |
|     if (NewFileName == NULL) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     AsciiStrCpyS (NewFileName, Size, PrivateRoot->FilePath);
 | |
|     AsciiFilePtr    = NewFileName + AsciiStrLen (NewFileName);
 | |
|     UnicodeFilePtr  = NewFileInfo->FileName + 1;
 | |
|     *AsciiFilePtr++ = '/';
 | |
|   } else {
 | |
|     Size        = AsciiStrLen (PrivateFile->FileName) + 2 + StrLen (NewFileInfo->FileName) + 1;
 | |
|     NewFileName = malloc (Size);
 | |
|     if (NewFileName == NULL) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     AsciiStrCpyS (NewFileName, Size, PrivateRoot->FilePath);
 | |
|     AsciiFilePtr = NewFileName + AsciiStrLen (NewFileName);
 | |
|     if ((AsciiFilePtr[-1] != '/') && (NewFileInfo->FileName[0] != '/')) {
 | |
|       // make sure there is a / between Root FilePath and NewFileInfo Filename
 | |
|       AsciiFilePtr[0] = '/';
 | |
|       AsciiFilePtr[1] = '\0';
 | |
|       AsciiFilePtr++;
 | |
|     }
 | |
| 
 | |
|     UnicodeFilePtr = NewFileInfo->FileName;
 | |
|   }
 | |
| 
 | |
|   // Convert to ascii.
 | |
|   while (*UnicodeFilePtr) {
 | |
|     *AsciiFilePtr++ = *UnicodeFilePtr++;
 | |
|   }
 | |
| 
 | |
|   *AsciiFilePtr = 0;
 | |
| 
 | |
|   //
 | |
|   // Is there an attribute change request?
 | |
|   //
 | |
|   if (NewFileInfo->Attribute != OldFileInfo->Attribute) {
 | |
|     if ((NewFileInfo->Attribute & EFI_FILE_DIRECTORY) != (OldFileInfo->Attribute & EFI_FILE_DIRECTORY)) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     AttrChangeFlag = TRUE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Is there a name change request?
 | |
|   // bugbug: - Should really use EFI_UNICODE_COLLATION_PROTOCOL
 | |
|   //
 | |
|   if (StrCmp (NewFileInfo->FileName, OldFileInfo->FileName)) {
 | |
|     NameChangeFlag = TRUE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Is there a size change request?
 | |
|   //
 | |
|   if (NewFileInfo->FileSize != OldFileInfo->FileSize) {
 | |
|     SizeChangeFlag = TRUE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Is there a time stamp change request?
 | |
|   //
 | |
|   if (!IsZero (&NewFileInfo->CreateTime, sizeof (EFI_TIME)) &&
 | |
|       CompareMem (&NewFileInfo->CreateTime, &OldFileInfo->CreateTime, sizeof (EFI_TIME))
 | |
|       )
 | |
|   {
 | |
|     TimeChangeFlag = TRUE;
 | |
|   } else if (!IsZero (&NewFileInfo->LastAccessTime, sizeof (EFI_TIME)) &&
 | |
|              CompareMem (&NewFileInfo->LastAccessTime, &OldFileInfo->LastAccessTime, sizeof (EFI_TIME))
 | |
|              )
 | |
|   {
 | |
|     TimeChangeFlag = TRUE;
 | |
|   } else if (!IsZero (&NewFileInfo->ModificationTime, sizeof (EFI_TIME)) &&
 | |
|              CompareMem (&NewFileInfo->ModificationTime, &OldFileInfo->ModificationTime, sizeof (EFI_TIME))
 | |
|              )
 | |
|   {
 | |
|     TimeChangeFlag = TRUE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // All done if there are no change requests being made.
 | |
|   //
 | |
|   if (!(AttrChangeFlag || NameChangeFlag || SizeChangeFlag || TimeChangeFlag)) {
 | |
|     Status = EFI_SUCCESS;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set file or directory information.
 | |
|   //
 | |
|   if (stat (OldFileName, &OldAttr) != 0) {
 | |
|     Status = ErrnoToEfiStatus ();
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Name change.
 | |
|   //
 | |
|   if (NameChangeFlag) {
 | |
|     //
 | |
|     // Close the handles first
 | |
|     //
 | |
|     if (PrivateFile->IsOpenedByRead) {
 | |
|       Status = EFI_ACCESS_DENIED;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     for (CharPointer = NewFileName; *CharPointer != 0 && *CharPointer != L'/'; CharPointer++) {
 | |
|     }
 | |
| 
 | |
|     if (*CharPointer != 0) {
 | |
|       Status = EFI_ACCESS_DENIED;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     UnixStatus = rename (OldFileName, NewFileName);
 | |
|     if (UnixStatus == 0) {
 | |
|       //
 | |
|       // modify file name
 | |
|       //
 | |
|       free (PrivateFile->FileName);
 | |
| 
 | |
|       PrivateFile->FileName = malloc (AsciiStrSize (NewFileName));
 | |
|       if (PrivateFile->FileName == NULL) {
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       AsciiStrCpyS (
 | |
|         PrivateFile->FileName,
 | |
|         AsciiStrSize (NewFileName),
 | |
|         NewFileName
 | |
|         );
 | |
|     } else {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto Done;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   //  Size change
 | |
|   //
 | |
|   if (SizeChangeFlag) {
 | |
|     if (PrivateFile->IsDirectoryPath) {
 | |
|       Status = EFI_UNSUPPORTED;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     if (PrivateFile->IsOpenedByRead || OldFileInfo->Attribute & EFI_FILE_READ_ONLY) {
 | |
|       Status = EFI_ACCESS_DENIED;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     if (ftruncate (PrivateFile->fd, NewFileInfo->FileSize) != 0) {
 | |
|       Status = ErrnoToEfiStatus ();
 | |
|       goto Done;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Time change
 | |
|   //
 | |
|   if (TimeChangeFlag) {
 | |
|     NewLastAccessSystemTime.tm_year  = NewFileInfo->LastAccessTime.Year;
 | |
|     NewLastAccessSystemTime.tm_mon   = NewFileInfo->LastAccessTime.Month;
 | |
|     NewLastAccessSystemTime.tm_mday  = NewFileInfo->LastAccessTime.Day;
 | |
|     NewLastAccessSystemTime.tm_hour  = NewFileInfo->LastAccessTime.Hour;
 | |
|     NewLastAccessSystemTime.tm_min   = NewFileInfo->LastAccessTime.Minute;
 | |
|     NewLastAccessSystemTime.tm_sec   = NewFileInfo->LastAccessTime.Second;
 | |
|     NewLastAccessSystemTime.tm_isdst = 0;
 | |
| 
 | |
|     Utime.actime = mktime (&NewLastAccessSystemTime);
 | |
| 
 | |
|     NewLastWriteSystemTime.tm_year  = NewFileInfo->ModificationTime.Year;
 | |
|     NewLastWriteSystemTime.tm_mon   = NewFileInfo->ModificationTime.Month;
 | |
|     NewLastWriteSystemTime.tm_mday  = NewFileInfo->ModificationTime.Day;
 | |
|     NewLastWriteSystemTime.tm_hour  = NewFileInfo->ModificationTime.Hour;
 | |
|     NewLastWriteSystemTime.tm_min   = NewFileInfo->ModificationTime.Minute;
 | |
|     NewLastWriteSystemTime.tm_sec   = NewFileInfo->ModificationTime.Second;
 | |
|     NewLastWriteSystemTime.tm_isdst = 0;
 | |
| 
 | |
|     Utime.modtime = mktime (&NewLastWriteSystemTime);
 | |
| 
 | |
|     if ((Utime.actime == (time_t)-1) || (Utime.modtime == (time_t)-1)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     if (utime (PrivateFile->FileName, &Utime) == -1) {
 | |
|       Status = ErrnoToEfiStatus ();
 | |
|       goto Done;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // No matter about AttrChangeFlag, Attribute must be set.
 | |
|   // Because operation before may cause attribute change.
 | |
|   //
 | |
|   NewAttr = OldAttr.st_mode;
 | |
| 
 | |
|   if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) {
 | |
|     NewAttr &= ~(S_IRUSR | S_IRGRP | S_IROTH);
 | |
|   } else {
 | |
|     NewAttr |= S_IRUSR;
 | |
|   }
 | |
| 
 | |
|   if (chmod (NewFileName, NewAttr) != 0) {
 | |
|     Status = ErrnoToEfiStatus ();
 | |
|   }
 | |
| 
 | |
| Done:
 | |
|   if (OldFileInfo != NULL) {
 | |
|     free (OldFileInfo);
 | |
|   }
 | |
| 
 | |
|   if (OldFileName != NULL) {
 | |
|     free (OldFileName);
 | |
|   }
 | |
| 
 | |
|   if (NewFileName != NULL) {
 | |
|     free (NewFileName);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Flush data back for the file handle.
 | |
| 
 | |
|   @param  This Protocol instance pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Data was written.
 | |
|   @retval EFI_UNSUPPORTED      Writes to Open directory are not supported.
 | |
|   @retval EFI_NO_MEDIA         The device has no media.
 | |
|   @retval EFI_DEVICE_ERROR     The device reported an error.
 | |
|   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | |
|   @retval EFI_WRITE_PROTECTED  The device is write protected.
 | |
|   @retval EFI_ACCESS_DENIED    The file was open for read only.
 | |
|   @retval EFI_VOLUME_FULL      The volume is full.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PosixFileFlush (
 | |
|   IN EFI_FILE_PROTOCOL  *This
 | |
|   )
 | |
| {
 | |
|   EMU_EFI_FILE_PRIVATE  *PrivateFile;
 | |
| 
 | |
|   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   if (PrivateFile->IsDirectoryPath) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if (PrivateFile->IsOpenedByRead) {
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   if (PrivateFile->fd < 0) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   if (fsync (PrivateFile->fd) != 0) {
 | |
|     return ErrnoToEfiStatus ();
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| PosixFileSystmeThunkOpen (
 | |
|   IN  EMU_IO_THUNK_PROTOCOL  *This
 | |
|   )
 | |
| {
 | |
|   EMU_SIMPLE_FILE_SYSTEM_PRIVATE  *Private;
 | |
|   UINTN                           i;
 | |
| 
 | |
|   if (This->Private != NULL) {
 | |
|     return EFI_ALREADY_STARTED;
 | |
|   }
 | |
| 
 | |
|   if (!CompareGuid (This->Protocol, &gEfiSimpleFileSystemProtocolGuid)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   Private = malloc (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE));
 | |
|   if (Private == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   Private->FilePath = malloc (StrLen (This->ConfigString) + 1);
 | |
|   if (Private->FilePath == NULL) {
 | |
|     free (Private);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   // Convert Unicode to Ascii
 | |
|   for (i = 0; This->ConfigString[i] != 0; i++) {
 | |
|     Private->FilePath[i] = This->ConfigString[i];
 | |
|   }
 | |
| 
 | |
|   Private->FilePath[i] = 0;
 | |
| 
 | |
|   Private->VolumeLabel = malloc (StrSize (L"EFI_EMULATED"));
 | |
|   if (Private->VolumeLabel == NULL) {
 | |
|     free (Private->FilePath);
 | |
|     free (Private);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   StrCpyS (
 | |
|     Private->VolumeLabel,
 | |
|     StrSize (L"EFI_EMULATED") / sizeof (CHAR16),
 | |
|     L"EFI_EMULATED"
 | |
|     );
 | |
| 
 | |
|   Private->Signature = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE;
 | |
|   Private->Thunk     = This;
 | |
|   CopyMem (&Private->SimpleFileSystem, &gPosixFileSystemProtocol, sizeof (Private->SimpleFileSystem));
 | |
|   Private->FileHandlesOpen = FALSE;
 | |
| 
 | |
|   This->Interface = &Private->SimpleFileSystem;
 | |
|   This->Private   = Private;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| PosixFileSystmeThunkClose (
 | |
|   IN  EMU_IO_THUNK_PROTOCOL  *This
 | |
|   )
 | |
| {
 | |
|   EMU_SIMPLE_FILE_SYSTEM_PRIVATE  *Private;
 | |
| 
 | |
|   if (!CompareGuid (This->Protocol, &gEfiSimpleFileSystemProtocolGuid)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   Private = This->Private;
 | |
| 
 | |
|   if (Private->FileHandlesOpen) {
 | |
|     //
 | |
|     // Close only supported if all the EFI_FILE_HANDLEs have been closed.
 | |
|     //
 | |
|     return EFI_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   if (This->Private != NULL) {
 | |
|     if (Private->VolumeLabel != NULL) {
 | |
|       free (Private->VolumeLabel);
 | |
|     }
 | |
| 
 | |
|     free (This->Private);
 | |
|     This->Private = NULL;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EMU_IO_THUNK_PROTOCOL  gPosixFileSystemThunkIo = {
 | |
|   &gEfiSimpleFileSystemProtocolGuid,
 | |
|   NULL,
 | |
|   NULL,
 | |
|   0,
 | |
|   GasketPosixFileSystmeThunkOpen,
 | |
|   GasketPosixFileSystmeThunkClose,
 | |
|   NULL
 | |
| };
 |