]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/NvVarsFileLib/FsAccess.c
OvmfPkg: Remove superfluous return statements.
[mirror_edk2.git] / OvmfPkg / Library / NvVarsFileLib / FsAccess.c
CommitLineData
3e92a997
LE
1/** @file\r
2 File System Access for NvVarsFileLib\r
3\r
4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "NvVarsFileLib.h"\r
16\r
17#include <Library/BaseMemoryLib.h>\r
18#include <Library/DebugLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20\r
21\r
22/**\r
23 Open the NvVars file for reading or writing\r
24\r
25 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance\r
26 @param[in] ReadingFile - TRUE: open the file for reading. FALSE: writing\r
27 @param[out] NvVarsFile - If EFI_SUCCESS is returned, then this is updated\r
28 with the opened NvVars file.\r
29\r
30 @return EFI_SUCCESS if the file was opened\r
31\r
32**/\r
33EFI_STATUS\r
34GetNvVarsFile (\r
35 IN EFI_HANDLE FsHandle,\r
36 IN BOOLEAN ReadingFile,\r
37 OUT EFI_FILE_HANDLE *NvVarsFile\r
38 )\r
39{\r
40 EFI_STATUS Status;\r
41 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
42 EFI_FILE_HANDLE Root;\r
43\r
44 //\r
45 // Get the FileSystem protocol on that handle\r
46 //\r
47 Status = gBS->HandleProtocol (\r
48 FsHandle,\r
49 &gEfiSimpleFileSystemProtocolGuid,\r
50 (VOID **)&Fs\r
51 );\r
52 if (EFI_ERROR (Status)) {\r
53 return Status;\r
54 }\r
55\r
56 //\r
57 // Get the volume (the root directory)\r
58 //\r
59 Status = Fs->OpenVolume (Fs, &Root);\r
60 if (EFI_ERROR (Status)) {\r
61 return Status;\r
62 }\r
63\r
64 //\r
65 // Attempt to open the NvVars file in the root directory\r
66 //\r
67 Status = Root->Open (\r
68 Root,\r
69 NvVarsFile,\r
70 L"NvVars",\r
71 ReadingFile ?\r
72 EFI_FILE_MODE_READ :\r
73 (\r
74 EFI_FILE_MODE_CREATE |\r
75 EFI_FILE_MODE_READ |\r
76 EFI_FILE_MODE_WRITE\r
77 ),\r
78 0\r
79 );\r
3e92a997
LE
80\r
81 return Status;\r
82}\r
83\r
84\r
85/**\r
86 Open the NvVars file for reading or writing\r
87\r
88 @param[in] File - The file to inspect\r
89 @param[out] Exists - Returns whether the file exists\r
90 @param[out] Size - Returns the size of the file\r
91 (0 if the file does not exist)\r
92\r
93**/\r
94VOID\r
95NvVarsFileReadCheckup (\r
96 IN EFI_FILE_HANDLE File,\r
97 OUT BOOLEAN *Exists,\r
98 OUT UINTN *Size\r
99 )\r
100{\r
101 EFI_FILE_INFO *FileInfo;\r
102\r
103 *Exists = FALSE;\r
104 *Size = 0;\r
105\r
106 FileInfo = FileHandleGetInfo (File);\r
107 if (FileInfo == NULL) {\r
108 return;\r
109 }\r
110\r
111 if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {\r
112 FreePool (FileInfo);\r
113 return;\r
114 }\r
115\r
116 *Exists = TRUE;\r
117 *Size = (UINTN) FileInfo->FileSize;\r
118\r
119 FreePool (FileInfo);\r
120}\r
121\r
122\r
123/**\r
124 Open the NvVars file for reading or writing\r
125\r
126 @param[in] File - The file to inspect\r
127 @param[out] Exists - Returns whether the file exists\r
128 @param[out] Size - Returns the size of the file\r
129 (0 if the file does not exist)\r
130\r
131**/\r
132EFI_STATUS\r
133FileHandleEmpty (\r
134 IN EFI_FILE_HANDLE File\r
135 )\r
136{\r
137 EFI_STATUS Status;\r
138 EFI_FILE_INFO *FileInfo;\r
139\r
140 //\r
141 // Retrieve the FileInfo structure\r
142 //\r
143 FileInfo = FileHandleGetInfo (File);\r
144 if (FileInfo == NULL) {\r
145 return EFI_INVALID_PARAMETER;\r
146 }\r
147\r
148 //\r
149 // If the path is a directory, then return an error\r
150 //\r
151 if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {\r
152 FreePool (FileInfo);\r
153 return EFI_INVALID_PARAMETER;\r
154 }\r
155\r
156 //\r
157 // If the file size is already 0, then it is empty, so\r
158 // we can return success.\r
159 //\r
160 if (FileInfo->FileSize == 0) {\r
161 FreePool (FileInfo);\r
162 return EFI_SUCCESS;\r
163 }\r
164\r
165 //\r
166 // Set the file size to 0.\r
167 //\r
168 FileInfo->FileSize = 0;\r
169 Status = FileHandleSetInfo (File, FileInfo);\r
170\r
171 FreePool (FileInfo);\r
172\r
173 return Status;\r
174}\r
175\r
176\r
177/**\r
178 Reads a file to a newly allocated buffer\r
179\r
180 @param[in] File - The file to read\r
181 @param[in] ReadSize - The size of data to read from the file\r
182\r
183 @return Pointer to buffer allocated to hold the file\r
8c0b0b34 184 contents. NULL if an error occurred.\r
3e92a997
LE
185\r
186**/\r
187VOID*\r
188FileHandleReadToNewBuffer (\r
189 IN EFI_FILE_HANDLE FileHandle,\r
190 IN UINTN ReadSize\r
191 )\r
192{\r
193 EFI_STATUS Status;\r
194 UINTN ActualReadSize;\r
195 VOID *FileContents;\r
196\r
197 ActualReadSize = ReadSize;\r
198 FileContents = AllocatePool (ReadSize);\r
199 if (FileContents != NULL) {\r
200 Status = FileHandleRead (\r
201 FileHandle,\r
202 &ReadSize,\r
203 FileContents\r
204 );\r
205 if (EFI_ERROR (Status) || (ActualReadSize != ReadSize)) {\r
206 FreePool (FileContents);\r
207 return NULL;\r
208 }\r
209 }\r
210\r
211 return FileContents;\r
212}\r
213\r
214\r
215/**\r
216 Reads the contents of the NvVars file on the file system\r
217\r
218 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance\r
219\r
220 @return EFI_STATUS based on the success or failure of the file read\r
221\r
222**/\r
223EFI_STATUS\r
224ReadNvVarsFile (\r
225 IN EFI_HANDLE FsHandle\r
226 )\r
227{\r
228 EFI_STATUS Status;\r
229 EFI_FILE_HANDLE File;\r
230 UINTN FileSize;\r
231 BOOLEAN FileExists;\r
232 VOID *FileContents;\r
233 EFI_HANDLE SerializedVariables;\r
234\r
235 Status = GetNvVarsFile (FsHandle, TRUE, &File);\r
236 if (EFI_ERROR (Status)) {\r
237 DEBUG ((EFI_D_INFO, "FsAccess.c: Could not open NV Variables file on this file system\n"));\r
238 return Status;\r
239 }\r
240\r
241 NvVarsFileReadCheckup (File, &FileExists, &FileSize);\r
242 if (FileSize == 0) {\r
243 FileHandleClose (File);\r
244 return EFI_UNSUPPORTED;\r
245 }\r
246\r
247 FileContents = FileHandleReadToNewBuffer (File, FileSize);\r
248 if (FileContents == NULL) {\r
249 FileHandleClose (File);\r
250 return EFI_UNSUPPORTED;\r
251 }\r
252\r
253 DEBUG ((\r
254 EFI_D_INFO,\r
255 "FsAccess.c: Read %Lu bytes from NV Variables file\n",\r
256 (UINT64)FileSize\r
257 ));\r
258\r
259 Status = SerializeVariablesNewInstanceFromBuffer (\r
260 &SerializedVariables,\r
261 FileContents,\r
262 FileSize\r
263 );\r
264 if (!RETURN_ERROR (Status)) {\r
265 Status = SerializeVariablesSetSerializedVariables (SerializedVariables);\r
266 }\r
267\r
268 FreePool (FileContents);\r
269 FileHandleClose (File);\r
270\r
271 return Status;\r
272}\r
273\r
274\r
275/**\r
276 Writes a variable to indicate that the NV variables\r
277 have been loaded from the file system.\r
278\r
279**/\r
280STATIC\r
281VOID\r
282SetNvVarsVariable (\r
283 VOID\r
284 )\r
285{\r
286 BOOLEAN VarData;\r
287 UINTN Size;\r
288\r
289 //\r
290 // Write a variable to indicate we've already loaded the\r
291 // variable data. If it is found, we skip the loading on\r
292 // subsequent attempts.\r
293 //\r
294 Size = sizeof (VarData);\r
295 VarData = TRUE;\r
296 gRT->SetVariable (\r
297 L"NvVars",\r
298 &gEfiSimpleFileSystemProtocolGuid,\r
299 EFI_VARIABLE_NON_VOLATILE |\r
300 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
301 EFI_VARIABLE_RUNTIME_ACCESS,\r
302 Size,\r
303 (VOID*) &VarData\r
304 );\r
305}\r
306\r
307\r
308/**\r
309 Loads the non-volatile variables from the NvVars file on the\r
310 given file system.\r
311\r
312 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance\r
313\r
314 @return EFI_STATUS based on the success or failure of load operation\r
315\r
316**/\r
317EFI_STATUS\r
318LoadNvVarsFromFs (\r
319 EFI_HANDLE FsHandle\r
320 )\r
321{\r
322 EFI_STATUS Status;\r
323 BOOLEAN VarData;\r
324 UINTN Size;\r
325\r
326 DEBUG ((EFI_D_INFO, "FsAccess.c: LoadNvVarsFromFs\n"));\r
327\r
328 //\r
329 // We write a variable to indicate we've already loaded the\r
330 // variable data. If it is found, we skip the loading.\r
331 //\r
8c0b0b34 332 // This is relevant if the non-volatile variable have been\r
3e92a997
LE
333 // able to survive a reboot operation. In that case, we don't\r
334 // want to re-load the file as it would overwrite newer changes\r
335 // made to the variables.\r
336 //\r
337 Size = sizeof (VarData);\r
338 VarData = TRUE;\r
339 Status = gRT->GetVariable (\r
340 L"NvVars",\r
341 &gEfiSimpleFileSystemProtocolGuid,\r
342 NULL,\r
343 &Size,\r
344 (VOID*) &VarData\r
345 );\r
346 if (Status == EFI_SUCCESS) {\r
347 DEBUG ((EFI_D_INFO, "NV Variables were already loaded\n"));\r
348 return EFI_ALREADY_STARTED;\r
349 }\r
350\r
351 //\r
352 // Attempt to restore the variables from the NvVars file.\r
353 //\r
354 Status = ReadNvVarsFile (FsHandle);\r
355 if (EFI_ERROR (Status)) {\r
356 DEBUG ((EFI_D_INFO, "Error while restoring NV variable data\n"));\r
357 return Status;\r
358 }\r
359\r
360 //\r
361 // Write a variable to indicate we've already loaded the\r
362 // variable data. If it is found, we skip the loading on\r
363 // subsequent attempts.\r
364 //\r
365 SetNvVarsVariable();\r
366\r
367 DEBUG ((\r
368 EFI_D_INFO,\r
369 "FsAccess.c: Read NV Variables file (size=%Lu)\n",\r
370 (UINT64)Size\r
371 ));\r
372\r
373 return Status;\r
374}\r
375\r
376\r
377STATIC\r
378RETURN_STATUS\r
379EFIAPI\r
380IterateVariablesCallbackAddAllNvVariables (\r
381 IN VOID *Context,\r
382 IN CHAR16 *VariableName,\r
383 IN EFI_GUID *VendorGuid,\r
384 IN UINT32 Attributes,\r
385 IN UINTN DataSize,\r
386 IN VOID *Data\r
387 )\r
388{\r
389 EFI_HANDLE Instance;\r
390\r
391 Instance = (EFI_HANDLE) Context;\r
392\r
393 //\r
394 // Only save non-volatile variables\r
395 //\r
396 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
397 return RETURN_SUCCESS;\r
398 }\r
399\r
400 return SerializeVariablesAddVariable (\r
401 Instance,\r
402 VariableName,\r
403 VendorGuid,\r
404 Attributes,\r
405 DataSize,\r
406 Data\r
407 );\r
408}\r
409\r
410\r
411/**\r
412 Saves the non-volatile variables into the NvVars file on the\r
413 given file system.\r
414\r
415 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance\r
416\r
417 @return EFI_STATUS based on the success or failure of load operation\r
418\r
419**/\r
420EFI_STATUS\r
421SaveNvVarsToFs (\r
422 EFI_HANDLE FsHandle\r
423 )\r
424{\r
425 EFI_STATUS Status;\r
426 EFI_FILE_HANDLE File;\r
427 UINTN WriteSize;\r
428 UINTN VariableDataSize;\r
429 VOID *VariableData;\r
430 EFI_HANDLE SerializedVariables;\r
431\r
432 SerializedVariables = NULL;\r
433\r
434 Status = SerializeVariablesNewInstance (&SerializedVariables);\r
435 if (EFI_ERROR (Status)) {\r
436 return Status;\r
437 }\r
438\r
439 Status = SerializeVariablesIterateSystemVariables (\r
440 IterateVariablesCallbackAddAllNvVariables,\r
441 (VOID*) SerializedVariables\r
442 );\r
443 if (EFI_ERROR (Status)) {\r
444 return Status;\r
445 }\r
446\r
447 VariableData = NULL;\r
448 VariableDataSize = 0;\r
449 Status = SerializeVariablesToBuffer (\r
450 SerializedVariables,\r
451 NULL,\r
452 &VariableDataSize\r
453 );\r
454 if (Status == RETURN_BUFFER_TOO_SMALL) {\r
455 VariableData = AllocatePool (VariableDataSize);\r
456 if (VariableData == NULL) {\r
457 Status = EFI_OUT_OF_RESOURCES;\r
458 } else {\r
459 Status = SerializeVariablesToBuffer (\r
460 SerializedVariables,\r
461 VariableData,\r
462 &VariableDataSize\r
463 );\r
464 }\r
465 }\r
466\r
467 SerializeVariablesFreeInstance (SerializedVariables);\r
468\r
469 if (EFI_ERROR (Status)) {\r
470 return Status;\r
471 }\r
472\r
473 //\r
474 // Open the NvVars file for writing.\r
475 //\r
476 Status = GetNvVarsFile (FsHandle, FALSE, &File);\r
477 if (EFI_ERROR (Status)) {\r
478 DEBUG ((EFI_D_INFO, "FsAccess.c: Unable to open file to saved NV Variables\n"));\r
479 return Status;\r
480 }\r
481\r
482 //\r
483 // Empty the starting file contents.\r
484 //\r
485 Status = FileHandleEmpty (File);\r
486 if (EFI_ERROR (Status)) {\r
487 FileHandleClose (File);\r
488 return Status;\r
489 }\r
490\r
491 WriteSize = VariableDataSize;\r
492 Status = FileHandleWrite (File, &WriteSize, VariableData);\r
493 if (EFI_ERROR (Status)) {\r
494 return Status;\r
495 }\r
496\r
497 FileHandleClose (File);\r
498\r
499 if (!EFI_ERROR (Status)) {\r
500 //\r
501 // Write a variable to indicate we've already loaded the\r
502 // variable data. If it is found, we skip the loading on\r
503 // subsequent attempts.\r
504 //\r
505 SetNvVarsVariable();\r
506\r
507 DEBUG ((EFI_D_INFO, "Saved NV Variables to NvVars file\n"));\r
508 }\r
509\r
510 return Status;\r
511\r
512}\r
513\r
514\r