mirror of https://github.com/acidanthera/audk.git
2187 lines
56 KiB
C
2187 lines
56 KiB
C
/*++
|
|
|
|
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.
|
|
//
|
|
}
|
|
|
|
|