summaryrefslogtreecommitdiff
path: root/UnixPkg/UnixSimpleFileSystemDxe/UnixSimpleFileSystem.c
diff options
context:
space:
mode:
Diffstat (limited to 'UnixPkg/UnixSimpleFileSystemDxe/UnixSimpleFileSystem.c')
-rw-r--r--UnixPkg/UnixSimpleFileSystemDxe/UnixSimpleFileSystem.c2186
1 files changed, 2186 insertions, 0 deletions
diff --git a/UnixPkg/UnixSimpleFileSystemDxe/UnixSimpleFileSystem.c b/UnixPkg/UnixSimpleFileSystemDxe/UnixSimpleFileSystem.c
new file mode 100644
index 0000000000..84ba962739
--- /dev/null
+++ b/UnixPkg/UnixSimpleFileSystemDxe/UnixSimpleFileSystem.c
@@ -0,0 +1,2186 @@
+/*++
+
+Copyright (c) 2006 - 2007, Intel Corporation
+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.
+
+Module Name:
+
+ UnixSimpleFileSystem.c
+
+Abstract:
+
+ Produce Simple File System abstractions for directories on your PC using Posix APIs.
+ The configuration of what devices to mount or emulate comes from UNIX
+ environment variables. The variables must be visible to the Microsoft*
+ Developer Studio for them to work.
+
+ * Other names and brands may be claimed as the property of others.
+
+--*/
+
+#include "UnixSimpleFileSystem.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gUnixSimpleFileSystemDriverBinding = {
+ UnixSimpleFileSystemDriverBindingSupported,
+ UnixSimpleFileSystemDriverBindingStart,
+ UnixSimpleFileSystemDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+
+CHAR16 *
+EfiStrChr (
+ IN CHAR16 *Str,
+ IN CHAR16 Chr
+ )
+/*++
+
+Routine Description:
+
+ Locate the first occurance of a character in a string.
+
+Arguments:
+
+ Str - Pointer to NULL terminated unicode string.
+ Chr - Character to locate.
+
+Returns:
+
+ If Str is NULL, then NULL is returned.
+ If Chr is not contained in Str, then NULL is returned.
+ If Chr is contained in Str, then a pointer to the first occurance of Chr in Str is returned.
+
+--*/
+{
+ if (Str == NULL) {
+ return Str;
+ }
+
+ while (*Str != '\0' && *Str != Chr) {
+ ++Str;
+ }
+
+ return (*Str == Chr) ? Str : NULL;
+}
+
+BOOLEAN
+IsZero (
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ Buffer - TODO: add argument description
+ Length - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ 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;
+}
+
+VOID
+CutPrefix (
+ IN CHAR8 *Str,
+ IN UINTN Count
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ Str - TODO: add argument description
+ Count - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ CHAR8 *Pointer;
+
+ if (AsciiStrLen (Str) < Count) {
+ ASSERT (0);
+ }
+
+ for (Pointer = Str; *(Pointer + Count); Pointer++) {
+ *Pointer = *(Pointer + Count);
+ }
+
+ *Pointer = *(Pointer + Count);
+}
+
+
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+
+ Check to see if the driver supports a given controller.
+
+Arguments:
+
+ This - A pointer to an instance of the EFI_DRIVER_BINDING_PROTOCOL.
+
+ ControllerHandle - EFI handle of the controller to test.
+
+ RemainingDevicePath - Pointer to remaining portion of a device path.
+
+Returns:
+
+ EFI_SUCCESS - The device specified by ControllerHandle and RemainingDevicePath is supported by the driver
+ specified by This.
+
+ EFI_ALREADY_STARTED - The device specified by ControllerHandle and RemainingDevicePath is already being managed by
+ the driver specified by This.
+
+ EFI_ACCESS_DENIED - The device specified by ControllerHandle and RemainingDevicePath is already being managed by
+ a different driver or an application that requires exclusive access.
+
+ EFI_UNSUPPORTED - The device specified by ControllerHandle and RemainingDevicePath is not supported by the
+ driver specified by This.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_UNIX_IO_PROTOCOL *UnixIo;
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUnixIoProtocolGuid,
+ (VOID **)&UnixIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Make sure GUID is for a File System handle.
+ //
+ Status = EFI_UNSUPPORTED;
+ if (CompareGuid (UnixIo->TypeGuid, &gEfiUnixFileSystemGuid)) {
+ Status = EFI_SUCCESS;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUnixIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+
+ Starts a device controller or a bus controller.
+
+Arguments:
+
+ This - A pointer to an instance of the EFI_DRIVER_BINDING_PROTOCOL.
+
+ ControllerHandle - EFI handle of the controller to start.
+
+ RemainingDevicePath - Pointer to remaining portion of a device path.
+
+Returns:
+
+ EFI_SUCCESS - The device or bus controller has been started.
+
+ EFI_DEVICE_ERROR - The device could not be started due to a device failure.
+
+ EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_UNIX_IO_PROTOCOL *UnixIo;
+ UNIX_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
+ INTN i;
+
+ Private = NULL;
+
+ //
+ // Open the IO Abstraction(s) needed
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUnixIoProtocolGuid,
+ (VOID **)&UnixIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Validate GUID
+ //
+ if (!CompareGuid (UnixIo->TypeGuid, &gEfiUnixFileSystemGuid)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (UNIX_SIMPLE_FILE_SYSTEM_PRIVATE),
+ (VOID **)&Private
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Private->Signature = UNIX_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE;
+ Private->UnixThunk = UnixIo->UnixThunk;
+ Private->FilePath = NULL;
+ Private->VolumeLabel = NULL;
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ StrLen (UnixIo->EnvString) + 1,
+ (VOID **)&Private->FilePath
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ for (i = 0; UnixIo->EnvString[i] != 0; i++)
+ Private->FilePath[i] = UnixIo->EnvString[i];
+ Private->FilePath[i] = 0;
+
+ Private->VolumeLabel = NULL;
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ StrSize (L"EFI_EMULATED"),
+ (VOID **)&Private->VolumeLabel
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ StrCpy (Private->VolumeLabel, L"EFI_EMULATED");
+
+ Private->SimpleFileSystem.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
+ Private->SimpleFileSystem.OpenVolume = UnixSimpleFileSystemOpenVolume;
+
+ Private->ControllerNameTable = NULL;
+
+ AddUnicodeString (
+ "eng",
+ gUnixSimpleFileSystemComponentName.SupportedLanguages,
+ &Private->ControllerNameTable,
+ UnixIo->EnvString
+ );
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ &Private->SimpleFileSystem,
+ NULL
+ );
+
+Done:
+ if (EFI_ERROR (Status)) {
+
+ if (Private != NULL) {
+
+ if (Private->VolumeLabel != NULL)
+ gBS->FreePool (Private->VolumeLabel);
+ if (Private->FilePath != NULL)
+ gBS->FreePool (Private->FilePath);
+ FreeUnicodeStringTable (Private->ControllerNameTable);
+
+ gBS->FreePool (Private);
+ }
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUnixIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - A pointer to an instance of the EFI_DRIVER_BINDING_PROTOCOL.
+
+ ControllerHandle - A handle to the device to be stopped.
+
+ NumberOfChildren - The number of child device handles in ChildHandleBuffer.
+
+ ChildHandleBuffer - An array of child device handles to be freed.
+
+Returns:
+
+ EFI_SUCCESS - The device has been stopped.
+
+ EFI_DEVICE_ERROR - The device could not be stopped due to a device failure.
+
+--*/
+// TODO: EFI_UNSUPPORTED - add return value to function comment
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
+ UNIX_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
+
+ //
+ // Get our context back
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID **)&SimpleFileSystem,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Private = UNIX_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (SimpleFileSystem);
+
+ //
+ // Uninstall the Simple File System Protocol from ControllerHandle
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ &Private->SimpleFileSystem,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUnixIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Free our instance data
+ //
+ FreeUnicodeStringTable (Private->ControllerNameTable);
+
+ gBS->FreePool (Private);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemOpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE **Root
+ )
+/*++
+
+Routine Description:
+
+ Open the root directory on a volume.
+
+Arguments:
+
+ This - A pointer to the volume to open.
+
+ Root - A pointer to storage for the returned opened file handle of the root directory.
+
+Returns:
+
+ EFI_SUCCESS - The volume was opened.
+
+ EFI_UNSUPPORTED - The volume does not support the requested file system type.
+
+ EFI_NO_MEDIA - The device has no media.
+
+ EFI_DEVICE_ERROR - The device reported an error.
+
+ EFI_VOLUME_CORRUPTED - The file system structures are corrupted.
+
+ EFI_ACCESS_DENIED - The service denied access to the file.
+
+ EFI_OUT_OF_RESOURCES - The file volume could not be opened due to lack of resources.
+
+ EFI_MEDIA_CHANGED - The device has new media or the media is no longer supported.
+
+--*/
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+{
+ EFI_STATUS Status;
+ UNIX_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
+ UNIX_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_TPL OldTpl;
+
+ if (This == NULL || Root == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Private = UNIX_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This);
+
+ PrivateFile = NULL;
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (UNIX_EFI_FILE_PRIVATE),
+ (VOID **)&PrivateFile
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ PrivateFile->FileName = NULL;
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ AsciiStrSize (Private->FilePath),
+ (VOID **)&PrivateFile->FileName
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ AsciiStrCpy (PrivateFile->FileName, Private->FilePath);
+ PrivateFile->Signature = UNIX_EFI_FILE_PRIVATE_SIGNATURE;
+ PrivateFile->UnixThunk = Private->UnixThunk;
+ PrivateFile->SimpleFileSystem = This;
+ PrivateFile->IsRootDirectory = TRUE;
+ PrivateFile->IsDirectoryPath = TRUE;
+ PrivateFile->IsOpenedByRead = TRUE;
+ PrivateFile->EfiFile.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
+ PrivateFile->EfiFile.Open = UnixSimpleFileSystemOpen;
+ PrivateFile->EfiFile.Close = UnixSimpleFileSystemClose;
+ PrivateFile->EfiFile.Delete = UnixSimpleFileSystemDelete;
+ PrivateFile->EfiFile.Read = UnixSimpleFileSystemRead;
+ PrivateFile->EfiFile.Write = UnixSimpleFileSystemWrite;
+ PrivateFile->EfiFile.GetPosition = UnixSimpleFileSystemGetPosition;
+ PrivateFile->EfiFile.SetPosition = UnixSimpleFileSystemSetPosition;
+ PrivateFile->EfiFile.GetInfo = UnixSimpleFileSystemGetInfo;
+ PrivateFile->EfiFile.SetInfo = UnixSimpleFileSystemSetInfo;
+ PrivateFile->EfiFile.Flush = UnixSimpleFileSystemFlush;
+ PrivateFile->fd = -1;
+ PrivateFile->Dir = NULL;
+ PrivateFile->Dirent = NULL;
+
+ *Root = &PrivateFile->EfiFile;
+
+ PrivateFile->Dir = PrivateFile->UnixThunk->OpenDir(PrivateFile->FileName);
+
+ if (PrivateFile->Dir == NULL) {
+ Status = EFI_ACCESS_DENIED;
+ }
+ else {
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if (PrivateFile) {
+ if (PrivateFile->FileName) {
+ gBS->FreePool (PrivateFile->FileName);
+ }
+
+ gBS->FreePool (PrivateFile);
+ }
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemOpen (
+ IN EFI_FILE *This,
+ OUT EFI_FILE **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+/*++
+
+Routine Description:
+
+ Open a file relative to the source file location.
+
+Arguments:
+
+ This - A pointer to the source file location.
+
+ NewHandle - Pointer to storage for the new file handle.
+
+ FileName - Pointer to the file name to be opened.
+
+ OpenMode - File open mode information.
+
+ Attributes - File creation attributes.
+
+Returns:
+
+ EFI_SUCCESS - The file was opened.
+
+ EFI_NOT_FOUND - The file could not be found in the volume.
+
+ EFI_NO_MEDIA - The device has no media.
+
+ EFI_MEDIA_CHANGED - The device has new media or the media is no longer supported.
+
+ EFI_DEVICE_ERROR - The device reported an error.
+
+ EFI_VOLUME_CORRUPTED - The file system structures are corrupted.
+
+ EFI_WRITE_PROTECTED - The volume or file is write protected.
+
+ EFI_ACCESS_DENIED - The service denied access to the file.
+
+ EFI_OUT_OF_RESOURCES - Not enough resources were available to open the file.
+
+ EFI_VOLUME_FULL - There is not enough space left to create the new file.
+
+--*/
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+{
+ EFI_FILE *Root;
+ UNIX_EFI_FILE_PRIVATE *PrivateFile;
+ UNIX_EFI_FILE_PRIVATE *NewPrivateFile;
+ UNIX_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;
+
+ TrailingDash = FALSE;
+
+ //
+ // Check for obvious invalid parameters.
+ //
+ if (This == NULL || NewHandle == NULL || FileName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (OpenMode) {
+ case EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
+ if (Attributes &~EFI_FILE_VALID_ATTR) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Attributes & EFI_FILE_READ_ONLY) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // fall through
+ //
+ case EFI_FILE_MODE_READ:
+ case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+ PrivateRoot = UNIX_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
+ NewPrivateFile = NULL;
+
+ //
+ // BUGBUG: assume an open of root
+ // if current location, return current data
+ //
+ if (StrCmp (FileName, L"\\") == 0
+ || (StrCmp (FileName, L".") == 0 && PrivateFile->IsRootDirectory)) {
+ //
+ // BUGBUG: assume an open root
+ //
+OpenRoot:
+ Status = UnixSimpleFileSystemOpenVolume (PrivateFile->SimpleFileSystem, &Root);
+ NewPrivateFile = UNIX_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
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (UNIX_EFI_FILE_PRIVATE),
+ (VOID **)&NewPrivateFile
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ CopyMem (NewPrivateFile, PrivateFile, sizeof (UNIX_EFI_FILE_PRIVATE));
+
+ NewPrivateFile->FileName = NULL;
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ AsciiStrSize (PrivateFile->FileName) + 1 + StrLen (FileName) + 1,
+ (VOID **)&NewPrivateFile->FileName
+ );
+
+ if (EFI_ERROR (Status)) {
+ 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;
+ gBS->FreePool (NewPrivateFile->FileName);
+ gBS->FreePool (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 {
+ struct stat finfo;
+ int res = NewPrivateFile->UnixThunk->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 (NewPrivateFile->UnixThunk->MkDir (NewPrivateFile->FileName, 0777) != 0) {
+ INTN LastError;
+
+ LastError = PrivateFile->UnixThunk->GetErrno ();
+ if (LastError != EEXIST) {
+ //gBS->FreePool (TempFileName);
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ }
+ }
+
+ NewPrivateFile->Dir = NewPrivateFile->UnixThunk->OpenDir
+ (NewPrivateFile->FileName);
+
+ if (NewPrivateFile->Dir == NULL) {
+ if (PrivateFile->UnixThunk->GetErrno () == EACCES) {
+ Status = EFI_ACCESS_DENIED;
+ } else {
+ Status = EFI_NOT_FOUND;
+ }
+
+ goto Done;
+ }
+
+ } else {
+ //
+ // deal with file
+ //
+ NewPrivateFile->fd = NewPrivateFile->UnixThunk->Open
+ (NewPrivateFile->FileName,
+ ((OpenMode & EFI_FILE_MODE_CREATE) ? O_CREAT : 0)
+ | (NewPrivateFile->IsOpenedByRead ? O_RDONLY : O_RDWR),
+ 0666);
+ if (NewPrivateFile->fd < 0) {
+ if (PrivateFile->UnixThunk->GetErrno () == 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 = UnixSimpleFileSystemGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ InfoSize,
+ (VOID **)&Info
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = UnixSimpleFileSystemGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Info->Attribute = Attributes;
+
+ UnixSimpleFileSystemSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info);
+ }
+
+Done: ;
+ if (TrailingDash) {
+ FileName[StrLen (FileName) + 1] = 0;
+ FileName[StrLen (FileName)] = L'\\';
+ }
+
+ if (EFI_ERROR (Status)) {
+ if (NewPrivateFile) {
+ if (NewPrivateFile->FileName) {
+ gBS->FreePool (NewPrivateFile->FileName);
+ }
+
+ gBS->FreePool (NewPrivateFile);
+ }
+ } else {
+ *NewHandle = &NewPrivateFile->EfiFile;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemClose (
+ IN EFI_FILE *This
+ )
+/*++
+
+Routine Description:
+
+ Close the specified file handle.
+
+Arguments:
+
+ This - Pointer to a returned opened file handle.
+
+Returns:
+
+ EFI_SUCCESS - The file handle has been closed.
+
+--*/
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+{
+ UNIX_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (PrivateFile->fd >= 0) {
+ PrivateFile->UnixThunk->Close (PrivateFile->fd);
+ }
+ if (PrivateFile->Dir != NULL) {
+ PrivateFile->UnixThunk->CloseDir (PrivateFile->Dir);
+ }
+
+ PrivateFile->fd = -1;
+ PrivateFile->Dir = NULL;
+
+ if (PrivateFile->FileName) {
+ gBS->FreePool (PrivateFile->FileName);
+ }
+
+ gBS->FreePool (PrivateFile);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemDelete (
+ IN EFI_FILE *This
+ )
+/*++
+
+Routine Description:
+
+ Close and delete a file.
+
+Arguments:
+
+ This - Pointer to a returned opened file handle.
+
+Returns:
+
+ EFI_SUCCESS - The file handle was closed and deleted.
+
+ EFI_WARN_DELETE_FAILURE - The handle was closed but could not be deleted.
+
+--*/
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+{
+ EFI_STATUS Status;
+ UNIX_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+ Status = EFI_WARN_DELETE_FAILURE;
+
+ if (PrivateFile->IsDirectoryPath) {
+ if (PrivateFile->Dir != NULL) {
+ PrivateFile->UnixThunk->CloseDir (PrivateFile->Dir);
+ PrivateFile->Dir = NULL;
+ }
+
+ if (PrivateFile->UnixThunk->RmDir (PrivateFile->FileName) == 0) {
+ Status = EFI_SUCCESS;
+ }
+ } else {
+ PrivateFile->UnixThunk->Close (PrivateFile->fd);
+ PrivateFile->fd = -1;
+
+ if (!PrivateFile->IsOpenedByRead) {
+ if (!PrivateFile->UnixThunk->UnLink (PrivateFile->FileName)) {
+ Status = EFI_SUCCESS;
+ }
+ }
+ }
+
+ gBS->FreePool (PrivateFile->FileName);
+ gBS->FreePool (PrivateFile);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+STATIC
+VOID
+UnixSystemTimeToEfiTime (
+ EFI_UNIX_THUNK_PROTOCOL *UnixThunk,
+ IN time_t SystemTime,
+ OUT EFI_TIME *Time
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SystemTime - TODO: add argument description
+ TimeZone - TODO: add argument description
+ Time - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ struct tm *tm;
+ tm = UnixThunk->GmTime (&SystemTime);
+ Time->Year = tm->tm_year;
+ Time->Month = tm->tm_mon;
+ 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 = UnixThunk->GetTimeZone ();
+
+ if (UnixThunk->GetDayLight ()) {
+ Time->Daylight = EFI_TIME_ADJUST_DAYLIGHT;
+ }
+}
+
+STATIC
+EFI_STATUS
+UnixSimpleFileSystemFileInfo (
+ UNIX_EFI_FILE_PRIVATE *PrivateFile,
+ IN CHAR8 *FileName,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PrivateFile - TODO: add argument description
+ BufferSize - TODO: add argument description
+ Buffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ 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 (PrivateFile->UnixThunk->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);
+
+ UnixSystemTimeToEfiTime (PrivateFile->UnixThunk, buf.st_ctime, &Info->CreateTime);
+ UnixSystemTimeToEfiTime (PrivateFile->UnixThunk, buf.st_atime, &Info->LastAccessTime);
+ UnixSystemTimeToEfiTime (PrivateFile->UnixThunk, 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;
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemRead (
+ IN EFI_FILE *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Read data from a file.
+
+Arguments:
+
+ This - Pointer to a returned open file handle.
+
+ BufferSize - On input, the size of the Buffer. On output, the number of bytes stored in the Buffer.
+
+ Buffer - Pointer to the first byte of the read Buffer.
+
+Returns:
+
+ EFI_SUCCESS - The data was read.
+
+ EFI_NO_MEDIA - The device has no media.
+
+ EFI_DEVICE_ERROR - The device reported an error.
+
+ EFI_VOLUME_CORRUPTED - The file system structures are corrupted.
+
+ EFI_BUFFER_TOO_SMALL - The supplied buffer size was too small to store the current directory entry.
+ *BufferSize has been updated with the size needed to complete the request.
+
+--*/
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+{
+ UNIX_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_STATUS Status;
+ INTN Res;
+ UINTN Size;
+ UINTN NameSize;
+ UINTN ResultSize;
+ CHAR8 *FullFileName;
+ EFI_TPL OldTpl;
+
+ if (This == NULL || BufferSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+ if (!PrivateFile->IsDirectoryPath) {
+
+ if (PrivateFile->fd < 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ Res = PrivateFile->UnixThunk->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 = PrivateFile->UnixThunk->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;
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ AsciiStrLen(PrivateFile->FileName) + 1 + NameSize,
+ (VOID **)&FullFileName
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ AsciiStrCpy(FullFileName, PrivateFile->FileName);
+ AsciiStrCat(FullFileName, "/");
+ AsciiStrCat(FullFileName, PrivateFile->Dirent->d_name);
+ Status = UnixSimpleFileSystemFileInfo (PrivateFile,
+ FullFileName,
+ BufferSize,
+ Buffer);
+ gBS->FreePool (FullFileName);
+
+ PrivateFile->Dirent = NULL;
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemWrite (
+ IN EFI_FILE *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Write data to a file.
+
+Arguments:
+
+ This - Pointer to an opened file handle.
+
+ BufferSize - On input, the number of bytes in the Buffer to write to the file. On output, the number of bytes
+ of data written to the file.
+
+ Buffer - Pointer to the first by of data in the buffer to write to the file.
+
+Returns:
+
+ EFI_SUCCESS - The data was written to the file.
+
+ EFI_UNSUPPORTED - Writes to an open directory are not supported.
+
+ EFI_NO_MEDIA - The device has no media.
+
+ EFI_DEVICE_ERROR - The device reported an error.
+
+ EFI_VOLUME_CORRUPTED - The file system structures are corrupt.
+
+ EFI_WRITE_PROTECTED - The file, directory, volume, or device is write protected.
+
+ EFI_ACCESS_DENIED - The file was opened read-only.
+
+ EFI_VOLUME_FULL - The volume is full.
+
+--*/
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+{
+ UNIX_EFI_FILE_PRIVATE *PrivateFile;
+ UINTN Res;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (This == NULL || BufferSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ PrivateFile = UNIX_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 = PrivateFile->UnixThunk->Write (
+ PrivateFile->fd,
+ Buffer,
+ *BufferSize);
+ if (Res == (UINTN)-1) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ *BufferSize = Res;
+ Status = EFI_SUCCESS;
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+
+ //
+ // bugbug: need to access unix error reporting
+ //
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemSetPosition (
+ IN EFI_FILE *This,
+ IN UINT64 Position
+ )
+/*++
+
+Routine Description:
+
+ Set a file's current position.
+
+Arguments:
+
+ This - Pointer to an opened file handle.
+
+ Position - The byte position from the start of the file to set.
+
+Returns:
+
+ EFI_SUCCESS - The file position has been changed.
+
+ EFI_UNSUPPORTED - The seek request for non-zero is not supported for directories.
+
+--*/
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+{
+ EFI_STATUS Status;
+ UNIX_EFI_FILE_PRIVATE *PrivateFile;
+ UINT64 Pos;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+ if (PrivateFile->IsDirectoryPath) {
+ if (Position != 0) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (PrivateFile->Dir == NULL) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ PrivateFile->UnixThunk->RewindDir (PrivateFile->Dir);
+ Status = EFI_SUCCESS;
+ goto Done;
+ } else {
+ if (Position == (UINT64) -1) {
+ Pos = PrivateFile->UnixThunk->Lseek (PrivateFile->fd, 0, SEEK_END);
+ } else {
+ Pos = PrivateFile->UnixThunk->Lseek (PrivateFile->fd, Position, SEEK_SET);
+ }
+ Status = (Pos == (UINT64) -1) ? EFI_DEVICE_ERROR : EFI_SUCCESS;
+ }
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemGetPosition (
+ IN EFI_FILE *This,
+ OUT UINT64 *Position
+ )
+/*++
+
+Routine Description:
+
+ Get a file's current position.
+
+Arguments:
+
+ This - Pointer to an opened file handle.
+
+ Position - Pointer to storage for the current position.
+
+Returns:
+
+ EFI_SUCCESS - The file position has been reported.
+
+ EFI_UNSUPPORTED - Not valid for directories.
+
+--*/
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+{
+ EFI_STATUS Status;
+ UNIX_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_TPL OldTpl;
+
+ if (This == NULL || Position == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+ if (PrivateFile->IsDirectoryPath) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ *Position = PrivateFile->UnixThunk->Lseek (PrivateFile->fd, 0, SEEK_CUR);
+ Status = (*Position == (UINT64) -1) ? EFI_DEVICE_ERROR : EFI_SUCCESS;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemGetInfo (
+ IN EFI_FILE *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Return information about a file or volume.
+
+Arguments:
+
+ This - Pointer to an opened file handle.
+
+ InformationType - GUID describing the type of information to be returned.
+
+ BufferSize - On input, the size of the information buffer. On output, the number of bytes written to the
+ information buffer.
+
+ Buffer - Pointer to the first byte of the information buffer.
+
+Returns:
+
+ EFI_SUCCESS - The requested information has been written into the buffer.
+
+ EFI_UNSUPPORTED - The InformationType is not known.
+
+ EFI_NO_MEDIA - The device has no media.
+
+ EFI_DEVICE_ERROR - The device reported an error.
+
+ EFI_VOLUME_CORRUPTED - The file system structures are corrupt.
+
+ EFI_BUFFER_TOO_SMALL - The buffer size was too small to contain the requested information. The buffer size has
+ been updated with the size needed to complete the requested operation.
+
+--*/
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+{
+ EFI_STATUS Status;
+ UNIX_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_FILE_SYSTEM_INFO *FileSystemInfoBuffer;
+ INTN UnixStatus;
+ UNIX_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
+ struct statfs buf;
+ EFI_TPL OldTpl;
+
+ if (This == NULL || InformationType == NULL || BufferSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+ PrivateRoot = UNIX_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
+
+ Status = EFI_UNSUPPORTED;
+
+ 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);
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ UnixStatus = PrivateFile->UnixThunk->StatFs (PrivateFile->FileName, &buf);
+ if (UnixStatus < 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ 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);
+ Status = EFI_SUCCESS;
+ } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+ if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) {
+ *BufferSize = StrSize (PrivateRoot->VolumeLabel);
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ StrCpy ((CHAR16 *) Buffer, PrivateRoot->VolumeLabel);
+ *BufferSize = StrSize (PrivateRoot->VolumeLabel);
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemSetInfo (
+ IN EFI_FILE *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Set information about a file or volume.
+
+Arguments:
+
+ This - Pointer to an opened file handle.
+
+ InformationType - GUID identifying the type of information to set.
+
+ BufferSize - Number of bytes of data in the information buffer.
+
+ Buffer - Pointer to the first byte of data in the information buffer.
+
+Returns:
+
+ EFI_SUCCESS - The file or volume information has been updated.
+
+ EFI_UNSUPPORTED - The information identifier is not recognised.
+
+ EFI_NO_MEDIA - The device has no media.
+
+ EFI_DEVICE_ERROR - The device reported an error.
+
+ EFI_VOLUME_CORRUPTED - The file system structures are corrupt.
+
+ EFI_WRITE_PROTECTED - The file, directory, volume, or device is write protected.
+
+ EFI_ACCESS_DENIED - The file was opened read-only.
+
+ EFI_VOLUME_FULL - The volume is full.
+
+ EFI_BAD_BUFFER_SIZE - The buffer size is smaller than the type indicated by InformationType.
+
+--*/
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+{
+ UNIX_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
+ UNIX_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_FILE_INFO *OldFileInfo;
+ EFI_FILE_INFO *NewFileInfo;
+ EFI_STATUS Status;
+ UINTN OldInfoSize;
+ EFI_TPL OldTpl;
+ 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;
+ INTN UnixStatus;
+
+ //
+ // Check for invalid parameters.
+ //
+ if (This == NULL || InformationType == NULL || BufferSize == 0 || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Initialise locals.
+ //
+ PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+ PrivateRoot = UNIX_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
+
+ 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;
+
+ gBS->FreePool (PrivateRoot->VolumeLabel);
+
+ PrivateRoot->VolumeLabel = NULL;
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ StrSize (NewFileSystemInfo->VolumeLabel),
+ (VOID **)&PrivateRoot->VolumeLabel
+ );
+
+ if (EFI_ERROR (Status)) {
+ 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;
+ }
+
+ //
+ // bugbug: - This is not safe. We need something like EfiStrMaxSize()
+ // that would have an additional parameter that would be the size
+ // of the string array just in case there are no NULL characters in
+ // the string array.
+ //
+ //
+ // 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;
+ }
+
+ Status = gBS->AllocatePool (EfiBootServicesData, OldInfoSize,
+ (VOID **)&OldFileInfo);
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, OldFileInfo);
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ AsciiStrSize (PrivateFile->FileName),
+ (VOID **)&OldFileName
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ AsciiStrCpy (OldFileName, PrivateFile->FileName);
+
+ //
+ // Make full pathname from new filename and rootpath.
+ //
+ if (NewFileInfo->FileName[0] == '\\') {
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ AsciiStrLen (PrivateRoot->FilePath) + 1 + StrLen (NewFileInfo->FileName) + 1,
+ (VOID **)&NewFileName
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ AsciiStrCpy (NewFileName, PrivateRoot->FilePath);
+ AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName);
+ UnicodeFilePtr = NewFileInfo->FileName + 1;
+ *AsciiFilePtr++ ='/';
+ } else {
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ AsciiStrLen (PrivateFile->FileName) + 1 + StrLen (NewFileInfo->FileName) + 1,
+ (VOID **)&NewFileName
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ AsciiStrCpy (NewFileName, PrivateRoot->FilePath);
+ AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName);
+ while (AsciiFilePtr > NewFileName && AsciiFilePtr[-1] != '/') {
+ 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: - Need EfiStrCaseCmp()
+ //
+ 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 (PrivateFile->UnixThunk->Stat (OldFileName, &OldAttr) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ 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 = PrivateFile->UnixThunk->Rename (OldFileName, NewFileName);
+
+ if (UnixStatus == 0) {
+ //
+ // modify file name
+ //
+ gBS->FreePool (PrivateFile->FileName);
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ AsciiStrSize (NewFileName),
+ (VOID **)&PrivateFile->FileName
+ );
+
+ if (EFI_ERROR (Status)) {
+ 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 (PrivateFile->UnixThunk->FTruncate (PrivateFile->fd, NewFileInfo->FileSize) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ }
+
+ //
+ // Time change
+ //
+ if (TimeChangeFlag) {
+ struct utimbuf utime;
+
+ 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 = PrivateFile->UnixThunk->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 = PrivateFile->UnixThunk->MkTime (&NewLastWriteSystemTime);
+
+ if (utime.actime == (time_t)-1 || utime.modtime == (time_t)-1) {
+ goto Done;
+ }
+
+ if (PrivateFile->UnixThunk->UTime (PrivateFile->FileName, &utime) == -1) {
+ 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;
+ }
+
+ UnixStatus = PrivateFile->UnixThunk->Chmod (NewFileName, NewAttr);
+
+ if (UnixStatus != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Done:
+ if (OldFileInfo != NULL) {
+ gBS->FreePool (OldFileInfo);
+ }
+
+ if (OldFileName != NULL) {
+ gBS->FreePool (OldFileName);
+ }
+
+ if (NewFileName != NULL) {
+ gBS->FreePool (NewFileName);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UnixSimpleFileSystemFlush (
+ IN EFI_FILE *This
+ )
+/*++
+
+Routine Description:
+
+ Flush all modified data to the media.
+
+Arguments:
+
+ This - Pointer to an opened file handle.
+
+Returns:
+
+ EFI_SUCCESS - The data has been flushed.
+
+ EFI_NO_MEDIA - The device has no media.
+
+ EFI_DEVICE_ERROR - The device reported an error.
+
+ EFI_VOLUME_CORRUPTED - The file system structures have been corrupted.
+
+ EFI_WRITE_PROTECTED - The file, directory, volume, or device is write protected.
+
+ EFI_ACCESS_DENIED - The file was opened read-only.
+
+ EFI_VOLUME_FULL - The volume is full.
+
+--*/
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+{
+ UNIX_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+
+ if (PrivateFile->IsDirectoryPath) {
+ goto Done;
+ }
+
+ if (PrivateFile->IsOpenedByRead) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ if (PrivateFile->fd < 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ PrivateFile->UnixThunk->FSync (PrivateFile->fd) == 0 ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+
+ //
+ // bugbug: - Use Unix error reporting.
+ //
+}
+
+