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