]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c
ArmPlatformPkg/BootMonFs: Fix finding space for new files
[mirror_edk2.git] / ArmPlatformPkg / FileSystem / BootMonFs / BootMonFsOpenClose.c
CommitLineData
94e0955d
OM
1/** @file\r
2*\r
3* Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
4*\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 "BootMonFsInternal.h"\r
16\r
17// Clear a file's image description on storage media:\r
18// UEFI allows you to seek past the end of a file, a subsequent write will grow\r
19// the file. It does not specify how space between the former end of the file\r
20// and the beginning of the write should be filled. It's therefore possible that\r
21// BootMonFs metadata, that comes after the end of a file, could be left there\r
22// and wrongly detected by BootMonFsImageInBlock.\r
23STATIC\r
24EFI_STATUS\r
25InvalidateImageDescription (\r
26 IN BOOTMON_FS_FILE *File\r
27 )\r
28{\r
29 EFI_DISK_IO_PROTOCOL *DiskIo;\r
30 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
31 UINT32 MediaId;\r
32 UINT32 BlockSize;\r
33 VOID *Buffer;\r
34 EFI_STATUS Status;\r
35 UINT64 DescriptionAddress;\r
36\r
37 DiskIo = File->Instance->DiskIo;\r
38 BlockIo = File->Instance->BlockIo;\r
39 MediaId = BlockIo->Media->MediaId;\r
40 BlockSize = BlockIo->Media->BlockSize;\r
41\r
42 DescriptionAddress = (File->HwDescription.BlockEnd * BlockSize)\r
43 - sizeof (HW_IMAGE_DESCRIPTION);\r
44\r
45 Buffer = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));\r
46\r
47 Status = DiskIo->WriteDisk (DiskIo,\r
48 MediaId,\r
49 DescriptionAddress,\r
50 sizeof (HW_IMAGE_DESCRIPTION),\r
51 Buffer\r
52 );\r
53\r
54 FreePool(Buffer);\r
55\r
56 return Status;\r
57}\r
58\r
59// Flush file data that will extend the file's length. Update and, if necessary,\r
60// move the image description.\r
61// We need to pass the file's starting position on media (FileStart), because\r
62// if the file hasn't been flushed before its Description->BlockStart won't\r
63// have been initialised.\r
64// FileStart must be aligned to the media's block size.\r
65// Note that this function uses DiskIo to flush, so call BlockIo->FlushBlocks()\r
66// after calling it.\r
67STATIC\r
68EFI_STATUS\r
69FlushAppendRegion (\r
70 IN BOOTMON_FS_FILE *File,\r
71 IN BOOTMON_FS_FILE_REGION *Region,\r
72 IN UINT64 NewFileSize,\r
73 IN UINT64 FileStart\r
74 )\r
75{\r
76 EFI_STATUS Status;\r
77 EFI_DISK_IO_PROTOCOL *DiskIo;\r
78 UINTN BlockSize;\r
79 HW_IMAGE_DESCRIPTION *Description;\r
80\r
81 DiskIo = File->Instance->DiskIo;\r
82\r
83 BlockSize = File->Instance->BlockIo->Media->BlockSize;\r
84\r
85 ASSERT (FileStart % BlockSize == 0);\r
86\r
87 // Only invalidate the Image Description of files that have already been\r
88 // written in Flash\r
89 if (File->HwDescription.RegionCount > 0) {\r
90 Status = InvalidateImageDescription (File);\r
91 ASSERT_EFI_ERROR (Status);\r
92 }\r
93\r
94 //\r
95 // Update File Description\r
96 //\r
97 Description = &File->HwDescription;\r
98 Description->Attributes = 1;\r
99 Description->BlockStart = FileStart / BlockSize;\r
100 Description->BlockEnd = Description->BlockStart + (NewFileSize / BlockSize);\r
101 Description->Footer.FooterSignature1 = HW_IMAGE_FOOTER_SIGNATURE_1;\r
102 Description->Footer.FooterSignature2 = HW_IMAGE_FOOTER_SIGNATURE_2;\r
cb77b48a 103#ifdef MDE_CPU_ARM\r
94e0955d
OM
104 Description->Footer.Version = HW_IMAGE_FOOTER_VERSION;\r
105 Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET;\r
cb77b48a
OM
106#else\r
107 Description->Footer.Version = HW_IMAGE_FOOTER_VERSION2;\r
108 Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET2;\r
109#endif\r
94e0955d
OM
110 Description->RegionCount = 1;\r
111 Description->Region[0].Checksum = 0;\r
112 Description->Region[0].Offset = Description->BlockStart * BlockSize;\r
113 Description->Region[0].Size = NewFileSize - sizeof (HW_IMAGE_DESCRIPTION);\r
114\r
115 Status = BootMonFsComputeFooterChecksum (Description);\r
116 if (EFI_ERROR (Status)) {\r
117 return Status;\r
118 }\r
119\r
120 // Write the new file data\r
121 Status = DiskIo->WriteDisk (\r
122 DiskIo,\r
123 File->Instance->Media->MediaId,\r
124 FileStart + Region->Offset,\r
125 Region->Size,\r
126 Region->Buffer\r
127 );\r
128 ASSERT_EFI_ERROR (Status);\r
129\r
130 // Round the file size up to the nearest block size\r
131 if ((NewFileSize % BlockSize) > 0) {\r
132 NewFileSize += BlockSize - (NewFileSize % BlockSize);\r
133 }\r
134 // Update the file description on the media\r
135 Status = DiskIo->WriteDisk (\r
136 DiskIo,\r
137 File->Instance->Media->MediaId,\r
138 (FileStart + NewFileSize) - sizeof (HW_IMAGE_DESCRIPTION),\r
139 sizeof (HW_IMAGE_DESCRIPTION),\r
140 Description\r
141 );\r
142 ASSERT_EFI_ERROR (Status);\r
143\r
144 return Status;\r
145}\r
146\r
147BOOLEAN\r
148BootMonFsFileNeedFlush (\r
149 IN BOOTMON_FS_FILE *File\r
150 )\r
151{\r
152 return !IsListEmpty (&File->RegionToFlushLink);\r
153}\r
154\r
155// Find a space on media for a file that has not yet been flushed to disk.\r
156// Just returns the first space that's big enough.\r
157// This function could easily be adapted to:\r
158// - Find space for moving an existing file that has outgrown its space\r
159// (We do not currently move files, just return EFI_VOLUME_FULL)\r
160// - Find space for a fragment of a file that has outgrown its space\r
161// (We do not currently fragment files - it's not clear whether fragmentation\r
162// is actually part of BootMonFs as there is no spec)\r
163// - Be more clever about finding space (choosing the largest or smallest\r
164// suitable space)\r
165// Parameters:\r
166// File - the new (not yet flushed) file for which we need to find space.\r
167// FileStart - the position on media of the file (in bytes).\r
168STATIC\r
169EFI_STATUS\r
170BootMonFsFindSpaceForNewFile (\r
171 IN BOOTMON_FS_FILE *File,\r
172 OUT UINT64 *FileStart\r
173 )\r
174{\r
175 LIST_ENTRY *FileLink;\r
176 BOOTMON_FS_FILE *RootFile;\r
177 BOOTMON_FS_FILE *FileEntry;\r
178 UINTN BlockSize;\r
179 UINT64 FileSize;\r
180 EFI_BLOCK_IO_MEDIA *Media;\r
181\r
182 Media = File->Instance->BlockIo->Media;\r
183 BlockSize = Media->BlockSize;\r
184 RootFile = File->Instance->RootFile;\r
185\r
186 if (IsListEmpty (&RootFile->Link)) {\r
187 return EFI_SUCCESS;\r
188 }\r
189\r
190 // This function must only be called for file which has not been flushed into\r
191 // Flash yet\r
192 ASSERT (File->HwDescription.RegionCount == 0);\r
193\r
194 // Find out how big the file will be\r
195 FileSize = BootMonFsGetImageLength (File);\r
196 // Add the file header to the file\r
197 FileSize += sizeof (HW_IMAGE_DESCRIPTION);\r
198\r
199 *FileStart = 0;\r
200 // Go through all the files in the list\r
201 for (FileLink = GetFirstNode (&RootFile->Link);\r
202 !IsNull (&RootFile->Link, FileLink);\r
203 FileLink = GetNextNode (&RootFile->Link, FileLink)\r
204 )\r
205 {\r
206 FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);\r
bf6091a9
BJ
207 // Skip files that aren't on disk yet\r
208 if (FileEntry->HwDescription.RegionCount == 0) {\r
209 continue;\r
210 }\r
211\r
94e0955d
OM
212 // If the free space preceding the file is big enough to contain the new\r
213 // file then use it!\r
214 if (((FileEntry->HwDescription.BlockStart * BlockSize) - *FileStart)\r
215 >= FileSize) {\r
216 // The file list must be in disk-order\r
217 RemoveEntryList (&File->Link);\r
218 File->Link.BackLink = FileLink->BackLink;\r
219 File->Link.ForwardLink = FileLink;\r
220 FileLink->BackLink->ForwardLink = &File->Link;\r
221 FileLink->BackLink = &File->Link;\r
222\r
223 return EFI_SUCCESS;\r
224 } else {\r
225 *FileStart = (FileEntry->HwDescription.BlockEnd + 1) * BlockSize;\r
226 }\r
227 }\r
228 // See if there's space after the last file\r
229 if ((((Media->LastBlock + 1) * BlockSize) - *FileStart) >= FileSize) {\r
230 return EFI_SUCCESS;\r
231 } else {\r
232 return EFI_VOLUME_FULL;\r
233 }\r
234}\r
235\r
236// Free the resources in the file's Region list.\r
237STATIC\r
238VOID\r
239FreeFileRegions (\r
240 IN BOOTMON_FS_FILE *File\r
241 )\r
242{\r
243 LIST_ENTRY *RegionToFlushLink;\r
244 BOOTMON_FS_FILE_REGION *Region;\r
245\r
246 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
247 while (!IsNull (&File->RegionToFlushLink, RegionToFlushLink)) {\r
248 // Repeatedly remove the first node from the list and free its resources.\r
249 Region = (BOOTMON_FS_FILE_REGION *) RegionToFlushLink;\r
250 RemoveEntryList (RegionToFlushLink);\r
251 FreePool (Region->Buffer);\r
252 FreePool (Region);\r
253\r
254 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
255 }\r
256}\r
257\r
258EFIAPI\r
259EFI_STATUS\r
260BootMonFsFlushFile (\r
261 IN EFI_FILE_PROTOCOL *This\r
262 )\r
263{\r
264 EFI_STATUS Status;\r
265 BOOTMON_FS_INSTANCE *Instance;\r
266 LIST_ENTRY *RegionToFlushLink;\r
267 BOOTMON_FS_FILE *File;\r
268 BOOTMON_FS_FILE *NextFile;\r
269 BOOTMON_FS_FILE_REGION *Region;\r
270 LIST_ENTRY *FileLink;\r
271 UINTN CurrentPhysicalSize;\r
272 UINTN BlockSize;\r
273 UINT64 FileStart;\r
274 UINT64 FileEnd;\r
275 UINT64 RegionStart;\r
276 UINT64 RegionEnd;\r
277 UINT64 NewFileSize;\r
278 UINT64 EndOfAppendSpace;\r
279 BOOLEAN HasSpace;\r
280 EFI_DISK_IO_PROTOCOL *DiskIo;\r
281 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
282\r
283 Status = EFI_SUCCESS;\r
284 FileStart = 0;\r
285\r
286 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
287 if (File == NULL) {\r
288 return EFI_INVALID_PARAMETER;\r
289 }\r
290\r
291 // Check if the file needs to be flushed\r
292 if (!BootMonFsFileNeedFlush (File)) {\r
293 return Status;\r
294 }\r
295\r
296 Instance = File->Instance;\r
297 BlockIo = Instance->BlockIo;\r
298 DiskIo = Instance->DiskIo;\r
299 BlockSize = BlockIo->Media->BlockSize;\r
300\r
301 // If the file doesn't exist then find a space for it\r
302 if (File->HwDescription.RegionCount == 0) {\r
303 Status = BootMonFsFindSpaceForNewFile (File, &FileStart);\r
304 // FileStart has changed so we need to recompute RegionEnd\r
305 if (EFI_ERROR (Status)) {\r
306 return Status;\r
307 }\r
308 } else {\r
309 FileStart = File->HwDescription.BlockStart * BlockSize;\r
310 }\r
311\r
312 // FileEnd is the NOR address of the end of the file's data\r
313 FileEnd = FileStart + BootMonFsGetImageLength (File);\r
314\r
315 for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
316 !IsNull (&File->RegionToFlushLink, RegionToFlushLink);\r
317 RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)\r
318 )\r
319 {\r
320 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;\r
321\r
322 // RegionStart and RegionEnd are the the intended NOR address of the\r
323 // start and end of the region\r
324 RegionStart = FileStart + Region->Offset;\r
325 RegionEnd = RegionStart + Region->Size;\r
326\r
327 if (RegionEnd < FileEnd) {\r
328 // Handle regions representing edits to existing portions of the file\r
329 // Write the region data straight into the file\r
330 Status = DiskIo->WriteDisk (DiskIo,\r
331 BlockIo->Media->MediaId,\r
332 RegionStart,\r
333 Region->Size,\r
334 Region->Buffer\r
335 );\r
336 if (EFI_ERROR (Status)) {\r
337 return Status;\r
338 }\r
339 } else {\r
340 // Handle regions representing appends to the file\r
341 //\r
342 // Note: Since seeking past the end of the file with SetPosition() is\r
343 // valid, it's possible there will be a gap between the current end of\r
344 // the file and the beginning of the new region. Since the UEFI spec\r
345 // says nothing about this case (except "a subsequent write would grow\r
346 // the file"), we just leave garbage in the gap.\r
347\r
348 // Check if there is space to append the new region\r
349 HasSpace = FALSE;\r
350 NewFileSize = (RegionEnd - FileStart) + sizeof (HW_IMAGE_DESCRIPTION);\r
351 CurrentPhysicalSize = BootMonFsGetPhysicalSize (File);\r
352 if (NewFileSize <= CurrentPhysicalSize) {\r
353 HasSpace = TRUE;\r
354 } else {\r
355 // Get the File Description for the next file\r
356 FileLink = GetNextNode (&Instance->RootFile->Link, &File->Link);\r
357 if (!IsNull (&Instance->RootFile->Link, FileLink)) {\r
358 NextFile = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);\r
359\r
360 // If there is space between the beginning of the current file and the\r
361 // beginning of the next file then use it\r
362 EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize;\r
363 } else {\r
364 // We are flushing the last file.\r
365 EndOfAppendSpace = (BlockIo->Media->LastBlock + 1) * BlockSize;\r
366 }\r
367 if (EndOfAppendSpace - FileStart >= NewFileSize) {\r
368 HasSpace = TRUE;\r
369 }\r
370 }\r
371\r
372 if (HasSpace == TRUE) {\r
373 Status = FlushAppendRegion (File, Region, NewFileSize, FileStart);\r
374 if (EFI_ERROR (Status)) {\r
375 return Status;\r
376 }\r
377 } else {\r
378 // There isn't a space for the file.\r
379 // Options here are to move the file or fragment it. However as files\r
380 // may represent boot images at fixed positions, these options will\r
381 // break booting if the bootloader doesn't use BootMonFs to find the\r
382 // image.\r
383\r
384 return EFI_VOLUME_FULL;\r
385 }\r
386 }\r
387 }\r
388\r
389 FreeFileRegions (File);\r
390\r
391 // Flush DiskIo Buffers (see UEFI Spec 12.7 - DiskIo buffers are flushed by\r
392 // calling FlushBlocks on the same device's BlockIo).\r
393 BlockIo->FlushBlocks (BlockIo);\r
394\r
395 return Status;\r
396}\r
397\r
398/**\r
399 Closes a file on the Nor Flash FS volume.\r
400\r
401 @param This The EFI_FILE_PROTOCOL to close.\r
402\r
403 @return Always returns EFI_SUCCESS.\r
404\r
405**/\r
406EFIAPI\r
407EFI_STATUS\r
408BootMonFsCloseFile (\r
409 IN EFI_FILE_PROTOCOL *This\r
410 )\r
411{\r
412 // Flush the file if needed\r
413 This->Flush (This);\r
414 return EFI_SUCCESS;\r
415}\r
416\r
417// Create a new instance of BOOTMON_FS_FILE.\r
418// Uses BootMonFsCreateFile to\r
419STATIC\r
420EFI_STATUS\r
421CreateNewFile (\r
422 IN BOOTMON_FS_INSTANCE *Instance,\r
423 IN CHAR8* AsciiFileName,\r
424 OUT BOOTMON_FS_FILE **NewHandle\r
425 )\r
426{\r
427 EFI_STATUS Status;\r
428 BOOTMON_FS_FILE *File;\r
429\r
430 Status = BootMonFsCreateFile (Instance, &File);\r
431 if (EFI_ERROR (Status)) {\r
432 return Status;\r
433 }\r
434\r
435 // Remove the leading '\\'\r
436 if (*AsciiFileName == '\\') {\r
437 AsciiFileName++;\r
438 }\r
439\r
440 // Set the file name\r
441 CopyMem (File->HwDescription.Footer.Filename, AsciiFileName, MAX_NAME_LENGTH);\r
442\r
443 // Add the file to list of files of the File System\r
444 InsertHeadList (&Instance->RootFile->Link, &File->Link);\r
445\r
446 *NewHandle = File;\r
447 return Status;\r
448}\r
449\r
450/**\r
451 Opens a file on the Nor Flash FS volume\r
452\r
453 Calls BootMonFsGetFileFromAsciiFilename to search the list of tracked files.\r
454\r
455 @param This The EFI_FILE_PROTOCOL parent handle.\r
456 @param NewHandle Double-pointer to the newly created protocol.\r
457 @param FileName The name of the image/metadata on flash\r
458 @param OpenMode Read,write,append etc\r
459 @param Attributes ?\r
460\r
461 @return EFI_STATUS\r
462 OUT_OF_RESOURCES\r
463 Run out of space to keep track of the allocated structures\r
464 DEVICE_ERROR\r
465 Unable to locate the volume associated with the parent file handle\r
466 NOT_FOUND\r
467 Filename wasn't found on flash\r
468 SUCCESS\r
469\r
470**/\r
471EFIAPI\r
472EFI_STATUS\r
473BootMonFsOpenFile (\r
474 IN EFI_FILE_PROTOCOL *This,\r
475 OUT EFI_FILE_PROTOCOL **NewHandle,\r
476 IN CHAR16 *FileName,\r
477 IN UINT64 OpenMode,\r
478 IN UINT64 Attributes\r
479 )\r
480{\r
481 BOOTMON_FS_FILE *Directory;\r
482 BOOTMON_FS_FILE *File;\r
483 BOOTMON_FS_INSTANCE *Instance;\r
484 CHAR8* AsciiFileName;\r
485 EFI_STATUS Status;\r
486\r
487 if ((FileName == NULL) || (NewHandle == NULL)) {\r
488 return EFI_INVALID_PARAMETER;\r
489 }\r
490\r
491 // The only valid modes are read, read/write, and read/write/create\r
492 if (!(OpenMode & EFI_FILE_MODE_READ) || ((OpenMode & EFI_FILE_MODE_CREATE) && !(OpenMode & EFI_FILE_MODE_WRITE))) {\r
493 return EFI_INVALID_PARAMETER;\r
494 }\r
495\r
496 Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
497 if (Directory == NULL) {\r
498 return EFI_DEVICE_ERROR;\r
499 }\r
500\r
501 Instance = Directory->Instance;\r
502\r
503 // If the instance has not been initialized it yet then do it ...\r
504 if (!Instance->Initialized) {\r
505 Status = BootMonFsInitialize (Instance);\r
506 if (EFI_ERROR (Status)) {\r
507 return Status;\r
508 }\r
509 }\r
510\r
511 // BootMonFs interface requires ASCII filenames\r
512 AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));\r
513 if (AsciiFileName == NULL) {\r
514 return EFI_OUT_OF_RESOURCES;\r
515 }\r
516 UnicodeStrToAsciiStr (FileName, AsciiFileName);\r
517\r
518 if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||\r
519 (AsciiStrCmp (AsciiFileName, "/") == 0) ||\r
520 (AsciiStrCmp (AsciiFileName, "") == 0) ||\r
521 (AsciiStrCmp (AsciiFileName, ".") == 0))\r
522 {\r
523 //\r
524 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory\r
525 //\r
526\r
527 *NewHandle = &Instance->RootFile->File;\r
528 Instance->RootFile->Position = 0;\r
529 Status = EFI_SUCCESS;\r
530 } else {\r
531 //\r
532 // Open or Create a regular file\r
533 //\r
534\r
535 // Check if the file already exists\r
536 Status = BootMonGetFileFromAsciiFileName (Instance, AsciiFileName, &File);\r
537 if (Status == EFI_NOT_FOUND) {\r
538 // The file doesn't exist.\r
539 if (OpenMode & EFI_FILE_MODE_CREATE) {\r
540 // If the file does not exist but is required then create it.\r
541 if (Attributes & EFI_FILE_DIRECTORY) {\r
542 // BootMonFS doesn't support subdirectories\r
543 Status = EFI_UNSUPPORTED;\r
544 } else {\r
545 // Create a new file\r
546 Status = CreateNewFile (Instance, AsciiFileName, &File);\r
547 if (!EFI_ERROR (Status)) {\r
548 File->OpenMode = OpenMode;\r
549 *NewHandle = &File->File;\r
550 File->Position = 0;\r
551 }\r
552 }\r
553 }\r
554 } else if (Status == EFI_SUCCESS) {\r
555 // The file exists\r
556 File->OpenMode = OpenMode;\r
557 *NewHandle = &File->File;\r
558 File->Position = 0;\r
559 }\r
560 }\r
561\r
562 FreePool (AsciiFileName);\r
563\r
564 return Status;\r
565}\r
566\r
567// Delete() for the root directory's EFI_FILE_PROTOCOL instance\r
568EFIAPI\r
569EFI_STATUS\r
570BootMonFsDeleteFail (\r
571 IN EFI_FILE_PROTOCOL *This\r
572 )\r
573{\r
574 This->Close(This);\r
575 // You can't delete the root directory\r
576 return EFI_WARN_DELETE_FAILURE;\r
577}\r
578EFIAPI\r
579EFI_STATUS\r
580BootMonFsDelete (\r
581 IN EFI_FILE_PROTOCOL *This\r
582 )\r
583{\r
584 EFI_STATUS Status;\r
585 BOOTMON_FS_FILE *File;\r
586 LIST_ENTRY *RegionToFlushLink;\r
587 BOOTMON_FS_FILE_REGION *Region;\r
588 HW_IMAGE_DESCRIPTION *Description;\r
589 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
590 UINT8 *EmptyBuffer;\r
591\r
592 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
593 if (File == NULL) {\r
594 return EFI_DEVICE_ERROR;\r
595 }\r
596\r
597 Status = EFI_SUCCESS;\r
598\r
599 if (BootMonFsFileNeedFlush (File)) {\r
600 // Free the entries from the Buffer List\r
601 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
602 do {\r
603 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;\r
604\r
605 // Get Next entry\r
606 RegionToFlushLink = RemoveEntryList (RegionToFlushLink);\r
607\r
608 // Free the buffers\r
609 FreePool (Region->Buffer);\r
610 FreePool (Region);\r
611 } while (!IsListEmpty (&File->RegionToFlushLink));\r
612 }\r
613\r
614 // If (RegionCount is greater than 0) then the file already exists\r
615 if (File->HwDescription.RegionCount > 0) {\r
616 Description = &File->HwDescription;\r
617 BlockIo = File->Instance->BlockIo;\r
618\r
619 // Create an empty buffer\r
620 EmptyBuffer = AllocateZeroPool (BlockIo->Media->BlockSize);\r
621 if (EmptyBuffer == NULL) {\r
622 FreePool (File);\r
623 return EFI_OUT_OF_RESOURCES;\r
624 }\r
625\r
626 // Invalidate the last Block\r
627 Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Description->BlockEnd, BlockIo->Media->BlockSize, EmptyBuffer);\r
628 ASSERT_EFI_ERROR (Status);\r
629\r
630 FreePool (EmptyBuffer);\r
631 }\r
632\r
633 // Remove the entry from the list\r
634 RemoveEntryList (&File->Link);\r
635 FreePool (File);\r
636 return Status;\r
637}\r
638\r