1 /** @file
2 *
3 * Copyright (c) 2012-2014, ARM Limited. All rights reserved.
4 *
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
9 *
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 *
13 **/
14
15 #include "BootMonFsInternal.h"
16
17 EFIAPI
18 EFI_STATUS
OpenBootMonFsOpenVolume(IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL * This,OUT EFI_FILE_PROTOCOL ** Root)19 OpenBootMonFsOpenVolume (
20 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
21 OUT EFI_FILE_PROTOCOL **Root
22 )
23 {
24 BOOTMON_FS_INSTANCE *Instance;
25
26 Instance = BOOTMON_FS_FROM_FS_THIS (This);
27 if (Instance == NULL) {
28 return EFI_DEVICE_ERROR;
29 }
30
31 Instance->RootFile->Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
32
33 *Root = &Instance->RootFile->File;
34
35 return EFI_SUCCESS;
36 }
37
38 UINT32
BootMonFsGetImageLength(IN BOOTMON_FS_FILE * File)39 BootMonFsGetImageLength (
40 IN BOOTMON_FS_FILE *File
41 )
42 {
43 UINT32 Index;
44 UINT32 FileSize;
45 LIST_ENTRY *RegionToFlushLink;
46 BOOTMON_FS_FILE_REGION *Region;
47
48 FileSize = 0;
49
50 // Look at all Flash areas to determine file size
51 for (Index = 0; Index < HW_IMAGE_DESCRIPTION_REGION_MAX; Index++) {
52 FileSize += File->HwDescription.Region[Index].Size;
53 }
54
55 // Add the regions that have not been flushed yet
56 for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
57 !IsNull (&File->RegionToFlushLink, RegionToFlushLink);
58 RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)
59 )
60 {
61 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
62 if (Region->Offset + Region->Size > FileSize) {
63 FileSize += Region->Offset + Region->Size;
64 }
65 }
66
67 return FileSize;
68 }
69
70 UINTN
BootMonFsGetPhysicalSize(IN BOOTMON_FS_FILE * File)71 BootMonFsGetPhysicalSize (
72 IN BOOTMON_FS_FILE* File
73 )
74 {
75 // Return 0 for files that haven't yet been flushed to media
76 if (File->HwDescription.RegionCount == 0) {
77 return 0;
78 }
79
80 return ((File->HwDescription.BlockEnd - File->HwDescription.BlockStart) + 1 )
81 * File->Instance->Media->BlockSize;
82 }
83
84 EFIAPI
85 EFI_STATUS
BootMonFsSetDirPosition(IN EFI_FILE_PROTOCOL * This,IN UINT64 Position)86 BootMonFsSetDirPosition (
87 IN EFI_FILE_PROTOCOL *This,
88 IN UINT64 Position
89 )
90 {
91 BOOTMON_FS_FILE *File;
92
93 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
94 if (File == NULL) {
95 return EFI_INVALID_PARAMETER;
96 }
97
98 // UEFI Spec section 12.5:
99 // "The seek request for nonzero is not valid on open directories."
100 if (Position != 0) {
101 return EFI_UNSUPPORTED;
102 }
103 File->Position = Position;
104
105 return EFI_SUCCESS;
106 }
107
108 EFI_STATUS
BootMonFsOpenDirectory(OUT EFI_FILE_PROTOCOL ** NewHandle,IN CHAR16 * FileName,IN BOOTMON_FS_INSTANCE * Volume)109 BootMonFsOpenDirectory (
110 OUT EFI_FILE_PROTOCOL **NewHandle,
111 IN CHAR16 *FileName,
112 IN BOOTMON_FS_INSTANCE *Volume
113 )
114 {
115 ASSERT(0);
116
117 return EFI_UNSUPPORTED;
118 }
119
120 STATIC
121 EFI_STATUS
GetFileSystemVolumeLabelInfo(IN BOOTMON_FS_INSTANCE * Instance,IN OUT UINTN * BufferSize,OUT VOID * Buffer)122 GetFileSystemVolumeLabelInfo (
123 IN BOOTMON_FS_INSTANCE *Instance,
124 IN OUT UINTN *BufferSize,
125 OUT VOID *Buffer
126 )
127 {
128 UINTN Size;
129 EFI_FILE_SYSTEM_VOLUME_LABEL *Label;
130 EFI_STATUS Status;
131
132 Label = Buffer;
133
134 // Value returned by StrSize includes null terminator.
135 Size = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL
136 + StrSize (Instance->FsInfo.VolumeLabel);
137
138 if (*BufferSize >= Size) {
139 CopyMem (&Label->VolumeLabel, &Instance->FsInfo.VolumeLabel, Size);
140 Status = EFI_SUCCESS;
141 } else {
142 Status = EFI_BUFFER_TOO_SMALL;
143 }
144 *BufferSize = Size;
145 return Status;
146 }
147
148 // Helper function that calculates a rough "free space" by:
149 // - Taking the media size
150 // - Subtracting the sum of all file sizes
151 // - Subtracting the block size times the number of files
152 // (To account for the blocks containing the HW_IMAGE_INFO
153 STATIC
154 UINT64
ComputeFreeSpace(IN BOOTMON_FS_INSTANCE * Instance)155 ComputeFreeSpace (
156 IN BOOTMON_FS_INSTANCE *Instance
157 )
158 {
159 LIST_ENTRY *FileLink;
160 UINT64 FileSizeSum;
161 UINT64 MediaSize;
162 UINTN NumFiles;
163 EFI_BLOCK_IO_MEDIA *Media;
164 BOOTMON_FS_FILE *File;
165
166 Media = Instance->BlockIo->Media;
167 MediaSize = Media->BlockSize * (Media->LastBlock + 1);
168
169 NumFiles = 0;
170 FileSizeSum = 0;
171 for (FileLink = GetFirstNode (&Instance->RootFile->Link);
172 !IsNull (&Instance->RootFile->Link, FileLink);
173 FileLink = GetNextNode (&Instance->RootFile->Link, FileLink)
174 )
175 {
176 File = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);
177 FileSizeSum += BootMonFsGetImageLength (File);
178
179 NumFiles++;
180 }
181
182 return MediaSize - (FileSizeSum + (Media->BlockSize + NumFiles));
183 }
184
185 STATIC
186 EFI_STATUS
GetFilesystemInfo(IN BOOTMON_FS_INSTANCE * Instance,IN OUT UINTN * BufferSize,OUT VOID * Buffer)187 GetFilesystemInfo (
188 IN BOOTMON_FS_INSTANCE *Instance,
189 IN OUT UINTN *BufferSize,
190 OUT VOID *Buffer
191 )
192 {
193 EFI_STATUS Status;
194
195 if (*BufferSize >= Instance->FsInfo.Size) {
196 Instance->FsInfo.FreeSpace = ComputeFreeSpace (Instance);
197 CopyMem (Buffer, &Instance->FsInfo, Instance->FsInfo.Size);
198 Status = EFI_SUCCESS;
199 } else {
200 Status = EFI_BUFFER_TOO_SMALL;
201 }
202
203 *BufferSize = Instance->FsInfo.Size;
204 return Status;
205 }
206
207 STATIC
208 EFI_STATUS
GetFileInfo(IN BOOTMON_FS_INSTANCE * Instance,IN BOOTMON_FS_FILE * File,IN OUT UINTN * BufferSize,OUT VOID * Buffer)209 GetFileInfo (
210 IN BOOTMON_FS_INSTANCE *Instance,
211 IN BOOTMON_FS_FILE *File,
212 IN OUT UINTN *BufferSize,
213 OUT VOID *Buffer
214 )
215 {
216 EFI_FILE_INFO *Info;
217 UINTN ResultSize;
218
219 ResultSize = SIZE_OF_EFI_FILE_INFO + StrSize (File->Info->FileName);
220
221 if (*BufferSize < ResultSize) {
222 *BufferSize = ResultSize;
223 return EFI_BUFFER_TOO_SMALL;
224 }
225
226 Info = Buffer;
227
228 CopyMem (Info, File->Info, ResultSize);
229 // Size of the information
230 Info->Size = ResultSize;
231
232 *BufferSize = ResultSize;
233
234 return EFI_SUCCESS;
235 }
236
237 STATIC
238 EFI_STATUS
GetBootMonFsFileInfo(IN BOOTMON_FS_INSTANCE * Instance,IN BOOTMON_FS_FILE * File,IN OUT UINTN * BufferSize,OUT VOID * Buffer)239 GetBootMonFsFileInfo (
240 IN BOOTMON_FS_INSTANCE *Instance,
241 IN BOOTMON_FS_FILE *File,
242 IN OUT UINTN *BufferSize,
243 OUT VOID *Buffer
244 )
245 {
246 EFI_STATUS Status;
247 BOOTMON_FS_FILE_INFO *Info;
248 UINTN ResultSize;
249 UINTN Index;
250
251 if (File == Instance->RootFile) {
252 Status = EFI_UNSUPPORTED;
253 } else {
254 ResultSize = SIZE_OF_BOOTMON_FS_FILE_INFO;
255
256 if (*BufferSize < ResultSize) {
257 *BufferSize = ResultSize;
258 Status = EFI_BUFFER_TOO_SMALL;
259 } else {
260 Info = Buffer;
261
262 // Zero out the structure
263 ZeroMem (Info, ResultSize);
264
265 // Fill in the structure
266 Info->Size = ResultSize;
267
268 Info->EntryPoint = File->HwDescription.EntryPoint;
269 Info->RegionCount = File->HwDescription.RegionCount;
270 for (Index = 0; Index < File->HwDescription.RegionCount; Index++) {
271 Info->Region[Index].LoadAddress = File->HwDescription.Region[Index].LoadAddress;
272 Info->Region[Index].Size = File->HwDescription.Region[Index].Size;
273 Info->Region[Index].Offset = File->HwDescription.Region[Index].Offset;
274 Info->Region[Index].Checksum = File->HwDescription.Region[Index].Checksum;
275 }
276 *BufferSize = ResultSize;
277 Status = EFI_SUCCESS;
278 }
279 }
280
281 return Status;
282 }
283
284 /**
285 Set the name of a file.
286
287 This is a helper function for SetFileInfo().
288
289 @param[in] Instance A pointer to the description of the volume
290 the file belongs to.
291 @param[in] File A pointer to the description of the file.
292 @param[in] FileName A pointer to the new name of the file.
293
294 @retval EFI_SUCCESS The name was set.
295 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
296 to a file that is already present.
297
298 **/
299 STATIC
300 EFI_STATUS
SetFileName(IN BOOTMON_FS_INSTANCE * Instance,IN BOOTMON_FS_FILE * File,IN CONST CHAR16 * FileName)301 SetFileName (
302 IN BOOTMON_FS_INSTANCE *Instance,
303 IN BOOTMON_FS_FILE *File,
304 IN CONST CHAR16 *FileName
305 )
306 {
307 CHAR8 AsciiFileName[MAX_NAME_LENGTH];
308 BOOTMON_FS_FILE *SameFile;
309
310 // If the file path start with a \ strip it. The EFI Shell may
311 // insert a \ in front of the file name.
312 if (FileName[0] == L'\\') {
313 FileName++;
314 }
315
316 UnicodeStrToAsciiStrS (FileName, AsciiFileName, MAX_NAME_LENGTH);
317
318 if (BootMonGetFileFromAsciiFileName (
319 File->Instance,
320 AsciiFileName,
321 &SameFile
322 ) != EFI_NOT_FOUND) {
323 // A file with that name already exists.
324 return EFI_ACCESS_DENIED;
325 } else {
326 // OK, change the filename.
327 AsciiStrToUnicodeStrS (AsciiFileName, File->Info->FileName,
328 (File->Info->Size - SIZE_OF_EFI_FILE_INFO) / sizeof (CHAR16));
329 return EFI_SUCCESS;
330 }
331 }
332
333 /**
334 Set the size of a file.
335
336 This is a helper function for SetFileInfo().
337
338 @param[in] Instance A pointer to the description of the volume
339 the file belongs to.
340 @param[in] File A pointer to the description of the file.
341 @param[in] NewSize The requested new size for the file.
342
343 @retval EFI_SUCCESS The size was set.
344 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed.
345
346 **/
347 STATIC
348 EFI_STATUS
SetFileSize(IN BOOTMON_FS_INSTANCE * Instance,IN BOOTMON_FS_FILE * BootMonFsFile,IN UINTN NewSize)349 SetFileSize (
350 IN BOOTMON_FS_INSTANCE *Instance,
351 IN BOOTMON_FS_FILE *BootMonFsFile,
352 IN UINTN NewSize
353 )
354 {
355 EFI_STATUS Status;
356 UINT32 OldSize;
357 LIST_ENTRY *RegionToFlushLink;
358 LIST_ENTRY *NextRegionToFlushLink;
359 BOOTMON_FS_FILE_REGION *Region;
360 EFI_FILE_PROTOCOL *File;
361 CHAR8 *Buffer;
362 UINTN BufferSize;
363 UINT64 StoredPosition;
364
365 OldSize = BootMonFsFile->Info->FileSize;
366
367 //
368 // In case of file truncation, force the regions waiting for writing to
369 // not overflow the new size of the file.
370 //
371 if (NewSize < OldSize) {
372 for (RegionToFlushLink = GetFirstNode (&BootMonFsFile->RegionToFlushLink);
373 !IsNull (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink);
374 )
375 {
376 NextRegionToFlushLink = GetNextNode (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink);
377 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
378 if (Region->Offset > NewSize) {
379 RemoveEntryList (RegionToFlushLink);
380 FreePool (Region->Buffer);
381 FreePool (Region);
382 } else {
383 Region->Size = MIN (Region->Size, NewSize - Region->Offset);
384 }
385 RegionToFlushLink = NextRegionToFlushLink;
386 }
387
388 } else if (NewSize > OldSize) {
389 // Increasing a file's size is potentially complicated as it may require
390 // moving the image description on media. The simplest way to do it is to
391 // seek past the end of the file (which is valid in UEFI) and perform a
392 // Write.
393 File = &BootMonFsFile->File;
394
395 // Save position
396 Status = File->GetPosition (File, &StoredPosition);
397 if (EFI_ERROR (Status)) {
398 return Status;
399 }
400 // Set position at the end of the file
401 Status = File->SetPosition (File, OldSize);
402 if (EFI_ERROR (Status)) {
403 return Status;
404 }
405
406 BufferSize = NewSize - OldSize;
407 Buffer = AllocateZeroPool (BufferSize);
408 if (Buffer == NULL) {
409 return EFI_OUT_OF_RESOURCES;
410 }
411
412 Status = File->Write (File, &BufferSize, Buffer);
413 FreePool (Buffer);
414 if (EFI_ERROR (Status)) {
415 return Status;
416 }
417
418 // Restore saved position
419 Status = File->SetPosition (File, StoredPosition);
420 if (EFI_ERROR (Status)) {
421 return Status;
422 }
423 }
424
425 BootMonFsFile->Info->FileSize = NewSize;
426
427 return EFI_SUCCESS;
428 }
429
430 /**
431 Set information about a file.
432
433 @param[in] Instance A pointer to the description of the volume
434 the file belongs to.
435 @param[in] File A pointer to the description of the file.
436 @param[in] Info A pointer to the file information to write.
437
438 @retval EFI_SUCCESS The information was set.
439 @retval EFI_ACCESS_DENIED An attempt is being made to change the
440 EFI_FILE_DIRECTORY Attribute.
441 @retval EFI_ACCESS_DENIED The file was opened in read-only mode and an
442 attempt is being made to modify a field other
443 than Attribute.
444 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
445 to a file that is already present.
446 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only
447 attribute.
448 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request
449 failed.
450
451 **/
452 STATIC
453 EFI_STATUS
SetFileInfo(IN BOOTMON_FS_INSTANCE * Instance,IN BOOTMON_FS_FILE * File,IN EFI_FILE_INFO * Info)454 SetFileInfo (
455 IN BOOTMON_FS_INSTANCE *Instance,
456 IN BOOTMON_FS_FILE *File,
457 IN EFI_FILE_INFO *Info
458 )
459 {
460 EFI_STATUS Status;
461 BOOLEAN FileSizeIsDifferent;
462 BOOLEAN FileNameIsDifferent;
463 BOOLEAN TimeIsDifferent;
464
465 //
466 // A directory can not be changed to a file and a file can
467 // not be changed to a directory.
468 //
469 if ((Info->Attribute & EFI_FILE_DIRECTORY) !=
470 (File->Info->Attribute & EFI_FILE_DIRECTORY) ) {
471 return EFI_ACCESS_DENIED;
472 }
473
474 FileSizeIsDifferent = (Info->FileSize != File->Info->FileSize);
475 FileNameIsDifferent = (StrnCmp (
476 Info->FileName,
477 File->Info->FileName,
478 MAX_NAME_LENGTH - 1
479 ) != 0);
480 //
481 // Check if the CreateTime, LastAccess or ModificationTime
482 // have been changed. The file system does not support file
483 // timestamps thus the three times in "File->Info" are
484 // always equal to zero. The following comparison actually
485 // checks if all three times are still equal to 0 or not.
486 //
487 TimeIsDifferent = CompareMem (
488 &Info->CreateTime,
489 &File->Info->CreateTime,
490 3 * sizeof (EFI_TIME)
491 ) != 0;
492
493 //
494 // For a file opened in read-only mode, only the Attribute field can be
495 // modified. The root directory open mode is forced to read-only at opening
496 // thus the following test protects the root directory to be somehow modified.
497 //
498 if (File->OpenMode == EFI_FILE_MODE_READ) {
499 if (FileSizeIsDifferent || FileNameIsDifferent || TimeIsDifferent) {
500 return EFI_ACCESS_DENIED;
501 }
502 }
503
504 if (TimeIsDifferent) {
505 return EFI_WRITE_PROTECTED;
506 }
507
508 if (FileSizeIsDifferent) {
509 Status = SetFileSize (Instance, File, Info->FileSize);
510 if (EFI_ERROR (Status)) {
511 return Status;
512 }
513 }
514
515 //
516 // Note down in RAM the Attribute field but we can not
517 // ask to store it in flash for the time being.
518 //
519 File->Info->Attribute = Info->Attribute;
520
521 if (FileNameIsDifferent) {
522 Status = SetFileName (Instance, File, Info->FileName);
523 if (EFI_ERROR (Status)) {
524 return Status;
525 }
526 }
527
528 return EFI_SUCCESS;
529 }
530
531 EFIAPI
532 EFI_STATUS
BootMonFsGetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN OUT UINTN * BufferSize,OUT VOID * Buffer)533 BootMonFsGetInfo (
534 IN EFI_FILE_PROTOCOL *This,
535 IN EFI_GUID *InformationType,
536 IN OUT UINTN *BufferSize,
537 OUT VOID *Buffer
538 )
539 {
540 EFI_STATUS Status;
541 BOOTMON_FS_FILE *File;
542 BOOTMON_FS_INSTANCE *Instance;
543
544 if ((This == NULL) ||
545 (InformationType == NULL) ||
546 (BufferSize == NULL) ||
547 ((Buffer == NULL) && (*BufferSize > 0)) ) {
548 return EFI_INVALID_PARAMETER;
549 }
550
551 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
552 if (File->Info == NULL) {
553 return EFI_INVALID_PARAMETER;
554 }
555 Instance = File->Instance;
556
557 // If the instance has not been initialized yet then do it ...
558 if (!Instance->Initialized) {
559 Status = BootMonFsInitialize (Instance);
560 } else {
561 Status = EFI_SUCCESS;
562 }
563
564 if (!EFI_ERROR (Status)) {
565 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)
566 != 0) {
567 Status = GetFileSystemVolumeLabelInfo (Instance, BufferSize, Buffer);
568 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) {
569 Status = GetFilesystemInfo (Instance, BufferSize, Buffer);
570 } else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {
571 Status = GetFileInfo (Instance, File, BufferSize, Buffer);
572 } else if (CompareGuid (InformationType, &gArmBootMonFsFileInfoGuid) != 0) {
573 Status = GetBootMonFsFileInfo (Instance, File, BufferSize, Buffer);
574 } else {
575 Status = EFI_UNSUPPORTED;
576 }
577 }
578
579 return Status;
580 }
581
582 /**
583 Set information about a file or a volume.
584
585 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
586 is the file handle the information is for.
587 @param[in] InformationType The type identifier for the information being set :
588 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
589 EFI_FILE_SYSTEM_VOLUME_LABEL_ID
590 @param[in] BufferSize The size, in bytes, of Buffer.
591 @param[in] Buffer A pointer to the data buffer to write. The type of the
592 data inside the buffer is indicated by InformationType.
593
594 @retval EFI_SUCCESS The information was set.
595 @retval EFI_UNSUPPORTED The InformationType is not known.
596 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
597 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
598 to a file that is already present.
599 @retval EFI_ACCESS_DENIED An attempt is being made to change the
600 EFI_FILE_DIRECTORY Attribute.
601 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and
602 the file was opened in read-only mode and an
603 attempt is being made to modify a field other
604 than Attribute.
605 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only
606 attribute.
607 @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by
608 the data inside the buffer.
609 @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.
610 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
611
612 **/
613 EFIAPI
614 EFI_STATUS
BootMonFsSetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN UINTN BufferSize,IN VOID * Buffer)615 BootMonFsSetInfo (
616 IN EFI_FILE_PROTOCOL *This,
617 IN EFI_GUID *InformationType,
618 IN UINTN BufferSize,
619 IN VOID *Buffer
620 )
621 {
622 BOOTMON_FS_FILE *File;
623 EFI_FILE_INFO *Info;
624 EFI_FILE_SYSTEM_INFO *SystemInfo;
625
626 if ((This == NULL) ||
627 (InformationType == NULL) ||
628 (Buffer == NULL) ) {
629 return EFI_INVALID_PARAMETER;
630 }
631
632 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
633 if (File->Info == NULL) {
634 return EFI_INVALID_PARAMETER;
635 }
636
637 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
638 Info = Buffer;
639 if (Info->Size < (SIZE_OF_EFI_FILE_INFO + StrSize (Info->FileName))) {
640 return EFI_INVALID_PARAMETER;
641 }
642 if (BufferSize < Info->Size) {
643 return EFI_BAD_BUFFER_SIZE;
644 }
645 return (SetFileInfo (File->Instance, File, Info));
646 }
647
648 //
649 // The only writable field in the other two information types
650 // (i.e. EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL) is the
651 // filesystem volume label. This can be retrieved with GetInfo, but it is
652 // hard-coded into this driver, not stored on media.
653 //
654
655 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
656 SystemInfo = Buffer;
657 if (SystemInfo->Size <
658 (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (SystemInfo->VolumeLabel))) {
659 return EFI_INVALID_PARAMETER;
660 }
661 if (BufferSize < SystemInfo->Size) {
662 return EFI_BAD_BUFFER_SIZE;
663 }
664 return EFI_WRITE_PROTECTED;
665 }
666
667 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
668 return EFI_WRITE_PROTECTED;
669 }
670
671 return EFI_UNSUPPORTED;
672 }
673
674 EFIAPI
675 EFI_STATUS
BootMonFsReadDirectory(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)676 BootMonFsReadDirectory (
677 IN EFI_FILE_PROTOCOL *This,
678 IN OUT UINTN *BufferSize,
679 OUT VOID *Buffer
680 )
681 {
682 BOOTMON_FS_INSTANCE *Instance;
683 BOOTMON_FS_FILE *RootFile;
684 BOOTMON_FS_FILE *File;
685 EFI_FILE_INFO *Info;
686 UINTN NameSize;
687 UINTN ResultSize;
688 EFI_STATUS Status;
689 UINTN Index;
690
691 RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
692 if (RootFile == NULL) {
693 return EFI_INVALID_PARAMETER;
694 }
695
696 Instance = RootFile->Instance;
697 Status = BootMonGetFileFromPosition (Instance, RootFile->Position, &File);
698 if (EFI_ERROR (Status)) {
699 // No more file
700 *BufferSize = 0;
701 return EFI_SUCCESS;
702 }
703
704 NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1;
705 ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16));
706 if (*BufferSize < ResultSize) {
707 *BufferSize = ResultSize;
708 return EFI_BUFFER_TOO_SMALL;
709 }
710
711 // Zero out the structure
712 Info = Buffer;
713 ZeroMem (Info, ResultSize);
714
715 // Fill in the structure
716 Info->Size = ResultSize;
717 Info->FileSize = BootMonFsGetImageLength (File);
718 Info->PhysicalSize = BootMonFsGetPhysicalSize (File);
719 for (Index = 0; Index < NameSize; Index++) {
720 Info->FileName[Index] = File->HwDescription.Footer.Filename[Index];
721 }
722
723 *BufferSize = ResultSize;
724 RootFile->Position++;
725
726 return EFI_SUCCESS;
727 }
728
729 EFIAPI
730 EFI_STATUS
BootMonFsFlushDirectory(IN EFI_FILE_PROTOCOL * This)731 BootMonFsFlushDirectory (
732 IN EFI_FILE_PROTOCOL *This
733 )
734 {
735 BOOTMON_FS_FILE *RootFile;
736 LIST_ENTRY *ListFiles;
737 LIST_ENTRY *Link;
738 BOOTMON_FS_FILE *File;
739
740 RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
741 if (RootFile == NULL) {
742 return EFI_INVALID_PARAMETER;
743 }
744
745 ListFiles = &RootFile->Link;
746
747 if (IsListEmpty (ListFiles)) {
748 return EFI_SUCCESS;
749 }
750
751 //
752 // Flush all the files that need to be flushed
753 //
754
755 // Go through all the list of files to flush them
756 for (Link = GetFirstNode (ListFiles);
757 !IsNull (ListFiles, Link);
758 Link = GetNextNode (ListFiles, Link)
759 )
760 {
761 File = BOOTMON_FS_FILE_FROM_LINK_THIS (Link);
762 File->File.Flush (&File->File);
763 }
764
765 return EFI_SUCCESS;
766 }
767