/**@file | |
Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> | |
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: | |
WinNtSimpleFileSystem.c | |
Abstract: | |
Produce Simple File System abstractions for directories on your PC using Win32 APIs. | |
The configuration of what devices to mount or emulate comes from NT | |
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. | |
**/ | |
// | |
// The package level header files this module uses | |
// | |
#include <Uefi.h> | |
#include <WinNtDxe.h> | |
// | |
// The protocols, PPI and GUID defintions for this module | |
// | |
#include <Guid/FileSystemVolumeLabelInfo.h> | |
#include <Protocol/WinNtIo.h> | |
#include <Protocol/ComponentName.h> | |
#include <Guid/FileInfo.h> | |
#include <Protocol/DriverBinding.h> | |
#include <Guid/FileSystemInfo.h> | |
#include <Protocol/SimpleFileSystem.h> | |
// | |
// The Library classes this module consumes | |
// | |
#include <Library/DebugLib.h> | |
#include <Library/BaseLib.h> | |
#include <Library/UefiDriverEntryPoint.h> | |
#include <Library/UefiLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/UefiBootServicesTableLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include "WinNtSimpleFileSystem.h" | |
EFI_DRIVER_BINDING_PROTOCOL gWinNtSimpleFileSystemDriverBinding = { | |
WinNtSimpleFileSystemDriverBindingSupported, | |
WinNtSimpleFileSystemDriverBindingStart, | |
WinNtSimpleFileSystemDriverBindingStop, | |
0xa, | |
NULL, | |
NULL | |
}; | |
/** | |
The user Entry Point for module WinNtSimpleFileSystem. The user code starts with this function. | |
@param[in] ImageHandle The firmware allocated handle for the EFI image. | |
@param[in] SystemTable A pointer to the EFI System Table. | |
@retval EFI_SUCCESS The entry point is executed successfully. | |
@retval other Some error occurs when executing this entry point. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
InitializeWinNtSimpleFileSystem( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Install driver model protocol(s). | |
// | |
Status = EfiLibInstallDriverBindingComponentName2 ( | |
ImageHandle, | |
SystemTable, | |
&gWinNtSimpleFileSystemDriverBinding, | |
ImageHandle, | |
&gWinNtSimpleFileSystemComponentName, | |
&gWinNtSimpleFileSystemComponentName2 | |
); | |
ASSERT_EFI_ERROR (Status); | |
return Status; | |
} | |
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 CHAR16 *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 | |
--*/ | |
{ | |
CHAR16 *Pointer; | |
if (StrLen (Str) < Count) { | |
ASSERT (0); | |
} | |
if (Count != 0) { | |
for (Pointer = Str; *(Pointer + Count); Pointer++) { | |
*Pointer = *(Pointer + Count); | |
} | |
*Pointer = *(Pointer + Count); | |
} | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemDriverBindingSupported ( | |
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_WIN_NT_IO_PROTOCOL *WinNtIo; | |
// | |
// Open the IO Abstraction(s) needed to perform the supported test | |
// | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiWinNtIoProtocolGuid, | |
(VOID **) &WinNtIo, | |
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 (WinNtIo->TypeGuid, &gEfiWinNtFileSystemGuid)) { | |
Status = EFI_SUCCESS; | |
} | |
// | |
// Close the I/O Abstraction(s) used to perform the supported test | |
// | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiWinNtIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemDriverBindingStart ( | |
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_WIN_NT_IO_PROTOCOL *WinNtIo; | |
WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private; | |
Private = NULL; | |
// | |
// Open the IO Abstraction(s) needed | |
// | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiWinNtIoProtocolGuid, | |
(VOID **) &WinNtIo, | |
This->DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Validate GUID | |
// | |
if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtFileSystemGuid)) { | |
Status = EFI_UNSUPPORTED; | |
goto Done; | |
} | |
Private = AllocatePool (sizeof (WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE)); | |
if (Private == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
Private->Signature = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE; | |
Private->WinNtThunk = WinNtIo->WinNtThunk; | |
Private->FilePath = WinNtIo->EnvString; | |
Private->VolumeLabel = AllocatePool (StrSize (L"EFI_EMULATED")); | |
if (Private->VolumeLabel == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
StrCpy (Private->VolumeLabel, L"EFI_EMULATED"); | |
Private->SimpleFileSystem.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION; | |
Private->SimpleFileSystem.OpenVolume = WinNtSimpleFileSystemOpenVolume; | |
Private->WinNtThunk->SetErrorMode (SEM_FAILCRITICALERRORS); | |
Private->ControllerNameTable = NULL; | |
AddUnicodeString2 ( | |
"eng", | |
gWinNtSimpleFileSystemComponentName.SupportedLanguages, | |
&Private->ControllerNameTable, | |
WinNtIo->EnvString, | |
TRUE | |
); | |
AddUnicodeString2 ( | |
"en", | |
gWinNtSimpleFileSystemComponentName2.SupportedLanguages, | |
&Private->ControllerNameTable, | |
WinNtIo->EnvString, | |
FALSE | |
); | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&ControllerHandle, | |
&gEfiSimpleFileSystemProtocolGuid, | |
&Private->SimpleFileSystem, | |
NULL | |
); | |
Done: | |
if (EFI_ERROR (Status)) { | |
if (Private != NULL) { | |
FreeUnicodeStringTable (Private->ControllerNameTable); | |
FreePool (Private); | |
} | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiWinNtIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
} | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemDriverBindingStop ( | |
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; | |
WIN_NT_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 = WIN_NT_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, | |
&gEfiWinNtIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
} | |
if (!EFI_ERROR (Status)) { | |
// | |
// Free our instance data | |
// | |
FreeUnicodeStringTable (Private->ControllerNameTable); | |
FreePool (Private); | |
} | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemOpenVolume ( | |
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, | |
OUT EFI_FILE_PROTOCOL **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; | |
WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private; | |
WIN_NT_EFI_FILE_PRIVATE *PrivateFile; | |
EFI_TPL OldTpl; | |
CHAR16 *TempFileName; | |
UINTN Size; | |
if (This == NULL || Root == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
Private = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This); | |
PrivateFile = AllocatePool (sizeof (WIN_NT_EFI_FILE_PRIVATE)); | |
if (PrivateFile == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
PrivateFile->FileName = AllocatePool (StrSize (Private->FilePath)); | |
if (PrivateFile->FileName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
PrivateFile->FilePath = AllocatePool (StrSize (Private->FilePath)); | |
if (PrivateFile->FilePath == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
StrCpy (PrivateFile->FilePath, Private->FilePath); | |
StrCpy (PrivateFile->FileName, PrivateFile->FilePath); | |
PrivateFile->Signature = WIN_NT_EFI_FILE_PRIVATE_SIGNATURE; | |
PrivateFile->WinNtThunk = Private->WinNtThunk; | |
PrivateFile->SimpleFileSystem = This; | |
PrivateFile->IsRootDirectory = TRUE; | |
PrivateFile->IsDirectoryPath = TRUE; | |
PrivateFile->IsOpenedByRead = TRUE; | |
PrivateFile->EfiFile.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION; | |
PrivateFile->EfiFile.Open = WinNtSimpleFileSystemOpen; | |
PrivateFile->EfiFile.Close = WinNtSimpleFileSystemClose; | |
PrivateFile->EfiFile.Delete = WinNtSimpleFileSystemDelete; | |
PrivateFile->EfiFile.Read = WinNtSimpleFileSystemRead; | |
PrivateFile->EfiFile.Write = WinNtSimpleFileSystemWrite; | |
PrivateFile->EfiFile.GetPosition = WinNtSimpleFileSystemGetPosition; | |
PrivateFile->EfiFile.SetPosition = WinNtSimpleFileSystemSetPosition; | |
PrivateFile->EfiFile.GetInfo = WinNtSimpleFileSystemGetInfo; | |
PrivateFile->EfiFile.SetInfo = WinNtSimpleFileSystemSetInfo; | |
PrivateFile->EfiFile.Flush = WinNtSimpleFileSystemFlush; | |
PrivateFile->IsValidFindBuf = FALSE; | |
// | |
// Set DirHandle | |
// | |
PrivateFile->DirHandle = PrivateFile->WinNtThunk->CreateFile ( | |
PrivateFile->FilePath, | |
GENERIC_READ, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, | |
OPEN_EXISTING, | |
FILE_FLAG_BACKUP_SEMANTICS, | |
NULL | |
); | |
if (PrivateFile->DirHandle == INVALID_HANDLE_VALUE) { | |
Status = EFI_NOT_FOUND; | |
goto Done; | |
} | |
// | |
// Find the first file under it | |
// | |
Size = StrSize (PrivateFile->FilePath); | |
Size += StrSize (L"\\*"); | |
Status = gBS->AllocatePool ( | |
EfiBootServicesData, | |
Size, | |
(VOID **)&TempFileName | |
); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
StrCpy (TempFileName, PrivateFile->FilePath); | |
StrCat (TempFileName, L"\\*"); | |
PrivateFile->LHandle = PrivateFile->WinNtThunk->FindFirstFile (TempFileName, &PrivateFile->FindBuf); | |
if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { | |
PrivateFile->IsValidFindBuf = FALSE; | |
} else { | |
PrivateFile->IsValidFindBuf = TRUE; | |
} | |
*Root = &PrivateFile->EfiFile; | |
Status = EFI_SUCCESS; | |
Done: | |
if (EFI_ERROR (Status)) { | |
if (PrivateFile) { | |
if (PrivateFile->FileName) { | |
FreePool (PrivateFile->FileName); | |
} | |
if (PrivateFile->FilePath) { | |
FreePool (PrivateFile->FilePath); | |
} | |
FreePool (PrivateFile); | |
} | |
} | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
/** | |
Count the number of Leading Dot in FileNameToken. | |
@param FileNameToken A string representing a token in the path name. | |
@return UINTN The number of leading dot in the name. | |
**/ | |
UINTN | |
CountLeadingDots ( | |
IN CONST CHAR16 * FileNameToken | |
) | |
{ | |
UINTN Num; | |
Num = 0; | |
while (*FileNameToken == L'.') { | |
Num++; | |
FileNameToken++; | |
} | |
return Num; | |
} | |
BOOLEAN | |
IsFileNameTokenValid ( | |
IN CONST CHAR16 * FileNameToken | |
) | |
{ | |
UINTN Num; | |
if (StrStr (FileNameToken, L"/") != NULL) { | |
// | |
// No L'/' in file name. | |
// | |
return FALSE; | |
} else { | |
// | |
// If Token has all dot, the number should not exceed 2 | |
// | |
Num = CountLeadingDots (FileNameToken); | |
if (Num == StrLen (FileNameToken)) { | |
// | |
// If the FileNameToken only contains a number of L'.'. | |
// | |
if (Num > 2) { | |
return FALSE; | |
} | |
} | |
} | |
return TRUE; | |
} | |
/** | |
Return the first string token found in the indirect pointer a String named by FileName. | |
On input, FileName is a indirect pointer pointing to a String. | |
On output, FileName is a updated to point to the next character after the first | |
found L"\" or NULL if there is no L"\" found. | |
@param FileName A indirect pointer pointing to a FileName. | |
@return Token The first string token found before a L"\". | |
**/ | |
CHAR16 * | |
GetNextFileNameToken ( | |
IN OUT CONST CHAR16 ** FileName | |
) | |
{ | |
CHAR16 *SlashPos; | |
CHAR16 *Token; | |
UINTN Offset; | |
ASSERT (**FileName != L'\\'); | |
ASSERT (**FileName != L'\0'); | |
SlashPos = StrStr (*FileName, L"\\"); | |
if (SlashPos == NULL) { | |
Token = AllocateCopyPool (StrSize(*FileName), *FileName); | |
*FileName = NULL; | |
} else { | |
Offset = SlashPos - *FileName; | |
Token = AllocateZeroPool ((Offset + 1) * sizeof (CHAR16)); | |
StrnCpy (Token, *FileName, Offset); | |
// | |
// Point *FileName to the next character after L'\'. | |
// | |
*FileName = *FileName + Offset + 1; | |
} | |
return Token; | |
} | |
/** | |
Check if a FileName contains only Valid Characters. | |
If FileName contains only a single L'\', return TRUE. | |
If FileName contains two adjacent L'\', return FALSE. | |
If FileName conatins L'/' , return FALSE. | |
If FielName contains more than two dots seperated with other FileName characters | |
by L'\', return FALSE. For example, L'.\...\filename.txt' is invalid path name. But L'..TwoDots\filename.txt' is valid path name. | |
@param FileName The File Name String to check. | |
@return TRUE FileName only contains valid characters. | |
@return FALSE FileName contains at least one invalid character. | |
**/ | |
BOOLEAN | |
IsFileNameValid ( | |
IN CONST CHAR16 *FileName | |
) | |
{ | |
CHAR16 *Token; | |
BOOLEAN Valid; | |
// | |
// If FileName is just L'\', then it is a valid pathname. | |
// | |
if (StrCmp (FileName, L"\\") == 0) { | |
return TRUE; | |
} | |
// | |
// We don't support two or more adjacent L'\'. | |
// | |
if (StrStr (FileName, L"\\\\") != NULL) { | |
return FALSE; | |
} | |
// | |
// Is FileName has a leading L"\", skip to next character. | |
// | |
if (FileName [0] == L'\\') { | |
FileName++; | |
} | |
do { | |
Token = GetNextFileNameToken (&FileName); | |
Valid = IsFileNameTokenValid (Token); | |
FreePool (Token); | |
if (!Valid) | |
return FALSE; | |
} while (FileName != NULL); | |
return TRUE; | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemOpen ( | |
IN EFI_FILE_PROTOCOL *This, | |
OUT EFI_FILE_PROTOCOL **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 | |
{ | |
WIN_NT_EFI_FILE_PRIVATE *PrivateFile; | |
WIN_NT_EFI_FILE_PRIVATE *NewPrivateFile; | |
WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; | |
EFI_STATUS Status; | |
CHAR16 *RealFileName; | |
CHAR16 *TempFileName; | |
CHAR16 *ParseFileName; | |
CHAR16 *GuardPointer; | |
CHAR16 TempChar; | |
DWORD LastError; | |
UINTN Count; | |
BOOLEAN LoopFinish; | |
UINTN InfoSize; | |
EFI_FILE_INFO *Info; | |
UINTN Size; | |
// | |
// 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; | |
} | |
// | |
// Init local variables | |
// | |
PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); | |
PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); | |
NewPrivateFile = NULL; | |
// | |
// Allocate buffer for FileName as the passed in FileName may be read only | |
// | |
TempFileName = AllocatePool (StrSize (FileName)); | |
if (TempFileName == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
StrCpy (TempFileName, FileName); | |
FileName = TempFileName; | |
if (FileName[StrLen (FileName) - 1] == L'\\') { | |
FileName[StrLen (FileName) - 1] = 0; | |
} | |
// | |
// If file name does not equal to "." or ".." and not trailed with "\..", | |
// then we trim the leading/trailing blanks and trailing dots | |
// | |
if (StrCmp (FileName, L".") != 0 && StrCmp (FileName, L"..") != 0 && | |
((StrLen (FileName) >= 3) ? (StrCmp (&FileName[StrLen (FileName) - 3], L"\\..") != 0) : TRUE)) { | |
// | |
// Trim leading blanks | |
// | |
Count = 0; | |
for (TempFileName = FileName; | |
*TempFileName != 0 && *TempFileName == L' '; | |
TempFileName++) { | |
Count++; | |
} | |
CutPrefix (FileName, Count); | |
// | |
// Trim trailing blanks | |
// | |
for (TempFileName = FileName + StrLen (FileName) - 1; | |
TempFileName >= FileName && (*TempFileName == L' '); | |
TempFileName--) { | |
; | |
} | |
*(TempFileName + 1) = 0; | |
} | |
// | |
// Attempt to open the file | |
// | |
NewPrivateFile = AllocatePool (sizeof (WIN_NT_EFI_FILE_PRIVATE)); | |
if (NewPrivateFile == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
CopyMem (NewPrivateFile, PrivateFile, sizeof (WIN_NT_EFI_FILE_PRIVATE)); | |
NewPrivateFile->FilePath = AllocatePool (StrSize (PrivateFile->FileName)); | |
if (NewPrivateFile->FilePath == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
if (PrivateFile->IsDirectoryPath) { | |
StrCpy (NewPrivateFile->FilePath, PrivateFile->FileName); | |
} else { | |
StrCpy (NewPrivateFile->FilePath, PrivateFile->FilePath); | |
} | |
Size = StrSize (NewPrivateFile->FilePath); | |
Size += StrSize (L"\\"); | |
Size += StrSize (FileName); | |
NewPrivateFile->FileName = AllocatePool (Size); | |
if (NewPrivateFile->FileName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
if (*FileName == L'\\') { | |
StrCpy (NewPrivateFile->FileName, PrivateRoot->FilePath); | |
StrCat (NewPrivateFile->FileName, L"\\"); | |
StrCat (NewPrivateFile->FileName, FileName + 1); | |
} else { | |
StrCpy (NewPrivateFile->FileName, NewPrivateFile->FilePath); | |
if (StrCmp (FileName, L"") != 0) { | |
// | |
// In case the filename becomes empty, especially after trimming dots and blanks | |
// | |
StrCat (NewPrivateFile->FileName, L"\\"); | |
StrCat (NewPrivateFile->FileName, FileName); | |
} | |
} | |
if (!IsFileNameValid (NewPrivateFile->FileName)) { | |
Status = EFI_NOT_FOUND; | |
goto Done; | |
} | |
// | |
// Get rid of . and .., except leading . or .. | |
// | |
// | |
// GuardPointer protect simplefilesystem root path not be destroyed | |
// | |
GuardPointer = NewPrivateFile->FileName + StrLen (PrivateRoot->FilePath); | |
LoopFinish = FALSE; | |
while (!LoopFinish) { | |
LoopFinish = TRUE; | |
for (ParseFileName = GuardPointer; *ParseFileName; ParseFileName++) { | |
if (*ParseFileName == L'.' && | |
(*(ParseFileName + 1) == 0 || *(ParseFileName + 1) == L'\\') && | |
*(ParseFileName - 1) == L'\\' | |
) { | |
// | |
// cut \. | |
// | |
CutPrefix (ParseFileName - 1, 2); | |
LoopFinish = FALSE; | |
break; | |
} | |
if (*ParseFileName == L'.' && | |
*(ParseFileName + 1) == L'.' && | |
(*(ParseFileName + 2) == 0 || *(ParseFileName + 2) == L'\\') && | |
*(ParseFileName - 1) == L'\\' | |
) { | |
ParseFileName--; | |
Count = 3; | |
while (ParseFileName != GuardPointer) { | |
ParseFileName--; | |
Count++; | |
if (*ParseFileName == L'\\') { | |
break; | |
} | |
} | |
// | |
// cut \.. and its left directory | |
// | |
CutPrefix (ParseFileName, Count); | |
LoopFinish = FALSE; | |
break; | |
} | |
} | |
} | |
RealFileName = NewPrivateFile->FileName; | |
while (EfiStrChr (RealFileName, L'\\') != NULL) { | |
RealFileName = EfiStrChr (RealFileName, L'\\') + 1; | |
} | |
TempChar = 0; | |
if (RealFileName != NewPrivateFile->FileName) { | |
TempChar = *(RealFileName - 1); | |
*(RealFileName - 1) = 0; | |
} | |
FreePool (NewPrivateFile->FilePath); | |
NewPrivateFile->FilePath = NULL; | |
NewPrivateFile->FilePath = AllocatePool (StrSize (NewPrivateFile->FileName)); | |
if (NewPrivateFile->FilePath == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
StrCpy (NewPrivateFile->FilePath, NewPrivateFile->FileName); | |
if (TempChar != 0) { | |
*(RealFileName - 1) = TempChar; | |
} | |
NewPrivateFile->IsRootDirectory = FALSE; | |
// | |
// Test whether file or directory | |
// | |
if (OpenMode & EFI_FILE_MODE_CREATE) { | |
if (Attributes & EFI_FILE_DIRECTORY) { | |
NewPrivateFile->IsDirectoryPath = TRUE; | |
} else { | |
NewPrivateFile->IsDirectoryPath = FALSE; | |
} | |
} else { | |
NewPrivateFile->LHandle = INVALID_HANDLE_VALUE; | |
NewPrivateFile->LHandle = NewPrivateFile->WinNtThunk->CreateFile ( | |
NewPrivateFile->FileName, | |
GENERIC_READ, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, | |
OPEN_EXISTING, | |
0, | |
NULL | |
); | |
if (NewPrivateFile->LHandle != INVALID_HANDLE_VALUE) { | |
NewPrivateFile->IsDirectoryPath = FALSE; | |
NewPrivateFile->WinNtThunk->CloseHandle (NewPrivateFile->LHandle); | |
} else { | |
NewPrivateFile->IsDirectoryPath = TRUE; | |
} | |
NewPrivateFile->LHandle = INVALID_HANDLE_VALUE; | |
} | |
if (OpenMode & EFI_FILE_MODE_WRITE) { | |
NewPrivateFile->IsOpenedByRead = FALSE; | |
} else { | |
NewPrivateFile->IsOpenedByRead = TRUE; | |
} | |
Status = EFI_SUCCESS; | |
// | |
// deal with directory | |
// | |
if (NewPrivateFile->IsDirectoryPath) { | |
Size = StrSize (NewPrivateFile->FileName); | |
Size += StrSize (L"\\*"); | |
TempFileName = AllocatePool (Size); | |
if (TempFileName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
StrCpy (TempFileName, NewPrivateFile->FileName); | |
if ((OpenMode & EFI_FILE_MODE_CREATE)) { | |
// | |
// Create a directory | |
// | |
if (!NewPrivateFile->WinNtThunk->CreateDirectory (TempFileName, NULL)) { | |
LastError = PrivateFile->WinNtThunk->GetLastError (); | |
if (LastError != ERROR_ALREADY_EXISTS) { | |
FreePool (TempFileName); | |
Status = EFI_ACCESS_DENIED; | |
goto Done; | |
} | |
} | |
} | |
NewPrivateFile->DirHandle = NewPrivateFile->WinNtThunk->CreateFile ( | |
TempFileName, | |
NewPrivateFile->IsOpenedByRead ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE), | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, | |
OPEN_EXISTING, | |
FILE_FLAG_BACKUP_SEMANTICS, | |
NULL | |
); | |
if (NewPrivateFile->DirHandle == INVALID_HANDLE_VALUE) { | |
NewPrivateFile->DirHandle = NewPrivateFile->WinNtThunk->CreateFile ( | |
TempFileName, | |
GENERIC_READ, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, | |
OPEN_EXISTING, | |
FILE_FLAG_BACKUP_SEMANTICS, | |
NULL | |
); | |
if (NewPrivateFile->DirHandle != INVALID_HANDLE_VALUE) { | |
NewPrivateFile->WinNtThunk->CloseHandle (NewPrivateFile->DirHandle); | |
NewPrivateFile->DirHandle = INVALID_HANDLE_VALUE; | |
Status = EFI_ACCESS_DENIED; | |
} else { | |
Status = EFI_NOT_FOUND; | |
} | |
goto Done; | |
} | |
// | |
// Find the first file under it | |
// | |
StrCat (TempFileName, L"\\*"); | |
NewPrivateFile->LHandle = NewPrivateFile->WinNtThunk->FindFirstFile (TempFileName, &NewPrivateFile->FindBuf); | |
if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) { | |
NewPrivateFile->IsValidFindBuf = FALSE; | |
} else { | |
NewPrivateFile->IsValidFindBuf = TRUE; | |
} | |
} else { | |
// | |
// deal with file | |
// | |
if (!NewPrivateFile->IsOpenedByRead) { | |
NewPrivateFile->LHandle = NewPrivateFile->WinNtThunk->CreateFile ( | |
NewPrivateFile->FileName, | |
GENERIC_READ | GENERIC_WRITE, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, | |
(OpenMode & EFI_FILE_MODE_CREATE) ? OPEN_ALWAYS : OPEN_EXISTING, | |
0, | |
NULL | |
); | |
if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) { | |
NewPrivateFile->LHandle = NewPrivateFile->WinNtThunk->CreateFile ( | |
NewPrivateFile->FileName, | |
GENERIC_READ, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, | |
OPEN_EXISTING, | |
0, | |
NULL | |
); | |
if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) { | |
Status = EFI_NOT_FOUND; | |
} else { | |
Status = EFI_ACCESS_DENIED; | |
NewPrivateFile->WinNtThunk->CloseHandle (NewPrivateFile->LHandle); | |
NewPrivateFile->LHandle = INVALID_HANDLE_VALUE; | |
} | |
} | |
} else { | |
NewPrivateFile->LHandle = NewPrivateFile->WinNtThunk->CreateFile ( | |
NewPrivateFile->FileName, | |
GENERIC_READ, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, | |
OPEN_EXISTING, | |
0, | |
NULL | |
); | |
if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) { | |
Status = EFI_NOT_FOUND; | |
} | |
} | |
} | |
if ((OpenMode & EFI_FILE_MODE_CREATE) && Status == EFI_SUCCESS) { | |
// | |
// Set the attribute | |
// | |
InfoSize = 0; | |
Info = NULL; | |
Status = WinNtSimpleFileSystemGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info); | |
if (Status != EFI_BUFFER_TOO_SMALL) { | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
Info = AllocatePool (InfoSize); | |
if (Info == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
Status = WinNtSimpleFileSystemGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
Info->Attribute = Attributes; | |
WinNtSimpleFileSystemSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info); | |
} | |
Done: | |
FreePool (FileName); | |
if (EFI_ERROR (Status)) { | |
if (NewPrivateFile) { | |
if (NewPrivateFile->FileName) { | |
FreePool (NewPrivateFile->FileName); | |
} | |
if (NewPrivateFile->FilePath) { | |
FreePool (NewPrivateFile->FilePath); | |
} | |
FreePool (NewPrivateFile); | |
} | |
} else { | |
*NewHandle = &NewPrivateFile->EfiFile; | |
if (StrCmp (NewPrivateFile->FileName, PrivateRoot->FilePath) == 0) { | |
NewPrivateFile->IsRootDirectory = TRUE; | |
} | |
} | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemClose ( | |
IN EFI_FILE_PROTOCOL *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 | |
{ | |
WIN_NT_EFI_FILE_PRIVATE *PrivateFile; | |
EFI_TPL OldTpl; | |
if (This == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); | |
if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) { | |
if (PrivateFile->IsDirectoryPath) { | |
PrivateFile->WinNtThunk->FindClose (PrivateFile->LHandle); | |
} else { | |
PrivateFile->WinNtThunk->CloseHandle (PrivateFile->LHandle); | |
} | |
PrivateFile->LHandle = INVALID_HANDLE_VALUE; | |
} | |
if (PrivateFile->IsDirectoryPath && PrivateFile->DirHandle != INVALID_HANDLE_VALUE) { | |
PrivateFile->WinNtThunk->CloseHandle (PrivateFile->DirHandle); | |
PrivateFile->DirHandle = INVALID_HANDLE_VALUE; | |
} | |
if (PrivateFile->FileName) { | |
FreePool (PrivateFile->FileName); | |
} | |
FreePool (PrivateFile); | |
gBS->RestoreTPL (OldTpl); | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemDelete ( | |
IN EFI_FILE_PROTOCOL *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; | |
WIN_NT_EFI_FILE_PRIVATE *PrivateFile; | |
EFI_TPL OldTpl; | |
if (This == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); | |
Status = EFI_WARN_DELETE_FAILURE; | |
if (PrivateFile->IsDirectoryPath) { | |
if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) { | |
PrivateFile->WinNtThunk->FindClose (PrivateFile->LHandle); | |
} | |
if (PrivateFile->DirHandle != INVALID_HANDLE_VALUE) { | |
PrivateFile->WinNtThunk->CloseHandle (PrivateFile->DirHandle); | |
PrivateFile->DirHandle = INVALID_HANDLE_VALUE; | |
} | |
if (PrivateFile->WinNtThunk->RemoveDirectory (PrivateFile->FileName)) { | |
Status = EFI_SUCCESS; | |
} | |
} else { | |
PrivateFile->WinNtThunk->CloseHandle (PrivateFile->LHandle); | |
PrivateFile->LHandle = INVALID_HANDLE_VALUE; | |
if (!PrivateFile->IsOpenedByRead) { | |
if (PrivateFile->WinNtThunk->DeleteFile (PrivateFile->FileName)) { | |
Status = EFI_SUCCESS; | |
} | |
} | |
} | |
FreePool (PrivateFile->FileName); | |
FreePool (PrivateFile); | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
VOID | |
WinNtSystemTimeToEfiTime ( | |
IN SYSTEMTIME *SystemTime, | |
IN TIME_ZONE_INFORMATION *TimeZone, | |
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 | |
--*/ | |
{ | |
Time->Year = (UINT16) SystemTime->wYear; | |
Time->Month = (UINT8) SystemTime->wMonth; | |
Time->Day = (UINT8) SystemTime->wDay; | |
Time->Hour = (UINT8) SystemTime->wHour; | |
Time->Minute = (UINT8) SystemTime->wMinute; | |
Time->Second = (UINT8) SystemTime->wSecond; | |
Time->Nanosecond = (UINT32) SystemTime->wMilliseconds * 1000000; | |
Time->TimeZone = (INT16) TimeZone->Bias; | |
if (TimeZone->StandardDate.wMonth) { | |
Time->Daylight = EFI_TIME_ADJUST_DAYLIGHT; | |
} | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemRead ( | |
IN EFI_FILE_PROTOCOL *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 | |
{ | |
WIN_NT_EFI_FILE_PRIVATE *PrivateFile; | |
EFI_STATUS Status; | |
UINTN Size; | |
UINTN NameSize; | |
UINTN ResultSize; | |
UINTN Index; | |
SYSTEMTIME SystemTime; | |
EFI_FILE_INFO *Info; | |
WCHAR *pw; | |
TIME_ZONE_INFORMATION TimeZone; | |
EFI_FILE_INFO *FileInfo; | |
UINT64 Pos; | |
UINT64 FileSize; | |
UINTN FileInfoSize; | |
EFI_TPL OldTpl; | |
if (This == NULL || BufferSize == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); | |
if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
if (!PrivateFile->IsDirectoryPath) { | |
if (This->GetPosition (This, &Pos) != EFI_SUCCESS) { | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
FileInfoSize = SIZE_OF_EFI_FILE_SYSTEM_INFO; | |
FileInfo = AllocatePool (FileInfoSize); | |
Status = This->GetInfo ( | |
This, | |
&gEfiFileInfoGuid, | |
&FileInfoSize, | |
FileInfo | |
); | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
FreePool (FileInfo); | |
FileInfo = AllocatePool (FileInfoSize); | |
Status = This->GetInfo ( | |
This, | |
&gEfiFileInfoGuid, | |
&FileInfoSize, | |
FileInfo | |
); | |
} | |
if (EFI_ERROR (Status)) { | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
FileSize = FileInfo->FileSize; | |
FreePool (FileInfo); | |
if (Pos >= FileSize) { | |
*BufferSize = 0; | |
if (Pos == FileSize) { | |
Status = EFI_SUCCESS; | |
goto Done; | |
} else { | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
} | |
Status = PrivateFile->WinNtThunk->ReadFile ( | |
PrivateFile->LHandle, | |
Buffer, | |
(DWORD)*BufferSize, | |
(LPDWORD)BufferSize, | |
NULL | |
) ? EFI_SUCCESS : EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
// | |
// Read on a directory. Perform a find next | |
// | |
if (!PrivateFile->IsValidFindBuf) { | |
*BufferSize = 0; | |
Status = EFI_SUCCESS; | |
goto Done; | |
} | |
Size = SIZE_OF_EFI_FILE_INFO; | |
NameSize = StrSize (PrivateFile->FindBuf.cFileName); | |
ResultSize = Size + NameSize; | |
Status = EFI_BUFFER_TOO_SMALL; | |
if (*BufferSize >= ResultSize) { | |
Status = EFI_SUCCESS; | |
Info = Buffer; | |
ZeroMem (Info, ResultSize); | |
Info->Size = ResultSize; | |
PrivateFile->WinNtThunk->GetTimeZoneInformation (&TimeZone); | |
PrivateFile->WinNtThunk->FileTimeToLocalFileTime ( | |
&PrivateFile->FindBuf.ftCreationTime, | |
&PrivateFile->FindBuf.ftCreationTime | |
); | |
PrivateFile->WinNtThunk->FileTimeToSystemTime (&PrivateFile->FindBuf.ftCreationTime, &SystemTime); | |
WinNtSystemTimeToEfiTime (&SystemTime, &TimeZone, &Info->CreateTime); | |
PrivateFile->WinNtThunk->FileTimeToLocalFileTime ( | |
&PrivateFile->FindBuf.ftLastWriteTime, | |
&PrivateFile->FindBuf.ftLastWriteTime | |
); | |
PrivateFile->WinNtThunk->FileTimeToSystemTime (&PrivateFile->FindBuf.ftLastWriteTime, &SystemTime); | |
WinNtSystemTimeToEfiTime (&SystemTime, &TimeZone, &Info->ModificationTime); | |
Info->FileSize = PrivateFile->FindBuf.nFileSizeLow; | |
Info->PhysicalSize = PrivateFile->FindBuf.nFileSizeLow; | |
if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) { | |
Info->Attribute |= EFI_FILE_ARCHIVE; | |
} | |
if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) { | |
Info->Attribute |= EFI_FILE_HIDDEN; | |
} | |
if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) { | |
Info->Attribute |= EFI_FILE_SYSTEM; | |
} | |
if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { | |
Info->Attribute |= EFI_FILE_READ_ONLY; | |
} | |
if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | |
Info->Attribute |= EFI_FILE_DIRECTORY; | |
} | |
NameSize = NameSize / sizeof (WCHAR); | |
pw = (WCHAR *) (((CHAR8 *) Buffer) + Size); | |
for (Index = 0; Index < NameSize; Index++) { | |
pw[Index] = PrivateFile->FindBuf.cFileName[Index]; | |
} | |
if (PrivateFile->WinNtThunk->FindNextFile (PrivateFile->LHandle, &PrivateFile->FindBuf)) { | |
PrivateFile->IsValidFindBuf = TRUE; | |
} else { | |
PrivateFile->IsValidFindBuf = FALSE; | |
} | |
} | |
*BufferSize = ResultSize; | |
Done: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemWrite ( | |
IN EFI_FILE_PROTOCOL *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 | |
{ | |
WIN_NT_EFI_FILE_PRIVATE *PrivateFile; | |
EFI_STATUS Status; | |
EFI_TPL OldTpl; | |
if (This == NULL || BufferSize == NULL || Buffer == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); | |
if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
if (PrivateFile->IsDirectoryPath) { | |
Status = EFI_UNSUPPORTED; | |
goto Done; | |
} | |
if (PrivateFile->IsOpenedByRead) { | |
Status = EFI_ACCESS_DENIED; | |
goto Done; | |
} | |
Status = PrivateFile->WinNtThunk->WriteFile ( | |
PrivateFile->LHandle, | |
Buffer, | |
(DWORD)*BufferSize, | |
(LPDWORD)BufferSize, | |
NULL | |
) ? EFI_SUCCESS : EFI_DEVICE_ERROR; | |
Done: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
// | |
// bugbug: need to access windows error reporting | |
// | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemSetPosition ( | |
IN EFI_FILE_PROTOCOL *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; | |
WIN_NT_EFI_FILE_PRIVATE *PrivateFile; | |
UINT32 PosLow; | |
UINT32 PosHigh; | |
CHAR16 *FileName; | |
EFI_TPL OldTpl; | |
UINTN Size; | |
if (This == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); | |
if (PrivateFile->IsDirectoryPath) { | |
if (Position != 0) { | |
Status = EFI_UNSUPPORTED; | |
goto Done; | |
} | |
Size = StrSize (PrivateFile->FileName); | |
Size += StrSize (L"\\*"); | |
FileName = AllocatePool (Size); | |
if (FileName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
StrCpy (FileName, PrivateFile->FileName); | |
StrCat (FileName, L"\\*"); | |
if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) { | |
PrivateFile->WinNtThunk->FindClose (PrivateFile->LHandle); | |
} | |
PrivateFile->LHandle = PrivateFile->WinNtThunk->FindFirstFile (FileName, &PrivateFile->FindBuf); | |
if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { | |
PrivateFile->IsValidFindBuf = FALSE; | |
} else { | |
PrivateFile->IsValidFindBuf = TRUE; | |
} | |
FreePool (FileName); | |
Status = (PrivateFile->LHandle == INVALID_HANDLE_VALUE) ? EFI_DEVICE_ERROR : EFI_SUCCESS; | |
} else { | |
if (Position == (UINT64) -1) { | |
PosLow = PrivateFile->WinNtThunk->SetFilePointer (PrivateFile->LHandle, (ULONG) 0, NULL, FILE_END); | |
} else { | |
PosHigh = (UINT32) RShiftU64 (Position, 32); | |
PosLow = PrivateFile->WinNtThunk->SetFilePointer (PrivateFile->LHandle, (ULONG) Position, (PLONG)&PosHigh, FILE_BEGIN); | |
} | |
Status = (PosLow == 0xFFFFFFFF) ? EFI_DEVICE_ERROR : EFI_SUCCESS; | |
} | |
Done: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemGetPosition ( | |
IN EFI_FILE_PROTOCOL *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; | |
WIN_NT_EFI_FILE_PRIVATE *PrivateFile; | |
INT32 PositionHigh; | |
UINT64 PosHigh64; | |
EFI_TPL OldTpl; | |
if (This == NULL || Position == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); | |
PositionHigh = 0; | |
PosHigh64 = 0; | |
if (PrivateFile->IsDirectoryPath) { | |
Status = EFI_UNSUPPORTED; | |
goto Done; | |
} else { | |
PositionHigh = 0; | |
*Position = PrivateFile->WinNtThunk->SetFilePointer ( | |
PrivateFile->LHandle, | |
0, | |
(PLONG)&PositionHigh, | |
FILE_CURRENT | |
); | |
Status = *Position == 0xffffffff ? EFI_DEVICE_ERROR : EFI_SUCCESS; | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
PosHigh64 = PositionHigh; | |
*Position += LShiftU64 (PosHigh64, 32); | |
} | |
Done: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
EFI_STATUS | |
WinNtSimpleFileSystemFileInfo ( | |
IN WIN_NT_EFI_FILE_PRIVATE *PrivateFile, | |
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; | |
BY_HANDLE_FILE_INFORMATION FileInfo; | |
SYSTEMTIME SystemTime; | |
CHAR16 *RealFileName; | |
CHAR16 *TempPointer; | |
Size = SIZE_OF_EFI_FILE_INFO; | |
NameSize = StrSize (PrivateFile->FileName); | |
ResultSize = Size + NameSize; | |
Status = EFI_BUFFER_TOO_SMALL; | |
if (*BufferSize >= ResultSize) { | |
Status = EFI_SUCCESS; | |
Info = Buffer; | |
ZeroMem (Info, ResultSize); | |
Info->Size = ResultSize; | |
PrivateFile->WinNtThunk->GetFileInformationByHandle ( | |
PrivateFile->IsDirectoryPath ? PrivateFile->DirHandle : PrivateFile->LHandle, | |
&FileInfo | |
); | |
Info->FileSize = FileInfo.nFileSizeLow; | |
Info->PhysicalSize = Info->FileSize; | |
PrivateFile->WinNtThunk->FileTimeToLocalFileTime(&FileInfo.ftCreationTime, &FileInfo.ftCreationTime); | |
PrivateFile->WinNtThunk->FileTimeToSystemTime (&FileInfo.ftCreationTime, &SystemTime); | |
Info->CreateTime.Year = SystemTime.wYear; | |
Info->CreateTime.Month = (UINT8) SystemTime.wMonth; | |
Info->CreateTime.Day = (UINT8) SystemTime.wDay; | |
Info->CreateTime.Hour = (UINT8) SystemTime.wHour; | |
Info->CreateTime.Minute = (UINT8) SystemTime.wMinute; | |
Info->CreateTime.Second = (UINT8) SystemTime.wSecond; | |
PrivateFile->WinNtThunk->FileTimeToLocalFileTime(&FileInfo.ftLastAccessTime, &FileInfo.ftLastAccessTime); | |
PrivateFile->WinNtThunk->FileTimeToSystemTime (&FileInfo.ftLastAccessTime, &SystemTime); | |
Info->LastAccessTime.Year = SystemTime.wYear; | |
Info->LastAccessTime.Month = (UINT8) SystemTime.wMonth; | |
Info->LastAccessTime.Day = (UINT8) SystemTime.wDay; | |
Info->LastAccessTime.Hour = (UINT8) SystemTime.wHour; | |
Info->LastAccessTime.Minute = (UINT8) SystemTime.wMinute; | |
Info->LastAccessTime.Second = (UINT8) SystemTime.wSecond; | |
PrivateFile->WinNtThunk->FileTimeToLocalFileTime(&FileInfo.ftLastWriteTime, &FileInfo.ftLastWriteTime); | |
PrivateFile->WinNtThunk->FileTimeToSystemTime (&FileInfo.ftLastWriteTime, &SystemTime); | |
Info->ModificationTime.Year = SystemTime.wYear; | |
Info->ModificationTime.Month = (UINT8) SystemTime.wMonth; | |
Info->ModificationTime.Day = (UINT8) SystemTime.wDay; | |
Info->ModificationTime.Hour = (UINT8) SystemTime.wHour; | |
Info->ModificationTime.Minute = (UINT8) SystemTime.wMinute; | |
Info->ModificationTime.Second = (UINT8) SystemTime.wSecond; | |
if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) { | |
Info->Attribute |= EFI_FILE_ARCHIVE; | |
} | |
if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) { | |
Info->Attribute |= EFI_FILE_HIDDEN; | |
} | |
if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { | |
Info->Attribute |= EFI_FILE_READ_ONLY; | |
} | |
if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) { | |
Info->Attribute |= EFI_FILE_SYSTEM; | |
} | |
if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | |
Info->Attribute |= EFI_FILE_DIRECTORY; | |
} | |
if (PrivateFile->IsDirectoryPath) { | |
Info->Attribute |= EFI_FILE_DIRECTORY; | |
} | |
RealFileName = PrivateFile->FileName; | |
TempPointer = RealFileName; | |
while (*TempPointer) { | |
if (*TempPointer == '\\') { | |
RealFileName = TempPointer + 1; | |
} | |
TempPointer++; | |
} | |
if (PrivateFile->IsRootDirectory) { | |
*((CHAR8 *) Buffer + Size) = 0; | |
} else { | |
CopyMem ((CHAR8 *) Buffer + Size, RealFileName, NameSize); | |
} | |
} | |
*BufferSize = ResultSize; | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemGetInfo ( | |
IN EFI_FILE_PROTOCOL *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; | |
WIN_NT_EFI_FILE_PRIVATE *PrivateFile; | |
EFI_FILE_SYSTEM_INFO *FileSystemInfoBuffer; | |
UINT32 SectorsPerCluster; | |
UINT32 BytesPerSector; | |
UINT32 FreeClusters; | |
UINT32 TotalClusters; | |
UINT32 BytesPerCluster; | |
CHAR16 *DriveName; | |
BOOLEAN DriveNameFound; | |
BOOL NtStatus; | |
UINTN Index; | |
WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; | |
EFI_TPL OldTpl; | |
if (This == NULL || InformationType == NULL || BufferSize == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); | |
PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); | |
Status = EFI_UNSUPPORTED; | |
if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { | |
Status = WinNtSimpleFileSystemFileInfo (PrivateFile, BufferSize, Buffer); | |
} | |
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; | |
} | |
FileSystemInfoBuffer = (EFI_FILE_SYSTEM_INFO *) Buffer; | |
FileSystemInfoBuffer->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); | |
FileSystemInfoBuffer->ReadOnly = FALSE; | |
// | |
// Try to get the drive name | |
// | |
DriveNameFound = FALSE; | |
DriveName = AllocatePool (StrSize (PrivateFile->FilePath) + 1); | |
if (DriveName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
StrCpy (DriveName, PrivateFile->FilePath); | |
for (Index = 0; DriveName[Index] != 0 && DriveName[Index] != ':'; Index++) { | |
; | |
} | |
if (DriveName[Index] == ':') { | |
DriveName[Index + 1] = '\\'; | |
DriveName[Index + 2] = 0; | |
DriveNameFound = TRUE; | |
} else if (DriveName[0] == '\\' && DriveName[1] == '\\') { | |
for (Index = 2; DriveName[Index] != 0 && DriveName[Index] != '\\'; Index++) { | |
; | |
} | |
if (DriveName[Index] == '\\') { | |
DriveNameFound = TRUE; | |
for (Index++; DriveName[Index] != 0 && DriveName[Index] != '\\'; Index++) { | |
; | |
} | |
DriveName[Index] = '\\'; | |
DriveName[Index + 1] = 0; | |
} | |
} | |
// | |
// Try GetDiskFreeSpace first | |
// | |
NtStatus = PrivateFile->WinNtThunk->GetDiskFreeSpace ( | |
DriveNameFound ? DriveName : NULL, | |
(LPDWORD)&SectorsPerCluster, | |
(LPDWORD)&BytesPerSector, | |
(LPDWORD)&FreeClusters, | |
(LPDWORD)&TotalClusters | |
); | |
if (DriveName) { | |
FreePool (DriveName); | |
} | |
if (NtStatus) { | |
// | |
// Succeeded | |
// | |
BytesPerCluster = BytesPerSector * SectorsPerCluster; | |
FileSystemInfoBuffer->VolumeSize = MultU64x32 (TotalClusters, BytesPerCluster); | |
FileSystemInfoBuffer->FreeSpace = MultU64x32 (FreeClusters, BytesPerCluster); | |
FileSystemInfoBuffer->BlockSize = BytesPerCluster; | |
} else { | |
// | |
// try GetDiskFreeSpaceEx then | |
// | |
FileSystemInfoBuffer->BlockSize = 0; | |
NtStatus = PrivateFile->WinNtThunk->GetDiskFreeSpaceEx ( | |
PrivateFile->FilePath, | |
(PULARGE_INTEGER) (&FileSystemInfoBuffer->FreeSpace), | |
(PULARGE_INTEGER) (&FileSystemInfoBuffer->VolumeSize), | |
NULL | |
); | |
if (!NtStatus) { | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
} | |
StrCpy ((CHAR16 *) FileSystemInfoBuffer->VolumeLabel, PrivateRoot->VolumeLabel); | |
*BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); | |
Status = EFI_SUCCESS; | |
} | |
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 | |
WinNtSimpleFileSystemSetInfo ( | |
IN EFI_FILE_PROTOCOL*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 | |
{ | |
WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; | |
WIN_NT_EFI_FILE_PRIVATE *PrivateFile; | |
EFI_FILE_INFO *OldFileInfo; | |
EFI_FILE_INFO *NewFileInfo; | |
EFI_STATUS Status; | |
UINTN OldInfoSize; | |
INTN NtStatus; | |
UINT32 NewAttr; | |
UINT32 OldAttr; | |
CHAR16 *OldFileName; | |
CHAR16 *NewFileName; | |
CHAR16 *TempFileName; | |
CHAR16 *CharPointer; | |
BOOLEAN AttrChangeFlag; | |
BOOLEAN NameChangeFlag; | |
BOOLEAN SizeChangeFlag; | |
BOOLEAN TimeChangeFlag; | |
UINT64 CurPos; | |
SYSTEMTIME NewCreationSystemTime; | |
SYSTEMTIME NewLastAccessSystemTime; | |
SYSTEMTIME NewLastWriteSystemTime; | |
FILETIME NewCreationFileTime; | |
FILETIME NewLastAccessFileTime; | |
FILETIME NewLastWriteFileTime; | |
WIN32_FIND_DATA FindBuf; | |
EFI_FILE_SYSTEM_INFO *NewFileSystemInfo; | |
EFI_TPL OldTpl; | |
UINTN Size; | |
// | |
// 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 = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); | |
PrivateRoot = WIN_NT_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)) { | |
NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *) Buffer; | |
if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (NewFileSystemInfo->VolumeLabel)) { | |
Status = EFI_BAD_BUFFER_SIZE; | |
goto Done; | |
} | |
FreePool (PrivateRoot->VolumeLabel); | |
PrivateRoot->VolumeLabel = AllocatePool (StrSize (NewFileSystemInfo->VolumeLabel)); | |
if (PrivateRoot->VolumeLabel == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
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 <= SIZE_OF_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 = WinNtSimpleFileSystemFileInfo (PrivateFile, &OldInfoSize, NULL); | |
if (Status != EFI_BUFFER_TOO_SMALL) { | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
OldFileInfo = AllocatePool (OldInfoSize); | |
if (OldFileInfo == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
Status = WinNtSimpleFileSystemFileInfo (PrivateFile, &OldInfoSize, OldFileInfo); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
OldFileName = AllocatePool (StrSize (PrivateFile->FileName)); | |
if (OldFileName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
StrCpy (OldFileName, PrivateFile->FileName); | |
// | |
// Make full pathname from new filename and rootpath. | |
// | |
if (NewFileInfo->FileName[0] == '\\') { | |
Size = StrSize (PrivateRoot->FilePath); | |
Size += StrSize (L"\\"); | |
Size += StrSize (NewFileInfo->FileName); | |
NewFileName = AllocatePool (Size); | |
if (NewFileName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
StrCpy (NewFileName, PrivateRoot->FilePath); | |
StrCat (NewFileName, L"\\"); | |
StrCat (NewFileName, NewFileInfo->FileName + 1); | |
} else { | |
Size = StrSize (PrivateFile->FilePath); | |
Size += StrSize (L"\\"); | |
Size += StrSize (NewFileInfo->FileName); | |
NewFileName = AllocatePool (Size); | |
if (NewFileName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
StrCpy (NewFileName, PrivateFile->FilePath); | |
StrCat (NewFileName, L"\\"); | |
StrCat (NewFileName, NewFileInfo->FileName); | |
} | |
// | |
// 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. | |
// | |
OldAttr = PrivateFile->WinNtThunk->GetFileAttributes (OldFileName); | |
// | |
// 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; | |
} | |
if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) { | |
if (PrivateFile->IsDirectoryPath) { | |
PrivateFile->WinNtThunk->FindClose (PrivateFile->LHandle); | |
} else { | |
PrivateFile->WinNtThunk->CloseHandle (PrivateFile->LHandle); | |
PrivateFile->LHandle = INVALID_HANDLE_VALUE; | |
} | |
} | |
if (PrivateFile->IsDirectoryPath && PrivateFile->DirHandle != INVALID_HANDLE_VALUE) { | |
PrivateFile->WinNtThunk->CloseHandle (PrivateFile->DirHandle); | |
PrivateFile->DirHandle = INVALID_HANDLE_VALUE; | |
} | |
NtStatus = PrivateFile->WinNtThunk->MoveFile (OldFileName, NewFileName); | |
if (NtStatus) { | |
// | |
// modify file name | |
// | |
FreePool (PrivateFile->FileName); | |
PrivateFile->FileName = AllocatePool (StrSize (NewFileName)); | |
if (PrivateFile->FileName == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
StrCpy (PrivateFile->FileName, NewFileName); | |
Size = StrSize (NewFileName); | |
Size += StrSize (L"\\*"); | |
TempFileName = AllocatePool (Size); | |
StrCpy (TempFileName, NewFileName); | |
if (!PrivateFile->IsDirectoryPath) { | |
PrivateFile->LHandle = PrivateFile->WinNtThunk->CreateFile ( | |
TempFileName, | |
PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, | |
OPEN_EXISTING, | |
0, | |
NULL | |
); | |
FreePool (TempFileName); | |
// | |
// Flush buffers just in case | |
// | |
if (PrivateFile->WinNtThunk->FlushFileBuffers (PrivateFile->LHandle) == 0) { | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
} else { | |
PrivateFile->DirHandle = PrivateFile->WinNtThunk->CreateFile ( | |
TempFileName, | |
PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, | |
OPEN_EXISTING, | |
FILE_FLAG_BACKUP_SEMANTICS, | |
NULL | |
); | |
StrCat (TempFileName, L"\\*"); | |
PrivateFile->LHandle = PrivateFile->WinNtThunk->FindFirstFile (TempFileName, &FindBuf); | |
FreePool (TempFileName); | |
} | |
} else { | |
Status = EFI_ACCESS_DENIED; | |
Reopen: ; | |
NtStatus = PrivateFile->WinNtThunk->SetFileAttributes (OldFileName, OldAttr); | |
if (!NtStatus) { | |
goto Done; | |
} | |
Size = StrSize (OldFileName); | |
Size += StrSize (L"\\*"); | |
TempFileName = AllocatePool (Size); | |
StrCpy (TempFileName, OldFileName); | |
if (!PrivateFile->IsDirectoryPath) { | |
PrivateFile->LHandle = PrivateFile->WinNtThunk->CreateFile ( | |
TempFileName, | |
PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, | |
OPEN_EXISTING, | |
0, | |
NULL | |
); | |
} else { | |
PrivateFile->DirHandle = PrivateFile->WinNtThunk->CreateFile ( | |
TempFileName, | |
PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, | |
OPEN_EXISTING, | |
FILE_FLAG_BACKUP_SEMANTICS, | |
NULL | |
); | |
StrCat (TempFileName, L"\\*"); | |
PrivateFile->LHandle = PrivateFile->WinNtThunk->FindFirstFile (TempFileName, &FindBuf); | |
} | |
FreePool (TempFileName); | |
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; | |
} | |
Status = This->GetPosition (This, &CurPos); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
Status = This->SetPosition (This, NewFileInfo->FileSize); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
if (PrivateFile->WinNtThunk->SetEndOfFile (PrivateFile->LHandle) == 0) { | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
Status = This->SetPosition (This, CurPos); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
} | |
// | |
// Time change | |
// | |
if (TimeChangeFlag) { | |
NewCreationSystemTime.wYear = NewFileInfo->CreateTime.Year; | |
NewCreationSystemTime.wMonth = NewFileInfo->CreateTime.Month; | |
NewCreationSystemTime.wDay = NewFileInfo->CreateTime.Day; | |
NewCreationSystemTime.wHour = NewFileInfo->CreateTime.Hour; | |
NewCreationSystemTime.wMinute = NewFileInfo->CreateTime.Minute; | |
NewCreationSystemTime.wSecond = NewFileInfo->CreateTime.Second; | |
NewCreationSystemTime.wMilliseconds = 0; | |
if (!PrivateFile->WinNtThunk->SystemTimeToFileTime ( | |
&NewCreationSystemTime, | |
&NewCreationFileTime | |
)) { | |
goto Done; | |
} | |
if (!PrivateFile->WinNtThunk->LocalFileTimeToFileTime ( | |
&NewCreationFileTime, | |
&NewCreationFileTime | |
)) { | |
goto Done; | |
} | |
NewLastAccessSystemTime.wYear = NewFileInfo->LastAccessTime.Year; | |
NewLastAccessSystemTime.wMonth = NewFileInfo->LastAccessTime.Month; | |
NewLastAccessSystemTime.wDay = NewFileInfo->LastAccessTime.Day; | |
NewLastAccessSystemTime.wHour = NewFileInfo->LastAccessTime.Hour; | |
NewLastAccessSystemTime.wMinute = NewFileInfo->LastAccessTime.Minute; | |
NewLastAccessSystemTime.wSecond = NewFileInfo->LastAccessTime.Second; | |
NewLastAccessSystemTime.wMilliseconds = 0; | |
if (!PrivateFile->WinNtThunk->SystemTimeToFileTime ( | |
&NewLastAccessSystemTime, | |
&NewLastAccessFileTime | |
)) { | |
goto Done; | |
} | |
if (!PrivateFile->WinNtThunk->LocalFileTimeToFileTime ( | |
&NewLastAccessFileTime, | |
&NewLastAccessFileTime | |
)) { | |
goto Done; | |
} | |
NewLastWriteSystemTime.wYear = NewFileInfo->ModificationTime.Year; | |
NewLastWriteSystemTime.wMonth = NewFileInfo->ModificationTime.Month; | |
NewLastWriteSystemTime.wDay = NewFileInfo->ModificationTime.Day; | |
NewLastWriteSystemTime.wHour = NewFileInfo->ModificationTime.Hour; | |
NewLastWriteSystemTime.wMinute = NewFileInfo->ModificationTime.Minute; | |
NewLastWriteSystemTime.wSecond = NewFileInfo->ModificationTime.Second; | |
NewLastWriteSystemTime.wMilliseconds = 0; | |
if (!PrivateFile->WinNtThunk->SystemTimeToFileTime ( | |
&NewLastWriteSystemTime, | |
&NewLastWriteFileTime | |
)) { | |
goto Done; | |
} | |
if (!PrivateFile->WinNtThunk->LocalFileTimeToFileTime ( | |
&NewLastWriteFileTime, | |
&NewLastWriteFileTime | |
)) { | |
goto Done; | |
} | |
if (!PrivateFile->WinNtThunk->SetFileTime ( | |
PrivateFile->IsDirectoryPath ? PrivateFile->DirHandle : PrivateFile->LHandle, | |
&NewCreationFileTime, | |
&NewLastAccessFileTime, | |
&NewLastWriteFileTime | |
)) { | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
} | |
// | |
// No matter about AttrChangeFlag, Attribute must be set. | |
// Because operation before may cause attribute change. | |
// | |
NewAttr = OldAttr; | |
if (NewFileInfo->Attribute & EFI_FILE_ARCHIVE) { | |
NewAttr |= FILE_ATTRIBUTE_ARCHIVE; | |
} else { | |
NewAttr &= ~FILE_ATTRIBUTE_ARCHIVE; | |
} | |
if (NewFileInfo->Attribute & EFI_FILE_HIDDEN) { | |
NewAttr |= FILE_ATTRIBUTE_HIDDEN; | |
} else { | |
NewAttr &= ~FILE_ATTRIBUTE_HIDDEN; | |
} | |
if (NewFileInfo->Attribute & EFI_FILE_SYSTEM) { | |
NewAttr |= FILE_ATTRIBUTE_SYSTEM; | |
} else { | |
NewAttr &= ~FILE_ATTRIBUTE_SYSTEM; | |
} | |
if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) { | |
NewAttr |= FILE_ATTRIBUTE_READONLY; | |
} else { | |
NewAttr &= ~FILE_ATTRIBUTE_READONLY; | |
} | |
NtStatus = PrivateFile->WinNtThunk->SetFileAttributes (NewFileName, NewAttr); | |
if (!NtStatus) { | |
Status = EFI_DEVICE_ERROR; | |
goto Reopen; | |
} | |
Done: | |
if (OldFileInfo != NULL) { | |
FreePool (OldFileInfo); | |
} | |
if (OldFileName != NULL) { | |
FreePool (OldFileName); | |
} | |
if (NewFileName != NULL) { | |
FreePool (NewFileName); | |
} | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
WinNtSimpleFileSystemFlush ( | |
IN EFI_FILE_PROTOCOL *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 | |
{ | |
BY_HANDLE_FILE_INFORMATION FileInfo; | |
WIN_NT_EFI_FILE_PRIVATE *PrivateFile; | |
EFI_STATUS Status; | |
EFI_TPL OldTpl; | |
if (This == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); | |
if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
if (PrivateFile->IsDirectoryPath) { | |
Status = EFI_SUCCESS; | |
goto Done; | |
} | |
if (PrivateFile->IsOpenedByRead) { | |
Status = EFI_ACCESS_DENIED; | |
goto Done; | |
} | |
PrivateFile->WinNtThunk->GetFileInformationByHandle (PrivateFile->LHandle, &FileInfo); | |
if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { | |
Status = EFI_ACCESS_DENIED; | |
goto Done; | |
} | |
Status = PrivateFile->WinNtThunk->FlushFileBuffers (PrivateFile->LHandle) ? EFI_SUCCESS : EFI_DEVICE_ERROR; | |
Done: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
// | |
// bugbug: - Use Windows error reporting. | |
// | |
} | |