diff options
Diffstat (limited to 'EmulatorPkg/Unix/Host/PosixFileSystem.c')
-rw-r--r-- | EmulatorPkg/Unix/Host/PosixFileSystem.c | 3112 |
1 files changed, 1556 insertions, 1556 deletions
diff --git a/EmulatorPkg/Unix/Host/PosixFileSystem.c b/EmulatorPkg/Unix/Host/PosixFileSystem.c index 98e8c894eb..529543d6eb 100644 --- a/EmulatorPkg/Unix/Host/PosixFileSystem.c +++ b/EmulatorPkg/Unix/Host/PosixFileSystem.c @@ -1,1556 +1,1556 @@ -/*++ @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 "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; - } - 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 - // - 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)); - - 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
+ 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 "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;
+ }
+ 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
+ //
+ 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));
+
+ 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
+};
+
+
|