123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507 |
- /** @file
- File System Access for NvVarsFileLib
- Copyright (c) 2004 - 2019 Intel Corporation. All rights reserved. <BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "NvVarsFileLib.h"
- #include <Library/BaseMemoryLib.h>
- #include <Library/DebugLib.h>
- #include <Library/MemoryAllocationLib.h>
- /**
- Open the NvVars file for reading or writing
- @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
- @param[in] ReadingFile - TRUE: open the file for reading. FALSE: writing
- @param[out] NvVarsFile - If EFI_SUCCESS is returned, then this is updated
- with the opened NvVars file.
- @return EFI_SUCCESS if the file was opened
- **/
- EFI_STATUS
- GetNvVarsFile (
- IN EFI_HANDLE FsHandle,
- IN BOOLEAN ReadingFile,
- OUT EFI_FILE_HANDLE *NvVarsFile
- )
- {
- EFI_STATUS Status;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
- EFI_FILE_HANDLE Root;
- //
- // Get the FileSystem protocol on that handle
- //
- Status = gBS->HandleProtocol (
- FsHandle,
- &gEfiSimpleFileSystemProtocolGuid,
- (VOID **)&Fs
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Get the volume (the root directory)
- //
- Status = Fs->OpenVolume (Fs, &Root);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Attempt to open the NvVars file in the root directory
- //
- Status = Root->Open (
- Root,
- NvVarsFile,
- L"NvVars",
- ReadingFile ?
- EFI_FILE_MODE_READ :
- (
- EFI_FILE_MODE_CREATE |
- EFI_FILE_MODE_READ |
- EFI_FILE_MODE_WRITE
- ),
- 0
- );
- return Status;
- }
- /**
- Open the NvVars file for reading or writing
- @param[in] File - The file to inspect
- @param[out] Exists - Returns whether the file exists
- @param[out] Size - Returns the size of the file
- (0 if the file does not exist)
- **/
- VOID
- NvVarsFileReadCheckup (
- IN EFI_FILE_HANDLE File,
- OUT BOOLEAN *Exists,
- OUT UINTN *Size
- )
- {
- EFI_FILE_INFO *FileInfo;
- *Exists = FALSE;
- *Size = 0;
- FileInfo = FileHandleGetInfo (File);
- if (FileInfo == NULL) {
- return;
- }
- if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {
- FreePool (FileInfo);
- return;
- }
- *Exists = TRUE;
- *Size = (UINTN) FileInfo->FileSize;
- FreePool (FileInfo);
- }
- /**
- Open the NvVars file for reading or writing
- @param[in] File - The file to inspect
- @param[out] Exists - Returns whether the file exists
- @param[out] Size - Returns the size of the file
- (0 if the file does not exist)
- **/
- EFI_STATUS
- FileHandleEmpty (
- IN EFI_FILE_HANDLE File
- )
- {
- EFI_STATUS Status;
- EFI_FILE_INFO *FileInfo;
- //
- // Retrieve the FileInfo structure
- //
- FileInfo = FileHandleGetInfo (File);
- if (FileInfo == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // If the path is a directory, then return an error
- //
- if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {
- FreePool (FileInfo);
- return EFI_INVALID_PARAMETER;
- }
- //
- // If the file size is already 0, then it is empty, so
- // we can return success.
- //
- if (FileInfo->FileSize == 0) {
- FreePool (FileInfo);
- return EFI_SUCCESS;
- }
- //
- // Set the file size to 0.
- //
- FileInfo->FileSize = 0;
- Status = FileHandleSetInfo (File, FileInfo);
- FreePool (FileInfo);
- return Status;
- }
- /**
- Reads a file to a newly allocated buffer
- @param[in] File - The file to read
- @param[in] ReadSize - The size of data to read from the file
- @return Pointer to buffer allocated to hold the file
- contents. NULL if an error occurred.
- **/
- VOID*
- FileHandleReadToNewBuffer (
- IN EFI_FILE_HANDLE FileHandle,
- IN UINTN ReadSize
- )
- {
- EFI_STATUS Status;
- UINTN ActualReadSize;
- VOID *FileContents;
- ActualReadSize = ReadSize;
- FileContents = AllocatePool (ReadSize);
- if (FileContents != NULL) {
- Status = FileHandleRead (
- FileHandle,
- &ReadSize,
- FileContents
- );
- if (EFI_ERROR (Status) || (ActualReadSize != ReadSize)) {
- FreePool (FileContents);
- return NULL;
- }
- }
- return FileContents;
- }
- /**
- Reads the contents of the NvVars file on the file system
- @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
- @return EFI_STATUS based on the success or failure of the file read
- **/
- EFI_STATUS
- ReadNvVarsFile (
- IN EFI_HANDLE FsHandle
- )
- {
- EFI_STATUS Status;
- EFI_FILE_HANDLE File;
- UINTN FileSize;
- BOOLEAN FileExists;
- VOID *FileContents;
- EFI_HANDLE SerializedVariables;
- Status = GetNvVarsFile (FsHandle, TRUE, &File);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_INFO, "FsAccess.c: Could not open NV Variables file on this file system\n"));
- return Status;
- }
- NvVarsFileReadCheckup (File, &FileExists, &FileSize);
- if (FileSize == 0) {
- FileHandleClose (File);
- return EFI_UNSUPPORTED;
- }
- FileContents = FileHandleReadToNewBuffer (File, FileSize);
- if (FileContents == NULL) {
- FileHandleClose (File);
- return EFI_UNSUPPORTED;
- }
- DEBUG ((
- EFI_D_INFO,
- "FsAccess.c: Read %Lu bytes from NV Variables file\n",
- (UINT64)FileSize
- ));
- Status = SerializeVariablesNewInstanceFromBuffer (
- &SerializedVariables,
- FileContents,
- FileSize
- );
- if (!RETURN_ERROR (Status)) {
- Status = SerializeVariablesSetSerializedVariables (SerializedVariables);
- }
- FreePool (FileContents);
- FileHandleClose (File);
- return Status;
- }
- /**
- Writes a variable to indicate that the NV variables
- have been loaded from the file system.
- **/
- STATIC
- VOID
- SetNvVarsVariable (
- VOID
- )
- {
- BOOLEAN VarData;
- UINTN Size;
- //
- // Write a variable to indicate we've already loaded the
- // variable data. If it is found, we skip the loading on
- // subsequent attempts.
- //
- Size = sizeof (VarData);
- VarData = TRUE;
- gRT->SetVariable (
- L"NvVars",
- &gEfiSimpleFileSystemProtocolGuid,
- EFI_VARIABLE_NON_VOLATILE |
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS,
- Size,
- (VOID*) &VarData
- );
- }
- /**
- Loads the non-volatile variables from the NvVars file on the
- given file system.
- @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
- @return EFI_STATUS based on the success or failure of load operation
- **/
- EFI_STATUS
- LoadNvVarsFromFs (
- EFI_HANDLE FsHandle
- )
- {
- EFI_STATUS Status;
- BOOLEAN VarData;
- UINTN Size;
- DEBUG ((EFI_D_INFO, "FsAccess.c: LoadNvVarsFromFs\n"));
- //
- // We write a variable to indicate we've already loaded the
- // variable data. If it is found, we skip the loading.
- //
- // This is relevant if the non-volatile variable have been
- // able to survive a reboot operation. In that case, we don't
- // want to re-load the file as it would overwrite newer changes
- // made to the variables.
- //
- Size = sizeof (VarData);
- VarData = TRUE;
- Status = gRT->GetVariable (
- L"NvVars",
- &gEfiSimpleFileSystemProtocolGuid,
- NULL,
- &Size,
- (VOID*) &VarData
- );
- if (Status == EFI_SUCCESS) {
- DEBUG ((EFI_D_INFO, "NV Variables were already loaded\n"));
- return EFI_ALREADY_STARTED;
- }
- //
- // Attempt to restore the variables from the NvVars file.
- //
- Status = ReadNvVarsFile (FsHandle);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_INFO, "Error while restoring NV variable data\n"));
- return Status;
- }
- //
- // Write a variable to indicate we've already loaded the
- // variable data. If it is found, we skip the loading on
- // subsequent attempts.
- //
- SetNvVarsVariable();
- DEBUG ((
- EFI_D_INFO,
- "FsAccess.c: Read NV Variables file (size=%Lu)\n",
- (UINT64)Size
- ));
- return Status;
- }
- STATIC
- RETURN_STATUS
- EFIAPI
- IterateVariablesCallbackAddAllNvVariables (
- IN VOID *Context,
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN UINT32 Attributes,
- IN UINTN DataSize,
- IN VOID *Data
- )
- {
- EFI_HANDLE Instance;
- Instance = (EFI_HANDLE) Context;
- //
- // Only save non-volatile variables
- //
- if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
- return RETURN_SUCCESS;
- }
- return SerializeVariablesAddVariable (
- Instance,
- VariableName,
- VendorGuid,
- Attributes,
- DataSize,
- Data
- );
- }
- /**
- Saves the non-volatile variables into the NvVars file on the
- given file system.
- @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
- @return EFI_STATUS based on the success or failure of load operation
- **/
- EFI_STATUS
- SaveNvVarsToFs (
- EFI_HANDLE FsHandle
- )
- {
- EFI_STATUS Status;
- EFI_FILE_HANDLE File;
- UINTN WriteSize;
- UINTN VariableDataSize;
- VOID *VariableData;
- EFI_HANDLE SerializedVariables;
- SerializedVariables = NULL;
- Status = SerializeVariablesNewInstance (&SerializedVariables);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = SerializeVariablesIterateSystemVariables (
- IterateVariablesCallbackAddAllNvVariables,
- (VOID*) SerializedVariables
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- VariableData = NULL;
- VariableDataSize = 0;
- Status = SerializeVariablesToBuffer (
- SerializedVariables,
- NULL,
- &VariableDataSize
- );
- if (Status == RETURN_BUFFER_TOO_SMALL) {
- VariableData = AllocatePool (VariableDataSize);
- if (VariableData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- } else {
- Status = SerializeVariablesToBuffer (
- SerializedVariables,
- VariableData,
- &VariableDataSize
- );
- }
- }
- SerializeVariablesFreeInstance (SerializedVariables);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Open the NvVars file for writing.
- //
- Status = GetNvVarsFile (FsHandle, FALSE, &File);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_INFO, "FsAccess.c: Unable to open file to saved NV Variables\n"));
- return Status;
- }
- //
- // Empty the starting file contents.
- //
- Status = FileHandleEmpty (File);
- if (EFI_ERROR (Status)) {
- FileHandleClose (File);
- return Status;
- }
- WriteSize = VariableDataSize;
- Status = FileHandleWrite (File, &WriteSize, VariableData);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- FileHandleClose (File);
- if (!EFI_ERROR (Status)) {
- //
- // Write a variable to indicate we've already loaded the
- // variable data. If it is found, we skip the loading on
- // subsequent attempts.
- //
- SetNvVarsVariable();
- DEBUG ((EFI_D_INFO, "Saved NV Variables to NvVars file\n"));
- }
- return Status;
- }
|