/** @file | |
This driver uses the EFI_FIRMWARE_VOLUME2_PROTOCOL to expose files in firmware | |
volumes via the the EFI_SIMPLE_FILESYSTEM_PROTOCOL and EFI_FILE_PROTOCOL. | |
It will expose a single directory, containing one file for each file in the firmware | |
volume. If a file has a UI section, its contents will be used as a filename. | |
Otherwise, a string representation of the GUID will be used. | |
Files of an executable type (That is PEIM, DRIVER, COMBINED_PEIM_DRIVER and APPLICATION) | |
will have ".efi" added to their filename. | |
Its primary intended use is to be able to start EFI applications embedded in FVs | |
from the UEFI shell. It is entirely read-only. | |
Copyright (c) 2014, ARM Limited. All rights reserved. | |
Copyright (c) 2014, 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. | |
**/ | |
#include "FvSimpleFileSystemInternal.h" | |
EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; | |
// | |
// A Guid string is 32 hex characters with 4 hyphens and a NULL-terminated char: 37 characters total | |
// | |
#define GUID_STRING_SIZE (37 * sizeof (CHAR16)) | |
#define FVFS_VOLUME_LABEL_PREFIX L"Firmware Volume: " | |
#define FVFS_VOLUME_LABEL_SIZE (sizeof (FVFS_VOLUME_LABEL_PREFIX) + GUID_STRING_SIZE - sizeof (CHAR16)) | |
#define FVFS_FALLBACK_VOLUME_LABEL L"Firmware Volume" | |
// | |
// Template for EFI_SIMPLE_FILE_SYSTEM_PROTOCOL data structure. | |
// | |
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mSimpleFsTemplate = { | |
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION, | |
FvSimpleFileSystemOpenVolume | |
}; | |
// | |
// Template for EFI_DRIVER_BINDING_PROTOCOL data structure. | |
// | |
EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = { | |
FvSimpleFileSystemDriverSupported, | |
FvSimpleFileSystemDriverStart, | |
FvSimpleFileSystemDriverStop, | |
0, | |
NULL, | |
NULL | |
}; | |
/** | |
Open the root directory on a volume. | |
@param This A pointer to the volume to open the root directory. | |
@param RootFile A pointer to the location to return the opened file handle for the | |
root directory. | |
@retval EFI_SUCCESS The device was opened. | |
@retval EFI_UNSUPPORTED This volume does not support the requested file system type. | |
@retval EFI_NO_MEDIA The device has no medium. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@retval EFI_ACCESS_DENIED The service denied access to the file. | |
@retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. | |
@retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no | |
longer supported. Any existing file handles for this volume are | |
no longer valid. To access the files on the new medium, the | |
volume must be reopened with OpenVolume(). | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FvSimpleFileSystemOpenVolume ( | |
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, | |
OUT EFI_FILE_PROTOCOL **RootFile | |
) | |
{ | |
EFI_STATUS Status; | |
FV_FILESYSTEM_FILE *Root; | |
CHAR16 *UiSection; | |
EFI_GUID NameGuid; | |
EFI_FV_FILE_ATTRIBUTES Attributes; | |
UINT32 Authentication; | |
UINTN Key; | |
EFI_FV_FILETYPE FileType; | |
UINTN Size; | |
FV_FILESYSTEM_INSTANCE *Instance; | |
FV_FILESYSTEM_FILE_INFO *FvFileInfo; | |
EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; | |
CHAR16 *Name; | |
UINTN NameLen; | |
UINTN NumChars; | |
UINTN DestMax; | |
Instance = FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (This); | |
Status = EFI_SUCCESS; | |
if (Instance->Root == NULL) { | |
// | |
// Allocate file structure for root file | |
// | |
Root = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE)); | |
if (Root == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Instance->Root = Root; | |
Root->Instance = Instance; | |
Root->Signature = FVFS_FILE_SIGNATURE; | |
CopyMem (&Root->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate)); | |
Root->FvFileInfo = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO)); | |
if (Root->FvFileInfo == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Root->FvFileInfo->FileInfo.Size = sizeof (EFI_FILE_INFO); | |
Root->FvFileInfo->FileInfo.Attribute = EFI_FILE_DIRECTORY | EFI_FILE_READ_ONLY; | |
// | |
// Populate the instance's list of files. We consider anything a file that | |
// has a UI_SECTION, which we consider to be its filename. | |
// | |
FvProtocol = Instance->FvProtocol; | |
// | |
// Allocate Key | |
// | |
Key = 0; | |
do { | |
FileType = EFI_FV_FILETYPE_ALL; | |
Status = FvProtocol->GetNextFile ( | |
FvProtocol, | |
&Key, | |
&FileType, | |
&NameGuid, | |
&Attributes, | |
&Size | |
); | |
if (EFI_ERROR (Status)) { | |
ASSERT (Status == EFI_NOT_FOUND); | |
break; | |
} | |
// | |
// Get a file's name: If it has a UI section, use that, otherwise use | |
// its NameGuid. | |
// | |
UiSection = NULL; | |
Status = FvProtocol->ReadSection ( | |
FvProtocol, | |
&NameGuid, | |
EFI_SECTION_USER_INTERFACE, | |
0, | |
(VOID **)&UiSection, | |
&Size, | |
&Authentication | |
); | |
if (!EFI_ERROR (Status)) { | |
Name = UiSection; | |
} else { | |
Name = AllocateZeroPool (GUID_STRING_SIZE); | |
if (Name == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
NumChars = UnicodeSPrint (Name, GUID_STRING_SIZE, L"%g", &NameGuid); | |
ASSERT ((NumChars + 1) * sizeof (CHAR16) == GUID_STRING_SIZE); | |
} | |
// | |
// Found a file. | |
// Allocate a file structure and populate it. | |
// | |
NameLen = StrSize (Name); | |
if (FV_FILETYPE_IS_EXECUTABLE (FileType)) { | |
NameLen += StrSize (L".efi") - sizeof (CHAR16); | |
} | |
FvFileInfo = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO) + NameLen - sizeof (CHAR16)); | |
if (FvFileInfo == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
FvFileInfo->Signature = FVFS_FILE_INFO_SIGNATURE; | |
InitializeListHead (&FvFileInfo->Link); | |
CopyMem (&FvFileInfo->NameGuid, &NameGuid, sizeof (EFI_GUID)); | |
FvFileInfo->Type = FileType; | |
// | |
// Add ".efi" to filenames of drivers and applications. | |
// | |
DestMax = NameLen / sizeof (CHAR16); | |
Status = StrnCpyS (&FvFileInfo->FileInfo.FileName[0], DestMax, Name, StrLen (Name)); | |
ASSERT_EFI_ERROR (Status); | |
if (FV_FILETYPE_IS_EXECUTABLE (FileType)) { | |
Status = StrnCatS (&FvFileInfo->FileInfo.FileName[0], DestMax, L".efi", StrLen (L".efi")); | |
ASSERT_EFI_ERROR (Status); | |
} | |
FvFileInfo->FileInfo.Size = sizeof (EFI_FILE_INFO) + NameLen - sizeof (CHAR16); | |
Status = FvFsGetFileSize (FvProtocol, FvFileInfo); | |
ASSERT_EFI_ERROR (Status); | |
FvFileInfo->FileInfo.PhysicalSize = FvFileInfo->FileInfo.FileSize; | |
FvFileInfo->FileInfo.Attribute = EFI_FILE_READ_ONLY; | |
InsertHeadList (&Instance->FileInfoHead, &FvFileInfo->Link); | |
FreePool (Name); | |
} while (TRUE); | |
if (Status == EFI_NOT_FOUND) { | |
Status = EFI_SUCCESS; | |
} | |
} | |
Instance->Root->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance); | |
*RootFile = &Instance->Root->FileProtocol; | |
return Status; | |
} | |
/** | |
Worker function to initialize Unicode Collation support. | |
It tries to locate Unicode Collation (2) protocol and matches it with current | |
platform language code. | |
@param AgentHandle The handle used to open Unicode Collation (2) protocol. | |
@param ProtocolGuid The pointer to Unicode Collation (2) protocol GUID. | |
@param VariableName The name of the RFC 4646 or ISO 639-2 language variable. | |
@param DefaultLanguage The default language in case the RFC 4646 or ISO 639-2 language is absent. | |
@retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located. | |
@retval Others The Unicode Collation (2) protocol has not been located. | |
**/ | |
EFI_STATUS | |
InitializeUnicodeCollationSupportWorker ( | |
IN EFI_HANDLE AgentHandle, | |
IN EFI_GUID *ProtocolGuid, | |
IN CONST CHAR16 *VariableName, | |
IN CONST CHAR8 *DefaultLanguage | |
) | |
{ | |
EFI_STATUS ReturnStatus; | |
EFI_STATUS Status; | |
UINTN NumHandles; | |
UINTN Index; | |
EFI_HANDLE *Handles; | |
EFI_UNICODE_COLLATION_PROTOCOL *Uci; | |
BOOLEAN Iso639Language; | |
CHAR8 *Language; | |
CHAR8 *BestLanguage; | |
Status = gBS->LocateHandleBuffer ( | |
ByProtocol, | |
ProtocolGuid, | |
NULL, | |
&NumHandles, | |
&Handles | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Iso639Language = (BOOLEAN) (ProtocolGuid == &gEfiUnicodeCollationProtocolGuid); | |
GetEfiGlobalVariable2 (VariableName, (VOID**) &Language, NULL); | |
ReturnStatus = EFI_UNSUPPORTED; | |
for (Index = 0; Index < NumHandles; Index++) { | |
// | |
// Open Unicode Collation Protocol | |
// | |
Status = gBS->OpenProtocol ( | |
Handles[Index], | |
ProtocolGuid, | |
(VOID **) &Uci, | |
AgentHandle, | |
NULL, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
// | |
// Find the best matching matching language from the supported languages | |
// of Unicode Collation (2) protocol. | |
// | |
BestLanguage = GetBestLanguage ( | |
Uci->SupportedLanguages, | |
Iso639Language, | |
(Language == NULL) ? "" : Language, | |
DefaultLanguage, | |
NULL | |
); | |
if (BestLanguage != NULL) { | |
FreePool (BestLanguage); | |
mUnicodeCollation = Uci; | |
ReturnStatus = EFI_SUCCESS; | |
break; | |
} | |
} | |
if (Language != NULL) { | |
FreePool (Language); | |
} | |
FreePool (Handles); | |
return ReturnStatus; | |
} | |
/** | |
Initialize Unicode Collation support. | |
It tries to locate Unicode Collation 2 protocol and matches it with current | |
platform language code. If for any reason the first attempt fails, it then tries to | |
use Unicode Collation Protocol. | |
@param AgentHandle The handle used to open Unicode Collation (2) protocol. | |
@retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located. | |
@retval Others The Unicode Collation (2) protocol has not been located. | |
**/ | |
EFI_STATUS | |
InitializeUnicodeCollationSupport ( | |
IN EFI_HANDLE AgentHandle | |
) | |
{ | |
EFI_STATUS Status; | |
Status = EFI_UNSUPPORTED; | |
// | |
// First try to use RFC 4646 Unicode Collation 2 Protocol. | |
// | |
Status = InitializeUnicodeCollationSupportWorker ( | |
AgentHandle, | |
&gEfiUnicodeCollation2ProtocolGuid, | |
L"PlatformLang", | |
(CONST CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang) | |
); | |
// | |
// If the attempt to use Unicode Collation 2 Protocol fails, then we fall back | |
// on the ISO 639-2 Unicode Collation Protocol. | |
// | |
if (EFI_ERROR (Status)) { | |
Status = InitializeUnicodeCollationSupportWorker ( | |
AgentHandle, | |
&gEfiUnicodeCollationProtocolGuid, | |
L"Lang", | |
(CONST CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultLang) | |
); | |
} | |
return Status; | |
} | |
/** | |
Test to see if this driver supports ControllerHandle. | |
@param DriverBinding Protocol instance pointer. | |
@param ControllerHandle Handle of device to test | |
@param RemainingDevicePath Optional parameter use to pick a specific child | |
device to start. | |
@retval EFI_SUCCESS This driver supports this device | |
@retval EFI_ALREADY_STARTED This driver is already running on this device | |
@retval other This driver does not support this device | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FvSimpleFileSystemDriverSupported ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, | |
IN EFI_HANDLE ControllerHandle, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL | |
) | |
{ | |
return gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiFirmwareVolume2ProtocolGuid, | |
NULL, | |
gImageHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_TEST_PROTOCOL | |
); | |
} | |
/** | |
Start this driver on ControllerHandle by opening a FV protocol and | |
installing a SimpleFileSystem protocol on ControllerHandle. | |
@param DriverBinding Protocol instance pointer. | |
@param ControllerHandle Handle of device to bind driver to | |
@param RemainingDevicePath Optional parameter use to pick a specific child | |
device to start. | |
@retval EFI_SUCCESS This driver is added to ControllerHandle | |
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle | |
@retval other This driver does not support this device | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FvSimpleFileSystemDriverStart ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, | |
IN EFI_HANDLE ControllerHandle, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; | |
FV_FILESYSTEM_INSTANCE *Instance; | |
EFI_DEVICE_PATH_PROTOCOL *FvDevicePath; | |
EFI_GUID *FvGuid; | |
UINTN NumChars; | |
Status = InitializeUnicodeCollationSupport (DriverBinding->DriverBindingHandle); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Open FV protocol | |
// | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiFirmwareVolume2ProtocolGuid, | |
(VOID **) &FvProtocol, | |
gImageHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Create an instance | |
// | |
Instance = AllocateZeroPool (sizeof (FV_FILESYSTEM_INSTANCE)); | |
if (Instance == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Instance->Root = NULL; | |
Instance->FvProtocol = FvProtocol; | |
Instance->Signature = FVFS_INSTANCE_SIGNATURE; | |
InitializeListHead (&Instance->FileInfoHead); | |
InitializeListHead (&Instance->FileHead); | |
CopyMem (&Instance->SimpleFs, &mSimpleFsTemplate, sizeof (mSimpleFsTemplate)); | |
Status = gBS->InstallProtocolInterface( | |
&ControllerHandle, | |
&gEfiSimpleFileSystemProtocolGuid, | |
EFI_NATIVE_INTERFACE, | |
&Instance->SimpleFs | |
); | |
// | |
// Decide on a filesystem volume label, which will include the FV's guid. | |
// Get the device path to find the FV's GUID | |
// | |
Instance->VolumeLabel = NULL; | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiDevicePathProtocolGuid, | |
(VOID **) &FvDevicePath, | |
gImageHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (!EFI_ERROR (Status)) { | |
// | |
// Iterate over device path until we find a firmware volume node | |
// | |
while (!IsDevicePathEndType (FvDevicePath)) { | |
if (DevicePathType (FvDevicePath) == MEDIA_DEVICE_PATH && | |
DevicePathSubType (FvDevicePath) == MEDIA_PIWG_FW_VOL_DP) { | |
// | |
// Allocate the volume label | |
// | |
Instance->VolumeLabel = AllocateZeroPool (FVFS_VOLUME_LABEL_SIZE); | |
// | |
// Check the allocation was successful | |
// | |
if (Instance->VolumeLabel != NULL) { | |
// | |
// Extract the FV's guid | |
// | |
FvGuid = &((MEDIA_FW_VOL_DEVICE_PATH *) FvDevicePath)->FvName; | |
// | |
// Build the volume label string | |
// | |
NumChars = UnicodeSPrint ( | |
Instance->VolumeLabel, | |
FVFS_VOLUME_LABEL_SIZE, | |
FVFS_VOLUME_LABEL_PREFIX L"%g", | |
FvGuid | |
); | |
ASSERT ((NumChars + 1) * sizeof (CHAR16) == FVFS_VOLUME_LABEL_SIZE); | |
} | |
break; | |
} | |
FvDevicePath = NextDevicePathNode (FvDevicePath); | |
} | |
} | |
// | |
// If we didn't decide on a volume label, set a fallback one | |
// | |
if (Instance->VolumeLabel == NULL) { | |
Instance->VolumeLabel = AllocateCopyPool ( | |
sizeof (FVFS_FALLBACK_VOLUME_LABEL), | |
FVFS_FALLBACK_VOLUME_LABEL | |
); | |
} | |
return Status; | |
} | |
/** | |
Stop this driver on ControllerHandle by removing SimpleFileSystem protocol and closing | |
the FV protocol on ControllerHandle. | |
@param DriverBinding Protocol instance pointer. | |
@param ControllerHandle Handle of device to stop driver on | |
@param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of | |
children is zero stop the entire bus driver. | |
@param ChildHandleBuffer List of Child Handles to Stop. | |
@retval EFI_SUCCESS This driver is removed ControllerHandle | |
@retval other This driver was not removed from this device | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FvSimpleFileSystemDriverStop ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, | |
IN EFI_HANDLE ControllerHandle, | |
IN UINTN NumberOfChildren, | |
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL | |
) | |
{ | |
EFI_STATUS Status; | |
FV_FILESYSTEM_INSTANCE *Instance; | |
FV_FILESYSTEM_FILE_INFO *FvFileInfo; | |
LIST_ENTRY *Entry; | |
LIST_ENTRY *DelEntry; | |
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFile; | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiSimpleFileSystemProtocolGuid, | |
(VOID **) &SimpleFile, | |
DriverBinding->DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Instance = FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (SimpleFile); | |
if (IsListEmpty (&Instance->FileHead) == FALSE) { | |
// | |
// Not all opened files are closed | |
// | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// Close and uninstall protocols. | |
// | |
Status = gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiFirmwareVolume2ProtocolGuid, | |
gImageHandle, | |
ControllerHandle | |
); | |
ASSERT_EFI_ERROR (Status); | |
Status = gBS->UninstallProtocolInterface ( | |
ControllerHandle, | |
&gEfiSimpleFileSystemProtocolGuid, | |
&Instance->SimpleFs | |
); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Free file structures | |
// | |
if (!IsListEmpty (&Instance->FileInfoHead)) { | |
// | |
// Free the Subtask list. | |
// | |
for(Entry = Instance->FileInfoHead.ForwardLink; | |
Entry != (&Instance->FileInfoHead); | |
) { | |
DelEntry = Entry; | |
Entry = Entry->ForwardLink; | |
FvFileInfo = FVFS_FILE_INFO_FROM_LINK (DelEntry); | |
RemoveEntryList (DelEntry); | |
FreePool (FvFileInfo); | |
} | |
} | |
if (Instance->Root != NULL) { | |
// | |
// Root->Name is statically allocated, no need to free. | |
// | |
if (Instance->Root->FvFileInfo != NULL) { | |
FreePool (Instance->Root->FvFileInfo); | |
} | |
FreePool (Instance->Root); | |
} | |
// | |
// Free Instance | |
// | |
if (Instance->VolumeLabel != NULL) { | |
FreePool (Instance->VolumeLabel); | |
} | |
FreePool (Instance); | |
return EFI_SUCCESS; | |
} | |
/** | |
The user Entry Point for module FvSimpleFileSystem. 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 | |
FvSimpleFileSystemEntryPoint ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Install driver model protocol(s). | |
// | |
Status = EfiLibInstallDriverBindingComponentName2 ( | |
ImageHandle, | |
SystemTable, | |
&mDriverBinding, | |
ImageHandle, | |
&gFvSimpleFileSystemComponentName, | |
&gFvSimpleFileSystemComponentName2 | |
); | |
ASSERT_EFI_ERROR (Status); | |
return Status; | |
} |