]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/NvVarsFileLib/FsAccess.c
OvmfPkg: Fix typing errors
[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
80 if (EFI_ERROR (Status)) {\r
81 return Status;\r
82 }\r
83\r
84 return Status;\r
85}\r
86\r
87\r
88/**\r
89 Open the NvVars file for reading or writing\r
90\r
91 @param[in] File - The file to inspect\r
92 @param[out] Exists - Returns whether the file exists\r
93 @param[out] Size - Returns the size of the file\r
94 (0 if the file does not exist)\r
95\r
96**/\r
97VOID\r
98NvVarsFileReadCheckup (\r
99 IN EFI_FILE_HANDLE File,\r
100 OUT BOOLEAN *Exists,\r
101 OUT UINTN *Size\r
102 )\r
103{\r
104 EFI_FILE_INFO *FileInfo;\r
105\r
106 *Exists = FALSE;\r
107 *Size = 0;\r
108\r
109 FileInfo = FileHandleGetInfo (File);\r
110 if (FileInfo == NULL) {\r
111 return;\r
112 }\r
113\r
114 if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {\r
115 FreePool (FileInfo);\r
116 return;\r
117 }\r
118\r
119 *Exists = TRUE;\r
120 *Size = (UINTN) FileInfo->FileSize;\r
121\r
122 FreePool (FileInfo);\r
123}\r
124\r
125\r
126/**\r
127 Open the NvVars file for reading or writing\r
128\r
129 @param[in] File - The file to inspect\r
130 @param[out] Exists - Returns whether the file exists\r
131 @param[out] Size - Returns the size of the file\r
132 (0 if the file does not exist)\r
133\r
134**/\r
135EFI_STATUS\r
136FileHandleEmpty (\r
137 IN EFI_FILE_HANDLE File\r
138 )\r
139{\r
140 EFI_STATUS Status;\r
141 EFI_FILE_INFO *FileInfo;\r
142\r
143 //\r
144 // Retrieve the FileInfo structure\r
145 //\r
146 FileInfo = FileHandleGetInfo (File);\r
147 if (FileInfo == NULL) {\r
148 return EFI_INVALID_PARAMETER;\r
149 }\r
150\r
151 //\r
152 // If the path is a directory, then return an error\r
153 //\r
154 if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {\r
155 FreePool (FileInfo);\r
156 return EFI_INVALID_PARAMETER;\r
157 }\r
158\r
159 //\r
160 // If the file size is already 0, then it is empty, so\r
161 // we can return success.\r
162 //\r
163 if (FileInfo->FileSize == 0) {\r
164 FreePool (FileInfo);\r
165 return EFI_SUCCESS;\r
166 }\r
167\r
168 //\r
169 // Set the file size to 0.\r
170 //\r
171 FileInfo->FileSize = 0;\r
172 Status = FileHandleSetInfo (File, FileInfo);\r
173\r
174 FreePool (FileInfo);\r
175\r
176 return Status;\r
177}\r
178\r
179\r
180/**\r
181 Reads a file to a newly allocated buffer\r
182\r
183 @param[in] File - The file to read\r
184 @param[in] ReadSize - The size of data to read from the file\r
185\r
186 @return Pointer to buffer allocated to hold the file\r
8c0b0b34 187 contents. NULL if an error occurred.\r
3e92a997
LE
188\r
189**/\r
190VOID*\r
191FileHandleReadToNewBuffer (\r
192 IN EFI_FILE_HANDLE FileHandle,\r
193 IN UINTN ReadSize\r
194 )\r
195{\r
196 EFI_STATUS Status;\r
197 UINTN ActualReadSize;\r
198 VOID *FileContents;\r
199\r
200 ActualReadSize = ReadSize;\r
201 FileContents = AllocatePool (ReadSize);\r
202 if (FileContents != NULL) {\r
203 Status = FileHandleRead (\r
204 FileHandle,\r
205 &ReadSize,\r
206 FileContents\r
207 );\r
208 if (EFI_ERROR (Status) || (ActualReadSize != ReadSize)) {\r
209 FreePool (FileContents);\r
210 return NULL;\r
211 }\r
212 }\r
213\r
214 return FileContents;\r
215}\r
216\r
217\r
218/**\r
219 Reads the contents of the NvVars file on the file system\r
220\r
221 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance\r
222\r
223 @return EFI_STATUS based on the success or failure of the file read\r
224\r
225**/\r
226EFI_STATUS\r
227ReadNvVarsFile (\r
228 IN EFI_HANDLE FsHandle\r
229 )\r
230{\r
231 EFI_STATUS Status;\r
232 EFI_FILE_HANDLE File;\r
233 UINTN FileSize;\r
234 BOOLEAN FileExists;\r
235 VOID *FileContents;\r
236 EFI_HANDLE SerializedVariables;\r
237\r
238 Status = GetNvVarsFile (FsHandle, TRUE, &File);\r
239 if (EFI_ERROR (Status)) {\r
240 DEBUG ((EFI_D_INFO, "FsAccess.c: Could not open NV Variables file on this file system\n"));\r
241 return Status;\r
242 }\r
243\r
244 NvVarsFileReadCheckup (File, &FileExists, &FileSize);\r
245 if (FileSize == 0) {\r
246 FileHandleClose (File);\r
247 return EFI_UNSUPPORTED;\r
248 }\r
249\r
250 FileContents = FileHandleReadToNewBuffer (File, FileSize);\r
251 if (FileContents == NULL) {\r
252 FileHandleClose (File);\r
253 return EFI_UNSUPPORTED;\r
254 }\r
255\r
256 DEBUG ((\r
257 EFI_D_INFO,\r
258 "FsAccess.c: Read %Lu bytes from NV Variables file\n",\r
259 (UINT64)FileSize\r
260 ));\r
261\r
262 Status = SerializeVariablesNewInstanceFromBuffer (\r
263 &SerializedVariables,\r
264 FileContents,\r
265 FileSize\r
266 );\r
267 if (!RETURN_ERROR (Status)) {\r
268 Status = SerializeVariablesSetSerializedVariables (SerializedVariables);\r
269 }\r
270\r
271 FreePool (FileContents);\r
272 FileHandleClose (File);\r
273\r
274 return Status;\r
275}\r
276\r
277\r
278/**\r
279 Writes a variable to indicate that the NV variables\r
280 have been loaded from the file system.\r
281\r
282**/\r
283STATIC\r
284VOID\r
285SetNvVarsVariable (\r
286 VOID\r
287 )\r
288{\r
289 BOOLEAN VarData;\r
290 UINTN Size;\r
291\r
292 //\r
293 // Write a variable to indicate we've already loaded the\r
294 // variable data. If it is found, we skip the loading on\r
295 // subsequent attempts.\r
296 //\r
297 Size = sizeof (VarData);\r
298 VarData = TRUE;\r
299 gRT->SetVariable (\r
300 L"NvVars",\r
301 &gEfiSimpleFileSystemProtocolGuid,\r
302 EFI_VARIABLE_NON_VOLATILE |\r
303 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
304 EFI_VARIABLE_RUNTIME_ACCESS,\r
305 Size,\r
306 (VOID*) &VarData\r
307 );\r
308}\r
309\r
310\r
311/**\r
312 Loads the non-volatile variables from the NvVars file on the\r
313 given file system.\r
314\r
315 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance\r
316\r
317 @return EFI_STATUS based on the success or failure of load operation\r
318\r
319**/\r
320EFI_STATUS\r
321LoadNvVarsFromFs (\r
322 EFI_HANDLE FsHandle\r
323 )\r
324{\r
325 EFI_STATUS Status;\r
326 BOOLEAN VarData;\r
327 UINTN Size;\r
328\r
329 DEBUG ((EFI_D_INFO, "FsAccess.c: LoadNvVarsFromFs\n"));\r
330\r
331 //\r
332 // We write a variable to indicate we've already loaded the\r
333 // variable data. If it is found, we skip the loading.\r
334 //\r
8c0b0b34 335 // This is relevant if the non-volatile variable have been\r
3e92a997
LE
336 // able to survive a reboot operation. In that case, we don't\r
337 // want to re-load the file as it would overwrite newer changes\r
338 // made to the variables.\r
339 //\r
340 Size = sizeof (VarData);\r
341 VarData = TRUE;\r
342 Status = gRT->GetVariable (\r
343 L"NvVars",\r
344 &gEfiSimpleFileSystemProtocolGuid,\r
345 NULL,\r
346 &Size,\r
347 (VOID*) &VarData\r
348 );\r
349 if (Status == EFI_SUCCESS) {\r
350 DEBUG ((EFI_D_INFO, "NV Variables were already loaded\n"));\r
351 return EFI_ALREADY_STARTED;\r
352 }\r
353\r
354 //\r
355 // Attempt to restore the variables from the NvVars file.\r
356 //\r
357 Status = ReadNvVarsFile (FsHandle);\r
358 if (EFI_ERROR (Status)) {\r
359 DEBUG ((EFI_D_INFO, "Error while restoring NV variable data\n"));\r
360 return Status;\r
361 }\r
362\r
363 //\r
364 // Write a variable to indicate we've already loaded the\r
365 // variable data. If it is found, we skip the loading on\r
366 // subsequent attempts.\r
367 //\r
368 SetNvVarsVariable();\r
369\r
370 DEBUG ((\r
371 EFI_D_INFO,\r
372 "FsAccess.c: Read NV Variables file (size=%Lu)\n",\r
373 (UINT64)Size\r
374 ));\r
375\r
376 return Status;\r
377}\r
378\r
379\r
380STATIC\r
381RETURN_STATUS\r
382EFIAPI\r
383IterateVariablesCallbackAddAllNvVariables (\r
384 IN VOID *Context,\r
385 IN CHAR16 *VariableName,\r
386 IN EFI_GUID *VendorGuid,\r
387 IN UINT32 Attributes,\r
388 IN UINTN DataSize,\r
389 IN VOID *Data\r
390 )\r
391{\r
392 EFI_HANDLE Instance;\r
393\r
394 Instance = (EFI_HANDLE) Context;\r
395\r
396 //\r
397 // Only save non-volatile variables\r
398 //\r
399 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
400 return RETURN_SUCCESS;\r
401 }\r
402\r
403 return SerializeVariablesAddVariable (\r
404 Instance,\r
405 VariableName,\r
406 VendorGuid,\r
407 Attributes,\r
408 DataSize,\r
409 Data\r
410 );\r
411}\r
412\r
413\r
414/**\r
415 Saves the non-volatile variables into the NvVars file on the\r
416 given file system.\r
417\r
418 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance\r
419\r
420 @return EFI_STATUS based on the success or failure of load operation\r
421\r
422**/\r
423EFI_STATUS\r
424SaveNvVarsToFs (\r
425 EFI_HANDLE FsHandle\r
426 )\r
427{\r
428 EFI_STATUS Status;\r
429 EFI_FILE_HANDLE File;\r
430 UINTN WriteSize;\r
431 UINTN VariableDataSize;\r
432 VOID *VariableData;\r
433 EFI_HANDLE SerializedVariables;\r
434\r
435 SerializedVariables = NULL;\r
436\r
437 Status = SerializeVariablesNewInstance (&SerializedVariables);\r
438 if (EFI_ERROR (Status)) {\r
439 return Status;\r
440 }\r
441\r
442 Status = SerializeVariablesIterateSystemVariables (\r
443 IterateVariablesCallbackAddAllNvVariables,\r
444 (VOID*) SerializedVariables\r
445 );\r
446 if (EFI_ERROR (Status)) {\r
447 return Status;\r
448 }\r
449\r
450 VariableData = NULL;\r
451 VariableDataSize = 0;\r
452 Status = SerializeVariablesToBuffer (\r
453 SerializedVariables,\r
454 NULL,\r
455 &VariableDataSize\r
456 );\r
457 if (Status == RETURN_BUFFER_TOO_SMALL) {\r
458 VariableData = AllocatePool (VariableDataSize);\r
459 if (VariableData == NULL) {\r
460 Status = EFI_OUT_OF_RESOURCES;\r
461 } else {\r
462 Status = SerializeVariablesToBuffer (\r
463 SerializedVariables,\r
464 VariableData,\r
465 &VariableDataSize\r
466 );\r
467 }\r
468 }\r
469\r
470 SerializeVariablesFreeInstance (SerializedVariables);\r
471\r
472 if (EFI_ERROR (Status)) {\r
473 return Status;\r
474 }\r
475\r
476 //\r
477 // Open the NvVars file for writing.\r
478 //\r
479 Status = GetNvVarsFile (FsHandle, FALSE, &File);\r
480 if (EFI_ERROR (Status)) {\r
481 DEBUG ((EFI_D_INFO, "FsAccess.c: Unable to open file to saved NV Variables\n"));\r
482 return Status;\r
483 }\r
484\r
485 //\r
486 // Empty the starting file contents.\r
487 //\r
488 Status = FileHandleEmpty (File);\r
489 if (EFI_ERROR (Status)) {\r
490 FileHandleClose (File);\r
491 return Status;\r
492 }\r
493\r
494 WriteSize = VariableDataSize;\r
495 Status = FileHandleWrite (File, &WriteSize, VariableData);\r
496 if (EFI_ERROR (Status)) {\r
497 return Status;\r
498 }\r
499\r
500 FileHandleClose (File);\r
501\r
502 if (!EFI_ERROR (Status)) {\r
503 //\r
504 // Write a variable to indicate we've already loaded the\r
505 // variable data. If it is found, we skip the loading on\r
506 // subsequent attempts.\r
507 //\r
508 SetNvVarsVariable();\r
509\r
510 DEBUG ((EFI_D_INFO, "Saved NV Variables to NvVars file\n"));\r
511 }\r
512\r
513 return Status;\r
514\r
515}\r
516\r
517\r