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