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
17EFIAPI
18EFI_STATUS
19OpenBootMonFsOpenVolume (
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
38UINT32
39BootMonFsGetImageLength (
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
70UINTN
71BootMonFsGetPhysicalSize (
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
84EFIAPI
85EFI_STATUS
86BootMonFsSetDirPosition (
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
108EFI_STATUS
109BootMonFsOpenDirectory (
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
120STATIC
121EFI_STATUS
122GetFileSystemVolumeLabelInfo (
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
153STATIC
154UINT64
155ComputeFreeSpace (
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
185STATIC
186EFI_STATUS
187GetFilesystemInfo (
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
207STATIC
208EFI_STATUS
209GetFileInfo (
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
237STATIC
238EFI_STATUS
239GetBootMonFsFileInfo (
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**/
299STATIC
300EFI_STATUS
301SetFileName (
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**/
347STATIC
348EFI_STATUS
349SetFileSize (
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**/
452STATIC
453EFI_STATUS
454SetFileInfo (
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
531EFIAPI
532EFI_STATUS
533BootMonFsGetInfo (
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**/
613EFIAPI
614EFI_STATUS
615BootMonFsSetInfo (
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
674EFIAPI
675EFI_STATUS
676BootMonFsReadDirectory (
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
729EFIAPI
730EFI_STATUS
731BootMonFsFlushDirectory (
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