|
@@ -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
|
|
|
+};
|
|
|
+
|
|
|
+
|