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