2 File System Access for NvVarsFileLib
4 Copyright (c) 2004 - 2009, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "NvVarsFileLib.h"
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/MemoryAllocationLib.h>
23 Open the NvVars file for reading or writing
25 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
26 @param[in] ReadingFile - TRUE: open the file for reading. FALSE: writing
27 @param[out] NvVarsFile - If EFI_SUCCESS is returned, then this is updated
28 with the opened NvVars file.
30 @return EFI_SUCCESS if the file was opened
35 IN EFI_HANDLE FsHandle
,
36 IN BOOLEAN ReadingFile
,
37 OUT EFI_FILE_HANDLE
*NvVarsFile
41 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
45 // Get the FileSystem protocol on that handle
47 Status
= gBS
->HandleProtocol (
49 &gEfiSimpleFileSystemProtocolGuid
,
52 if (EFI_ERROR (Status
)) {
57 // Get the volume (the root directory)
59 Status
= Fs
->OpenVolume (Fs
, &Root
);
60 if (EFI_ERROR (Status
)) {
65 // Attempt to open the NvVars file in the root directory
74 EFI_FILE_MODE_CREATE
|
80 if (EFI_ERROR (Status
)) {
89 Open the NvVars file for reading or writing
91 @param[in] File - The file to inspect
92 @param[out] Exists - Returns whether the file exists
93 @param[out] Size - Returns the size of the file
94 (0 if the file does not exist)
98 NvVarsFileReadCheckup (
99 IN EFI_FILE_HANDLE File
,
104 EFI_FILE_INFO
*FileInfo
;
109 FileInfo
= FileHandleGetInfo (File
);
110 if (FileInfo
== NULL
) {
114 if ((FileInfo
->Attribute
& EFI_FILE_DIRECTORY
) != 0) {
120 *Size
= FileInfo
->FileSize
;
127 Open the NvVars file for reading or writing
129 @param[in] File - The file to inspect
130 @param[out] Exists - Returns whether the file exists
131 @param[out] Size - Returns the size of the file
132 (0 if the file does not exist)
137 IN EFI_FILE_HANDLE File
141 EFI_FILE_INFO
*FileInfo
;
144 // Retrieve the FileInfo structure
146 FileInfo
= FileHandleGetInfo (File
);
147 if (FileInfo
== NULL
) {
148 return EFI_INVALID_PARAMETER
;
152 // If the path is a directory, then return an error
154 if ((FileInfo
->Attribute
& EFI_FILE_DIRECTORY
) != 0) {
156 return EFI_INVALID_PARAMETER
;
160 // If the file size is already 0, then it is empty, so
161 // we can return success.
163 if (FileInfo
->FileSize
== 0) {
169 // Set the file size to 0.
171 FileInfo
->FileSize
= 0;
172 Status
= FileHandleSetInfo (File
, FileInfo
);
181 Reads a file to a newly allocated buffer
183 @param[in] File - The file to read
184 @param[in] ReadSize - The size of data to read from the file
186 @return Pointer to buffer allocated to hold the file
187 contents. NULL if an error occured.
191 FileHandleReadToNewBuffer (
192 IN EFI_FILE_HANDLE FileHandle
,
197 UINTN ActualReadSize
;
200 ActualReadSize
= ReadSize
;
201 FileContents
= AllocatePool (ReadSize
);
202 if (FileContents
!= NULL
) {
203 Status
= FileHandleRead (
208 if (EFI_ERROR (Status
) || (ActualReadSize
!= ReadSize
)) {
209 FreePool (FileContents
);
219 Reads the contents of the NvVars file on the file system
221 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
223 @return EFI_STATUS based on the success or failure of the file read
228 IN EFI_HANDLE FsHandle
232 EFI_FILE_HANDLE File
;
237 Status
= GetNvVarsFile (FsHandle
, TRUE
, &File
);
238 if (EFI_ERROR (Status
)) {
239 DEBUG ((EFI_D_INFO
, "FsAccess.c: Could not open NV Variables file on this file system\n"));
243 NvVarsFileReadCheckup (File
, &FileExists
, &FileSize
);
245 FileHandleClose (File
);
246 return EFI_UNSUPPORTED
;
249 FileContents
= FileHandleReadToNewBuffer (File
, FileSize
);
250 if (FileContents
== NULL
) {
251 FileHandleClose (File
);
252 return EFI_UNSUPPORTED
;
257 "FsAccess.c: Read %d bytes from NV Variables file\n",
261 Status
= SetVariablesFromBuffer (FileContents
, FileSize
);
263 FreePool (FileContents
);
264 FileHandleClose (File
);
271 Loads the non-volatile variables from the NvVars file on the
274 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
276 @return EFI_STATUS based on the success or failure of load operation
288 DEBUG ((EFI_D_INFO
, "FsAccess.c: LoadNvVarsFromFs\n"));
291 // We write a variable to indicate we've already loaded the
292 // variable data. If it is found, we skip the loading.
294 // This is relevent if the non-volatile variable have been
295 // able to survive a reboot operation. In that case, we don't
296 // want to re-load the file as it would overwrite newer changes
297 // made to the variables.
299 Size
= sizeof (VarData
);
301 Status
= gRT
->GetVariable (
303 &gEfiSimpleFileSystemProtocolGuid
,
308 if (Status
== EFI_SUCCESS
) {
309 DEBUG ((EFI_D_INFO
, "NV Variables were already loaded\n"));
310 return EFI_ALREADY_STARTED
;
314 // Attempt to restore the variables from the NvVars file.
316 Status
= ReadNvVarsFile (FsHandle
);
317 if (EFI_ERROR (Status
)) {
318 DEBUG ((EFI_D_INFO
, "Error while restoring NV variable data\n"));
323 // Write a variable to indicate we've already loaded the
324 // variable data. If it is found, we skip the loading on
325 // subsequent attempts.
327 Size
= sizeof (VarData
);
331 &gEfiSimpleFileSystemProtocolGuid
,
332 EFI_VARIABLE_NON_VOLATILE
|
333 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
334 EFI_VARIABLE_RUNTIME_ACCESS
,
341 "FsAccess.c: Read NV Variables file (size=%d)\n",
350 Saves the non-volatile variables into the NvVars file on the
353 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
355 @return EFI_STATUS based on the success or failure of load operation
364 EFI_FILE_HANDLE File
;
365 UINTN VariableNameBufferSize
;
366 UINTN VariableNameSize
;
367 CHAR16
*VariableName
;
369 UINTN VariableDataBufferSize
;
370 UINTN VariableDataSize
;
372 UINT32 VariableAttributes
;
376 // Open the NvVars file for writing.
378 Status
= GetNvVarsFile (FsHandle
, FALSE
, &File
);
379 if (EFI_ERROR (Status
)) {
380 DEBUG ((EFI_D_INFO
, "FsAccess.c: Unable to open file to saved NV Variables\n"));
385 // Empty the starting file contents.
387 Status
= FileHandleEmpty (File
);
388 if (EFI_ERROR (Status
)) {
389 FileHandleClose (File
);
394 // Initialize the variable name and data buffer variables.
396 VariableNameBufferSize
= sizeof (CHAR16
);
397 VariableName
= AllocateZeroPool (VariableNameBufferSize
);
399 VariableDataBufferSize
= 0;
404 // Get the next variable name and guid
406 VariableNameSize
= VariableNameBufferSize
;
407 Status
= gRT
->GetNextVariableName (
412 if (Status
== EFI_BUFFER_TOO_SMALL
) {
414 // The currently allocated VariableName buffer is too small,
415 // so we allocate a larger buffer, and copy the old buffer
418 NewBuffer
= AllocatePool (VariableNameSize
);
419 if (NewBuffer
== NULL
) {
420 Status
= EFI_OUT_OF_RESOURCES
;
423 CopyMem (NewBuffer
, VariableName
, VariableNameBufferSize
);
424 if (VariableName
!= NULL
) {
425 FreePool (VariableName
);
427 VariableName
= NewBuffer
;
428 VariableNameBufferSize
= VariableNameSize
;
431 // Try to get the next variable name again with the larger buffer.
433 Status
= gRT
->GetNextVariableName (
440 if (EFI_ERROR (Status
)) {
441 if (Status
== EFI_NOT_FOUND
) {
442 Status
= EFI_SUCCESS
;
448 // Get the variable data and attributes
450 VariableDataSize
= VariableDataBufferSize
;
451 Status
= gRT
->GetVariable (
458 if (Status
== EFI_BUFFER_TOO_SMALL
) {
460 // The currently allocated VariableData buffer is too small,
461 // so we allocate a larger buffer.
463 if (VariableDataBufferSize
!= 0) {
464 FreePool (VariableData
);
466 VariableDataBufferSize
= 0;
468 VariableData
= AllocatePool (VariableDataSize
);
469 if (VariableData
== NULL
) {
470 Status
= EFI_OUT_OF_RESOURCES
;
473 VariableDataBufferSize
= VariableDataSize
;
476 // Try to read the variable again with the larger buffer.
478 Status
= gRT
->GetVariable (
486 if (EFI_ERROR (Status
)) {
491 // Skip volatile variables. We only preserve non-volatile variables.
493 if ((VariableAttributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
499 "Saving variable %g:%s to file\n",
505 // Write the variable information out to the file
507 Status
= PackVariableIntoFile (
516 if (EFI_ERROR (Status
)) {
522 if (VariableName
!= NULL
) {
523 FreePool (VariableName
);
526 if (VariableData
!= NULL
) {
527 FreePool (VariableData
);
530 FileHandleClose (File
);
532 if (!EFI_ERROR (Status
)) {
533 DEBUG ((EFI_D_INFO
, "Saved NV Variables to NvVars file\n"));