• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   This driver uses the EFI_FIRMWARE_VOLUME2_PROTOCOL to expose files in firmware
3   volumes via the the EFI_SIMPLE_FILESYSTEM_PROTOCOL and EFI_FILE_PROTOCOL.
4 
5   It will expose a single directory, containing one file for each file in the firmware
6   volume. If a file has a UI section, its contents will be used as a filename.
7   Otherwise, a string representation of the GUID will be used.
8   Files of an executable type (That is PEIM, DRIVER, COMBINED_PEIM_DRIVER and APPLICATION)
9   will have ".efi" added to their filename.
10 
11   Its primary intended use is to be able to start EFI applications embedded in FVs
12   from the UEFI shell. It is entirely read-only.
13 
14 Copyright (c) 2014, ARM Limited. All rights reserved.
15 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
16 
17 This program and the accompanying materials
18 are licensed and made available under the terms and conditions of the BSD License
19 which accompanies this distribution.  The full text of the license may be found at
20 http://opensource.org/licenses/bsd-license.php
21 
22 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
23 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
24 
25 **/
26 
27 #include "FvSimpleFileSystemInternal.h"
28 
29 //
30 // Template for EFI_FILE_SYSTEM_INFO data structure.
31 //
32 EFI_FILE_SYSTEM_INFO mFsInfoTemplate = {
33   0,    // Populate at runtime
34   TRUE, // Read-only
35   0,    // Don't know volume size
36   0,    // No free space
37   0,    // Don't know block size
38   L""   // Populate at runtime
39 };
40 
41 //
42 // Template for EFI_FILE_PROTOCOL data structure.
43 //
44 EFI_FILE_PROTOCOL mFileSystemTemplate = {
45   EFI_FILE_PROTOCOL_REVISION,
46   FvSimpleFileSystemOpen,
47   FvSimpleFileSystemClose,
48   FvSimpleFileSystemDelete,
49   FvSimpleFileSystemRead,
50   FvSimpleFileSystemWrite,
51   FvSimpleFileSystemGetPosition,
52   FvSimpleFileSystemSetPosition,
53   FvSimpleFileSystemGetInfo,
54   FvSimpleFileSystemSetInfo,
55   FvSimpleFileSystemFlush
56 };
57 
58 /**
59   Find and call ReadSection on the first section found of an executable type.
60 
61   @param  FvProtocol                  A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance.
62   @param  FvFileInfo                  A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
63                                       representing a file's info.
64   @param  BufferSize                  Pointer to a caller-allocated UINTN. It indicates the size of
65                                       the memory represented by *Buffer.
66   @param  Buffer                      Pointer to a pointer to a data buffer to contain file content.
67 
68   @retval EFI_SUCCESS                 The call completed successfully.
69   @retval EFI_WARN_BUFFER_TOO_SMALL   The buffer is too small to contain the requested output.
70   @retval EFI_ACCESS_DENIED           The firmware volume is configured to disallow reads.
71   @retval EFI_NOT_FOUND               The requested file was not found in the firmware volume.
72   @retval EFI_DEVICE_ERROR            A hardware error occurred when attempting toaccess the firmware volume.
73 
74 **/
75 EFI_STATUS
FvFsFindExecutableSection(IN EFI_FIRMWARE_VOLUME2_PROTOCOL * FvProtocol,IN FV_FILESYSTEM_FILE_INFO * FvFileInfo,IN OUT UINTN * BufferSize,IN OUT VOID ** Buffer)76 FvFsFindExecutableSection (
77   IN     EFI_FIRMWARE_VOLUME2_PROTOCOL     *FvProtocol,
78   IN     FV_FILESYSTEM_FILE_INFO           *FvFileInfo,
79   IN OUT UINTN                             *BufferSize,
80   IN OUT VOID                              **Buffer
81   )
82 {
83   EFI_SECTION_TYPE                    SectionType;
84   UINT32                              AuthenticationStatus;
85   EFI_STATUS                          Status;
86 
87   for (SectionType = EFI_SECTION_PE32; SectionType <= EFI_SECTION_TE; SectionType++) {
88     Status = FvProtocol->ReadSection (
89                            FvProtocol,
90                            &FvFileInfo->NameGuid,
91                            SectionType,
92                            0,
93                            Buffer,
94                            BufferSize,
95                            &AuthenticationStatus
96                            );
97     if (Status != EFI_NOT_FOUND) {
98       return Status;
99     }
100   }
101 
102   return EFI_NOT_FOUND;
103 }
104 
105 /**
106   Get the size of the buffer that will be returned by FvFsReadFile.
107 
108   @param  FvProtocol                  A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance.
109   @param  FvFileInfo                  A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
110                                       representing a file's info.
111 
112   @retval EFI_SUCCESS                 The file size was gotten correctly.
113   @retval Others                      The file size wasn't gotten correctly.
114 
115 **/
116 EFI_STATUS
FvFsGetFileSize(IN EFI_FIRMWARE_VOLUME2_PROTOCOL * FvProtocol,IN OUT FV_FILESYSTEM_FILE_INFO * FvFileInfo)117 FvFsGetFileSize (
118   IN     EFI_FIRMWARE_VOLUME2_PROTOCOL     *FvProtocol,
119   IN OUT FV_FILESYSTEM_FILE_INFO           *FvFileInfo
120   )
121 {
122   UINT32                         AuthenticationStatus;
123   EFI_FV_FILETYPE                FoundType;
124   EFI_FV_FILE_ATTRIBUTES         Attributes;
125   EFI_STATUS                     Status;
126   UINT8                          IgnoredByte;
127   VOID                           *IgnoredPtr;
128 
129   //
130   // To get the size of a section, we pass 0 for BufferSize. But we can't pass
131   // NULL for Buffer, as that will cause a return of INVALID_PARAMETER, and we
132   // can't pass NULL for *Buffer, as that will cause the callee to allocate
133   // a buffer of the sections size.
134   //
135   IgnoredPtr = &IgnoredByte;
136   FvFileInfo->FileInfo.FileSize = 0;
137 
138   if (FV_FILETYPE_IS_EXECUTABLE (FvFileInfo->Type)) {
139     //
140     // Get the size of the first executable section out of the file.
141     //
142     Status = FvFsFindExecutableSection (FvProtocol, FvFileInfo, (UINTN*)&FvFileInfo->FileInfo.FileSize, &IgnoredPtr);
143     if (Status == EFI_WARN_BUFFER_TOO_SMALL) {
144       return EFI_SUCCESS;
145     }
146   } else if (FvFileInfo->Type == EFI_FV_FILETYPE_FREEFORM) {
147     //
148     // Try to get the size of a raw section out of the file
149     //
150     Status = FvProtocol->ReadSection (
151                            FvProtocol,
152                            &FvFileInfo->NameGuid,
153                            EFI_SECTION_RAW,
154                            0,
155                            &IgnoredPtr,
156                            (UINTN*)&FvFileInfo->FileInfo.FileSize,
157                            &AuthenticationStatus
158                            );
159     if (Status == EFI_WARN_BUFFER_TOO_SMALL) {
160       return EFI_SUCCESS;
161     }
162     if (EFI_ERROR (Status)) {
163       //
164       // Didn't find a raw section, just return the whole file's size.
165       //
166       return FvProtocol->ReadFile (
167                            FvProtocol,
168                            &FvFileInfo->NameGuid,
169                            NULL,
170                            (UINTN*)&FvFileInfo->FileInfo.FileSize,
171                            &FoundType,
172                            &Attributes,
173                            &AuthenticationStatus
174                            );
175     }
176   } else {
177     //
178     // Get the size of the entire file
179     //
180     return FvProtocol->ReadFile (
181                          FvProtocol,
182                          &FvFileInfo->NameGuid,
183                          NULL,
184                          (UINTN*)&FvFileInfo->FileInfo.FileSize,
185                          &FoundType,
186                          &Attributes,
187                          &AuthenticationStatus
188                          );
189   }
190 
191   return Status;
192 }
193 
194 /**
195   Helper function to read a file.
196 
197   The data returned depends on the type of the underlying FV file:
198   - For executable types, the first section found that contains executable code is returned.
199   - For files of type FREEFORM, the driver attempts to return the first section of type RAW.
200     If none is found, the entire contents of the FV file are returned.
201   - On all other files the entire contents of the FV file is returned, as by
202     EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadFile.
203 
204   @param  FvProtocol                  A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance.
205   @param  FvFileInfo                  A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
206                                       representing a file's info.
207   @param  BufferSize                  Pointer to a caller-allocated UINTN. It indicates the size of
208                                       the memory represented by *Buffer.
209   @param  Buffer                      Pointer to a pointer to a data buffer to contain file content.
210 
211   @retval EFI_SUCCESS                 The call completed successfully.
212   @retval EFI_WARN_BUFFER_TOO_SMALL   The buffer is too small to contain the requested output.
213   @retval EFI_ACCESS_DENIED           The firmware volume is configured to disallow reads.
214   @retval EFI_NOT_FOUND               The requested file was not found in the firmware volume.
215   @retval EFI_DEVICE_ERROR            A hardware error occurred when attempting toaccess the firmware volume.
216 
217 **/
218 EFI_STATUS
FvFsReadFile(IN EFI_FIRMWARE_VOLUME2_PROTOCOL * FvProtocol,IN FV_FILESYSTEM_FILE_INFO * FvFileInfo,IN OUT UINTN * BufferSize,IN OUT VOID ** Buffer)219 FvFsReadFile (
220   IN     EFI_FIRMWARE_VOLUME2_PROTOCOL     *FvProtocol,
221   IN     FV_FILESYSTEM_FILE_INFO           *FvFileInfo,
222   IN OUT UINTN                             *BufferSize,
223   IN OUT VOID                              **Buffer
224   )
225 {
226   UINT32                         AuthenticationStatus;
227   EFI_FV_FILETYPE                FoundType;
228   EFI_FV_FILE_ATTRIBUTES         Attributes;
229   EFI_STATUS                     Status;
230 
231   if (FV_FILETYPE_IS_EXECUTABLE (FvFileInfo->Type)) {
232     //
233     // Read the first executable section out of the file.
234     //
235     Status = FvFsFindExecutableSection (FvProtocol, FvFileInfo, BufferSize, Buffer);
236   } else if (FvFileInfo->Type == EFI_FV_FILETYPE_FREEFORM) {
237     //
238     // Try to read a raw section out of the file
239     //
240     Status = FvProtocol->ReadSection (
241                            FvProtocol,
242                            &FvFileInfo->NameGuid,
243                            EFI_SECTION_RAW,
244                            0,
245                            Buffer,
246                            BufferSize,
247                            &AuthenticationStatus
248                            );
249     if (EFI_ERROR (Status)) {
250       //
251       // Didn't find a raw section, just return the whole file.
252       //
253       Status = FvProtocol->ReadFile (
254                              FvProtocol,
255                              &FvFileInfo->NameGuid,
256                              Buffer,
257                              BufferSize,
258                              &FoundType,
259                              &Attributes,
260                              &AuthenticationStatus
261                              );
262     }
263   } else {
264     //
265     // Read the entire file
266     //
267     Status = FvProtocol->ReadFile (
268                            FvProtocol,
269                            &FvFileInfo->NameGuid,
270                            Buffer,
271                            BufferSize,
272                            &FoundType,
273                            &Attributes,
274                            &AuthenticationStatus
275                            );
276   }
277 
278   return Status;
279 }
280 
281 /**
282   Helper function for populating an EFI_FILE_INFO for a file.
283 
284   Note the CreateTime, LastAccessTime and ModificationTime fields in EFI_FILE_INFO
285   are full zero as FV2 protocol has no corresponding info to fill.
286 
287   @param  FvFileInfo                  A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
288                                       representing a file's info.
289   @param  BufferSize                  Pointer to a caller-allocated UINTN. It indicates the size of
290                                       the memory represented by FileInfo.
291   @param  FileInfo                    A pointer to EFI_FILE_INFO to contain the returned file info.
292 
293   @retval EFI_SUCCESS                 The call completed successfully.
294   @retval EFI_BUFFER_TOO_SMALL        The buffer is too small to contain the requested output.
295 
296 **/
297 EFI_STATUS
FvFsGetFileInfo(IN FV_FILESYSTEM_FILE_INFO * FvFileInfo,IN OUT UINTN * BufferSize,OUT EFI_FILE_INFO * FileInfo)298 FvFsGetFileInfo (
299   IN     FV_FILESYSTEM_FILE_INFO           *FvFileInfo,
300   IN OUT UINTN                             *BufferSize,
301      OUT EFI_FILE_INFO                     *FileInfo
302   )
303 {
304   UINTN                      InfoSize;
305 
306   InfoSize = (UINTN)FvFileInfo->FileInfo.Size;
307   if (*BufferSize < InfoSize) {
308     *BufferSize = InfoSize;
309     return EFI_BUFFER_TOO_SMALL;
310   }
311 
312   //
313   // Initialize FileInfo
314   //
315   CopyMem (FileInfo, &FvFileInfo->FileInfo, InfoSize);
316 
317   *BufferSize = InfoSize;
318   return EFI_SUCCESS;
319 }
320 
321 /**
322   Removes the last directory or file entry in a path by changing the last
323   L'\' to a CHAR_NULL.
324 
325   @param  Path      The pointer to the path to modify.
326 
327   @retval FALSE     Nothing was found to remove.
328   @retval TRUE      A directory or file was removed.
329 
330 **/
331 BOOLEAN
332 EFIAPI
RemoveLastItemFromPath(IN OUT CHAR16 * Path)333 RemoveLastItemFromPath (
334   IN OUT CHAR16 *Path
335   )
336 {
337   CHAR16        *Walker;
338   CHAR16        *LastSlash;
339   //
340   // get directory name from path... ('chop' off extra)
341   //
342   for ( Walker = Path, LastSlash = NULL
343       ; Walker != NULL && *Walker != CHAR_NULL
344       ; Walker++
345      ){
346     if (*Walker == L'\\' && *(Walker + 1) != CHAR_NULL) {
347       LastSlash = Walker + 1;
348     }
349   }
350 
351   if (LastSlash != NULL) {
352     *LastSlash = CHAR_NULL;
353     return (TRUE);
354   }
355 
356   return (FALSE);
357 }
358 
359 /**
360   Function to clean up paths.
361 
362   - Single periods in the path are removed.
363   - Double periods in the path are removed along with a single parent directory.
364   - Forward slashes L'/' are converted to backward slashes L'\'.
365 
366   This will be done inline and the existing buffer may be larger than required
367   upon completion.
368 
369   @param  Path          The pointer to the string containing the path.
370 
371   @retval NULL          An error occured.
372   @return Path in all other instances.
373 
374 **/
375 CHAR16*
376 EFIAPI
TrimFilePathToAbsolutePath(IN CHAR16 * Path)377 TrimFilePathToAbsolutePath (
378   IN CHAR16 *Path
379   )
380 {
381   CHAR16  *TempString;
382   UINTN   TempSize;
383 
384   if (Path == NULL) {
385     return NULL;
386   }
387 
388   //
389   // Fix up the '/' vs '\'
390   //
391   for (TempString = Path ; (TempString != NULL) && (*TempString != CHAR_NULL); TempString++) {
392     if (*TempString == L'/') {
393       *TempString = L'\\';
394     }
395   }
396 
397   //
398   // Fix up the ..
399   //
400   while ((TempString = StrStr (Path, L"\\..\\")) != NULL) {
401     *TempString  = CHAR_NULL;
402     TempString  += 4;
403     RemoveLastItemFromPath (Path);
404     TempSize     = StrSize (TempString);
405     CopyMem (Path + StrLen (Path), TempString, TempSize);
406   }
407 
408   if (((TempString = StrStr (Path, L"\\..")) != NULL) && (*(TempString + 3) == CHAR_NULL)) {
409     *TempString  = CHAR_NULL;
410     RemoveLastItemFromPath (Path);
411   }
412 
413   //
414   // Fix up the .
415   //
416   while ((TempString = StrStr (Path, L"\\.\\")) != NULL) {
417     *TempString  = CHAR_NULL;
418     TempString  += 2;
419     TempSize     = StrSize (TempString);
420     CopyMem(Path + StrLen (Path), TempString, TempSize);
421   }
422 
423   if (((TempString = StrStr (Path, L"\\.")) != NULL) && (*(TempString + 2) == CHAR_NULL)) {
424     *(TempString + 1) = CHAR_NULL;
425   }
426 
427   while ((TempString = StrStr (Path, L"\\\\")) != NULL) {
428     *TempString  = CHAR_NULL;
429     TempString  += 1;
430     TempSize     = StrSize(TempString);
431     CopyMem(Path + StrLen(Path), TempString, TempSize);
432   }
433 
434   if (((TempString = StrStr(Path, L"\\\\")) != NULL) && (*(TempString + 1) == CHAR_NULL)) {
435     *(TempString) = CHAR_NULL;
436   }
437 
438   return Path;
439 }
440 
441 /**
442   Opens a new file relative to the source file's location.
443 
444   @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
445                      handle to the source location. This would typically be an open
446                      handle to a directory.
447   @param  NewHandle  A pointer to the location to return the opened handle for the new
448                      file.
449   @param  FileName   The Null-terminated string of the name of the file to be opened.
450                      The file name may contain the following path modifiers: "\", ".",
451                      and "..".
452   @param  OpenMode   The mode to open the file. The only valid combinations that the
453                      file may be opened with are: Read, Read/Write, or Create/Read/Write.
454   @param  Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the
455                      attribute bits for the newly created file.
456 
457   @retval EFI_SUCCESS          The file was opened.
458   @retval EFI_NOT_FOUND        The specified file could not be found on the device.
459   @retval EFI_NO_MEDIA         The device has no medium.
460   @retval EFI_MEDIA_CHANGED    The device has a different medium in it or the medium is no
461                                longer supported.
462   @retval EFI_DEVICE_ERROR     The device reported an error.
463   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
464   @retval EFI_WRITE_PROTECTED  An attempt was made to create a file, or open a file for write
465                                when the media is write-protected.
466   @retval EFI_ACCESS_DENIED    The service denied access to the file.
467   @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
468   @retval EFI_VOLUME_FULL      The volume is full.
469 
470 **/
471 EFI_STATUS
472 EFIAPI
FvSimpleFileSystemOpen(IN EFI_FILE_PROTOCOL * This,OUT EFI_FILE_PROTOCOL ** NewHandle,IN CHAR16 * FileName,IN UINT64 OpenMode,IN UINT64 Attributes)473 FvSimpleFileSystemOpen (
474   IN     EFI_FILE_PROTOCOL    *This,
475      OUT EFI_FILE_PROTOCOL    **NewHandle,
476   IN     CHAR16               *FileName,
477   IN     UINT64               OpenMode,
478   IN     UINT64               Attributes
479   )
480 {
481   FV_FILESYSTEM_INSTANCE      *Instance;
482   FV_FILESYSTEM_FILE          *File;
483   FV_FILESYSTEM_FILE          *NewFile;
484   FV_FILESYSTEM_FILE_INFO     *FvFileInfo;
485   LIST_ENTRY                  *FvFileInfoLink;
486   EFI_STATUS                  Status;
487   UINTN                       FileNameLength;
488   UINTN                       NewFileNameLength;
489   CHAR16                      *FileNameWithExtension;
490 
491   //
492   // Check for a valid mode
493   //
494   switch (OpenMode) {
495   case EFI_FILE_MODE_READ:
496     break;
497 
498   default:
499     return EFI_WRITE_PROTECTED;
500   }
501 
502   File = FVFS_FILE_FROM_FILE_THIS (This);
503   Instance = File->Instance;
504 
505   FileName = TrimFilePathToAbsolutePath (FileName);
506   if (FileName == NULL) {
507     return EFI_INVALID_PARAMETER;
508   }
509 
510   if (FileName[0] == L'\\') {
511     FileName++;
512   }
513 
514   //
515   // Check for opening root
516   //
517   if (StrCmp (FileName, L".") == 0 || StrCmp (FileName, L"") == 0) {
518     NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE));
519     if (NewFile == NULL) {
520       return EFI_OUT_OF_RESOURCES;
521     }
522     NewFile->Signature = FVFS_FILE_SIGNATURE;
523     NewFile->Instance  = Instance;
524     NewFile->FvFileInfo = File->FvFileInfo;
525     CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate));
526     InitializeListHead (&NewFile->Link);
527     InsertHeadList (&Instance->FileHead, &NewFile->Link);
528 
529     NewFile->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance);
530 
531     *NewHandle = &NewFile->FileProtocol;
532     return EFI_SUCCESS;
533   }
534 
535   //
536   // Do a linear search for a file in the FV with a matching filename
537   //
538   Status     = EFI_NOT_FOUND;
539   FvFileInfo = NULL;
540   for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead);
541       !IsNull (&Instance->FileInfoHead, FvFileInfoLink);
542        FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) {
543     FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink);
544     if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileName) == 0) {
545       Status = EFI_SUCCESS;
546       break;
547     }
548   }
549 
550   // If the file has not been found check if the filename exists with an extension
551   // in case there was no extension present.
552   // FvFileSystem adds a 'virtual' extension '.EFI' to EFI applications and drivers
553   // present in the Firmware Volume
554   if (Status == EFI_NOT_FOUND) {
555     FileNameLength = StrLen (FileName);
556 
557     // Does the filename already contain the '.EFI' extension?
558     if (mUnicodeCollation->StriColl (mUnicodeCollation, FileName + FileNameLength - 4, L".efi") != 0) {
559       // No, there was no extension. So add one and search again for the file
560       // NewFileNameLength = FileNameLength + 1 + 4 = (Number of non-null character) + (file extension) + (a null character)
561       NewFileNameLength = FileNameLength + 1 + 4;
562       FileNameWithExtension = AllocateCopyPool (NewFileNameLength * 2, FileName);
563       StrCatS (FileNameWithExtension, NewFileNameLength, L".EFI");
564 
565       for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead);
566           !IsNull (&Instance->FileInfoHead, FvFileInfoLink);
567            FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) {
568         FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink);
569         if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileNameWithExtension) == 0) {
570           Status = EFI_SUCCESS;
571           break;
572         }
573       }
574     }
575   }
576 
577   if (!EFI_ERROR (Status)) {
578     NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE));
579     if (NewFile == NULL) {
580       return EFI_OUT_OF_RESOURCES;
581     }
582 
583     NewFile->Signature = FVFS_FILE_SIGNATURE;
584     NewFile->Instance  = Instance;
585     NewFile->FvFileInfo = FvFileInfo;
586     CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate));
587     InitializeListHead (&NewFile->Link);
588     InsertHeadList (&Instance->FileHead, &NewFile->Link);
589 
590     *NewHandle = &NewFile->FileProtocol;
591     return EFI_SUCCESS;
592   }
593 
594   return EFI_NOT_FOUND;
595 }
596 
597 /**
598   Closes a specified file handle.
599 
600   @param  This          A pointer to the EFI_FILE_PROTOCOL instance that is the file
601                         handle to close.
602 
603   @retval EFI_SUCCESS   The file was closed.
604 
605 **/
606 EFI_STATUS
607 EFIAPI
FvSimpleFileSystemClose(IN EFI_FILE_PROTOCOL * This)608 FvSimpleFileSystemClose (
609   IN EFI_FILE_PROTOCOL  *This
610   )
611 {
612   FV_FILESYSTEM_INSTANCE      *Instance;
613   FV_FILESYSTEM_FILE          *File;
614 
615   File = FVFS_FILE_FROM_FILE_THIS (This);
616   Instance = File->Instance;
617 
618   if (File != Instance->Root) {
619     RemoveEntryList (&File->Link);
620     FreePool (File);
621   }
622   return EFI_SUCCESS;
623 }
624 
625 /**
626   Reads data from a file.
627 
628   @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
629                      handle to read data from.
630   @param  BufferSize On input, the size of the Buffer. On output, the amount of data
631                      returned in Buffer. In both cases, the size is measured in bytes.
632   @param  Buffer     The buffer into which the data is read.
633 
634   @retval EFI_SUCCESS          Data was read.
635   @retval EFI_NO_MEDIA         The device has no medium.
636   @retval EFI_DEVICE_ERROR     The device reported an error.
637   @retval EFI_DEVICE_ERROR     An attempt was made to read from a deleted file.
638   @retval EFI_DEVICE_ERROR     On entry, the current file position is beyond the end of the file.
639   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
640   @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory
641                                entry. BufferSize has been updated with the size
642                                needed to complete the request.
643 
644 **/
645 EFI_STATUS
646 EFIAPI
FvSimpleFileSystemRead(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)647 FvSimpleFileSystemRead (
648   IN     EFI_FILE_PROTOCOL      *This,
649   IN OUT UINTN                  *BufferSize,
650      OUT VOID                   *Buffer
651   )
652 {
653   FV_FILESYSTEM_INSTANCE        *Instance;
654   FV_FILESYSTEM_FILE            *File;
655   EFI_STATUS                    Status;
656   LIST_ENTRY                    *FvFileInfoLink;
657   VOID                          *FileBuffer;
658   UINTN                         FileSize;
659 
660   File = FVFS_FILE_FROM_FILE_THIS (This);
661   Instance = File->Instance;
662 
663   if (File->FvFileInfo == Instance->Root->FvFileInfo) {
664     if (File->DirReadNext) {
665       //
666       // Directory read: populate Buffer with an EFI_FILE_INFO
667       //
668       Status = FvFsGetFileInfo (File->DirReadNext, BufferSize, Buffer);
669       if (!EFI_ERROR (Status)) {
670         //
671         // Successfully read a directory entry, now update the pointer to the
672         // next file, which will be read on the next call to this function
673         //
674         FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, &File->DirReadNext->Link);
675         if (IsNull (&Instance->FileInfoHead, FvFileInfoLink)) {
676           //
677           // No more files left
678           //
679           File->DirReadNext = NULL;
680         } else {
681           File->DirReadNext = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink);
682         }
683       }
684       return Status;
685     } else {
686       //
687       // Directory read. All entries have been read, so return a zero-size
688       // buffer.
689       //
690       *BufferSize = 0;
691       return EFI_SUCCESS;
692     }
693   } else {
694     FileSize = (UINTN)File->FvFileInfo->FileInfo.FileSize;
695 
696     FileBuffer = AllocateZeroPool (FileSize);
697     if (FileBuffer == NULL) {
698       return EFI_DEVICE_ERROR;
699     }
700 
701     Status = FvFsReadFile (File->Instance->FvProtocol, File->FvFileInfo, &FileSize, &FileBuffer);
702     if (EFI_ERROR (Status)) {
703       return EFI_DEVICE_ERROR;
704     }
705 
706     if (*BufferSize + File->Position > FileSize) {
707       *BufferSize = (UINTN)(FileSize - File->Position);
708     }
709 
710     CopyMem (Buffer, (UINT8*)FileBuffer + File->Position, *BufferSize);
711     File->Position += *BufferSize;
712 
713     return EFI_SUCCESS;
714   }
715 }
716 
717 /**
718   Writes data to a file.
719 
720   @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
721                      handle to write data to.
722   @param  BufferSize On input, the size of the Buffer. On output, the amount of data
723                      actually written. In both cases, the size is measured in bytes.
724   @param  Buffer     The buffer of data to write.
725 
726   @retval EFI_SUCCESS          Data was written.
727   @retval EFI_UNSUPPORTED      Writes to open directory files are not supported.
728   @retval EFI_NO_MEDIA         The device has no medium.
729   @retval EFI_DEVICE_ERROR     The device reported an error.
730   @retval EFI_DEVICE_ERROR     An attempt was made to write to a deleted file.
731   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
732   @retval EFI_WRITE_PROTECTED  The file or medium is write-protected.
733   @retval EFI_ACCESS_DENIED    The file was opened read only.
734   @retval EFI_VOLUME_FULL      The volume is full.
735 
736 **/
737 EFI_STATUS
738 EFIAPI
FvSimpleFileSystemWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)739 FvSimpleFileSystemWrite (
740   IN     EFI_FILE_PROTOCOL    *This,
741   IN OUT UINTN                *BufferSize,
742   IN     VOID                 *Buffer
743   )
744 {
745   FV_FILESYSTEM_INSTANCE        *Instance;
746   FV_FILESYSTEM_FILE            *File;
747 
748   File = FVFS_FILE_FROM_FILE_THIS (This);
749   Instance = File->Instance;
750 
751   if (File->FvFileInfo == Instance->Root->FvFileInfo) {
752     return EFI_UNSUPPORTED;
753   } else {
754     return EFI_WRITE_PROTECTED;
755   }
756 }
757 
758 /**
759   Returns a file's current position.
760 
761   @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
762                           handle to get the current position on.
763   @param  Position        The address to return the file's current position value.
764 
765   @retval EFI_SUCCESS      The position was returned.
766   @retval EFI_UNSUPPORTED  The request is not valid on open directories.
767   @retval EFI_DEVICE_ERROR An attempt was made to get the position from a deleted file.
768 
769 **/
770 EFI_STATUS
771 EFIAPI
FvSimpleFileSystemGetPosition(IN EFI_FILE_PROTOCOL * This,OUT UINT64 * Position)772 FvSimpleFileSystemGetPosition (
773   IN     EFI_FILE_PROTOCOL    *This,
774      OUT UINT64               *Position
775   )
776 {
777   FV_FILESYSTEM_INSTANCE        *Instance;
778   FV_FILESYSTEM_FILE            *File;
779 
780   File = FVFS_FILE_FROM_FILE_THIS (This);
781   Instance = File->Instance;
782 
783   if (File->FvFileInfo == Instance->Root->FvFileInfo) {
784     return EFI_UNSUPPORTED;
785   } else {
786     *Position = File->Position;
787     return EFI_SUCCESS;
788   }
789 }
790 
791 /**
792   Sets a file's current position.
793 
794   @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the
795                           file handle to set the requested position on.
796   @param  Position        The byte position from the start of the file to set.
797 
798   @retval EFI_SUCCESS      The position was set.
799   @retval EFI_UNSUPPORTED  The seek request for nonzero is not valid on open
800                            directories.
801   @retval EFI_DEVICE_ERROR An attempt was made to set the position of a deleted file.
802 
803 **/
804 EFI_STATUS
805 EFIAPI
FvSimpleFileSystemSetPosition(IN EFI_FILE_PROTOCOL * This,IN UINT64 Position)806 FvSimpleFileSystemSetPosition (
807   IN EFI_FILE_PROTOCOL        *This,
808   IN UINT64                   Position
809   )
810 {
811   FV_FILESYSTEM_INSTANCE      *Instance;
812   FV_FILESYSTEM_FILE          *File;
813 
814   File = FVFS_FILE_FROM_FILE_THIS (This);
815   Instance = File->Instance;
816 
817   if (File->FvFileInfo == Instance->Root->FvFileInfo) {
818     if (Position != 0) {
819       return EFI_UNSUPPORTED;
820     }
821     //
822     // Reset directory position to first entry
823     //
824     File->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance);
825   } else if (Position == 0xFFFFFFFFFFFFFFFFull) {
826     File->Position = File->FvFileInfo->FileInfo.FileSize;
827   } else {
828     File->Position = Position;
829   }
830 
831   return EFI_SUCCESS;
832 }
833 
834 /**
835   Flushes all modified data associated with a file to a device.
836 
837   @param  This A pointer to the EFI_FILE_PROTOCOL instance that is the file
838                handle to flush.
839 
840   @retval EFI_SUCCESS          The data was flushed.
841   @retval EFI_NO_MEDIA         The device has no medium.
842   @retval EFI_DEVICE_ERROR     The device reported an error.
843   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
844   @retval EFI_WRITE_PROTECTED  The file or medium is write-protected.
845   @retval EFI_ACCESS_DENIED    The file was opened read-only.
846   @retval EFI_VOLUME_FULL      The volume is full.
847 
848 **/
849 EFI_STATUS
850 EFIAPI
FvSimpleFileSystemFlush(IN EFI_FILE_PROTOCOL * This)851 FvSimpleFileSystemFlush (
852   IN EFI_FILE_PROTOCOL  *This
853   )
854 {
855   return EFI_WRITE_PROTECTED;
856 }
857 
858 /**
859   Close and delete the file handle.
860 
861   @param  This                     A pointer to the EFI_FILE_PROTOCOL instance that is the
862                                    handle to the file to delete.
863 
864   @retval EFI_SUCCESS              The file was closed and deleted, and the handle was closed.
865   @retval EFI_WARN_DELETE_FAILURE  The handle was closed, but the file was not deleted.
866 
867 **/
868 EFI_STATUS
869 EFIAPI
FvSimpleFileSystemDelete(IN EFI_FILE_PROTOCOL * This)870 FvSimpleFileSystemDelete (
871   IN EFI_FILE_PROTOCOL *This
872   )
873 {
874   EFI_STATUS       Status;
875 
876   Status = FvSimpleFileSystemClose (This);
877   ASSERT_EFI_ERROR (Status);
878 
879   return EFI_WARN_DELETE_FAILURE;
880 }
881 
882 /**
883   Returns information about a file.
884 
885   @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
886                           handle the requested information is for.
887   @param  InformationType The type identifier for the information being requested.
888   @param  BufferSize      On input, the size of Buffer. On output, the amount of data
889                           returned in Buffer. In both cases, the size is measured in bytes.
890   @param  Buffer          A pointer to the data buffer to return. The buffer's type is
891                           indicated by InformationType.
892 
893   @retval EFI_SUCCESS          The information was returned.
894   @retval EFI_UNSUPPORTED      The InformationType is not known.
895   @retval EFI_NO_MEDIA         The device has no medium.
896   @retval EFI_DEVICE_ERROR     The device reported an error.
897   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
898   @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
899                                BufferSize has been updated with the size needed to complete
900                                the request.
901 **/
902 EFI_STATUS
903 EFIAPI
FvSimpleFileSystemGetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN OUT UINTN * BufferSize,OUT VOID * Buffer)904 FvSimpleFileSystemGetInfo (
905   IN     EFI_FILE_PROTOCOL    *This,
906   IN     EFI_GUID             *InformationType,
907   IN OUT UINTN                *BufferSize,
908      OUT VOID                 *Buffer
909   )
910 {
911   FV_FILESYSTEM_FILE           *File;
912   EFI_FILE_SYSTEM_INFO         *FsInfoOut;
913   EFI_FILE_SYSTEM_VOLUME_LABEL *FsVolumeLabel;
914   FV_FILESYSTEM_INSTANCE       *Instance;
915   UINTN                        Size;
916   EFI_STATUS                   Status;
917 
918   File = FVFS_FILE_FROM_FILE_THIS (This);
919 
920   if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
921     //
922     // Return filesystem info
923     //
924     Instance = File->Instance;
925 
926     Size = sizeof (EFI_FILE_SYSTEM_INFO) + StrSize (Instance->VolumeLabel) - sizeof (CHAR16);
927 
928     if (*BufferSize < Size) {
929       *BufferSize = Size;
930       return EFI_BUFFER_TOO_SMALL;
931     }
932 
933     //
934     // Cast output buffer for convenience
935     //
936     FsInfoOut = (EFI_FILE_SYSTEM_INFO *) Buffer;
937 
938     CopyMem (FsInfoOut, &mFsInfoTemplate, sizeof (EFI_FILE_SYSTEM_INFO));
939     Status = StrnCpyS ( FsInfoOut->VolumeLabel,
940                         (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_INFO, VolumeLabel)) / sizeof (CHAR16),
941                         Instance->VolumeLabel,
942                         StrLen (Instance->VolumeLabel)
943                         );
944     ASSERT_EFI_ERROR (Status);
945     FsInfoOut->Size = Size;
946     return Status;
947   } else if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
948     //
949     // Return file info
950     //
951     return FvFsGetFileInfo (File->FvFileInfo, BufferSize, (EFI_FILE_INFO *) Buffer);
952   } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
953     //
954     // Return Volume Label
955     //
956     Instance = File->Instance;
957     Size     = sizeof (EFI_FILE_SYSTEM_VOLUME_LABEL) + StrSize (Instance->VolumeLabel) - sizeof (CHAR16);;
958     if (*BufferSize < Size) {
959       *BufferSize = Size;
960       return EFI_BUFFER_TOO_SMALL;
961     }
962 
963     FsVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL*) Buffer;
964     Status        = StrnCpyS (FsVolumeLabel->VolumeLabel,
965                               (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_VOLUME_LABEL, VolumeLabel)) / sizeof (CHAR16),
966                               Instance->VolumeLabel,
967                               StrLen (Instance->VolumeLabel)
968                               );
969     ASSERT_EFI_ERROR (Status);
970     return Status;
971   } else {
972     return EFI_UNSUPPORTED;
973   }
974 }
975 
976 /**
977   Sets information about a file.
978 
979   @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
980                           handle the information is for.
981   @param  InformationType The type identifier for the information being set.
982   @param  BufferSize      The size, in bytes, of Buffer.
983   @param  Buffer          A pointer to the data buffer to write. The buffer's type is
984                           indicated by InformationType.
985 
986   @retval EFI_SUCCESS          The information was set.
987   @retval EFI_UNSUPPORTED      The InformationType is not known.
988   @retval EFI_NO_MEDIA         The device has no medium.
989   @retval EFI_DEVICE_ERROR     The device reported an error.
990   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
991   @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_INFO_ID and the media is
992                                read-only.
993   @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_PROTOCOL_SYSTEM_INFO_ID
994                                and the media is read only.
995   @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_SYSTEM_VOLUME_LABEL_ID
996                                and the media is read-only.
997   @retval EFI_ACCESS_DENIED    An attempt is made to change the name of a file to a
998                                file that is already present.
999   @retval EFI_ACCESS_DENIED    An attempt is being made to change the EFI_FILE_DIRECTORY
1000                                Attribute.
1001   @retval EFI_ACCESS_DENIED    An attempt is being made to change the size of a directory.
1002   @retval EFI_ACCESS_DENIED    InformationType is EFI_FILE_INFO_ID and the file was opened
1003                                read-only and an attempt is being made to modify a field
1004                                other than Attribute.
1005   @retval EFI_VOLUME_FULL      The volume is full.
1006   @retval EFI_BAD_BUFFER_SIZE  BufferSize is smaller than the size of the type indicated
1007                                by InformationType.
1008 
1009 **/
1010 EFI_STATUS
1011 EFIAPI
FvSimpleFileSystemSetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN UINTN BufferSize,IN VOID * Buffer)1012 FvSimpleFileSystemSetInfo (
1013   IN EFI_FILE_PROTOCOL        *This,
1014   IN EFI_GUID                 *InformationType,
1015   IN UINTN                    BufferSize,
1016   IN VOID                     *Buffer
1017   )
1018 {
1019   if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) ||
1020       CompareGuid (InformationType, &gEfiFileInfoGuid) ||
1021       CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
1022     return EFI_WRITE_PROTECTED;
1023   }
1024 
1025   return EFI_UNSUPPORTED;
1026 }
1027 
1028