]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c
28e28e5f67d5bc4d6cb81663b28c43470a26c2e0
[mirror_edk2.git] / MdePkg / Library / UefiFileHandleLib / UefiFileHandleLib.c
1 /** @file
2 Provides interface to EFI_FILE_HANDLE functionality.
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <Uefi.h>
10
11 #include <Protocol/SimpleFileSystem.h>
12 #include <Protocol/UnicodeCollation.h>
13
14 #include <Guid/FileInfo.h>
15
16 #include <Library/DebugLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/FileHandleLib.h>
21 #include <Library/PcdLib.h>
22 #include <Library/PrintLib.h>
23
24 CONST UINT16 gUnicodeFileTag = EFI_UNICODE_BYTE_ORDER_MARK;
25
26 #define MAX_FILE_NAME_LEN 522 // (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)
27 #define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN)
28
29 /**
30 This function will retrieve the information about the file for the handle
31 specified and store it in allocated pool memory.
32
33 This function allocates a buffer to store the file's information. It is the
34 caller's responsibility to free the buffer
35
36 @param FileHandle The file handle of the file for which information is
37 being requested.
38
39 @retval NULL information could not be retrieved.
40
41 @return the information about the file
42 **/
43 EFI_FILE_INFO*
44 EFIAPI
45 FileHandleGetInfo (
46 IN EFI_FILE_HANDLE FileHandle
47 )
48 {
49 EFI_FILE_INFO *FileInfo;
50 UINTN FileInfoSize;
51 EFI_STATUS Status;
52
53 if (FileHandle == NULL) {
54 return (NULL);
55 }
56
57 //
58 // Get the required size to allocate
59 //
60 FileInfoSize = 0;
61 FileInfo = NULL;
62 Status = FileHandle->GetInfo(FileHandle,
63 &gEfiFileInfoGuid,
64 &FileInfoSize,
65 NULL);
66 if (Status == EFI_BUFFER_TOO_SMALL){
67 //
68 // error is expected. getting size to allocate
69 //
70 FileInfo = AllocateZeroPool(FileInfoSize);
71 if (FileInfo != NULL) {
72 //
73 // now get the information
74 //
75 Status = FileHandle->GetInfo(FileHandle,
76 &gEfiFileInfoGuid,
77 &FileInfoSize,
78 FileInfo);
79 //
80 // if we got an error free the memory and return NULL
81 //
82 if (EFI_ERROR(Status)) {
83 FreePool(FileInfo);
84 FileInfo = NULL;
85 }
86 }
87 }
88 return (FileInfo);
89 }
90
91 /**
92 This function sets the information about the file for the opened handle
93 specified.
94
95 @param[in] FileHandle The file handle of the file for which information
96 is being set.
97
98 @param[in] FileInfo The information to set.
99
100 @retval EFI_SUCCESS The information was set.
101 @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid.
102 @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo.
103 @retval EFI_NO_MEDIA The device has no medium.
104 @retval EFI_DEVICE_ERROR The device reported an error.
105 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
106 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
107 @retval EFI_ACCESS_DENIED The file was opened read only.
108 @retval EFI_VOLUME_FULL The volume is full.
109 **/
110 EFI_STATUS
111 EFIAPI
112 FileHandleSetInfo (
113 IN EFI_FILE_HANDLE FileHandle,
114 IN CONST EFI_FILE_INFO *FileInfo
115 )
116 {
117
118 if (FileHandle == NULL || FileInfo == NULL) {
119 return (EFI_INVALID_PARAMETER);
120 }
121
122 //
123 // Set the info
124 //
125 return (FileHandle->SetInfo(FileHandle,
126 &gEfiFileInfoGuid,
127 (UINTN)FileInfo->Size,
128 (EFI_FILE_INFO*)FileInfo));
129 }
130
131 /**
132 This function reads information from an opened file.
133
134 If FileHandle is not a directory, the function reads the requested number of
135 bytes from the file at the file's current position and returns them in Buffer.
136 If the read goes beyond the end of the file, the read length is truncated to the
137 end of the file. The file's current position is increased by the number of bytes
138 returned. If FileHandle is a directory, the function reads the directory entry
139 at the file's current position and returns the entry in Buffer. If the Buffer
140 is not large enough to hold the current directory entry, then
141 EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated.
142 BufferSize is set to be the size of the buffer needed to read the entry. On
143 success, the current position is updated to the next directory entry. If there
144 are no more directory entries, the read returns a zero-length buffer.
145 EFI_FILE_INFO is the structure returned as the directory entry.
146
147 @param FileHandle the opened file handle
148 @param BufferSize on input the size of buffer in bytes. on return
149 the number of bytes written.
150 @param Buffer the buffer to put read data into.
151
152 @retval EFI_SUCCESS Data was read.
153 @retval EFI_NO_MEDIA The device has no media.
154 @retval EFI_DEVICE_ERROR The device reported an error.
155 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
156 @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required
157 size.
158
159 **/
160 EFI_STATUS
161 EFIAPI
162 FileHandleRead(
163 IN EFI_FILE_HANDLE FileHandle,
164 IN OUT UINTN *BufferSize,
165 OUT VOID *Buffer
166 )
167 {
168 if (FileHandle == NULL) {
169 return (EFI_INVALID_PARAMETER);
170 }
171
172 //
173 // Perform the read based on EFI_FILE_PROTOCOL
174 //
175 return (FileHandle->Read(FileHandle, BufferSize, Buffer));
176 }
177
178
179 /**
180 Write data to a file.
181
182 This function writes the specified number of bytes to the file at the current
183 file position. The current file position is advanced the actual number of bytes
184 written, which is returned in BufferSize. Partial writes only occur when there
185 has been a data error during the write attempt (such as "volume space full").
186 The file is automatically grown to hold the data if required. Direct writes to
187 opened directories are not supported.
188
189 @param FileHandle The opened file for writing
190 @param BufferSize on input the number of bytes in Buffer. On output
191 the number of bytes written.
192 @param Buffer the buffer containing data to write is stored.
193
194 @retval EFI_SUCCESS Data was written.
195 @retval EFI_UNSUPPORTED Writes to an open directory are not supported.
196 @retval EFI_NO_MEDIA The device has no media.
197 @retval EFI_DEVICE_ERROR The device reported an error.
198 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
199 @retval EFI_WRITE_PROTECTED The device is write-protected.
200 @retval EFI_ACCESS_DENIED The file was open for read only.
201 @retval EFI_VOLUME_FULL The volume is full.
202 **/
203 EFI_STATUS
204 EFIAPI
205 FileHandleWrite(
206 IN EFI_FILE_HANDLE FileHandle,
207 IN OUT UINTN *BufferSize,
208 IN VOID *Buffer
209 )
210 {
211 if (FileHandle == NULL) {
212 return (EFI_INVALID_PARAMETER);
213 }
214
215 //
216 // Perform the write based on EFI_FILE_PROTOCOL
217 //
218 return (FileHandle->Write(FileHandle, BufferSize, Buffer));
219 }
220
221 /**
222 Close an open file handle.
223
224 This function closes a specified file handle. All "dirty" cached file data is
225 flushed to the device, and the file is closed. In all cases the handle is
226 closed.
227
228 @param FileHandle the file handle to close.
229
230 @retval EFI_SUCCESS the file handle was closed successfully.
231 **/
232 EFI_STATUS
233 EFIAPI
234 FileHandleClose (
235 IN EFI_FILE_HANDLE FileHandle
236 )
237 {
238 EFI_STATUS Status;
239
240 if (FileHandle == NULL) {
241 return (EFI_INVALID_PARAMETER);
242 }
243
244 //
245 // Perform the Close based on EFI_FILE_PROTOCOL
246 //
247 Status = FileHandle->Close(FileHandle);
248 return Status;
249 }
250
251 /**
252 Delete a file and close the handle
253
254 This function closes and deletes a file. In all cases the file handle is closed.
255 If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is
256 returned, but the handle is still closed.
257
258 @param FileHandle the file handle to delete
259
260 @retval EFI_SUCCESS the file was closed successfully
261 @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
262 deleted
263 @retval INVALID_PARAMETER One of the parameters has an invalid value.
264 **/
265 EFI_STATUS
266 EFIAPI
267 FileHandleDelete (
268 IN EFI_FILE_HANDLE FileHandle
269 )
270 {
271 EFI_STATUS Status;
272
273 if (FileHandle == NULL) {
274 return (EFI_INVALID_PARAMETER);
275 }
276
277 //
278 // Perform the Delete based on EFI_FILE_PROTOCOL
279 //
280 Status = FileHandle->Delete(FileHandle);
281 return Status;
282 }
283
284 /**
285 Set the current position in a file.
286
287 This function sets the current file position for the handle to the position
288 supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only
289 absolute positioning is supported, and seeking past the end of the file is
290 allowed (a subsequent write would grow the file). Seeking to position
291 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file.
292 If FileHandle is a directory, the only position that may be set is zero. This
293 has the effect of starting the read process of the directory entries over.
294
295 @param FileHandle The file handle on which the position is being set
296 @param Position Byte position from beginning of file
297
298 @retval EFI_SUCCESS Operation completed successfully.
299 @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on
300 directories.
301 @retval INVALID_PARAMETER One of the parameters has an invalid value.
302 **/
303 EFI_STATUS
304 EFIAPI
305 FileHandleSetPosition (
306 IN EFI_FILE_HANDLE FileHandle,
307 IN UINT64 Position
308 )
309 {
310 if (FileHandle == NULL) {
311 return (EFI_INVALID_PARAMETER);
312 }
313
314 //
315 // Perform the SetPosition based on EFI_FILE_PROTOCOL
316 //
317 return (FileHandle->SetPosition(FileHandle, Position));
318 }
319
320 /**
321 Gets a file's current position
322
323 This function retrieves the current file position for the file handle. For
324 directories, the current file position has no meaning outside of the file
325 system driver and as such the operation is not supported. An error is returned
326 if FileHandle is a directory.
327
328 @param FileHandle The open file handle on which to get the position.
329 @param Position Byte position from beginning of file.
330
331 @retval EFI_SUCCESS the operation completed successfully.
332 @retval INVALID_PARAMETER One of the parameters has an invalid value.
333 @retval EFI_UNSUPPORTED the request is not valid on directories.
334 **/
335 EFI_STATUS
336 EFIAPI
337 FileHandleGetPosition (
338 IN EFI_FILE_HANDLE FileHandle,
339 OUT UINT64 *Position
340 )
341 {
342 if (Position == NULL || FileHandle == NULL) {
343 return (EFI_INVALID_PARAMETER);
344 }
345
346 //
347 // Perform the GetPosition based on EFI_FILE_PROTOCOL
348 //
349 return (FileHandle->GetPosition(FileHandle, Position));
350 }
351 /**
352 Flushes data on a file
353
354 This function flushes all modified data associated with a file to a device.
355
356 @param FileHandle The file handle on which to flush data
357
358 @retval EFI_SUCCESS The data was flushed.
359 @retval EFI_NO_MEDIA The device has no media.
360 @retval EFI_DEVICE_ERROR The device reported an error.
361 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
362 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
363 @retval EFI_ACCESS_DENIED The file was opened for read only.
364 **/
365 EFI_STATUS
366 EFIAPI
367 FileHandleFlush (
368 IN EFI_FILE_HANDLE FileHandle
369 )
370 {
371 if (FileHandle == NULL) {
372 return (EFI_INVALID_PARAMETER);
373 }
374
375 //
376 // Perform the Flush based on EFI_FILE_PROTOCOL
377 //
378 return (FileHandle->Flush(FileHandle));
379 }
380
381 /**
382 Function to determine if a given handle is a directory handle.
383
384 Open the file information on the DirHandle and verify that the Attribute
385 includes EFI_FILE_DIRECTORY bit set.
386
387 @param[in] DirHandle Handle to open file.
388
389 @retval EFI_SUCCESS DirHandle is a directory.
390 @retval EFI_INVALID_PARAMETER DirHandle is NULL.
391 The file information returns from FileHandleGetInfo is NULL.
392 @retval EFI_NOT_FOUND DirHandle is not a directory.
393 **/
394 EFI_STATUS
395 EFIAPI
396 FileHandleIsDirectory (
397 IN EFI_FILE_HANDLE DirHandle
398 )
399 {
400 EFI_FILE_INFO *DirInfo;
401
402 if (DirHandle == NULL) {
403 return (EFI_INVALID_PARAMETER);
404 }
405
406 //
407 // get the file information for DirHandle
408 //
409 DirInfo = FileHandleGetInfo (DirHandle);
410
411 //
412 // Parse DirInfo
413 //
414 if (DirInfo == NULL) {
415 //
416 // We got nothing...
417 //
418 return (EFI_INVALID_PARAMETER);
419 }
420 if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
421 //
422 // Attributes say this is not a directory
423 //
424 FreePool (DirInfo);
425 return (EFI_NOT_FOUND);
426 }
427 //
428 // all good...
429 //
430 FreePool (DirInfo);
431 return (EFI_SUCCESS);
432 }
433
434 /** Retrieve first entry from a directory.
435
436 This function takes an open directory handle and gets information from the
437 first entry in the directory. A buffer is allocated to contain
438 the information and a pointer to the buffer is returned in *Buffer. The
439 caller can use FileHandleFindNextFile() to get subsequent directory entries.
440
441 The buffer will be freed by FileHandleFindNextFile() when the last directory
442 entry is read. Otherwise, the caller must free the buffer, using FreePool,
443 when finished with it.
444
445 @param[in] DirHandle The file handle of the directory to search.
446 @param[out] Buffer The pointer to pointer to buffer for file's information.
447
448 @retval EFI_SUCCESS Found the first file.
449 @retval EFI_NOT_FOUND Cannot find the directory.
450 @retval EFI_NO_MEDIA The device has no media.
451 @retval EFI_DEVICE_ERROR The device reported an error.
452 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
453 @return Others status of FileHandleGetInfo, FileHandleSetPosition,
454 or FileHandleRead
455 **/
456 EFI_STATUS
457 EFIAPI
458 FileHandleFindFirstFile (
459 IN EFI_FILE_HANDLE DirHandle,
460 OUT EFI_FILE_INFO **Buffer
461 )
462 {
463 EFI_STATUS Status;
464 UINTN BufferSize;
465
466 if (Buffer == NULL || DirHandle == NULL) {
467 return (EFI_INVALID_PARAMETER);
468 }
469
470 //
471 // verify that DirHandle is a directory
472 //
473 Status = FileHandleIsDirectory(DirHandle);
474 if (EFI_ERROR(Status)) {
475 return (Status);
476 }
477
478 //
479 // Allocate a buffer sized to struct size + enough for the string at the end
480 //
481 BufferSize = FIND_XXXXX_FILE_BUFFER_SIZE;
482 *Buffer = AllocateZeroPool(BufferSize);
483 if (*Buffer == NULL){
484 return (EFI_OUT_OF_RESOURCES);
485 }
486
487 //
488 // reset to the beginning of the directory
489 //
490 Status = FileHandleSetPosition(DirHandle, 0);
491 if (EFI_ERROR(Status)) {
492 FreePool(*Buffer);
493 *Buffer = NULL;
494 return (Status);
495 }
496
497 //
498 // read in the info about the first file
499 //
500 Status = FileHandleRead (DirHandle, &BufferSize, *Buffer);
501 ASSERT(Status != EFI_BUFFER_TOO_SMALL);
502 if (EFI_ERROR(Status) || BufferSize == 0) {
503 FreePool(*Buffer);
504 *Buffer = NULL;
505 if (BufferSize == 0) {
506 return (EFI_NOT_FOUND);
507 }
508 return (Status);
509 }
510 return (EFI_SUCCESS);
511 }
512
513 /** Retrieve next entries from a directory.
514
515 To use this function, the caller must first call the FileHandleFindFirstFile()
516 function to get the first directory entry. Subsequent directory entries are
517 retrieved by using the FileHandleFindNextFile() function. This function can
518 be called several times to get each entry from the directory. If the call of
519 FileHandleFindNextFile() retrieved the last directory entry, the next call of
520 this function will set *NoFile to TRUE and free the buffer.
521
522 @param[in] DirHandle The file handle of the directory.
523 @param[out] Buffer The pointer to buffer for file's information.
524 @param[out] NoFile The pointer to boolean when last file is found.
525
526 @retval EFI_SUCCESS Found the next file, or reached last file
527 @retval EFI_NO_MEDIA The device has no media.
528 @retval EFI_DEVICE_ERROR The device reported an error.
529 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
530 **/
531 EFI_STATUS
532 EFIAPI
533 FileHandleFindNextFile(
534 IN EFI_FILE_HANDLE DirHandle,
535 OUT EFI_FILE_INFO *Buffer,
536 OUT BOOLEAN *NoFile
537 )
538 {
539 EFI_STATUS Status;
540 UINTN BufferSize;
541
542 if (DirHandle == NULL || Buffer == NULL || NoFile == NULL) {
543 return (EFI_INVALID_PARAMETER);
544 }
545
546 //
547 // This BufferSize MUST stay equal to the originally allocated one in GetFirstFile
548 //
549 BufferSize = FIND_XXXXX_FILE_BUFFER_SIZE;
550
551 //
552 // read in the info about the next file
553 //
554 Status = FileHandleRead (DirHandle, &BufferSize, Buffer);
555 ASSERT(Status != EFI_BUFFER_TOO_SMALL);
556 if (EFI_ERROR(Status)) {
557 return (Status);
558 }
559
560 //
561 // If we read 0 bytes (but did not have erros) we already read in the last file.
562 //
563 if (BufferSize == 0) {
564 FreePool(Buffer);
565 *NoFile = TRUE;
566 }
567
568 return (EFI_SUCCESS);
569 }
570
571 /**
572 Retrieve the size of a file.
573
574 This function extracts the file size info from the FileHandle's EFI_FILE_INFO
575 data.
576
577 @param[in] FileHandle The file handle from which size is retrieved.
578 @param[out] Size The pointer to size.
579
580 @retval EFI_SUCCESS Operation was completed successfully.
581 @retval EFI_DEVICE_ERROR Cannot access the file.
582 @retval EFI_INVALID_PARAMETER FileHandle is NULL.
583 Size is NULL.
584 **/
585 EFI_STATUS
586 EFIAPI
587 FileHandleGetSize (
588 IN EFI_FILE_HANDLE FileHandle,
589 OUT UINT64 *Size
590 )
591 {
592 EFI_FILE_INFO *FileInfo;
593
594 if (FileHandle == NULL || Size == NULL) {
595 return (EFI_INVALID_PARAMETER);
596 }
597
598 //
599 // get the FileInfo structure
600 //
601 FileInfo = FileHandleGetInfo(FileHandle);
602 if (FileInfo == NULL) {
603 return (EFI_DEVICE_ERROR);
604 }
605
606 //
607 // Assign the Size pointer to the correct value
608 //
609 *Size = FileInfo->FileSize;
610
611 //
612 // free the FileInfo memory
613 //
614 FreePool(FileInfo);
615
616 return (EFI_SUCCESS);
617 }
618
619 /**
620 Set the size of a file.
621
622 This function changes the file size info from the FileHandle's EFI_FILE_INFO
623 data.
624
625 @param[in] FileHandle The file handle whose size is to be changed.
626 @param[in] Size The new size.
627
628 @retval EFI_SUCCESS The operation completed successfully.
629 @retval EFI_DEVICE_ERROR Cannot access the file.
630 @retval EFI_INVALID_PARAMETER FileHandle is NULL.
631 **/
632 EFI_STATUS
633 EFIAPI
634 FileHandleSetSize (
635 IN EFI_FILE_HANDLE FileHandle,
636 IN UINT64 Size
637 )
638 {
639 EFI_FILE_INFO *FileInfo;
640 EFI_STATUS Status;
641
642 if (FileHandle == NULL) {
643 return (EFI_INVALID_PARAMETER);
644 }
645
646 //
647 // get the FileInfo structure
648 //
649 FileInfo = FileHandleGetInfo(FileHandle);
650 if (FileInfo == NULL) {
651 return (EFI_DEVICE_ERROR);
652 }
653
654 //
655 // Assign the FileSize pointer to the new value
656 //
657 FileInfo->FileSize = Size;
658
659 Status = FileHandleSetInfo(FileHandle, FileInfo);
660 //
661 // free the FileInfo memory
662 //
663 FreePool(FileInfo);
664
665 return (Status);
666 }
667
668 /**
669 Safely append (on the left) with automatic string resizing given length of Destination and
670 desired length of copy from Source.
671
672 append the first D characters of Source to the end of Destination, where D is
673 the lesser of Count and the StrLen() of Source. If appending those D characters
674 will fit within Destination (whose Size is given as CurrentSize) and
675 still leave room for a NULL terminator, then those characters are appended,
676 starting at the original terminating NULL of Destination, and a new terminating
677 NULL is appended.
678
679 If appending D characters onto Destination will result in a overflow of the size
680 given in CurrentSize the string will be grown such that the copy can be performed
681 and CurrentSize will be updated to the new size.
682
683 If Source is NULL, there is nothing to append, just return the current buffer in
684 Destination.
685
686 if Destination is NULL, then return error
687 if Destination's current length (including NULL terminator) is already more then
688 CurrentSize, then ASSERT()
689
690 @param[in, out] Destination The String to append onto
691 @param[in, out] CurrentSize on call the number of bytes in Destination. On
692 return possibly the new size (still in bytes). if NULL
693 then allocate whatever is needed.
694 @param[in] Source The String to append from
695 @param[in] Count Maximum number of characters to append. if 0 then
696 all are appended.
697
698 @return Destination return the resultant string.
699 **/
700 CHAR16*
701 EFIAPI
702 StrnCatGrowLeft (
703 IN OUT CHAR16 **Destination,
704 IN OUT UINTN *CurrentSize,
705 IN CONST CHAR16 *Source,
706 IN UINTN Count
707 )
708 {
709 UINTN DestinationStartSize;
710 UINTN NewSize;
711 UINTN CopySize;
712
713 if (Destination == NULL) {
714 return (NULL);
715 }
716
717 //
718 // If there's nothing to do then just return Destination
719 //
720 if (Source == NULL) {
721 return (*Destination);
722 }
723
724 //
725 // allow for NULL pointers address as Destination
726 //
727 if (*Destination != NULL) {
728 ASSERT(CurrentSize != 0);
729 DestinationStartSize = StrSize(*Destination);
730 ASSERT(DestinationStartSize <= *CurrentSize);
731 } else {
732 DestinationStartSize = 0;
733 // ASSERT(*CurrentSize == 0);
734 }
735
736 //
737 // Append all of Source?
738 //
739 if (Count == 0) {
740 Count = StrSize(Source);
741 }
742
743 //
744 // Test and grow if required
745 //
746 if (CurrentSize != NULL) {
747 NewSize = *CurrentSize;
748 while (NewSize < (DestinationStartSize + Count)) {
749 NewSize += 2 * Count;
750 }
751 *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);
752 *CurrentSize = NewSize;
753 } else {
754 *Destination = AllocateZeroPool(Count+sizeof(CHAR16));
755 }
756 if (*Destination == NULL) {
757 return NULL;
758 }
759
760 CopySize = StrSize(*Destination);
761 CopyMem((*Destination)+((Count-2)/sizeof(CHAR16)), *Destination, CopySize);
762 CopyMem(*Destination, Source, Count-2);
763 return (*Destination);
764 }
765
766 /**
767 Function to get a full filename given a EFI_FILE_HANDLE somewhere lower on the
768 directory 'stack'. If the file is a directory, then append the '\' char at the
769 end of name string. If it's not a directory, then the last '\' should not be
770 added.
771
772 if Handle is NULL, return EFI_INVALID_PARAMETER
773
774 @param[in] Handle Handle to the Directory or File to create path to.
775 @param[out] FullFileName pointer to pointer to generated full file name. It
776 is the responsibility of the caller to free this memory
777 with a call to FreePool().
778 @retval EFI_SUCCESS the operation was sucessful and the FullFileName is valid.
779 @retval EFI_INVALID_PARAMETER Handle was NULL.
780 @retval EFI_INVALID_PARAMETER FullFileName was NULL.
781 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.
782 **/
783 EFI_STATUS
784 EFIAPI
785 FileHandleGetFileName (
786 IN CONST EFI_FILE_HANDLE Handle,
787 OUT CHAR16 **FullFileName
788 )
789 {
790 EFI_STATUS Status;
791 UINTN Size;
792 EFI_FILE_HANDLE CurrentHandle;
793 EFI_FILE_HANDLE NextHigherHandle;
794 EFI_FILE_INFO *FileInfo;
795
796 Size = 0;
797
798 //
799 // Check our parameters
800 //
801 if (FullFileName == NULL || Handle == NULL) {
802 return (EFI_INVALID_PARAMETER);
803 }
804
805 *FullFileName = NULL;
806 CurrentHandle = NULL;
807
808 Status = Handle->Open(Handle, &CurrentHandle, L".", EFI_FILE_MODE_READ, 0);
809 if (!EFI_ERROR(Status)) {
810 //
811 // Reverse out the current directory on the device
812 //
813 for (;;) {
814 FileInfo = FileHandleGetInfo(CurrentHandle);
815 if (FileInfo == NULL) {
816 Status = EFI_OUT_OF_RESOURCES;
817 break;
818 } else {
819 //
820 // Prepare to move to the parent directory.
821 // Also determine whether CurrentHandle refers to the Root directory.
822 //
823 Status = CurrentHandle->Open (CurrentHandle, &NextHigherHandle, L"..", EFI_FILE_MODE_READ, 0);
824 //
825 // We got info... do we have a name? if yes precede the current path with it...
826 //
827 if ((StrLen (FileInfo->FileName) == 0) || EFI_ERROR (Status)) {
828 //
829 // Both FileInfo->FileName being '\0' and EFI_ERROR() suggest that
830 // CurrentHandle refers to the Root directory. As this loop ensures
831 // FullFileName is starting with '\\' at all times, signal success
832 // and exit the loop.
833 // While FileInfo->FileName could theoretically be a value other than
834 // '\0' or '\\', '\\' is guaranteed to be supported by the
835 // specification and hence its value can safely be ignored.
836 //
837 Status = EFI_SUCCESS;
838 if (*FullFileName == NULL) {
839 ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL));
840 *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0);
841 }
842 FreePool(FileInfo);
843 break;
844 } else {
845 if (*FullFileName == NULL) {
846 ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL));
847 *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0);
848 }
849 ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL));
850 *FullFileName = StrnCatGrowLeft(FullFileName, &Size, FileInfo->FileName, 0);
851 *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0);
852 FreePool(FileInfo);
853 }
854 }
855
856 FileHandleClose(CurrentHandle);
857 //
858 // Move to the parent directory
859 //
860 CurrentHandle = NextHigherHandle;
861 }
862 } else if (Status == EFI_NOT_FOUND) {
863 Status = EFI_SUCCESS;
864 ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL));
865 *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0);
866 }
867
868 if (*FullFileName != NULL &&
869 (*FullFileName)[StrLen(*FullFileName) - 1] == L'\\' &&
870 StrLen(*FullFileName) > 1 &&
871 FileHandleIsDirectory(Handle) == EFI_NOT_FOUND
872 ) {
873 (*FullFileName)[StrLen(*FullFileName) - 1] = CHAR_NULL;
874 }
875
876 if (CurrentHandle != NULL) {
877 CurrentHandle->Close (CurrentHandle);
878 }
879
880 if (EFI_ERROR(Status) && *FullFileName != NULL) {
881 FreePool(*FullFileName);
882 }
883
884 return (Status);
885 }
886
887 /**
888 Function to read a single line from a file. The \n is not included in the returned
889 buffer. The returned buffer must be callee freed.
890
891 If the position upon start is 0, then the Ascii Boolean will be set. This should be
892 maintained and not changed for all operations with the same file.
893
894 @param[in] Handle FileHandle to read from.
895 @param[in, out] Ascii Boolean value for indicating whether the file is Ascii (TRUE) or UCS2 (FALSE);
896
897 @return The line of text from the file.
898
899 @sa FileHandleReadLine
900 **/
901 CHAR16*
902 EFIAPI
903 FileHandleReturnLine(
904 IN EFI_FILE_HANDLE Handle,
905 IN OUT BOOLEAN *Ascii
906 )
907 {
908 CHAR16 *RetVal;
909 UINTN Size;
910 EFI_STATUS Status;
911
912 Size = 0;
913 RetVal = NULL;
914
915 Status = FileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);
916 if (Status == EFI_BUFFER_TOO_SMALL) {
917 RetVal = AllocateZeroPool(Size);
918 Status = FileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);
919 }
920 ASSERT_EFI_ERROR(Status);
921 if (EFI_ERROR(Status) && (RetVal != NULL)) {
922 FreePool(RetVal);
923 RetVal = NULL;
924 }
925 return (RetVal);
926 }
927
928 /**
929 Function to read a single line (up to but not including the \n) from a file.
930
931 If the position upon start is 0, then the Ascii Boolean will be set. This should be
932 maintained and not changed for all operations with the same file.
933 The function will not return the \r and \n character in buffer. When an empty line is
934 read a CHAR_NULL character will be returned in buffer.
935
936 @param[in] Handle FileHandle to read from.
937 @param[in, out] Buffer The pointer to buffer to read into.
938 @param[in, out] Size The pointer to number of bytes in Buffer.
939 @param[in] Truncate If the buffer is large enough, this has no effect.
940 If the buffer is is too small and Truncate is TRUE,
941 the line will be truncated.
942 If the buffer is is too small and Truncate is FALSE,
943 then no read will occur.
944
945 @param[in, out] Ascii Boolean value for indicating whether the file is
946 Ascii (TRUE) or UCS2 (FALSE).
947
948 @retval EFI_SUCCESS The operation was successful. The line is stored in
949 Buffer.
950 @retval EFI_INVALID_PARAMETER Handle was NULL.
951 @retval EFI_INVALID_PARAMETER Size was NULL.
952 @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line.
953 Size was updated to the minimum space required.
954 @sa FileHandleRead
955 **/
956 EFI_STATUS
957 EFIAPI
958 FileHandleReadLine(
959 IN EFI_FILE_HANDLE Handle,
960 IN OUT CHAR16 *Buffer,
961 IN OUT UINTN *Size,
962 IN BOOLEAN Truncate,
963 IN OUT BOOLEAN *Ascii
964 )
965 {
966 EFI_STATUS Status;
967 CHAR16 CharBuffer;
968 UINT64 FileSize;
969 UINTN CharSize;
970 UINTN CountSoFar;
971 UINTN CrCount;
972 UINT64 OriginalFilePosition;
973
974 if (Handle == NULL
975 ||Size == NULL
976 ||(Buffer==NULL&&*Size!=0)
977 ){
978 return (EFI_INVALID_PARAMETER);
979 }
980
981 if (Buffer != NULL && *Size != 0) {
982 *Buffer = CHAR_NULL;
983 }
984
985 Status = FileHandleGetSize (Handle, &FileSize);
986 if (EFI_ERROR (Status)) {
987 return Status;
988 } else if (FileSize == 0) {
989 *Ascii = TRUE;
990 return EFI_SUCCESS;
991 }
992
993 FileHandleGetPosition(Handle, &OriginalFilePosition);
994 if (OriginalFilePosition == 0) {
995 CharSize = sizeof(CHAR16);
996 Status = FileHandleRead(Handle, &CharSize, &CharBuffer);
997 ASSERT_EFI_ERROR(Status);
998 if (CharBuffer == gUnicodeFileTag) {
999 *Ascii = FALSE;
1000 } else {
1001 *Ascii = TRUE;
1002 FileHandleSetPosition(Handle, OriginalFilePosition);
1003 }
1004 }
1005
1006 CrCount = 0;
1007 for (CountSoFar = 0;;CountSoFar++){
1008 CharBuffer = 0;
1009 if (*Ascii) {
1010 CharSize = sizeof(CHAR8);
1011 } else {
1012 CharSize = sizeof(CHAR16);
1013 }
1014 Status = FileHandleRead(Handle, &CharSize, &CharBuffer);
1015 if ( EFI_ERROR(Status)
1016 || CharSize == 0
1017 || (CharBuffer == L'\n' && !(*Ascii))
1018 || (CharBuffer == '\n' && *Ascii)
1019 ){
1020 break;
1021 } else if (
1022 (CharBuffer == L'\r' && !(*Ascii)) ||
1023 (CharBuffer == '\r' && *Ascii)
1024 ) {
1025 CrCount++;
1026 continue;
1027 }
1028 //
1029 // if we have space save it...
1030 //
1031 if ((CountSoFar+1-CrCount)*sizeof(CHAR16) < *Size){
1032 ASSERT(Buffer != NULL);
1033 ((CHAR16*)Buffer)[CountSoFar-CrCount] = CharBuffer;
1034 ((CHAR16*)Buffer)[CountSoFar+1-CrCount] = CHAR_NULL;
1035 }
1036 }
1037
1038 //
1039 // if we ran out of space tell when...
1040 //
1041 if ((CountSoFar+1-CrCount)*sizeof(CHAR16) > *Size){
1042 *Size = (CountSoFar+1-CrCount)*sizeof(CHAR16);
1043 if (!Truncate) {
1044 if (Buffer != NULL && *Size != 0) {
1045 ZeroMem(Buffer, *Size);
1046 }
1047 FileHandleSetPosition(Handle, OriginalFilePosition);
1048 return (EFI_BUFFER_TOO_SMALL);
1049 } else {
1050 DEBUG((DEBUG_WARN, "The line was truncated in FileHandleReadLine"));
1051 return (EFI_SUCCESS);
1052 }
1053 }
1054
1055 return (Status);
1056 }
1057
1058 /**
1059 Function to write a line of text to a file.
1060
1061 If the file is a Unicode file (with UNICODE file tag) then write the unicode
1062 text.
1063 If the file is an ASCII file then write the ASCII text.
1064 If the size of file is zero (without file tag at the beginning) then write
1065 ASCII text as default.
1066
1067 @param[in] Handle FileHandle to write to.
1068 @param[in] Buffer Buffer to write, if NULL the function will
1069 take no action and return EFI_SUCCESS.
1070
1071 @retval EFI_SUCCESS The data was written.
1072 Buffer is NULL.
1073 @retval EFI_INVALID_PARAMETER Handle is NULL.
1074 @retval EFI_OUT_OF_RESOURCES Unable to allocate temporary space for ASCII
1075 string due to out of resources.
1076
1077 @sa FileHandleWrite
1078 **/
1079 EFI_STATUS
1080 EFIAPI
1081 FileHandleWriteLine(
1082 IN EFI_FILE_HANDLE Handle,
1083 IN CHAR16 *Buffer
1084 )
1085 {
1086 EFI_STATUS Status;
1087 CHAR16 CharBuffer;
1088 UINTN Size;
1089 UINTN Index;
1090 UINTN CharSize;
1091 UINT64 FileSize;
1092 UINT64 OriginalFilePosition;
1093 BOOLEAN Ascii;
1094 CHAR8 *AsciiBuffer;
1095
1096 if (Buffer == NULL) {
1097 return (EFI_SUCCESS);
1098 }
1099
1100 if (Handle == NULL) {
1101 return (EFI_INVALID_PARAMETER);
1102 }
1103
1104 Ascii = FALSE;
1105 AsciiBuffer = NULL;
1106
1107 Status = FileHandleGetPosition(Handle, &OriginalFilePosition);
1108 if (EFI_ERROR(Status)) {
1109 return Status;
1110 }
1111
1112 Status = FileHandleSetPosition(Handle, 0);
1113 if (EFI_ERROR(Status)) {
1114 return Status;
1115 }
1116
1117 Status = FileHandleGetSize(Handle, &FileSize);
1118 if (EFI_ERROR(Status)) {
1119 return Status;
1120 }
1121
1122 if (FileSize == 0) {
1123 Ascii = TRUE;
1124 } else {
1125 CharSize = sizeof (CHAR16);
1126 Status = FileHandleRead (Handle, &CharSize, &CharBuffer);
1127 ASSERT_EFI_ERROR (Status);
1128 if (CharBuffer == gUnicodeFileTag) {
1129 Ascii = FALSE;
1130 } else {
1131 Ascii = TRUE;
1132 }
1133 }
1134
1135 Status = FileHandleSetPosition(Handle, OriginalFilePosition);
1136 if (EFI_ERROR(Status)) {
1137 return Status;
1138 }
1139
1140 if (Ascii) {
1141 Size = ( StrSize(Buffer) / sizeof(CHAR16) ) * sizeof(CHAR8);
1142 AsciiBuffer = (CHAR8 *)AllocateZeroPool(Size);
1143 if (AsciiBuffer == NULL) {
1144 return EFI_OUT_OF_RESOURCES;
1145 }
1146 UnicodeStrToAsciiStrS (Buffer, AsciiBuffer, Size);
1147 for (Index = 0; Index < Size; Index++) {
1148 if ((AsciiBuffer[Index] & BIT7) != 0) {
1149 FreePool(AsciiBuffer);
1150 return EFI_INVALID_PARAMETER;
1151 }
1152 }
1153
1154 Size = AsciiStrSize(AsciiBuffer) - sizeof(CHAR8);
1155 Status = FileHandleWrite(Handle, &Size, AsciiBuffer);
1156 if (EFI_ERROR(Status)) {
1157 FreePool (AsciiBuffer);
1158 return (Status);
1159 }
1160 Size = AsciiStrSize("\r\n") - sizeof(CHAR8);
1161 Status = FileHandleWrite(Handle, &Size, "\r\n");
1162 } else {
1163 if (OriginalFilePosition == 0) {
1164 Status = FileHandleSetPosition (Handle, sizeof(CHAR16));
1165 if (EFI_ERROR(Status)) {
1166 return Status;
1167 }
1168 }
1169 Size = StrSize(Buffer) - sizeof(CHAR16);
1170 Status = FileHandleWrite(Handle, &Size, Buffer);
1171 if (EFI_ERROR(Status)) {
1172 return (Status);
1173 }
1174 Size = StrSize(L"\r\n") - sizeof(CHAR16);
1175 Status = FileHandleWrite(Handle, &Size, L"\r\n");
1176 }
1177
1178 if (AsciiBuffer != NULL) {
1179 FreePool (AsciiBuffer);
1180 }
1181 return Status;
1182 }
1183
1184 /**
1185 function to take a formatted argument and print it to a file.
1186
1187 @param[in] Handle the file handle for the file to write to
1188 @param[in] Format the format argument (see printlib for format specifier)
1189 @param[in] ... the variable arguments for the format
1190
1191 @retval EFI_SUCCESS the operation was successful
1192 @return other a return value from FileHandleWriteLine
1193
1194 @sa FileHandleWriteLine
1195 **/
1196 EFI_STATUS
1197 EFIAPI
1198 FileHandlePrintLine(
1199 IN EFI_FILE_HANDLE Handle,
1200 IN CONST CHAR16 *Format,
1201 ...
1202 )
1203 {
1204 VA_LIST Marker;
1205 CHAR16 *Buffer;
1206 EFI_STATUS Status;
1207
1208 //
1209 // Get a buffer to print into
1210 //
1211 Buffer = AllocateZeroPool (PcdGet16 (PcdUefiFileHandleLibPrintBufferSize));
1212 if (Buffer == NULL) {
1213 return (EFI_OUT_OF_RESOURCES);
1214 }
1215
1216 //
1217 // Print into our buffer
1218 //
1219 VA_START (Marker, Format);
1220 UnicodeVSPrint (Buffer, PcdGet16 (PcdUefiFileHandleLibPrintBufferSize), Format, Marker);
1221 VA_END (Marker);
1222
1223 //
1224 // Print buffer into file
1225 //
1226 Status = FileHandleWriteLine(Handle, Buffer);
1227
1228 //
1229 // Cleanup and return
1230 //
1231 FreePool(Buffer);
1232 return (Status);
1233 }
1234
1235 /**
1236 Function to determine if a FILE_HANDLE is at the end of the file.
1237
1238 This will NOT work on directories.
1239
1240 If Handle is NULL, then return False.
1241
1242 @param[in] Handle the file handle
1243
1244 @retval TRUE the position is at the end of the file
1245 @retval FALSE the position is not at the end of the file
1246 **/
1247 BOOLEAN
1248 EFIAPI
1249 FileHandleEof(
1250 IN EFI_FILE_HANDLE Handle
1251 )
1252 {
1253 EFI_FILE_INFO *Info;
1254 UINT64 Pos;
1255 BOOLEAN RetVal;
1256
1257 if (Handle == NULL) {
1258 return (FALSE);
1259 }
1260
1261 FileHandleGetPosition(Handle, &Pos);
1262 Info = FileHandleGetInfo (Handle);
1263
1264 if (Info == NULL) {
1265 return (FALSE);
1266 }
1267
1268 FileHandleSetPosition(Handle, Pos);
1269
1270 if (Pos == Info->FileSize) {
1271 RetVal = TRUE;
1272 } else {
1273 RetVal = FALSE;
1274 }
1275
1276 FreePool (Info);
1277
1278 return (RetVal);
1279 }