]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c
BeagleBoardPkg: enable -DDISABLE_NEW_DEPRECATED_INTERFACES
[mirror_edk2.git] / ArmPlatformPkg / FileSystem / BootMonFs / BootMonFsOpenClose.c
CommitLineData
94e0955d
OM
1/** @file\r
2*\r
fa14cfc9 3* Copyright (c) 2012-2015, ARM Limited. All rights reserved.\r
94e0955d
OM
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
94e0955d
OM
32 VOID *Buffer;\r
33 EFI_STATUS Status;\r
94e0955d
OM
34\r
35 DiskIo = File->Instance->DiskIo;\r
36 BlockIo = File->Instance->BlockIo;\r
37 MediaId = BlockIo->Media->MediaId;\r
94e0955d
OM
38\r
39 Buffer = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));\r
40\r
95204533
RC
41 if (Buffer == NULL) {\r
42 return EFI_OUT_OF_RESOURCES;\r
43 }\r
44\r
94e0955d
OM
45 Status = DiskIo->WriteDisk (DiskIo,\r
46 MediaId,\r
79e12331 47 File->HwDescAddress,\r
94e0955d
OM
48 sizeof (HW_IMAGE_DESCRIPTION),\r
49 Buffer\r
50 );\r
51\r
52 FreePool(Buffer);\r
53\r
54 return Status;\r
55}\r
56\r
95204533
RC
57/**\r
58 Write the description of a file to storage media.\r
59\r
60 This function uses DiskIo to write to the media, so call BlockIo->FlushBlocks()\r
61 after calling it to ensure the data are written on the media.\r
62\r
63 @param[in] File Description of the file whose description on the\r
64 storage media has to be updated.\r
65 @param[in] FileName Name of the file. Its length is assumed to be\r
66 lower than MAX_NAME_LENGTH.\r
67 @param[in] DataSize Number of data bytes of the file.\r
68 @param[in] FileStart File's starting position on media. FileStart must\r
69 be aligned to the media's block size.\r
70\r
71 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
72 @retval EFI_DEVICE_ERROR The device reported an error while performing\r
73 the write operation.\r
74\r
75**/\r
94e0955d
OM
76STATIC\r
77EFI_STATUS\r
95204533
RC
78WriteFileDescription (\r
79 IN BOOTMON_FS_FILE *File,\r
80 IN CHAR8 *FileName,\r
81 IN UINT32 DataSize,\r
82 IN UINT64 FileStart\r
94e0955d
OM
83 )\r
84{\r
95204533
RC
85 EFI_STATUS Status;\r
86 EFI_DISK_IO_PROTOCOL *DiskIo;\r
87 UINTN BlockSize;\r
88 UINT32 FileSize;\r
89 HW_IMAGE_DESCRIPTION *Description;\r
94e0955d 90\r
95204533 91 DiskIo = File->Instance->DiskIo;\r
94e0955d 92 BlockSize = File->Instance->BlockIo->Media->BlockSize;\r
94e0955d
OM
93 ASSERT (FileStart % BlockSize == 0);\r
94\r
94e0955d 95 //\r
95204533 96 // Construct the file description\r
94e0955d 97 //\r
95204533
RC
98\r
99 FileSize = DataSize + sizeof (HW_IMAGE_DESCRIPTION);\r
94e0955d
OM
100 Description = &File->HwDescription;\r
101 Description->Attributes = 1;\r
102 Description->BlockStart = FileStart / BlockSize;\r
95204533
RC
103 Description->BlockEnd = Description->BlockStart + (FileSize / BlockSize);\r
104 AsciiStrCpy (Description->Footer.Filename, FileName);\r
105\r
cb77b48a 106#ifdef MDE_CPU_ARM\r
95204533 107 Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET;\r
94e0955d 108 Description->Footer.Version = HW_IMAGE_FOOTER_VERSION;\r
cb77b48a 109#else\r
95204533 110 Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET2;\r
cb77b48a 111 Description->Footer.Version = HW_IMAGE_FOOTER_VERSION2;\r
cb77b48a 112#endif\r
95204533
RC
113 Description->Footer.FooterSignature1 = HW_IMAGE_FOOTER_SIGNATURE_1;\r
114 Description->Footer.FooterSignature2 = HW_IMAGE_FOOTER_SIGNATURE_2;\r
94e0955d
OM
115 Description->RegionCount = 1;\r
116 Description->Region[0].Checksum = 0;\r
117 Description->Region[0].Offset = Description->BlockStart * BlockSize;\r
95204533 118 Description->Region[0].Size = DataSize;\r
94e0955d
OM
119\r
120 Status = BootMonFsComputeFooterChecksum (Description);\r
121 if (EFI_ERROR (Status)) {\r
122 return Status;\r
123 }\r
124\r
95204533 125 File->HwDescAddress = ((Description->BlockEnd + 1) * BlockSize) - sizeof (HW_IMAGE_DESCRIPTION);\r
79e12331 126\r
94e0955d
OM
127 // Update the file description on the media\r
128 Status = DiskIo->WriteDisk (\r
129 DiskIo,\r
130 File->Instance->Media->MediaId,\r
79e12331 131 File->HwDescAddress,\r
94e0955d
OM
132 sizeof (HW_IMAGE_DESCRIPTION),\r
133 Description\r
134 );\r
135 ASSERT_EFI_ERROR (Status);\r
136\r
137 return Status;\r
138}\r
139\r
94e0955d
OM
140// Find a space on media for a file that has not yet been flushed to disk.\r
141// Just returns the first space that's big enough.\r
142// This function could easily be adapted to:\r
143// - Find space for moving an existing file that has outgrown its space\r
144// (We do not currently move files, just return EFI_VOLUME_FULL)\r
145// - Find space for a fragment of a file that has outgrown its space\r
146// (We do not currently fragment files - it's not clear whether fragmentation\r
147// is actually part of BootMonFs as there is no spec)\r
148// - Be more clever about finding space (choosing the largest or smallest\r
149// suitable space)\r
150// Parameters:\r
151// File - the new (not yet flushed) file for which we need to find space.\r
152// FileStart - the position on media of the file (in bytes).\r
153STATIC\r
154EFI_STATUS\r
155BootMonFsFindSpaceForNewFile (\r
156 IN BOOTMON_FS_FILE *File,\r
95204533 157 IN UINT64 FileSize,\r
94e0955d
OM
158 OUT UINT64 *FileStart\r
159 )\r
160{\r
161 LIST_ENTRY *FileLink;\r
162 BOOTMON_FS_FILE *RootFile;\r
163 BOOTMON_FS_FILE *FileEntry;\r
164 UINTN BlockSize;\r
94e0955d
OM
165 EFI_BLOCK_IO_MEDIA *Media;\r
166\r
167 Media = File->Instance->BlockIo->Media;\r
168 BlockSize = Media->BlockSize;\r
169 RootFile = File->Instance->RootFile;\r
170\r
94e0955d
OM
171 // This function must only be called for file which has not been flushed into\r
172 // Flash yet\r
173 ASSERT (File->HwDescription.RegionCount == 0);\r
174\r
94e0955d
OM
175 *FileStart = 0;\r
176 // Go through all the files in the list\r
177 for (FileLink = GetFirstNode (&RootFile->Link);\r
178 !IsNull (&RootFile->Link, FileLink);\r
179 FileLink = GetNextNode (&RootFile->Link, FileLink)\r
180 )\r
181 {\r
182 FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);\r
bf6091a9
BJ
183 // Skip files that aren't on disk yet\r
184 if (FileEntry->HwDescription.RegionCount == 0) {\r
185 continue;\r
186 }\r
187\r
94e0955d
OM
188 // If the free space preceding the file is big enough to contain the new\r
189 // file then use it!\r
190 if (((FileEntry->HwDescription.BlockStart * BlockSize) - *FileStart)\r
191 >= FileSize) {\r
192 // The file list must be in disk-order\r
193 RemoveEntryList (&File->Link);\r
194 File->Link.BackLink = FileLink->BackLink;\r
195 File->Link.ForwardLink = FileLink;\r
196 FileLink->BackLink->ForwardLink = &File->Link;\r
197 FileLink->BackLink = &File->Link;\r
198\r
199 return EFI_SUCCESS;\r
200 } else {\r
201 *FileStart = (FileEntry->HwDescription.BlockEnd + 1) * BlockSize;\r
202 }\r
203 }\r
204 // See if there's space after the last file\r
205 if ((((Media->LastBlock + 1) * BlockSize) - *FileStart) >= FileSize) {\r
206 return EFI_SUCCESS;\r
207 } else {\r
208 return EFI_VOLUME_FULL;\r
209 }\r
210}\r
211\r
212// Free the resources in the file's Region list.\r
213STATIC\r
214VOID\r
215FreeFileRegions (\r
216 IN BOOTMON_FS_FILE *File\r
217 )\r
218{\r
219 LIST_ENTRY *RegionToFlushLink;\r
220 BOOTMON_FS_FILE_REGION *Region;\r
221\r
222 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
223 while (!IsNull (&File->RegionToFlushLink, RegionToFlushLink)) {\r
224 // Repeatedly remove the first node from the list and free its resources.\r
225 Region = (BOOTMON_FS_FILE_REGION *) RegionToFlushLink;\r
226 RemoveEntryList (RegionToFlushLink);\r
227 FreePool (Region->Buffer);\r
228 FreePool (Region);\r
229\r
230 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
231 }\r
232}\r
233\r
95204533
RC
234/**\r
235 Flush all modified data associated with a file to a device.\r
236\r
237 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the\r
238 file handle to flush.\r
239\r
240 @retval EFI_SUCCESS The data was flushed.\r
241 @retval EFI_ACCESS_DENIED The file was opened read-only.\r
242 @retval EFI_DEVICE_ERROR The device reported an error.\r
243 @retval EFI_VOLUME_FULL The volume is full.\r
244 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to flush the data.\r
245 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
246\r
247**/\r
94e0955d
OM
248EFIAPI\r
249EFI_STATUS\r
250BootMonFsFlushFile (\r
251 IN EFI_FILE_PROTOCOL *This\r
252 )\r
253{\r
254 EFI_STATUS Status;\r
255 BOOTMON_FS_INSTANCE *Instance;\r
95204533
RC
256 EFI_FILE_INFO *Info;\r
257 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
258 EFI_BLOCK_IO_MEDIA *Media;\r
259 EFI_DISK_IO_PROTOCOL *DiskIo;\r
260 UINTN BlockSize;\r
261 CHAR8 AsciiFileName[MAX_NAME_LENGTH];\r
94e0955d
OM
262 LIST_ENTRY *RegionToFlushLink;\r
263 BOOTMON_FS_FILE *File;\r
264 BOOTMON_FS_FILE *NextFile;\r
265 BOOTMON_FS_FILE_REGION *Region;\r
266 LIST_ENTRY *FileLink;\r
267 UINTN CurrentPhysicalSize;\r
94e0955d
OM
268 UINT64 FileStart;\r
269 UINT64 FileEnd;\r
270 UINT64 RegionStart;\r
271 UINT64 RegionEnd;\r
95204533 272 UINT64 NewDataSize;\r
94e0955d
OM
273 UINT64 NewFileSize;\r
274 UINT64 EndOfAppendSpace;\r
275 BOOLEAN HasSpace;\r
94e0955d 276\r
95204533
RC
277 if (This == NULL) {\r
278 return EFI_INVALID_PARAMETER;\r
279 }\r
94e0955d
OM
280\r
281 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
95204533 282 if (File->Info == NULL) {\r
94e0955d
OM
283 return EFI_INVALID_PARAMETER;\r
284 }\r
285\r
95204533
RC
286 if (File->OpenMode == EFI_FILE_MODE_READ) {\r
287 return EFI_ACCESS_DENIED;\r
94e0955d
OM
288 }\r
289\r
95204533
RC
290 Instance = File->Instance;\r
291 Info = File->Info;\r
292 BlockIo = Instance->BlockIo;\r
293 Media = BlockIo->Media;\r
294 DiskIo = Instance->DiskIo;\r
295 BlockSize = Media->BlockSize;\r
296\r
297 UnicodeStrToAsciiStr (Info->FileName, AsciiFileName);\r
94e0955d
OM
298\r
299 // If the file doesn't exist then find a space for it\r
300 if (File->HwDescription.RegionCount == 0) {\r
95204533
RC
301 Status = BootMonFsFindSpaceForNewFile (\r
302 File,\r
303 Info->FileSize + sizeof (HW_IMAGE_DESCRIPTION),\r
304 &FileStart\r
305 );\r
94e0955d
OM
306 if (EFI_ERROR (Status)) {\r
307 return Status;\r
308 }\r
309 } else {\r
310 FileStart = File->HwDescription.BlockStart * BlockSize;\r
311 }\r
e29771bb
BJ
312 // FileEnd is the current NOR address of the end of the file's data\r
313 FileEnd = FileStart + File->HwDescription.Region[0].Size;\r
94e0955d
OM
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
95204533
RC
321 if (Region->Size == 0) {\r
322 continue;\r
323 }\r
94e0955d
OM
324\r
325 // RegionStart and RegionEnd are the the intended NOR address of the\r
326 // start and end of the region\r
95204533
RC
327 RegionStart = FileStart + Region->Offset;\r
328 RegionEnd = RegionStart + Region->Size;\r
94e0955d
OM
329\r
330 if (RegionEnd < FileEnd) {\r
331 // Handle regions representing edits to existing portions of the file\r
332 // Write the region data straight into the file\r
333 Status = DiskIo->WriteDisk (DiskIo,\r
95204533 334 Media->MediaId,\r
94e0955d
OM
335 RegionStart,\r
336 Region->Size,\r
337 Region->Buffer\r
338 );\r
339 if (EFI_ERROR (Status)) {\r
340 return Status;\r
341 }\r
342 } else {\r
343 // Handle regions representing appends to the file\r
344 //\r
345 // Note: Since seeking past the end of the file with SetPosition() is\r
346 // valid, it's possible there will be a gap between the current end of\r
347 // the file and the beginning of the new region. Since the UEFI spec\r
348 // says nothing about this case (except "a subsequent write would grow\r
349 // the file"), we just leave garbage in the gap.\r
350\r
351 // Check if there is space to append the new region\r
352 HasSpace = FALSE;\r
95204533
RC
353 NewDataSize = RegionEnd - FileStart;\r
354 NewFileSize = NewDataSize + sizeof (HW_IMAGE_DESCRIPTION);\r
94e0955d
OM
355 CurrentPhysicalSize = BootMonFsGetPhysicalSize (File);\r
356 if (NewFileSize <= CurrentPhysicalSize) {\r
357 HasSpace = TRUE;\r
358 } else {\r
359 // Get the File Description for the next file\r
360 FileLink = GetNextNode (&Instance->RootFile->Link, &File->Link);\r
361 if (!IsNull (&Instance->RootFile->Link, FileLink)) {\r
362 NextFile = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);\r
363\r
364 // If there is space between the beginning of the current file and the\r
365 // beginning of the next file then use it\r
366 EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize;\r
367 } else {\r
368 // We are flushing the last file.\r
95204533 369 EndOfAppendSpace = (Media->LastBlock + 1) * BlockSize;\r
94e0955d
OM
370 }\r
371 if (EndOfAppendSpace - FileStart >= NewFileSize) {\r
372 HasSpace = TRUE;\r
373 }\r
374 }\r
375\r
376 if (HasSpace == TRUE) {\r
95204533
RC
377 // Invalidate the current image description of the file if any.\r
378 if (File->HwDescAddress != 0) {\r
379 Status = InvalidateImageDescription (File);\r
380 if (EFI_ERROR (Status)) {\r
381 return Status;\r
382 }\r
383 }\r
384\r
385 // Write the new file data\r
386 Status = DiskIo->WriteDisk (\r
387 DiskIo,\r
388 Media->MediaId,\r
389 RegionStart,\r
390 Region->Size,\r
391 Region->Buffer\r
392 );\r
94e0955d
OM
393 if (EFI_ERROR (Status)) {\r
394 return Status;\r
395 }\r
95204533
RC
396\r
397 Status = WriteFileDescription (File, AsciiFileName, NewDataSize, FileStart);\r
398 if (EFI_ERROR (Status)) {\r
399 return Status;\r
400 }\r
401\r
94e0955d
OM
402 } else {\r
403 // There isn't a space for the file.\r
404 // Options here are to move the file or fragment it. However as files\r
405 // may represent boot images at fixed positions, these options will\r
406 // break booting if the bootloader doesn't use BootMonFs to find the\r
407 // image.\r
408\r
409 return EFI_VOLUME_FULL;\r
410 }\r
411 }\r
412 }\r
413\r
414 FreeFileRegions (File);\r
95204533
RC
415 Info->PhysicalSize = BootMonFsGetPhysicalSize (File);\r
416\r
417 if ((AsciiStrCmp (AsciiFileName, File->HwDescription.Footer.Filename) != 0) ||\r
418 (Info->FileSize != File->HwDescription.Region[0].Size) ) {\r
419 Status = WriteFileDescription (File, AsciiFileName, Info->FileSize, FileStart);\r
420 if (EFI_ERROR (Status)) {\r
421 return Status;\r
422 }\r
423 }\r
94e0955d
OM
424\r
425 // Flush DiskIo Buffers (see UEFI Spec 12.7 - DiskIo buffers are flushed by\r
426 // calling FlushBlocks on the same device's BlockIo).\r
427 BlockIo->FlushBlocks (BlockIo);\r
428\r
95204533 429 return EFI_SUCCESS;\r
94e0955d
OM
430}\r
431\r
432/**\r
95204533 433 Close a specified file handle.\r
94e0955d 434\r
95204533
RC
435 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file\r
436 handle to close.\r
94e0955d 437\r
95204533
RC
438 @retval EFI_SUCCESS The file was closed.\r
439 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open\r
440 file handle.\r
94e0955d
OM
441\r
442**/\r
443EFIAPI\r
444EFI_STATUS\r
445BootMonFsCloseFile (\r
446 IN EFI_FILE_PROTOCOL *This\r
447 )\r
448{\r
95204533 449 BOOTMON_FS_FILE *File;\r
94e0955d 450\r
95204533
RC
451 if (This == NULL) {\r
452 return EFI_INVALID_PARAMETER;\r
94e0955d
OM
453 }\r
454\r
95204533
RC
455 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
456 if (File->Info == NULL) {\r
457 return EFI_INVALID_PARAMETER;\r
94e0955d
OM
458 }\r
459\r
95204533
RC
460 // In the case of a file and not the root directory\r
461 if (This != &File->Instance->RootFile->File) {\r
462 This->Flush (This);\r
463 FreePool (File->Info);\r
464 File->Info = NULL;\r
465 }\r
94e0955d 466\r
95204533 467 return EFI_SUCCESS;\r
94e0955d
OM
468}\r
469\r
470/**\r
fb08c455
RC
471 Open a file on the boot monitor file system.\r
472\r
473 The boot monitor file system does not allow for sub-directories. There is only\r
474 one directory, the root one. On any attempt to create a directory, the function\r
475 returns in error with the EFI_WRITE_PROTECTED error code.\r
476\r
477 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
478 the file handle to source location.\r
479 @param[out] NewHandle A pointer to the location to return the opened\r
480 handle for the new file.\r
481 @param[in] FileName The Null-terminated string of the name of the file\r
482 to be opened.\r
483 @param[in] OpenMode The mode to open the file : Read or Read/Write or\r
484 Read/Write/Create\r
485 @param[in] Attributes Attributes of the file in case of a file creation\r
486\r
487 @retval EFI_SUCCESS The file was open.\r
488 @retval EFI_NOT_FOUND The specified file could not be found or the specified\r
489 directory in which to create a file could not be found.\r
490 @retval EFI_DEVICE_ERROR The device reported an error.\r
491 @retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible\r
492 with the Boot Monitor file system.\r
493 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.\r
494 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
94e0955d
OM
495\r
496**/\r
497EFIAPI\r
498EFI_STATUS\r
499BootMonFsOpenFile (\r
fb08c455
RC
500 IN EFI_FILE_PROTOCOL *This,\r
501 OUT EFI_FILE_PROTOCOL **NewHandle,\r
502 IN CHAR16 *FileName,\r
503 IN UINT64 OpenMode,\r
504 IN UINT64 Attributes\r
94e0955d
OM
505 )\r
506{\r
94e0955d 507 EFI_STATUS Status;\r
fb08c455
RC
508 BOOTMON_FS_FILE *Directory;\r
509 BOOTMON_FS_FILE *File;\r
510 BOOTMON_FS_INSTANCE *Instance;\r
511 CHAR8 *Buf;\r
512 CHAR16 *Path;\r
513 CHAR16 *Separator;\r
514 CHAR8 *AsciiFileName;\r
95204533 515 EFI_FILE_INFO *Info;\r
fb08c455
RC
516\r
517 if (This == NULL) {\r
518 return EFI_INVALID_PARAMETER;\r
519 }\r
94e0955d 520\r
95204533
RC
521 Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
522 if (Directory->Info == NULL) {\r
523 return EFI_INVALID_PARAMETER;\r
524 }\r
525\r
94e0955d
OM
526 if ((FileName == NULL) || (NewHandle == NULL)) {\r
527 return EFI_INVALID_PARAMETER;\r
528 }\r
529\r
fb08c455 530 //\r
94e0955d 531 // The only valid modes are read, read/write, and read/write/create\r
fb08c455
RC
532 //\r
533 if ( (OpenMode != EFI_FILE_MODE_READ) &&\r
534 (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE)) &&\r
535 (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE)) ) {\r
94e0955d
OM
536 return EFI_INVALID_PARAMETER;\r
537 }\r
538\r
94e0955d
OM
539 Instance = Directory->Instance;\r
540\r
fb08c455
RC
541 //\r
542 // If the instance has not been initialized yet then do it ...\r
543 //\r
94e0955d
OM
544 if (!Instance->Initialized) {\r
545 Status = BootMonFsInitialize (Instance);\r
546 if (EFI_ERROR (Status)) {\r
547 return Status;\r
548 }\r
549 }\r
550\r
fb08c455
RC
551 //\r
552 // Copy the file path to be able to work on it. We do not want to\r
553 // modify the input file name string "FileName".\r
554 //\r
555 Buf = AllocateCopyPool (StrSize (FileName), FileName);\r
556 if (Buf == NULL) {\r
557 return EFI_OUT_OF_RESOURCES;\r
558 }\r
559 Path = (CHAR16*)Buf;\r
560 AsciiFileName = NULL;\r
95204533 561 Info = NULL;\r
fb08c455
RC
562\r
563 //\r
564 // Handle single periods, double periods and convert forward slashes '/'\r
565 // to backward '\' ones. Does not handle a '.' at the beginning of the\r
566 // path for the time being.\r
567 //\r
568 if (PathCleanUpDirectories (Path) == NULL) {\r
569 Status = EFI_INVALID_PARAMETER;\r
570 goto Error;\r
571 }\r
572\r
573 //\r
574 // Detect if the first component of the path refers to a directory.\r
575 // This is done to return the correct error code when trying to\r
576 // access or create a directory other than the root directory.\r
577 //\r
578\r
579 //\r
580 // Search for the '\\' sequence and if found return in error\r
581 // with the EFI_INVALID_PARAMETER error code. ere in the path.\r
582 //\r
583 if (StrStr (Path, L"\\\\") != NULL) {\r
584 Status = EFI_INVALID_PARAMETER;\r
585 goto Error;\r
586 }\r
587 //\r
588 // Get rid of the leading '\' if any.\r
589 //\r
590 Path += (Path[0] == L'\\');\r
591\r
592 //\r
593 // Look for a '\' in the file path. If one is found then\r
594 // the first component of the path refers to a directory\r
595 // that is not the root directory.\r
596 //\r
597 Separator = StrStr (Path, L"\\");\r
598 if (Separator != NULL) {\r
599 //\r
600 // In the case '<dir name>\' and a creation, return\r
601 // EFI_WRITE_PROTECTED if this is for a directory\r
602 // creation, EFI_INVALID_PARAMETER otherwise.\r
603 //\r
604 if ((*(Separator + 1) == '\0') && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) {\r
605 if (Attributes & EFI_FILE_DIRECTORY) {\r
606 Status = EFI_WRITE_PROTECTED;\r
607 } else {\r
608 Status = EFI_INVALID_PARAMETER;\r
609 }\r
610 } else {\r
611 //\r
612 // Attempt to open a file or a directory that is not in the\r
613 // root directory or to open without creation a directory\r
614 // located in the root directory, returns EFI_NOT_FOUND.\r
615 //\r
616 Status = EFI_NOT_FOUND;\r
617 }\r
618 goto Error;\r
619 }\r
620\r
621 //\r
94e0955d 622 // BootMonFs interface requires ASCII filenames\r
fb08c455
RC
623 //\r
624 AsciiFileName = AllocatePool (StrLen (Path) + 1);\r
94e0955d 625 if (AsciiFileName == NULL) {\r
fb08c455
RC
626 Status = EFI_OUT_OF_RESOURCES;\r
627 goto Error;\r
628 }\r
629 UnicodeStrToAsciiStr (Path, AsciiFileName);\r
630 if (AsciiStrSize (AsciiFileName) > MAX_NAME_LENGTH) {\r
631 AsciiFileName[MAX_NAME_LENGTH - 1] = '\0';\r
94e0955d 632 }\r
94e0955d 633\r
fb08c455
RC
634 if ((AsciiFileName[0] == '\0') ||\r
635 (AsciiFileName[0] == '.' ) ) {\r
94e0955d 636 //\r
fb08c455 637 // Opening the root directory\r
94e0955d
OM
638 //\r
639\r
640 *NewHandle = &Instance->RootFile->File;\r
641 Instance->RootFile->Position = 0;\r
642 Status = EFI_SUCCESS;\r
643 } else {\r
fb08c455
RC
644\r
645 if ((OpenMode & EFI_FILE_MODE_CREATE) &&\r
646 (Attributes & EFI_FILE_DIRECTORY) ) {\r
647 Status = EFI_WRITE_PROTECTED;\r
648 goto Error;\r
649 }\r
650\r
95204533
RC
651 //\r
652 // Allocate a buffer to store the characteristics of the file while the\r
653 // file is open. We allocate the maximum size to not have to reallocate\r
654 // if the file name is changed.\r
655 //\r
656 Info = AllocateZeroPool (\r
657 SIZE_OF_EFI_FILE_INFO + (sizeof (CHAR16) * MAX_NAME_LENGTH));\r
658 if (Info == NULL) {\r
659 Status = EFI_OUT_OF_RESOURCES;\r
660 goto Error;\r
661 }\r
662\r
94e0955d 663 //\r
fb08c455 664 // Open or create a file in the root directory.\r
94e0955d
OM
665 //\r
666\r
94e0955d
OM
667 Status = BootMonGetFileFromAsciiFileName (Instance, AsciiFileName, &File);\r
668 if (Status == EFI_NOT_FOUND) {\r
fb08c455
RC
669 if ((OpenMode & EFI_FILE_MODE_CREATE) == 0) {\r
670 goto Error;\r
94e0955d 671 }\r
fb08c455 672\r
95204533
RC
673 Status = BootMonFsCreateFile (Instance, &File);\r
674 if (EFI_ERROR (Status)) {\r
675 goto Error;\r
fb08c455 676 }\r
95204533
RC
677 InsertHeadList (&Instance->RootFile->Link, &File->Link);\r
678 Info->Attribute = Attributes;\r
fb08c455
RC
679 } else {\r
680 //\r
95204533 681 // File already open, not supported yet.\r
fb08c455 682 //\r
95204533
RC
683 if (File->Info != NULL) {\r
684 Status = EFI_UNSUPPORTED;\r
685 goto Error;\r
686 }\r
94e0955d 687 }\r
95204533
RC
688\r
689 Info->FileSize = BootMonFsGetImageLength (File);\r
690 Info->PhysicalSize = BootMonFsGetPhysicalSize (File);\r
691 AsciiStrToUnicodeStr (AsciiFileName, Info->FileName);\r
692\r
693 File->Info = Info;\r
694 Info = NULL;\r
695 File->Position = 0;\r
696 File->OpenMode = OpenMode;\r
697\r
698 *NewHandle = &File->File;\r
94e0955d
OM
699 }\r
700\r
fb08c455
RC
701Error:\r
702\r
703 FreePool (Buf);\r
704 if (AsciiFileName != NULL) {\r
705 FreePool (AsciiFileName);\r
706 }\r
95204533
RC
707 if (Info != NULL) {\r
708 FreePool (Info);\r
709 }\r
94e0955d
OM
710\r
711 return Status;\r
712}\r
713\r
714// Delete() for the root directory's EFI_FILE_PROTOCOL instance\r
715EFIAPI\r
716EFI_STATUS\r
717BootMonFsDeleteFail (\r
718 IN EFI_FILE_PROTOCOL *This\r
719 )\r
720{\r
721 This->Close(This);\r
722 // You can't delete the root directory\r
723 return EFI_WARN_DELETE_FAILURE;\r
724}\r
95204533
RC
725\r
726/**\r
727 Close and delete a file from the boot monitor file system.\r
728\r
729 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file\r
730 handle to delete.\r
731\r
732 @retval EFI_SUCCESS The file was closed and deleted.\r
733 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open\r
734 file handle.\r
735 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.\r
736\r
737**/\r
94e0955d
OM
738EFIAPI\r
739EFI_STATUS\r
740BootMonFsDelete (\r
741 IN EFI_FILE_PROTOCOL *This\r
742 )\r
743{\r
744 EFI_STATUS Status;\r
745 BOOTMON_FS_FILE *File;\r
746 LIST_ENTRY *RegionToFlushLink;\r
747 BOOTMON_FS_FILE_REGION *Region;\r
94e0955d 748\r
95204533
RC
749 if (This == NULL) {\r
750 return EFI_INVALID_PARAMETER;\r
94e0955d
OM
751 }\r
752\r
95204533
RC
753 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
754 if (File->Info == NULL) {\r
755 return EFI_INVALID_PARAMETER;\r
756 }\r
94e0955d 757\r
95204533 758 if (!IsListEmpty (&File->RegionToFlushLink)) {\r
94e0955d
OM
759 // Free the entries from the Buffer List\r
760 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
761 do {\r
762 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;\r
763\r
95204533
RC
764 //\r
765 // Get next element of the list before deleting the region description\r
766 // that contain the LIST_ENTRY structure.\r
767 //\r
94e0955d
OM
768 RegionToFlushLink = RemoveEntryList (RegionToFlushLink);\r
769\r
770 // Free the buffers\r
771 FreePool (Region->Buffer);\r
772 FreePool (Region);\r
773 } while (!IsListEmpty (&File->RegionToFlushLink));\r
774 }\r
775\r
776 // If (RegionCount is greater than 0) then the file already exists\r
777 if (File->HwDescription.RegionCount > 0) {\r
94e0955d 778 // Invalidate the last Block\r
79e12331 779 Status = InvalidateImageDescription (File);\r
94e0955d 780 ASSERT_EFI_ERROR (Status);\r
95204533
RC
781 if (EFI_ERROR (Status)) {\r
782 return EFI_WARN_DELETE_FAILURE;\r
783 }\r
94e0955d
OM
784 }\r
785\r
786 // Remove the entry from the list\r
787 RemoveEntryList (&File->Link);\r
95204533 788 FreePool (File->Info);\r
94e0955d 789 FreePool (File);\r
94e0955d 790\r
95204533
RC
791 return EFI_SUCCESS;\r
792}\r