mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-30 10:43:45 +01:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2368 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			628 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			628 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| Copyright (c) 2006, Intel Corporation                                                         
 | |
| All rights reserved. This program and the accompanying materials                          
 | |
| are licensed and made available under the terms and conditions of the BSD License         
 | |
| which accompanies this distribution.  The full text of the license may be found at        
 | |
| http://opensource.org/licenses/bsd-license.php                                            
 | |
|                                                                                           
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
 | |
| 
 | |
| Module Name:
 | |
| 
 | |
|   BmLib.c
 | |
|     
 | |
| AgBStract:
 | |
| 
 | |
|   Boot Maintainence Helper functions
 | |
| 
 | |
| --*/
 | |
| 
 | |
| #include "BootMaint.h"
 | |
| 
 | |
| EFI_STATUS
 | |
| EfiLibLocateProtocol (
 | |
|   IN  EFI_GUID    *ProtocolGuid,
 | |
|   OUT VOID        **Interface
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Find the first instance of this Protocol 
 | |
|   in the system and return it's interface
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   ProtocolGuid    - Provides the protocol to search for
 | |
|   Interface       - On return, a pointer to the first interface 
 | |
|                     that matches ProtocolGuid
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS     - A protocol instance matching ProtocolGuid was found
 | |
| 
 | |
|   EFI_NOT_FOUND   - No protocol instances were found that match ProtocolGuid
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   ProtocolGuid,
 | |
|                   NULL,
 | |
|                   Interface
 | |
|                   );
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_FILE_HANDLE
 | |
| EfiLibOpenRoot (
 | |
|   IN EFI_HANDLE                   DeviceHandle
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Function opens and returns a file handle to the root directory of a volume.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   DeviceHandle         - A handle for a device
 | |
| 
 | |
| Returns:
 | |
|   
 | |
|   A valid file handle or NULL is returned
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
 | |
|   EFI_FILE_HANDLE                 File;
 | |
| 
 | |
|   File = NULL;
 | |
| 
 | |
|   //
 | |
|   // File the file system interface to the device
 | |
|   //
 | |
|   Status = gBS->HandleProtocol (
 | |
|                   DeviceHandle,
 | |
|                   &gEfiSimpleFileSystemProtocolGuid,
 | |
|                   (VOID *) &Volume
 | |
|                   );
 | |
| 
 | |
|   //
 | |
|   // Open the root directory of the volume
 | |
|   //
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     Status = Volume->OpenVolume (
 | |
|                       Volume,
 | |
|                       &File
 | |
|                       );
 | |
|   }
 | |
|   //
 | |
|   // Done
 | |
|   //
 | |
|   return EFI_ERROR (Status) ? NULL : File;
 | |
| }
 | |
| 
 | |
| BOOLEAN
 | |
| EfiGrowBuffer (
 | |
|   IN OUT EFI_STATUS   *Status,
 | |
|   IN OUT VOID         **Buffer,
 | |
|   IN UINTN            BufferSize
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|     Helper function called as part of the code needed
 | |
|     to allocate the proper sized buffer for various 
 | |
|     EFI interfaces.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|     Status      - Current status
 | |
| 
 | |
|     Buffer      - Current allocated buffer, or NULL
 | |
| 
 | |
|     BufferSize  - Current buffer size needed
 | |
|     
 | |
| Returns:
 | |
|     
 | |
|     TRUE - if the buffer was reallocated and the caller 
 | |
|     should try the API again.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   BOOLEAN TryAgain;
 | |
| 
 | |
|   //
 | |
|   // If this is an initial request, buffer will be null with a new buffer size
 | |
|   //
 | |
|   if (!*Buffer && BufferSize) {
 | |
|     *Status = EFI_BUFFER_TOO_SMALL;
 | |
|   }
 | |
|   //
 | |
|   // If the status code is "buffer too small", resize the buffer
 | |
|   //
 | |
|   TryAgain = FALSE;
 | |
|   if (*Status == EFI_BUFFER_TOO_SMALL) {
 | |
| 
 | |
|     SafeFreePool (*Buffer);
 | |
| 
 | |
|     *Buffer = AllocateZeroPool (BufferSize);
 | |
| 
 | |
|     if (*Buffer) {
 | |
|       TryAgain = TRUE;
 | |
|     } else {
 | |
|       *Status = EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // If there's an error, free the buffer
 | |
|   //
 | |
|   if (!TryAgain && EFI_ERROR (*Status) && *Buffer) {
 | |
|     SafeFreePool (*Buffer);
 | |
|     *Buffer = NULL;
 | |
|   }
 | |
| 
 | |
|   return TryAgain;
 | |
| }
 | |
| 
 | |
| VOID *
 | |
| EfiLibGetVariable (
 | |
|   IN CHAR16               *Name,
 | |
|   IN EFI_GUID             *VendorGuid
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Function returns the value of the specified variable.
 | |
| 
 | |
| Arguments:
 | |
|   Name                - A Null-terminated Unicode string that is 
 | |
|                         the name of the vendor's variable.
 | |
| 
 | |
|   VendorGuid          - A unique identifier for the vendor.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINTN VarSize;
 | |
| 
 | |
|   return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize);
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EfiLibDeleteVariable (
 | |
|   IN CHAR16   *VarName,
 | |
|   IN EFI_GUID *VarGuid
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Function deletes the variable specified by VarName and VarGuid.
 | |
| 
 | |
| Arguments:
 | |
|   VarName              - A Null-terminated Unicode string that is 
 | |
|                          the name of the vendor's variable.
 | |
| 
 | |
|   VendorGuid           - A unique identifier for the vendor.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS          - The variable was found and removed
 | |
| 
 | |
|   EFI_UNSUPPORTED      - The variable store was inaccessible
 | |
| 
 | |
|   EFI_OUT_OF_RESOURCES - The temporary buffer was not available
 | |
| 
 | |
|   EFI_NOT_FOUND        - The variable was not found
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   VOID        *VarBuf;
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   VarBuf  = EfiLibGetVariable (VarName, VarGuid);
 | |
|   Status  = EFI_NOT_FOUND;
 | |
| 
 | |
|   if (VarBuf) {
 | |
|     //
 | |
|     // Delete variable from Storage
 | |
|     //
 | |
|     Status = gRT->SetVariable (VarName, VarGuid, VAR_FLAG, 0, NULL);
 | |
|     ASSERT (!EFI_ERROR (Status));
 | |
|     SafeFreePool (VarBuf);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *
 | |
| EfiLibFileSystemVolumeLabelInfo (
 | |
|   IN EFI_FILE_HANDLE      FHand
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Function gets the file system information from an open file descriptor, 
 | |
|   and stores it in a buffer allocated from pool.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fhand         - A file handle
 | |
| 
 | |
| Returns:
 | |
|   
 | |
|   A pointer to a buffer with file information or NULL is returned
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *Buffer;
 | |
|   UINTN                             BufferSize;
 | |
|   //
 | |
|   // Initialize for GrowBuffer loop
 | |
|   //
 | |
|   Buffer      = NULL;
 | |
|   BufferSize  = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + 200;
 | |
| 
 | |
|   //
 | |
|   // Call the real function
 | |
|   //
 | |
|   while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
 | |
|     Status = FHand->GetInfo (
 | |
|                       FHand,
 | |
|                       &gEfiFileSystemVolumeLabelInfoIdGuid,
 | |
|                       &BufferSize,
 | |
|                       Buffer
 | |
|                       );
 | |
|   }
 | |
| 
 | |
|   return Buffer;
 | |
| }
 | |
| 
 | |
| CHAR16 *
 | |
| EfiStrDuplicate (
 | |
|   IN CHAR16   *Src
 | |
|   )
 | |
| {
 | |
|   CHAR16  *Dest;
 | |
|   UINTN   Size;
 | |
| 
 | |
|   Size  = StrSize (Src);
 | |
|   Dest  = AllocateZeroPool (Size);
 | |
|   ASSERT (Dest != NULL);
 | |
|   if (Dest) {
 | |
|     CopyMem (Dest, Src, Size);
 | |
|   }
 | |
| 
 | |
|   return Dest;
 | |
| }
 | |
| 
 | |
| EFI_FILE_INFO *
 | |
| EfiLibFileInfo (
 | |
|   IN EFI_FILE_HANDLE      FHand
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Function gets the file information from an open file descriptor, and stores it 
 | |
|   in a buffer allocated from pool.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fhand         - A file handle
 | |
| 
 | |
| Returns:
 | |
|   
 | |
|   A pointer to a buffer with file information or NULL is returned
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS    Status;
 | |
|   EFI_FILE_INFO *Buffer;
 | |
|   UINTN         BufferSize;
 | |
| 
 | |
|   //
 | |
|   // Initialize for GrowBuffer loop
 | |
|   //
 | |
|   Buffer      = NULL;
 | |
|   BufferSize  = SIZE_OF_EFI_FILE_INFO + 200;
 | |
| 
 | |
|   //
 | |
|   // Call the real function
 | |
|   //
 | |
|   while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
 | |
|     Status = FHand->GetInfo (
 | |
|                       FHand,
 | |
|                       &gEfiFileInfoGuid,
 | |
|                       &BufferSize,
 | |
|                       Buffer
 | |
|                       );
 | |
|   }
 | |
| 
 | |
|   return Buffer;
 | |
| }
 | |
| 
 | |
| UINTN
 | |
| EfiDevicePathInstanceCount (
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL      *DevicePath
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Function is used to determine the number of device path instances 
 | |
|   that exist in a device path.
 | |
| 
 | |
| Arguments:
 | |
|   DevicePath           - A pointer to a device path data structure.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   This function counts and returns the number of device path instances 
 | |
|   in DevicePath.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINTN Count;
 | |
|   UINTN Size;
 | |
| 
 | |
|   Count = 0;
 | |
|   while (GetNextDevicePathInstance (&DevicePath, &Size)) {
 | |
|     Count += 1;
 | |
|   }
 | |
| 
 | |
|   return Count;
 | |
| }
 | |
| 
 | |
| VOID *
 | |
| EfiReallocatePool (
 | |
|   IN VOID                 *OldPool,
 | |
|   IN UINTN                OldSize,
 | |
|   IN UINTN                NewSize
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Adjusts the size of a previously allocated buffer.
 | |
| 
 | |
| Arguments:
 | |
|   OldPool               - A pointer to the buffer whose size is being adjusted.
 | |
|   OldSize               - The size of the current buffer.
 | |
|   NewSize               - The size of the new buffer.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCEESS           - The requested number of bytes were allocated.
 | |
| 
 | |
|   EFI_OUT_OF_RESOURCES  - The pool requested could not be allocated.
 | |
| 
 | |
|   EFI_INVALID_PARAMETER - The buffer was invalid.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   VOID  *NewPool;
 | |
| 
 | |
|   NewPool = NULL;
 | |
|   if (NewSize) {
 | |
|     NewPool = AllocateZeroPool (NewSize);
 | |
|   }
 | |
| 
 | |
|   if (OldPool) {
 | |
|     if (NewPool) {
 | |
|       CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);
 | |
|     }
 | |
| 
 | |
|     SafeFreePool (OldPool);
 | |
|   }
 | |
| 
 | |
|   return NewPool;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EfiLibGetStringFromToken (
 | |
|   IN      EFI_GUID                  *ProducerGuid,
 | |
|   IN      STRING_REF                Token,
 | |
|   OUT     CHAR16                    **String
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   
 | |
|   Acquire the string associated with the ProducerGuid and return it.
 | |
| 
 | |
| Arguments:
 | |
|   
 | |
|   ProducerGuid - The Guid to search the HII database for
 | |
|   Token        - The token value of the string to extract
 | |
|   String       - The string that is extracted
 | |
|   
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS           -  Buffer filled with the requested forms. BufferLength
 | |
|                            was updated.
 | |
|   EFI_BUFFER_TOO_SMALL  -  The buffer provided was not large enough to allow the form to be stored.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   UINT16            HandleBufferLength;
 | |
|   EFI_HII_HANDLE    *HiiHandleBuffer;
 | |
|   UINTN             StringBufferLength;
 | |
|   UINTN             NumberOfHiiHandles;
 | |
|   UINTN             Index;
 | |
|   UINT16            Length;
 | |
|   EFI_GUID          HiiGuid;
 | |
|   EFI_HII_PROTOCOL  *Hii;
 | |
| 
 | |
|   //
 | |
|   // Initialize params.
 | |
|   //
 | |
|   HandleBufferLength  = 0;
 | |
|   HiiHandleBuffer     = NULL;
 | |
|   
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   &gEfiHiiProtocolGuid,
 | |
|                   NULL,
 | |
|                   (VOID**) &Hii
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *String = NULL;
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Get all the Hii handles
 | |
|   //
 | |
|   Status = BdsLibGetHiiHandles (Hii, &HandleBufferLength, &HiiHandleBuffer);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
|   
 | |
|   //
 | |
|   // Get the Hii Handle that matches the StructureNode->ProducerName
 | |
|   //
 | |
|   NumberOfHiiHandles = HandleBufferLength / sizeof (EFI_HII_HANDLE);
 | |
|   for (Index = 0; Index < NumberOfHiiHandles; Index++) {
 | |
|     Length = 0;
 | |
|     Status = ExtractDataFromHiiHandle (
 | |
|               HiiHandleBuffer[Index],
 | |
|               &Length,
 | |
|               NULL,
 | |
|               &HiiGuid
 | |
|               );
 | |
|     if (CompareGuid (ProducerGuid, &HiiGuid)) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Find the string based on the current language
 | |
|   //
 | |
|   StringBufferLength  = 0x100;
 | |
|   *String             = AllocateZeroPool (0x100);
 | |
|   ASSERT (*String != NULL);
 | |
| 
 | |
|   Status = Hii->GetString (
 | |
|                   Hii,
 | |
|                   HiiHandleBuffer[Index],
 | |
|                   Token,
 | |
|                   FALSE,
 | |
|                   NULL,
 | |
|                   &StringBufferLength,
 | |
|                   *String
 | |
|                   );
 | |
| 
 | |
|   gBS->FreePool (HiiHandleBuffer);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| BOOLEAN
 | |
| TimeCompare (
 | |
|   IN EFI_TIME               *FirstTime,
 | |
|   IN EFI_TIME               *SecondTime
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Compare two EFI_TIME data.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FirstTime         - A pointer to the first EFI_TIME data.
 | |
|   SecondTime        - A pointer to the second EFI_TIME data.
 | |
| 
 | |
| Returns:
 | |
|   TRUE              The FirstTime is not later than the SecondTime.
 | |
|   FALSE             The FirstTime is later than the SecondTime.
 | |
|   
 | |
| --*/
 | |
| {
 | |
|   if (FirstTime->Year != SecondTime->Year) {
 | |
|     return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
 | |
|   } else if (FirstTime->Month != SecondTime->Month) {
 | |
|     return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
 | |
|   } else if (FirstTime->Day != SecondTime->Day) {
 | |
|     return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
 | |
|   } else if (FirstTime->Hour != SecondTime->Hour) {
 | |
|     return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
 | |
|   } else if (FirstTime->Minute != SecondTime->Minute) {
 | |
|     return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);
 | |
|   } else if (FirstTime->Second != SecondTime->Second) {
 | |
|     return (BOOLEAN) (FirstTime->Second < SecondTime->Second);
 | |
|   }
 | |
| 
 | |
|   return (BOOLEAN) (FirstTime->Nanosecond <= SecondTime->Nanosecond);
 | |
| }
 | |
| 
 | |
| UINT16 *
 | |
| EfiLibStrFromDatahub (
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL                 *DevPath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                                  Status;
 | |
|   UINT16                                      *Desc;
 | |
|   EFI_DATA_HUB_PROTOCOL                       *Datahub;
 | |
|   UINT64                                      Count;
 | |
|   EFI_DATA_RECORD_HEADER                      *Record;
 | |
|   EFI_SUBCLASS_TYPE1_HEADER                   *DataHdr;
 | |
|   EFI_GUID                                    MiscGuid = EFI_MISC_SUBCLASS_GUID;
 | |
|   EFI_MISC_ONBOARD_DEVICE_DATA                *ob;
 | |
|   EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *Port;
 | |
|   EFI_TIME                                    CurTime;
 | |
| 
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   &gEfiDataHubProtocolGuid,
 | |
|                   NULL,
 | |
|                   (VOID**) &Datahub
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   Status = gRT->GetTime (&CurTime, NULL);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   Count = 0;
 | |
|   do {
 | |
|     Status = Datahub->GetNextRecord (Datahub, &Count, NULL, &Record);
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA && CompareGuid (&Record->DataRecordGuid, &MiscGuid)) {
 | |
|       //
 | |
|       // This record is what we need
 | |
|       //
 | |
|       DataHdr = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1);
 | |
|       if (EFI_MISC_ONBOARD_DEVICE_RECORD_NUMBER == DataHdr->RecordType) {
 | |
|         ob = (EFI_MISC_ONBOARD_DEVICE_DATA *) (DataHdr + 1);
 | |
|         if (BdsLibMatchDevicePaths ((EFI_DEVICE_PATH_PROTOCOL *) &ob->OnBoardDevicePath, DevPath)) {
 | |
|           EfiLibGetStringFromToken (&Record->ProducerName, ob->OnBoardDeviceDescription, &Desc);
 | |
|           return Desc;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_RECORD_NUMBER == DataHdr->RecordType) {
 | |
|         Port = (EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) (DataHdr + 1);
 | |
|         if (BdsLibMatchDevicePaths ((EFI_DEVICE_PATH_PROTOCOL *) &Port->PortPath, DevPath)) {
 | |
|           EfiLibGetStringFromToken (&Record->ProducerName, Port->PortExternalConnectorDesignator, &Desc);
 | |
|           return Desc;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   } while (TimeCompare (&Record->LogTime, &CurTime) && Count != 0);
 | |
| 
 | |
|   return NULL;
 | |
| }
 |