]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EmbeddedPkg/Library/EfiFileLib/EfiFileLib.c
Adding support for BeagleBoard.
[mirror_edk2.git] / EmbeddedPkg / Library / EfiFileLib / EfiFileLib.c
... / ...
CommitLineData
1/** @file
2 File IO routines inspired by Streams with an EFI flavor
3
4 Copyright (c) 2007, Intel Corporation<BR>
5 Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
6
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 Basic support for opening files on different device types. The device string
16 is in the form of DevType:Path. Current DevType is required as there is no
17 current mounted device concept of current working directory concept implement
18 by this library.
19
20 Device names are case insensative and only check the leading characters for
21 unique matches. Thus the following are all the same:
22 LoadFile0:
23 l0:
24 L0:
25 Lo0:
26
27 Supported Device Names:
28 A0x1234:0x12 - A memory buffer starting at address 0x1234 for 0x12 bytes
29 l1: - EFI LoadFile device one.
30 B0: - EFI BlockIo zero.
31 fs3: - EFI Simple File System device 3
32 Fv2: - EFI Firmware VOlume device 2
33 10.0.1.102: - TFTP service IP followed by the file name
34**/
35
36#include <PiDxe.h>
37#include <Protocol/BlockIo.h>
38#include <Protocol/DiskIo.h>
39#include <Protocol/SimpleFileSystem.h>
40#include <Protocol/FirmwareVolume2.h>
41#include <Protocol/LoadFile.h>
42#include <Protocol/FirmwareVolumeBlock.h>
43#include <Guid/FileInfo.h>
44#include <Library/BaseLib.h>
45#include <Library/MemoryAllocationLib.h>
46#include <Library/DevicePathLib.h>
47#include <Library/PrintLib.h>
48#include <Library/BaseMemoryLib.h>
49#include <Library/UefiLib.h>
50#include <Library/UefiBootServicesTableLib.h>
51#include <Library/UefiRuntimeServicesTableLib.h>
52#include <Library/DebugLib.h>
53#include <Library/EfiFileLib.h>
54#include <Library/PcdLib.h>
55#include <Library/EblNetworkLib.h>
56
57
58#define EFI_OPEN_FILE_GUARD_HEADER 0x4B4D4641
59#define EFI_OPEN_FILE_GUARD_FOOTER 0x444D5A56
60
61// Need to defend against this overflowing
62#define MAX_CMD_LINE 0x200
63
64typedef struct {
65 UINT32 Header;
66 EFI_OPEN_FILE File;
67 UINT32 Footer;
68} EFI_OPEN_FILE_GUARD;
69
70
71// globals to store current open device info
72EFI_HANDLE *mBlkIo = NULL;
73UINTN mBlkIoCount = 0;
74
75EFI_HANDLE *mFs = NULL;
76UINTN mFsCount = 0;
77// mFsInfo[] array entries must match mFs[] handles
78EFI_FILE_SYSTEM_INFO **mFsInfo = NULL;
79
80EFI_HANDLE *mFv = NULL;
81UINTN mFvCount = 0;
82EFI_HANDLE *mLoadFile = NULL;
83UINTN mLoadFileCount = 0;
84
85
86
87/**
88 Internal worker function to validate a File handle.
89
90 @param File Open File Handle
91
92 @return TRUE File is valid
93 @return FALSE File is not valid
94
95
96**/
97BOOLEAN
98FileHandleValid (
99 IN EFI_OPEN_FILE *File
100 )
101{
102 EFI_OPEN_FILE_GUARD *GuardFile;
103
104 // Look right before and after file structure for the correct signatures
105 GuardFile = BASE_CR (File, EFI_OPEN_FILE_GUARD, File);
106 if ((GuardFile->Header != EFI_OPEN_FILE_GUARD_HEADER) ||
107 (GuardFile->Footer != EFI_OPEN_FILE_GUARD_FOOTER) ) {
108 return FALSE;
109 }
110
111 return TRUE;
112}
113
114/**
115 Internal worker function. If Buffer is not NULL free it.
116
117 @param Buffer Buffer to FreePool()
118
119**/
120VOID
121EblFreePool (
122 IN VOID *Buffer
123 )
124{
125 if (Buffer != NULL) {
126 FreePool (Buffer);
127 }
128}
129
130/**
131 Update Device List Global Variables
132
133**/
134VOID
135EblUpdateDeviceLists (
136 VOID
137 )
138{
139 EFI_STATUS Status;
140 UINTN Size;
141 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
142 EFI_FILE_HANDLE Root;
143 UINTN Index;
144
145 if (mBlkIo != NULL) {
146 FreePool (mBlkIo);
147 }
148 gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &mBlkIoCount, &mBlkIo);
149
150 if (mFv != NULL) {
151 FreePool (mFv);
152 }
153 gBS->LocateHandleBuffer (ByProtocol, &gEfiFirmwareVolume2ProtocolGuid, NULL, &mFvCount, &mFv);
154
155 if (mLoadFile != NULL) {
156 FreePool (mLoadFile);
157 }
158 gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &mLoadFileCount, &mLoadFile);
159
160 if (mFs != NULL) {
161 FreePool (mFs);
162 }
163
164 if (&mFsInfo[0] != NULL) {
165 // Need to Free the mFsInfo prior to reclaculating mFsCount so don't move this code
166 for (Index = 0; Index < mFsCount; Index++) {
167 if (mFsInfo[Index] != NULL) {
168 FreePool (mFsInfo[Index]);
169 }
170 }
171 FreePool (mFsInfo);
172 }
173
174 gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &mFsCount, &mFs);
175
176
177 mFsInfo = AllocateZeroPool (mFsCount * sizeof (EFI_FILE_SYSTEM_INFO *));
178 if (mFsInfo == NULL) {
179 // If we can't do this then we can't support file system entries
180 mFsCount = 0;
181 } else {
182 // Loop through all the file system structures and cache the file system info data
183 for (Index =0; Index < mFsCount; Index++) {
184 Status = gBS->HandleProtocol (mFs[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
185 if (!EFI_ERROR (Status)) {
186 Status = Fs->OpenVolume (Fs, &Root);
187 if (!EFI_ERROR (Status)) {
188 // Get information about the volume
189 Size = 0;
190 Status = Root->GetInfo (Root, &gEfiFileSystemInfoGuid, &Size, mFsInfo[Index]);
191 if (Status == EFI_BUFFER_TOO_SMALL) {
192 mFsInfo[Index] = AllocatePool (Size);
193 Status = Root->GetInfo (Root, &gEfiFileSystemInfoGuid, &Size, mFsInfo[Index]);
194 }
195
196 Root->Close (Root);
197 }
198 }
199 }
200 }
201}
202
203
204/**
205 PathName is in the form <device name>:<path> for example fs1:\ or ROOT:\.
206 Return TRUE if the <devce name> prefix of PathName matches a file system
207 Volume Name. MatchIndex is the array index in mFsInfo[] of the match,
208 and it can be used with mFs[] to find the handle that needs to be opened
209
210 @param PathName PathName to check
211 @param FileStart Index of the first character of the <path>
212 @param MatchIndex Index in mFsInfo[] that matches
213
214 @return TRUE PathName matches a Volume Label and MatchIndex is valid
215 @return FALSE PathName does not match a Volume Label MatchIndex undefined
216
217**/
218BOOLEAN
219EblMatchVolumeName (
220 IN CHAR8 *PathName,
221 IN UINTN FileStart,
222 OUT UINTN *MatchIndex
223 )
224{
225 UINTN Index;
226 UINTN Compare;
227 UINTN VolStrLen;
228 BOOLEAN Match;
229
230 for (Index =0; Index < mFsCount; Index++) {
231 if (mFsInfo[Index] == NULL) {
232 // FsInfo is not valid so skip it
233 continue;
234 }
235 VolStrLen = StrLen (mFsInfo[Index]->VolumeLabel);
236 for (Compare = 0, Match = TRUE; Compare < (FileStart - 1); Compare++) {
237 if (Compare > VolStrLen) {
238 Match = FALSE;
239 break;
240 }
241 if (PathName[Compare] != (CHAR8)mFsInfo[Index]->VolumeLabel[Compare]) {
242 // If the VolumeLabel has a space allow a _ to match with it in addition to ' '
243 if (!((PathName[Compare] == '_') && (mFsInfo[Index]->VolumeLabel[Compare] == L' '))) {
244 Match = FALSE;
245 break;
246 }
247 }
248 }
249 if (Match) {
250 *MatchIndex = Index;
251 return TRUE;
252 }
253 }
254
255 return FALSE;
256}
257
258
259/**
260 Return the number of devices of the current type active in the system
261
262 @param Type Device type to check
263
264 @return 0 Invalid type
265
266**/
267UINTN
268EfiGetDeviceCounts (
269 IN EFI_OPEN_FILE_TYPE DeviceType
270 )
271{
272 switch (DeviceType) {
273 case EfiOpenLoadFile:
274 return mLoadFileCount;
275 case EfiOpenFirmwareVolume:
276 return mFvCount;
277 case EfiOpenFileSystem:
278 return mFsCount;
279 case EfiOpenBlockIo:
280 return mBlkIoCount;
281 default:
282 return 0;
283 }
284}
285
286EFI_STATUS
287ConvertIpStringToEfiIp (
288 IN CHAR8 *PathName,
289 OUT EFI_IP_ADDRESS *ServerIp
290 )
291{
292 CHAR8 *Str;
293
294 Str = PathName;
295 ServerIp->v4.Addr[0] = (UINT8)AsciiStrDecimalToUintn (Str);
296
297 Str = AsciiStrStr (Str, ".");
298 if (Str == NULL) {
299 return EFI_DEVICE_ERROR;
300 }
301
302 ServerIp->v4.Addr[1] = (UINT8)AsciiStrDecimalToUintn (++Str);
303
304 Str = AsciiStrStr (Str, ".");
305 if (Str == NULL) {
306 return EFI_DEVICE_ERROR;
307 }
308
309 ServerIp->v4.Addr[2] = (UINT8)AsciiStrDecimalToUintn (++Str);
310
311 Str = AsciiStrStr (Str, ".");
312 if (Str == NULL) {
313 return EFI_DEVICE_ERROR;
314 }
315
316 ServerIp->v4.Addr[3] = (UINT8)AsciiStrDecimalToUintn (++Str);
317
318 return EFI_SUCCESS;
319}
320
321
322/**
323 Internal work function to extract a device number from a string skipping
324 text. Easy way to extract numbers from strings like blk7:.
325
326 @param Str String to extract device number form
327
328 @return -1 Device string is not valid
329 @return Device #
330
331**/
332UINTN
333EblConvertDevStringToNumber (
334 IN CHAR8 *Str
335 )
336{
337 UINTN Max;
338 UINTN Index;
339
340
341 // Find the first digit
342 Max = AsciiStrLen (Str);
343 for (Index = 0; !((*Str >= '0') && (*Str <= '9')) && (Index < Max); Index++) {
344 Str++;
345 }
346 if (Index == Max) {
347 return (UINTN)-1;
348 }
349
350 return AsciiStrDecimalToUintn (Str);
351}
352
353
354/**
355 Internal work function to fill in EFI_OPEN_FILE information for the Fs and BlkIo
356
357 @param File Open file handle
358 @param FileName Name of file after device stripped off
359
360
361**/
362EFI_STATUS
363EblFileDevicePath (
364 IN OUT EFI_OPEN_FILE *File,
365 IN CHAR8 *FileName,
366 IN CONST UINT64 OpenMode
367 )
368{
369 EFI_STATUS Status;
370 UINTN Size;
371 FILEPATH_DEVICE_PATH *FilePath;
372 EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
373 CHAR16 UnicodeFileName[MAX_PATHNAME];
374 EFI_BLOCK_IO_PROTOCOL *BlkIo;
375 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
376 EFI_FILE_HANDLE Root;
377
378
379 if ( *FileName != 0 ) {
380 AsciiStrToUnicodeStr (FileName, UnicodeFileName);
381 } else {
382 AsciiStrToUnicodeStr ("\\", UnicodeFileName);
383 }
384
385 Size = StrSize (UnicodeFileName);
386 FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + sizeof (EFI_DEVICE_PATH_PROTOCOL));
387 if (FileDevicePath != NULL) {
388 FilePath = (FILEPATH_DEVICE_PATH *) FileDevicePath;
389 FilePath->Header.Type = MEDIA_DEVICE_PATH;
390 FilePath->Header.SubType = MEDIA_FILEPATH_DP;
391 CopyMem (&FilePath->PathName, UnicodeFileName, Size);
392 SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);
393 SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header));
394
395 if (File->EfiHandle != NULL) {
396 File->DevicePath = DevicePathFromHandle (File->EfiHandle);
397 }
398
399 File->DevicePath = AppendDevicePath (File->DevicePath, FileDevicePath);
400 FreePool (FileDevicePath);
401 }
402
403 Status = gBS->HandleProtocol (File->EfiHandle, &gEfiBlockIoProtocolGuid, (VOID **)&BlkIo);
404 if (!EFI_ERROR (Status)) {
405 CopyMem (&File->FsBlockIoMedia, BlkIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
406
407 // If we are not opening the device this will get over written with file info
408 File->MaxPosition = MultU64x32 (BlkIo->Media->LastBlock + 1, BlkIo->Media->BlockSize);
409 }
410
411 if (File->Type == EfiOpenFileSystem) {
412 Status = gBS->HandleProtocol (File->EfiHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
413 if (!EFI_ERROR (Status)) {
414 Status = Fs->OpenVolume (Fs, &Root);
415 if (!EFI_ERROR (Status)) {
416 // Get information about the volume
417 Size = 0;
418 Status = Root->GetInfo (Root, &gEfiFileSystemInfoGuid, &Size, File->FsInfo);
419 if (Status == EFI_BUFFER_TOO_SMALL) {
420 File->FsInfo = AllocatePool (Size);
421 Status = Root->GetInfo (Root, &gEfiFileSystemInfoGuid, &Size, File->FsInfo);
422 }
423
424 // Get information about the file
425 Status = Root->Open (Root, &File->FsFileHandle, UnicodeFileName, OpenMode, 0);
426 if (!EFI_ERROR (Status)) {
427 Size = 0;
428 Status = File->FsFileHandle->GetInfo (File->FsFileHandle, &gEfiFileInfoGuid, &Size, NULL);
429 if (Status == EFI_BUFFER_TOO_SMALL) {
430 File->FsFileInfo = AllocatePool (Size);
431 Status = File->FsFileHandle->GetInfo (File->FsFileHandle, &gEfiFileInfoGuid, &Size, File->FsFileInfo);
432 if (!EFI_ERROR (Status)) {
433 File->Size = (UINTN)File->FsFileInfo->FileSize;
434 File->MaxPosition = (UINT64)File->Size;
435 }
436 }
437 }
438
439 Root->Close (Root);
440 }
441 }
442 } else if (File->Type == EfiOpenBlockIo) {
443 File->Size = (UINTN)File->MaxPosition;
444 }
445
446 return Status;
447}
448
449#define ToUpper(a) ((((a) >= 'a') && ((a) <= 'z')) ? ((a) - 'a' + 'A') : (a))
450
451EFI_STATUS
452CompareGuidToString (
453 IN EFI_GUID *Guid,
454 IN CHAR8 *String
455 )
456{
457 CHAR8 AsciiGuid[64];
458 CHAR8 *StringPtr;
459 CHAR8 *GuidPtr;
460
461 AsciiSPrint (AsciiGuid, sizeof(AsciiGuid), "%g", Guid);
462
463 StringPtr = String;
464 GuidPtr = AsciiGuid;
465
466 while ((*StringPtr != '\0') && (*GuidPtr != '\0')) {
467 // Skip dashes
468 if (*StringPtr == '-') {
469 StringPtr++;
470 continue;
471 }
472
473 if (*GuidPtr == '-') {
474 GuidPtr++;
475 continue;
476 }
477
478 if (ToUpper(*StringPtr) != ToUpper(*GuidPtr)) {
479 return EFI_NOT_FOUND;
480 }
481
482 StringPtr++;
483 GuidPtr++;
484 }
485
486 return EFI_SUCCESS;
487}
488
489
490/**
491 Internal work function to fill in EFI_OPEN_FILE information for the FV
492
493 @param File Open file handle
494 @param FileName Name of file after device stripped off
495
496
497**/
498EFI_STATUS
499EblFvFileDevicePath (
500 IN OUT EFI_OPEN_FILE *File,
501 IN CHAR8 *FileName,
502 IN CONST UINT64 OpenMode
503 )
504{
505 EFI_STATUS Status;
506 EFI_STATUS GetNextFileStatus;
507 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH DevicePathNode;
508 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
509 UINTN Key;
510 UINT32 AuthenticationStatus;
511 CHAR8 AsciiSection[MAX_PATHNAME];
512 VOID *Section;
513 UINTN SectionSize;
514 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
515 EFI_LBA Lba;
516 UINTN BlockSize;
517 UINTN NumberOfBlocks;
518
519
520 Status = gBS->HandleProtocol (File->EfiHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&File->Fv);
521 if (EFI_ERROR (Status)) {
522 return Status;
523 }
524
525 DevicePath = DevicePathFromHandle (File->EfiHandle);
526
527 if (*FileName == '\0') {
528 File->DevicePath = DuplicateDevicePath (DevicePath);
529 } else {
530 Key = 0;
531 do {
532 File->FvType = EFI_FV_FILETYPE_ALL;
533 GetNextFileStatus = File->Fv->GetNextFile (
534 File->Fv,
535 &Key,
536 &File->FvType,
537 &File->FvNameGuid,
538 &File->FvAttributes,
539 &File->Size
540 );
541 if (!EFI_ERROR (GetNextFileStatus)) {
542 Section = NULL;
543
544 // Compare GUID first
545 Status = CompareGuidToString (&File->FvNameGuid, FileName);
546 if (!EFI_ERROR(Status)) {
547 break;
548 }
549
550 Status = File->Fv->ReadSection (
551 File->Fv,
552 &File->FvNameGuid,
553 EFI_SECTION_USER_INTERFACE,
554 0,
555 &Section,
556 &SectionSize,
557 &AuthenticationStatus
558 );
559 if (!EFI_ERROR (Status)) {
560 UnicodeStrToAsciiStr (Section, AsciiSection);
561 if (AsciiStriCmp (FileName, AsciiSection) == 0) {
562 FreePool (Section);
563 break;
564 }
565 FreePool (Section);
566 }
567 }
568 } while (!EFI_ERROR (GetNextFileStatus));
569
570 if (EFI_ERROR (GetNextFileStatus)) {
571 return GetNextFileStatus;
572 }
573
574 File->MaxPosition = File->Size;
575 EfiInitializeFwVolDevicepathNode (&DevicePathNode, &File->FvNameGuid);
576 File->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&DevicePathNode);
577 }
578
579
580 // Get FVB Info about the handle
581 Status = gBS->HandleProtocol (File->EfiHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
582 if (!EFI_ERROR (Status)) {
583 Status = Fvb->GetPhysicalAddress (Fvb, &File->FvStart);
584 if (!EFI_ERROR (Status)) {
585 for (Lba = 0, File->FvSize = 0; ; File->FvSize += (BlockSize * NumberOfBlocks), Lba += NumberOfBlocks) {
586 Status = Fvb->GetBlockSize (Fvb, Lba, &BlockSize, &NumberOfBlocks);
587 if (EFI_ERROR (Status)) {
588 break;
589 }
590 }
591 }
592 }
593
594 // FVB not required if FV was soft loaded...
595 return EFI_SUCCESS;
596}
597
598
599
600
601/**
602 Open a device named by PathName. The PathName includes a device name and
603 path seperated by a :. See file header for more details on the PathName
604 syntax. There is no checking to prevent a file from being opened more than
605 one type.
606
607 SectionType is only used to open an FV. Each file in an FV contains multiple
608 secitons and only the SectionType section is opened.
609
610 For any file that is opened with EfiOpen() must be closed with EfiClose().
611
612 @param PathName Path to parse to open
613 @param OpenMode Same as EFI_FILE.Open()
614 @param SectionType Section in FV to open.
615
616 @return NULL Open failed
617 @return Valid EFI_OPEN_FILE handle
618
619**/
620EFI_OPEN_FILE *
621EfiOpen (
622 IN CHAR8 *PathName,
623 IN CONST UINT64 OpenMode,
624 IN CONST EFI_SECTION_TYPE SectionType
625 )
626{
627 EFI_STATUS Status;
628 EFI_OPEN_FILE *File;
629 EFI_OPEN_FILE FileData;
630 UINTN StrLen;
631 UINTN FileStart;
632 UINTN DevNumber = 0;
633 EFI_OPEN_FILE_GUARD *GuardFile;
634 BOOLEAN VolumeNameMatch;
635 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
636 UINTN Size;
637 EFI_IP_ADDRESS Ip;
638
639 EblUpdateDeviceLists ();
640
641 File = &FileData;
642 ZeroMem (File, sizeof (EFI_OPEN_FILE));
643 File->FvSectionType = SectionType;
644
645 StrLen = AsciiStrSize (PathName);
646 if (StrLen <= 2) {
647 // Smallest valid path is 1 char and a null
648 return NULL;
649 }
650
651 for (FileStart = 0; FileStart < StrLen; FileStart++) {
652 if (PathName[FileStart] == ':') {
653 FileStart++;
654 break;
655 }
656 }
657
658 if (FileStart == 0) {
659 // We could add a current working diretory concept
660 return NULL;
661 }
662
663 //
664 // Matching volume name has precedence over handle based names
665 //
666 VolumeNameMatch = EblMatchVolumeName (PathName, FileStart, &DevNumber);
667 if (!VolumeNameMatch) {
668 DevNumber = EblConvertDevStringToNumber ((CHAR8 *)PathName);
669 }
670
671 File->DeviceName = AllocatePool (StrLen);
672 AsciiStrCpy (File->DeviceName, PathName);
673 File->DeviceName[FileStart - 1] = '\0';
674 File->FileName = &File->DeviceName[FileStart];
675
676 //
677 // Use best match algorithm on the dev names so we only need to look at the
678 // first few charters to match the full device name. Short name forms are
679 // legal from the caller.
680 //
681 Status = EFI_SUCCESS;
682 if (*PathName == 'f' || *PathName == 'F' || VolumeNameMatch) {
683 if (PathName[1] == 's' || PathName[1] == 'S' || VolumeNameMatch) {
684 if (DevNumber >= mFsCount) {
685 goto ErrorExit;
686 }
687 File->Type = EfiOpenFileSystem;
688 File->EfiHandle = mFs[DevNumber];
689 Status = EblFileDevicePath (File, &PathName[FileStart], OpenMode);
690
691 } else if (PathName[1] == 'v' || PathName[1] == 'V') {
692 if (DevNumber >= mFvCount) {
693 goto ErrorExit;
694 }
695 File->Type = EfiOpenFirmwareVolume;
696 File->EfiHandle = mFv[DevNumber];
697
698 if ((PathName[FileStart] == '/') || (PathName[FileStart] == '\\')) {
699 // Skip leading / as its not really needed for the FV since no directories are supported
700 FileStart++;
701 }
702 Status = EblFvFileDevicePath (File, &PathName[FileStart], OpenMode);
703 }
704 } else if ((*PathName == 'A') || (*PathName == 'a')) {
705 // Handle a:0x10000000:0x1234 address form a:ADDRESS:SIZE
706 File->Type = EfiOpenMemoryBuffer;
707 // 1st colon is at PathName[FileStart - 1]
708 File->Buffer = (VOID *)AsciiStrHexToUintn (&PathName[FileStart]);
709
710 // Find 2nd colon
711 while ((PathName[FileStart] != ':') && (PathName[FileStart] != '\0')) {
712 FileStart++;
713 }
714
715 // If we ran out of string, there's no extra data
716 if (PathName[FileStart] == '\0') {
717 File->Size = 0;
718 } else {
719 File->Size = AsciiStrHexToUintn (&PathName[FileStart + 1]);
720 }
721
722 // if there's no number after the second colon, default
723 // the end of memory
724 if (File->Size == 0) {
725 File->Size = (UINTN)(0 - (UINTN)File->Buffer);
726 }
727
728 File->MaxPosition = File->Size;
729 File->BaseOffset = (UINTN)File->Buffer;
730
731 } else if (*PathName== 'l' || *PathName == 'L') {
732 if (DevNumber >= mLoadFileCount) {
733 goto ErrorExit;
734 }
735 File->Type = EfiOpenLoadFile;
736 File->EfiHandle = mLoadFile[DevNumber];
737
738 Status = gBS->HandleProtocol (File->EfiHandle, &gEfiLoadFileProtocolGuid, (VOID **)&File->LoadFile);
739 if (EFI_ERROR (Status)) {
740 goto ErrorExit;
741 }
742
743 Status = gBS->HandleProtocol (File->EfiHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
744 if (EFI_ERROR (Status)) {
745 goto ErrorExit;
746 }
747 File->DevicePath = DuplicateDevicePath (DevicePath);
748
749 } else if (*PathName == 'b' || *PathName == 'B') {
750 // Handle b#:0x10000000:0x1234 address form b#:ADDRESS:SIZE
751 if (DevNumber >= mBlkIoCount) {
752 goto ErrorExit;
753 }
754 File->Type = EfiOpenBlockIo;
755 File->EfiHandle = mBlkIo[DevNumber];
756 EblFileDevicePath (File, "", OpenMode);
757
758 // 1st colon is at PathName[FileStart - 1]
759 File->DiskOffset = AsciiStrHexToUintn (&PathName[FileStart]);
760
761 // Find 2nd colon
762 while ((PathName[FileStart] != ':') && (PathName[FileStart] != '\0')) {
763 FileStart++;
764 }
765
766 // If we ran out of string, there's no extra data
767 if (PathName[FileStart] == '\0') {
768 Size = 0;
769 } else {
770 Size = AsciiStrHexToUintn (&PathName[FileStart + 1]);
771 }
772
773 // if a zero size is passed in (or the size is left out entirely),
774 // go to the end of the device.
775 if (Size == 0) {
776 File->Size = File->Size - File->DiskOffset;
777 } else {
778 File->Size = Size;
779 }
780
781 File->MaxPosition = File->Size;
782 File->BaseOffset = File->DiskOffset;
783 } else if ((*PathName) >= '0' && (*PathName <= '9')) {
784
785 // Get current IP address
786 Status = EblGetCurrentIpAddress (&Ip);
787 if (EFI_ERROR(Status)) {
788 AsciiPrint("Device IP Address is not configured.\n");
789 goto ErrorExit;
790 }
791
792
793 // Parse X.X.X.X:Filename, only support IPv4 TFTP for now...
794 File->Type = EfiOpenTftp;
795 File->IsDirty = FALSE;
796 File->IsBufferValid = FALSE;
797
798 Status = ConvertIpStringToEfiIp (PathName, &File->ServerIp);
799 }
800
801 if (EFI_ERROR (Status)) {
802 goto ErrorExit;
803 }
804
805 GuardFile = (EFI_OPEN_FILE_GUARD *)AllocateZeroPool (sizeof (EFI_OPEN_FILE_GUARD));
806 if (GuardFile == NULL) {
807 goto ErrorExit;
808 }
809
810 GuardFile->Header = EFI_OPEN_FILE_GUARD_HEADER;
811 CopyMem (&(GuardFile->File), &FileData, sizeof (EFI_OPEN_FILE));
812 GuardFile->Footer = EFI_OPEN_FILE_GUARD_FOOTER;
813
814 return &(GuardFile->File);
815
816ErrorExit:
817 FreePool (File->DeviceName);
818 return NULL;
819}
820
821#define FILE_COPY_CHUNK 0x01000000
822
823EFI_STATUS
824EfiCopyFile (
825 IN CHAR8 *DestinationFile,
826 IN CHAR8 *SourceFile
827 )
828{
829 EFI_OPEN_FILE *Source = NULL;
830 EFI_OPEN_FILE *Destination = NULL;
831 EFI_STATUS Status = EFI_SUCCESS;
832 VOID *Buffer = NULL;
833 UINTN Size;
834 UINTN Offset;
835 UINTN Chunk = FILE_COPY_CHUNK;
836
837 Source = EfiOpen(SourceFile, EFI_FILE_MODE_READ, 0);
838 if (Source == NULL) {
839 AsciiPrint("Source file open error.\n");
840 Status = EFI_NOT_FOUND;
841 goto Exit;
842 }
843
844 Destination = EfiOpen(DestinationFile, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
845 if (Destination == NULL) {
846 AsciiPrint("Destination file open error.\n");
847 Status = EFI_NOT_FOUND;
848 goto Exit;
849 }
850
851 Buffer = AllocatePool(FILE_COPY_CHUNK);
852 if (Buffer == NULL) {
853 Status = EFI_OUT_OF_RESOURCES;
854 goto Exit;
855 }
856
857 Size = EfiTell(Source, NULL);
858
859 for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size; Offset += Chunk) {
860 Chunk = FILE_COPY_CHUNK;
861
862 Status = EfiRead(Source, Buffer, &Chunk);
863 if (EFI_ERROR(Status)) {
864 AsciiPrint("Read file error\n");
865 goto Exit;
866 }
867
868 Status = EfiWrite(Destination, Buffer, &Chunk);
869 if (EFI_ERROR(Status)) {
870 AsciiPrint("Write file error\n");
871 goto Exit;
872 }
873 }
874
875 // Any left over?
876 if (Offset < Size) {
877 Chunk = Size - Offset;
878
879 Status = EfiRead(Source, Buffer, &Chunk);
880 if (EFI_ERROR(Status)) {
881 AsciiPrint("Read file error\n");
882 goto Exit;
883 }
884
885 Status = EfiWrite(Destination, Buffer, &Chunk);
886 if (EFI_ERROR(Status)) {
887 AsciiPrint("Write file error\n");
888 goto Exit;
889 }
890 }
891
892Exit:
893 if (Source != NULL) {
894 Status = EfiClose(Source);
895 if (EFI_ERROR(Status)) {
896 AsciiPrint("Source close error");
897 }
898 }
899
900 if (Destination != NULL) {
901 Status = EfiClose(Destination);
902 if (EFI_ERROR(Status)) {
903 AsciiPrint("Destination close error");
904 }
905 }
906
907 if (Buffer != NULL) {
908 FreePool(Buffer);
909 }
910
911 return Status;
912}
913
914/**
915 Use DeviceType and Index to form a valid PathName and try and open it.
916
917 @param DeviceType Device type to open
918 @param Index Device Index to use. Zero relative.
919
920 @return NULL Open failed
921 @return Valid EFI_OPEN_FILE handle
922
923**/
924EFI_OPEN_FILE *
925EfiDeviceOpenByType (
926 IN EFI_OPEN_FILE_TYPE DeviceType,
927 IN UINTN Index
928 )
929{
930 CHAR8 *DevStr;
931 CHAR8 Path[MAX_CMD_LINE];
932
933 switch (DeviceType) {
934 case EfiOpenLoadFile:
935 DevStr = "loadfile%d:";
936 break;
937 case EfiOpenFirmwareVolume:
938 DevStr = "fv%d:";
939 break;
940 case EfiOpenFileSystem:
941 DevStr = "fs%d:";
942 break;
943 case EfiOpenBlockIo:
944 DevStr = "blk%d:";
945 break;
946 case EfiOpenMemoryBuffer:
947 DevStr = "a%d:";
948 break;
949 default:
950 return NULL;
951 }
952
953 AsciiSPrint (Path, MAX_PATHNAME, DevStr, Index);
954
955 return EfiOpen (Path, EFI_FILE_MODE_READ, 0);
956}
957
958
959/**
960 Close a file handle opened by EfiOpen() and free all resources allocated by
961 EfiOpen().
962
963 @param Stream Open File Handle
964
965 @return EFI_INVALID_PARAMETER Stream is not an Open File
966 @return EFI_SUCCESS Steam closed
967
968**/
969EFI_STATUS
970EfiClose (
971 IN EFI_OPEN_FILE *File
972 )
973{
974 EFI_STATUS Status;
975 UINT64 TftpBufferSize;
976
977 if (!FileHandleValid (File)) {
978 return EFI_INVALID_PARAMETER;
979 }
980
981 //Write the buffer contents to TFTP file.
982 if ((File->Type == EfiOpenTftp) && (File->IsDirty)) {
983
984 TftpBufferSize = File->Size;
985 Status = EblMtftp (
986 EFI_PXE_BASE_CODE_TFTP_WRITE_FILE,
987 File->Buffer,
988 TRUE,
989 &TftpBufferSize,
990 NULL,
991 &File->ServerIp,
992 (UINT8 *)File->FileName,
993 NULL,
994 FALSE
995 );
996 if (EFI_ERROR(Status)) {
997 AsciiPrint("TFTP error during APPLE_NSP_TFTP_WRITE_FILE: %r\n", Status);
998 return Status;
999 }
1000 }
1001
1002 if ((File->Type == EfiOpenLoadFile) ||
1003 ((File->Type == EfiOpenTftp) && (File->IsBufferValid == TRUE))) {
1004 EblFreePool(File->Buffer);
1005 }
1006
1007 EblFreePool (File->DevicePath);
1008 EblFreePool (File->DeviceName);
1009 EblFreePool (File->FsFileInfo);
1010 EblFreePool (File->FsInfo);
1011
1012 if (File->FsFileHandle != NULL) {
1013 File->FsFileHandle->Close (File->FsFileHandle);
1014 }
1015
1016 // Need to free File and it's Guard structures
1017 EblFreePool (BASE_CR (File, EFI_OPEN_FILE_GUARD, File));
1018 return EFI_SUCCESS;
1019}
1020
1021
1022/**
1023 Return the size of the file represented by Stream. Also return the current
1024 Seek position. Opening a file will enable a valid file size to be returned.
1025 LoadFile is an exception as a load file size is set to zero.
1026
1027 @param Stream Open File Handle
1028
1029 @return 0 Stream is not an Open File or a valid LoadFile handle
1030
1031**/
1032UINTN
1033EfiTell (
1034 IN EFI_OPEN_FILE *File,
1035 OUT EFI_LBA *CurrentPosition OPTIONAL
1036 )
1037{
1038 EFI_STATUS Status;
1039 UINT64 BufferSize = 0;
1040
1041 if (!FileHandleValid (File)) {
1042 return 0;
1043 }
1044
1045 if (CurrentPosition != NULL) {
1046 *CurrentPosition = File->CurrentPosition;
1047 }
1048
1049 if (File->Type == EfiOpenLoadFile) {
1050 // Figure out the File->Size
1051 File->Buffer = NULL;
1052 File->Size = 0;
1053 Status = File->LoadFile->LoadFile (File->LoadFile, File->DevicePath, FALSE, &File->Size, File->Buffer);
1054 if (Status != EFI_BUFFER_TOO_SMALL) {
1055 return 0;
1056 }
1057
1058 File->MaxPosition = (UINT64)File->Size;
1059 } else if (File->Type == EfiOpenTftp) {
1060
1061 Status = EblMtftp (
1062 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
1063 NULL,
1064 FALSE,
1065 &BufferSize,
1066 NULL,
1067 &File->ServerIp,
1068 (UINT8 *)File->FileName,
1069 NULL,
1070 TRUE
1071 );
1072 if (EFI_ERROR(Status)) {
1073 AsciiPrint("TFTP error during APPLE_NSP_TFTP_GET_FILE_SIZE: %r\n", Status);
1074 return 0;
1075 }
1076
1077 File->Size = BufferSize;
1078 File->MaxPosition = File->Size;
1079 }
1080
1081 return File->Size;
1082}
1083
1084
1085/**
1086 Seek to the Offset locaiton in the file. LoadFile and FV device types do
1087 not support EfiSeek(). It is not possible to grow the file size using
1088 EfiSeek().
1089
1090 SeekType defines how use Offset to calculate the new file position:
1091 EfiSeekStart : Position = Offset
1092 EfiSeekCurrent: Position is Offset bytes from the current position
1093 EfiSeekEnd : Only supported if Offset is zero to seek to end of file.
1094
1095 @param Stream Open File Handle
1096 @param Offset Offset to seek too.
1097 @param SeekType Type of seek to perform
1098
1099
1100 @return EFI_INVALID_PARAMETER Stream is not an Open File
1101 @return EFI_UNSUPPORTED LoadFile and FV doe not support Seek
1102 @return EFI_NOT_FOUND Seek past the end of the file.
1103 @return EFI_SUCCESS Steam closed
1104
1105**/
1106EFI_STATUS
1107EfiSeek (
1108 IN EFI_OPEN_FILE *File,
1109 IN EFI_LBA Offset,
1110 IN EFI_SEEK_TYPE SeekType
1111 )
1112{
1113 EFI_STATUS Status;
1114 UINT64 CurrentPosition;
1115
1116 if (!FileHandleValid (File)) {
1117 return EFI_INVALID_PARAMETER;
1118 }
1119
1120 if (File->Type == EfiOpenLoadFile || File->Type == EfiOpenFirmwareVolume) {
1121 // LoadFile and FV do not support Seek
1122 return EFI_UNSUPPORTED;
1123 }
1124
1125 CurrentPosition = File->CurrentPosition;
1126 switch (SeekType) {
1127 case EfiSeekStart:
1128 if (Offset > File->MaxPosition) {
1129 return EFI_NOT_FOUND;
1130 }
1131 CurrentPosition = Offset;
1132 break;
1133
1134 case EfiSeekCurrent:
1135 if ((File->CurrentPosition + Offset) > File->MaxPosition) {
1136 return EFI_NOT_FOUND;
1137 }
1138 CurrentPosition += Offset;
1139 break;
1140
1141 case EfiSeekEnd:
1142 if (Offset != 0) {
1143 // We don't support growing file size via seeking past end of file
1144 return EFI_UNSUPPORTED;
1145 }
1146 CurrentPosition = File->MaxPosition;
1147 break;
1148
1149 default:
1150 return EFI_NOT_FOUND;
1151 }
1152
1153 Status = EFI_SUCCESS;
1154 if (File->FsFileHandle != NULL) {
1155 Status = File->FsFileHandle->SetPosition (File->FsFileHandle, CurrentPosition);
1156 }
1157
1158 if (!EFI_ERROR (Status)) {
1159 File->CurrentPosition = CurrentPosition;
1160 }
1161
1162 return Status;
1163}
1164
1165EFI_STATUS
1166CacheTftpFile (
1167 IN OUT EFI_OPEN_FILE *File
1168 )
1169{
1170 EFI_STATUS Status;
1171 UINT64 TftpBufferSize;
1172
1173 if (File->IsBufferValid) {
1174 return EFI_SUCCESS;
1175 }
1176
1177 // Make sure the file size is set.
1178 EfiTell (File, NULL);
1179
1180 //Allocate a buffer to hold the whole file.
1181 File->Buffer = AllocatePool(File->Size);
1182 if (File->Buffer == NULL) {
1183 return EFI_OUT_OF_RESOURCES;
1184 }
1185
1186 TftpBufferSize = File->Size;
1187
1188 Status = EblMtftp (
1189 EFI_PXE_BASE_CODE_TFTP_READ_FILE,
1190 File->Buffer,
1191 FALSE,
1192 &TftpBufferSize,
1193 NULL,
1194 &File->ServerIp,
1195 (UINT8 *)File->FileName,
1196 NULL,
1197 FALSE);
1198 if (EFI_ERROR(Status)) {
1199 AsciiPrint("TFTP error during APPLE_NSP_TFTP_READ_FILE: %r\n", Status);
1200 FreePool(File->Buffer);
1201 return Status;
1202 }
1203
1204 // Set the buffer valid flag.
1205 File->IsBufferValid = TRUE;
1206
1207 return Status;
1208}
1209
1210/**
1211 Read BufferSize bytes from the current locaiton in the file. For load file,
1212 FV, and TFTP case you must read the entire file.
1213
1214 @param Stream Open File Handle
1215 @param Buffer Caller allocated buffer.
1216 @param BufferSize Size of buffer in bytes.
1217
1218
1219 @return EFI_SUCCESS Stream is not an Open File
1220 @return EFI_END_OF_FILE Tried to read past the end of the file
1221 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1222 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1223 @return "other" Error returned from device read
1224
1225**/
1226EFI_STATUS
1227EfiRead (
1228 IN EFI_OPEN_FILE *File,
1229 OUT VOID *Buffer,
1230 OUT UINTN *BufferSize
1231 )
1232{
1233 EFI_STATUS Status;
1234 UINT32 AuthenticationStatus;
1235 EFI_DISK_IO_PROTOCOL *DiskIo;
1236
1237 if (!FileHandleValid (File)) {
1238 return EFI_INVALID_PARAMETER;
1239 }
1240
1241 // Don't read past the end of the file.
1242 if ((File->CurrentPosition + *BufferSize) > File->MaxPosition) {
1243 return EFI_END_OF_FILE;
1244 }
1245
1246 switch (File->Type) {
1247 case EfiOpenMemoryBuffer:
1248 CopyMem (Buffer, File->Buffer + File->CurrentPosition, *BufferSize);
1249 File->CurrentPosition += *BufferSize;
1250 Status = EFI_SUCCESS;
1251 break;
1252
1253 case EfiOpenLoadFile:
1254 // Figure out the File->Size
1255 EfiTell (File, NULL);
1256
1257 Status = File->LoadFile->LoadFile (File->LoadFile, File->DevicePath, FALSE, BufferSize, Buffer);
1258 break;
1259
1260 case EfiOpenFirmwareVolume:
1261 if (File->FvSectionType == EFI_SECTION_ALL) {
1262 Status = File->Fv->ReadFile (
1263 File->Fv,
1264 &File->FvNameGuid,
1265 &Buffer,
1266 BufferSize,
1267 &File->FvType,
1268 &File->FvAttributes,
1269 &AuthenticationStatus
1270 );
1271 } else {
1272 Status = File->Fv->ReadSection (
1273 File->Fv,
1274 &File->FvNameGuid,
1275 File->FvSectionType,
1276 0,
1277 &Buffer,
1278 BufferSize,
1279 &AuthenticationStatus
1280 );
1281 }
1282 break;
1283
1284 case EfiOpenFileSystem:
1285 Status = File->FsFileHandle->Read (File->FsFileHandle, BufferSize, Buffer);
1286 File->CurrentPosition += *BufferSize;
1287 break;
1288
1289 case EfiOpenBlockIo:
1290 Status = gBS->HandleProtocol(File->EfiHandle, &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo);
1291 if (!EFI_ERROR(Status)) {
1292 Status = DiskIo->ReadDisk(DiskIo, File->FsBlockIoMedia.MediaId, File->DiskOffset + File->CurrentPosition, *BufferSize, Buffer);
1293 }
1294 File->CurrentPosition += *BufferSize;
1295 break;
1296
1297 case EfiOpenTftp:
1298 // Cache the file if it hasn't been cached yet.
1299 if (File->IsBufferValid == FALSE) {
1300 Status = CacheTftpFile (File);
1301 if (EFI_ERROR (Status)) {
1302 return Status;
1303 }
1304 }
1305
1306 // Copy out the requested data
1307 CopyMem (Buffer, File->Buffer + File->CurrentPosition, *BufferSize);
1308 File->CurrentPosition += *BufferSize;
1309
1310 Status = EFI_SUCCESS;
1311 break;
1312
1313 default:
1314 return EFI_INVALID_PARAMETER;
1315 };
1316
1317 return Status;
1318}
1319
1320
1321/**
1322 Read the entire file into a buffer. This routine allocates the buffer and
1323 returns it to the user full of the read data.
1324
1325 This is very useful for load flie where it's hard to know how big the buffer
1326 must be.
1327
1328 @param Stream Open File Handle
1329 @param Buffer Pointer to buffer to return.
1330 @param BufferSize Pointer to Size of buffer return..
1331
1332
1333 @return EFI_SUCCESS Stream is not an Open File
1334 @return EFI_END_OF_FILE Tried to read past the end of the file
1335 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1336 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1337 @return "other" Error returned from device read
1338
1339**/
1340EFI_STATUS
1341EfiReadAllocatePool (
1342 IN EFI_OPEN_FILE *File,
1343 OUT VOID **Buffer,
1344 OUT UINTN *BufferSize
1345 )
1346{
1347 if (!FileHandleValid (File)) {
1348 return EFI_INVALID_PARAMETER;
1349 }
1350
1351 // Loadfile defers file size determination on Open so use tell to find it
1352 EfiTell (File, NULL);
1353
1354 *BufferSize = File->Size;
1355 *Buffer = AllocatePool (*BufferSize);
1356 if (*Buffer == NULL) {
1357 return EFI_NOT_FOUND;
1358 }
1359
1360 return EfiRead (File, *Buffer, BufferSize);
1361}
1362
1363
1364/**
1365 Write data back to the file. For TFTP case you must write the entire file.
1366
1367 @param Stream Open File Handle
1368 @param Buffer Pointer to buffer to return.
1369 @param BufferSize Pointer to Size of buffer return..
1370
1371
1372 @return EFI_SUCCESS Stream is not an Open File
1373 @return EFI_END_OF_FILE Tried to read past the end of the file
1374 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1375 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1376 @return "other" Error returned from device write
1377
1378**/
1379EFI_STATUS
1380EfiWrite (
1381 IN EFI_OPEN_FILE *File,
1382 OUT VOID *Buffer,
1383 OUT UINTN *BufferSize
1384 )
1385{
1386 EFI_STATUS Status;
1387 EFI_FV_WRITE_FILE_DATA FileData;
1388 EFI_DISK_IO_PROTOCOL *DiskIo;
1389
1390 if (!FileHandleValid (File)) {
1391 return EFI_INVALID_PARAMETER;
1392 }
1393
1394 switch (File->Type) {
1395 case EfiOpenMemoryBuffer:
1396 if ((File->CurrentPosition + *BufferSize) > File->MaxPosition) {
1397 return EFI_END_OF_FILE;
1398 }
1399
1400 CopyMem (File->Buffer + File->CurrentPosition, Buffer, *BufferSize);
1401 File->CurrentPosition += *BufferSize;
1402 Status = EFI_SUCCESS;
1403
1404 case EfiOpenLoadFile:
1405 // LoadFile device is read only be definition
1406 Status = EFI_UNSUPPORTED;
1407
1408 case EfiOpenFirmwareVolume:
1409 if (File->FvSectionType != EFI_SECTION_ALL) {
1410 // Writes not support to a specific section. You have to update entire file
1411 return EFI_UNSUPPORTED;
1412 }
1413
1414 FileData.NameGuid = &(File->FvNameGuid);
1415 FileData.Type = File->FvType;
1416 FileData.FileAttributes = File->FvAttributes;
1417 FileData.Buffer = Buffer;
1418 FileData.BufferSize = (UINT32)*BufferSize;
1419 Status = File->Fv->WriteFile (File->Fv, 1, EFI_FV_UNRELIABLE_WRITE, &FileData);
1420 break;
1421
1422 case EfiOpenFileSystem:
1423 Status = File->FsFileHandle->Write (File->FsFileHandle, BufferSize, Buffer);
1424 File->CurrentPosition += *BufferSize;
1425 break;
1426
1427 case EfiOpenBlockIo:
1428 if ((File->CurrentPosition + *BufferSize) > File->MaxPosition) {
1429 return EFI_END_OF_FILE;
1430 }
1431
1432 Status = gBS->HandleProtocol (File->EfiHandle, &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo);
1433 if (!EFI_ERROR(Status)) {
1434 Status = DiskIo->WriteDisk (DiskIo, File->FsBlockIoMedia.MediaId, File->DiskOffset + File->CurrentPosition, *BufferSize, Buffer);
1435 }
1436 File->CurrentPosition += *BufferSize;
1437 break;
1438
1439 case EfiOpenTftp:
1440 // Cache the file if it hasn't been cached yet.
1441 if (File->IsBufferValid == FALSE) {
1442 Status = CacheTftpFile(File);
1443 if (EFI_ERROR(Status)) {
1444 return Status;
1445 }
1446 }
1447
1448 // Don't overwrite the buffer
1449 if ((File->CurrentPosition + *BufferSize) > File->MaxPosition) {
1450 UINT8 *TempBuffer;
1451
1452 TempBuffer = File->Buffer;
1453
1454 File->Buffer = AllocatePool (File->CurrentPosition + *BufferSize);
1455 if (File->Buffer == NULL) {
1456 return EFI_OUT_OF_RESOURCES;
1457 }
1458
1459 CopyMem (File->Buffer, TempBuffer, File->Size);
1460
1461 FreePool (TempBuffer);
1462
1463 File->Size = File->CurrentPosition + *BufferSize;
1464 File->MaxPosition = File->Size;
1465 }
1466
1467 // Copy in the requested data
1468 CopyMem (File->Buffer + File->CurrentPosition, Buffer, *BufferSize);
1469 File->CurrentPosition += *BufferSize;
1470
1471 // Mark the file dirty
1472 File->IsDirty = TRUE;
1473
1474 Status = EFI_SUCCESS;
1475 break;
1476
1477 default:
1478 Status = EFI_INVALID_PARAMETER;
1479 };
1480
1481 return Status;
1482}
1483