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