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