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