]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c
ARM Packages: Replace tabs by spaces for indentation
[mirror_edk2.git] / ArmPlatformPkg / FileSystem / BootMonFs / BootMonFsDir.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
17EFIAPI\r
18EFI_STATUS\r
19OpenBootMonFsOpenVolume (\r
20 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\r
21 OUT EFI_FILE_PROTOCOL **Root\r
22 )\r
23{\r
24 BOOTMON_FS_INSTANCE *Instance;\r
25\r
26 Instance = BOOTMON_FS_FROM_FS_THIS (This);\r
27 if (Instance == NULL) {\r
28 return EFI_DEVICE_ERROR;\r
29 }\r
30\r
31 *Root = &Instance->RootFile->File;\r
32\r
33 return EFI_SUCCESS;\r
34}\r
35\r
36UINT32\r
37BootMonFsGetImageLength (\r
38 IN BOOTMON_FS_FILE *File\r
39 )\r
40{\r
41 UINT32 Index;\r
42 UINT32 FileSize;\r
43 LIST_ENTRY *RegionToFlushLink;\r
44 BOOTMON_FS_FILE_REGION *Region;\r
45\r
46 FileSize = 0;\r
47\r
48 // Look at all Flash areas to determine file size\r
49 for (Index = 0; Index < HW_IMAGE_DESCRIPTION_REGION_MAX; Index++) {\r
50 FileSize += File->HwDescription.Region[Index].Size;\r
51 }\r
52\r
53 // Add the regions that have not been flushed yet\r
54 for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
55 !IsNull (&File->RegionToFlushLink, RegionToFlushLink);\r
56 RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)\r
57 )\r
58 {\r
59 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;\r
60 if (Region->Offset + Region->Size > FileSize) {\r
61 FileSize += Region->Offset + Region->Size;\r
62 }\r
63 }\r
64\r
65 return FileSize;\r
66}\r
67\r
68UINTN\r
69BootMonFsGetPhysicalSize (\r
70 IN BOOTMON_FS_FILE* File\r
71 )\r
72{\r
73 // Return 0 for files that haven't yet been flushed to media\r
74 if (File->HwDescription.RegionCount == 0) {\r
75 return 0;\r
76 }\r
77\r
78 return ((File->HwDescription.BlockEnd - File->HwDescription.BlockStart) + 1 )\r
79 * File->Instance->Media->BlockSize;\r
80}\r
81\r
82EFIAPI\r
83EFI_STATUS\r
84BootMonFsSetDirPosition (\r
85 IN EFI_FILE_PROTOCOL *This,\r
86 IN UINT64 Position\r
87 )\r
88{\r
89 BOOTMON_FS_FILE *File;\r
90\r
91 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
92 if (File == NULL) {\r
93 return EFI_INVALID_PARAMETER;\r
94 }\r
95\r
96 // UEFI Spec section 12.5:\r
97 // "The seek request for nonzero is not valid on open directories."\r
98 if (Position != 0) {\r
99 return EFI_UNSUPPORTED;\r
100 }\r
101 File->Position = Position;\r
102\r
103 return EFI_SUCCESS;\r
104}\r
105\r
106EFI_STATUS\r
107BootMonFsOpenDirectory (\r
108 OUT EFI_FILE_PROTOCOL **NewHandle,\r
109 IN CHAR16 *FileName,\r
110 IN BOOTMON_FS_INSTANCE *Volume\r
111 )\r
112{\r
113 ASSERT(0);\r
114\r
115 return EFI_UNSUPPORTED;\r
116}\r
117EFI_STATUS\r
118GetFileSystemVolumeLabelInfo (\r
119 IN BOOTMON_FS_INSTANCE *Instance,\r
120 IN OUT UINTN *BufferSize,\r
121 OUT VOID *Buffer\r
122 )\r
123{\r
124 UINTN Size;\r
125 EFI_FILE_SYSTEM_VOLUME_LABEL *Label;\r
126 EFI_STATUS Status;\r
127\r
128 Label = Buffer;\r
129\r
130 // Value returned by StrSize includes null terminator.\r
131 Size = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL\r
132 + StrSize (Instance->FsInfo.VolumeLabel);\r
133\r
134 if (*BufferSize >= Size) {\r
135 CopyMem (&Label->VolumeLabel, &Instance->FsInfo.VolumeLabel, Size);\r
136 Status = EFI_SUCCESS;\r
137 } else {\r
138 Status = EFI_BUFFER_TOO_SMALL;\r
139 }\r
140 *BufferSize = Size;\r
141 return Status;\r
142}\r
143\r
144// Helper function that calculates a rough "free space" by:\r
145// - Taking the media size\r
146// - Subtracting the sum of all file sizes\r
147// - Subtracting the block size times the number of files\r
148// (To account for the blocks containing the HW_IMAGE_INFO\r
149STATIC\r
150UINT64\r
151ComputeFreeSpace (\r
152 IN BOOTMON_FS_INSTANCE *Instance\r
153 )\r
154{\r
155 LIST_ENTRY *FileLink;\r
156 UINT64 FileSizeSum;\r
157 UINT64 MediaSize;\r
158 UINTN NumFiles;\r
159 EFI_BLOCK_IO_MEDIA *Media;\r
160 BOOTMON_FS_FILE *File;\r
161\r
162 Media = Instance->BlockIo->Media;\r
163 MediaSize = Media->BlockSize * (Media->LastBlock + 1);\r
164\r
165 NumFiles = 0;\r
166 FileSizeSum = 0;\r
167 for (FileLink = GetFirstNode (&Instance->RootFile->Link);\r
168 !IsNull (&Instance->RootFile->Link, FileLink);\r
169 FileLink = GetNextNode (&Instance->RootFile->Link, FileLink)\r
170 )\r
171 {\r
172 File = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);\r
173 FileSizeSum += BootMonFsGetImageLength (File);\r
174\r
175 NumFiles++;\r
176 }\r
177\r
178 return MediaSize - (FileSizeSum + (Media->BlockSize + NumFiles));\r
179}\r
180\r
181EFI_STATUS\r
182GetFilesystemInfo (\r
183 IN BOOTMON_FS_INSTANCE *Instance,\r
184 IN OUT UINTN *BufferSize,\r
185 OUT VOID *Buffer\r
186 )\r
187{\r
188 EFI_STATUS Status;\r
189\r
190 if (*BufferSize >= Instance->FsInfo.Size) {\r
191 Instance->FsInfo.FreeSpace = ComputeFreeSpace (Instance);\r
192 CopyMem (Buffer, &Instance->FsInfo, Instance->FsInfo.Size);\r
193 Status = EFI_SUCCESS;\r
194 } else {\r
195 Status = EFI_BUFFER_TOO_SMALL;\r
196 }\r
197\r
198 *BufferSize = Instance->FsInfo.Size;\r
199 return Status;\r
200}\r
201\r
202EFI_STATUS\r
203GetFileInfo (\r
204 IN BOOTMON_FS_INSTANCE *Instance,\r
205 IN BOOTMON_FS_FILE *File,\r
206 IN OUT UINTN *BufferSize,\r
207 OUT VOID *Buffer\r
208 )\r
209{\r
210 EFI_FILE_INFO *Info;\r
211 UINTN ResultSize;\r
212 UINTN NameSize;\r
213 UINTN Index;\r
214\r
215 if (File == Instance->RootFile) {\r
216 NameSize = 0;\r
217 ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof (CHAR16);\r
218 } else {\r
219 NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1;\r
220 ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16));\r
221 }\r
222\r
223 if (*BufferSize < ResultSize) {\r
224 *BufferSize = ResultSize;\r
225 return EFI_BUFFER_TOO_SMALL;\r
226 }\r
227\r
228 Info = Buffer;\r
229\r
230 // Zero out the structure\r
231 ZeroMem (Info, ResultSize);\r
232\r
233 // Fill in the structure\r
234 Info->Size = ResultSize;\r
235\r
236 if (File == Instance->RootFile) {\r
237 Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;\r
238 Info->FileName[0] = L'\0';\r
239 } else {\r
240 Info->FileSize = BootMonFsGetImageLength (File);\r
241 Info->PhysicalSize = BootMonFsGetPhysicalSize (File);\r
242\r
243 for (Index = 0; Index < NameSize; Index++) {\r
244 Info->FileName[Index] = File->HwDescription.Footer.Filename[Index];\r
245 }\r
246 }\r
247\r
248 *BufferSize = ResultSize;\r
249\r
250 return EFI_SUCCESS;\r
251}\r
252\r
253STATIC\r
254EFI_STATUS\r
255SetFileName (\r
256 IN BOOTMON_FS_FILE *File,\r
257 IN CHAR16 *FileNameUnicode\r
258 )\r
259{\r
260 CHAR8 *FileNameAscii;\r
261 UINT16 SavedChar;\r
262 UINTN FileNameSize;\r
263 BOOTMON_FS_FILE *SameFile;\r
264 EFI_STATUS Status;\r
265\r
266 // EFI Shell inserts '\' in front of the filename that must be stripped\r
267 if (FileNameUnicode[0] == L'\\') {\r
268 FileNameUnicode++;\r
269 }\r
270 //\r
271 // Convert Unicode into Ascii\r
272 //\r
273 SavedChar = L'\0';\r
274 FileNameSize = StrLen (FileNameUnicode) + 1;\r
275 FileNameAscii = AllocatePool (FileNameSize * sizeof (CHAR8));\r
276 if (FileNameAscii == NULL) {\r
277 return EFI_OUT_OF_RESOURCES;\r
278 }\r
279 // If Unicode string is too long then truncate it.\r
280 if (FileNameSize > MAX_NAME_LENGTH) {\r
281 SavedChar = FileNameUnicode[MAX_NAME_LENGTH - 1];\r
282 FileNameUnicode[MAX_NAME_LENGTH - 1] = L'\0';\r
283 }\r
284 UnicodeStrToAsciiStr (FileNameUnicode, FileNameAscii);\r
285 // If the unicode string was truncated then restore its original content.\r
286 if (SavedChar != L'\0') {\r
287 FileNameUnicode[MAX_NAME_LENGTH - 1] = SavedChar;\r
288 }\r
289\r
290 // If we're changing the file name\r
35d3b52d
BJ
291 if (AsciiStrCmp (FileNameAscii, File->HwDescription.Footer.Filename) == 0) {\r
292 // No change to filename.\r
293 Status = EFI_SUCCESS;\r
294 } else if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {\r
295 // You can only change the filename if you open the file for write.\r
296 Status = EFI_ACCESS_DENIED;\r
297 } else if (BootMonGetFileFromAsciiFileName (\r
298 File->Instance,\r
299 File->HwDescription.Footer.Filename,\r
300 &SameFile) != EFI_NOT_FOUND) {\r
301 // A file with that name already exists.\r
302 Status = EFI_ACCESS_DENIED;\r
94e0955d 303 } else {\r
35d3b52d
BJ
304 // OK, change the filename.\r
305 AsciiStrCpy (FileNameAscii, File->HwDescription.Footer.Filename);\r
94e0955d
OM
306 Status = EFI_SUCCESS;\r
307 }\r
308\r
309 FreePool (FileNameAscii);\r
310 return Status;\r
311}\r
312\r
313// Set the file's size (NB "size", not "physical size"). If the change amounts\r
314// to an increase, simply do a write followed by a flush.\r
315// (This is a helper function for SetFileInfo.)\r
316STATIC\r
317EFI_STATUS\r
318SetFileSize (\r
319 IN BOOTMON_FS_INSTANCE *Instance,\r
320 IN BOOTMON_FS_FILE *BootMonFsFile,\r
35d3b52d 321 IN UINTN NewSize\r
94e0955d
OM
322 )\r
323{\r
324 UINT64 StoredPosition;\r
325 EFI_STATUS Status;\r
326 EFI_FILE_PROTOCOL *File;\r
327 CHAR8 Buffer;\r
328 UINTN BufferSize;\r
35d3b52d
BJ
329 UINT32 OldSize;\r
330\r
331 OldSize = BootMonFsFile->HwDescription.Region[0].Size;\r
332\r
333 if (OldSize == NewSize) {\r
334 return EFI_SUCCESS;\r
335 }\r
94e0955d
OM
336\r
337 Buffer = 0;\r
338 BufferSize = sizeof (Buffer);\r
339\r
340 File = &BootMonFsFile->File;\r
341\r
342 if (!(BootMonFsFile->OpenMode & EFI_FILE_MODE_WRITE)) {\r
343 return EFI_ACCESS_DENIED;\r
344 }\r
345\r
35d3b52d
BJ
346 if (NewSize <= OldSize) {\r
347 OldSize = NewSize;\r
94e0955d
OM
348 } else {\r
349 // Increasing a file's size is potentially complicated as it may require\r
350 // moving the image description on media. The simplest way to do it is to\r
351 // seek past the end of the file (which is valid in UEFI) and perform a\r
352 // Write.\r
353\r
354 // Save position\r
355 Status = File->GetPosition (File, &StoredPosition);\r
356 if (EFI_ERROR (Status)) {\r
357 return Status;\r
358 }\r
359\r
35d3b52d 360 Status = File->SetPosition (File, NewSize - 1);\r
94e0955d
OM
361 if (EFI_ERROR (Status)) {\r
362 return Status;\r
363 }\r
364 Status = File->Write (File, &BufferSize, &Buffer);\r
365 if (EFI_ERROR (Status)) {\r
366 return Status;\r
367 }\r
368\r
369 // Restore saved position\r
35d3b52d 370 Status = File->SetPosition (File, NewSize - 1);\r
94e0955d
OM
371 if (EFI_ERROR (Status)) {\r
372 return Status;\r
373 }\r
374\r
375 Status = File->Flush (File);\r
376 if (EFI_ERROR (Status)) {\r
377 return Status;\r
378 }\r
379 }\r
380 return EFI_SUCCESS;\r
381}\r
382\r
383EFI_STATUS\r
384SetFileInfo (\r
385 IN BOOTMON_FS_INSTANCE *Instance,\r
386 IN BOOTMON_FS_FILE *File,\r
387 IN UINTN BufferSize,\r
388 IN EFI_FILE_INFO *Info\r
389 )\r
390{\r
391 EFI_STATUS Status;\r
94e0955d 392\r
dcaf7c90 393 Status = EFI_SUCCESS;\r
94e0955d
OM
394\r
395 // Note that a call to this function on a file opened read-only is only\r
396 // invalid if it actually changes fields, so we don't immediately fail if the\r
397 // OpenMode is wrong.\r
398 // Also note that the only fields supported are filename and size, others are\r
399 // ignored.\r
400\r
401 if (File != Instance->RootFile) {\r
402 if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {\r
403 return EFI_ACCESS_DENIED;\r
404 }\r
405\r
35d3b52d 406 Status = SetFileName (File, Info->FileName);\r
94e0955d
OM
407 if (EFI_ERROR (Status)) {\r
408 return Status;\r
409 }\r
410\r
411 // Update file size\r
412 Status = SetFileSize (Instance, File, Info->FileSize);\r
413 if (EFI_ERROR (Status)) {\r
414 return Status;\r
415 }\r
94e0955d
OM
416 }\r
417 return Status;\r
418}\r
419\r
420EFIAPI\r
421EFI_STATUS\r
422BootMonFsGetInfo (\r
423 IN EFI_FILE_PROTOCOL *This,\r
424 IN EFI_GUID *InformationType,\r
425 IN OUT UINTN *BufferSize,\r
426 OUT VOID *Buffer\r
427 )\r
428{\r
429 EFI_STATUS Status;\r
430 BOOTMON_FS_FILE *File;\r
431 BOOTMON_FS_INSTANCE *Instance;\r
432\r
433 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
434 if (File == NULL) {\r
435 return EFI_DEVICE_ERROR;\r
436 }\r
437\r
438 Instance = File->Instance;\r
439\r
440 // If the instance has not been initialized yet then do it ...\r
441 if (!Instance->Initialized) {\r
442 Status = BootMonFsInitialize (Instance);\r
443 } else {\r
444 Status = EFI_SUCCESS;\r
445 }\r
446\r
447 if (!EFI_ERROR (Status)) {\r
448 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)\r
449 != 0) {\r
450 Status = GetFileSystemVolumeLabelInfo (Instance, BufferSize, Buffer);\r
451 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) {\r
452 Status = GetFilesystemInfo (Instance, BufferSize, Buffer);\r
453 } else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {\r
454 Status = GetFileInfo (Instance, File, BufferSize, Buffer);\r
455 } else {\r
456 Status = EFI_UNSUPPORTED;\r
457 }\r
458 }\r
459\r
460 return Status;\r
461}\r
462\r
463EFIAPI\r
464EFI_STATUS\r
465BootMonFsSetInfo (\r
466 IN EFI_FILE_PROTOCOL *This,\r
467 IN EFI_GUID *InformationType,\r
468 IN UINTN BufferSize,\r
469 IN VOID *Buffer\r
470 )\r
471{\r
472 EFI_STATUS Status;\r
473 BOOTMON_FS_FILE *File;\r
474 BOOTMON_FS_INSTANCE *Instance;\r
475\r
476 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
477 if (File == NULL) {\r
478 return EFI_DEVICE_ERROR;\r
479 }\r
480\r
481 Instance = File->Instance;\r
482\r
483 if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {\r
484 Status = SetFileInfo (Instance, File, BufferSize, (EFI_FILE_INFO *) Buffer);\r
485 } else {\r
486 // The only writable field in the other two information types\r
487 // (i.e. EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL) is the\r
488 // filesystem volume label. This can be retrieved with GetInfo, but it is\r
489 // hard-coded into this driver, not stored on media.\r
490 Status = EFI_UNSUPPORTED;\r
491 }\r
492\r
493 return Status;\r
494}\r
495\r
496EFIAPI\r
497EFI_STATUS\r
498BootMonFsReadDirectory (\r
499 IN EFI_FILE_PROTOCOL *This,\r
500 IN OUT UINTN *BufferSize,\r
501 OUT VOID *Buffer\r
502 )\r
503{\r
504 BOOTMON_FS_INSTANCE *Instance;\r
505 BOOTMON_FS_FILE *RootFile;\r
506 BOOTMON_FS_FILE *File;\r
507 EFI_FILE_INFO *Info;\r
508 UINTN NameSize;\r
509 UINTN ResultSize;\r
510 EFI_STATUS Status;\r
511 UINTN Index;\r
512\r
513 RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
514 if (RootFile == NULL) {\r
515 return EFI_INVALID_PARAMETER;\r
516 }\r
517\r
518 Instance = RootFile->Instance;\r
519 Status = BootMonGetFileFromPosition (Instance, RootFile->Position, &File);\r
520 if (EFI_ERROR (Status)) {\r
521 // No more file\r
522 *BufferSize = 0;\r
523 return EFI_SUCCESS;\r
524 }\r
525\r
526 NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1;\r
527 ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16));\r
528 if (*BufferSize < ResultSize) {\r
529 *BufferSize = ResultSize;\r
530 return EFI_BUFFER_TOO_SMALL;\r
531 }\r
532\r
533 // Zero out the structure\r
534 Info = Buffer;\r
535 ZeroMem (Info, ResultSize);\r
536\r
537 // Fill in the structure\r
538 Info->Size = ResultSize;\r
539 Info->FileSize = BootMonFsGetImageLength (File);\r
540 Info->PhysicalSize = BootMonFsGetPhysicalSize (File);\r
541 for (Index = 0; Index < NameSize; Index++) {\r
542 Info->FileName[Index] = File->HwDescription.Footer.Filename[Index];\r
543 }\r
544\r
545 *BufferSize = ResultSize;\r
546 RootFile->Position++;\r
547\r
548 return EFI_SUCCESS;\r
549}\r
550\r
551EFIAPI\r
552EFI_STATUS\r
553BootMonFsFlushDirectory (\r
554 IN EFI_FILE_PROTOCOL *This\r
555 )\r
556{\r
557 BOOTMON_FS_FILE *RootFile;\r
558 LIST_ENTRY *ListFiles;\r
559 LIST_ENTRY *Link;\r
560 BOOTMON_FS_FILE *File;\r
561\r
562 RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
563 if (RootFile == NULL) {\r
564 return EFI_INVALID_PARAMETER;\r
565 }\r
566\r
567 ListFiles = &RootFile->Link;\r
568\r
569 if (IsListEmpty (ListFiles)) {\r
570 return EFI_SUCCESS;\r
571 }\r
572\r
573 //\r
574 // Flush all the files that need to be flushed\r
575 //\r
576\r
577 // Go through all the list of files to flush them\r
578 for (Link = GetFirstNode (ListFiles);\r
579 !IsNull (ListFiles, Link);\r
580 Link = GetNextNode (ListFiles, Link)\r
581 )\r
582 {\r
583 File = BOOTMON_FS_FILE_FROM_LINK_THIS (Link);\r
584 File->File.Flush (&File->File);\r
585 }\r
586\r
587 return EFI_SUCCESS;\r
588}\r