//======================================================================= // // Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved. // // File: v3applog.cpp // // Purpose: Reading WindowsUpdate V3 history logging // // History: 22-Feb-99 YAsmi Created // 02-May-01 JHou Modified // //======================================================================= #include "iuengine.h" #include #include "v3applog.h" // // CV3AppLog class // //-------------------------------------------------------------------------------- // CV3AppLog::CV3AppLog // // if the pszLogFileName=NULL, then the caller must set the log file name by // calling SetLogFile before using //-------------------------------------------------------------------------------- CV3AppLog::CV3AppLog(LPCTSTR pszLogFileName) : m_pFileBuf(NULL), m_pFieldBuf(NULL), m_pLine(NULL), m_dwFileSize(0), m_dwBufLen(0), m_dwFileOfs(0) { m_pszLogFN = NULL; SetLogFile(pszLogFileName); } //-------------------------------------------------------------------------------- // CV3AppLog::~CV3AppLog // // free resources //-------------------------------------------------------------------------------- CV3AppLog::~CV3AppLog() { SafeHeapFree(m_pszLogFN); SafeHeapFree(m_pFileBuf); SafeHeapFree(m_pFieldBuf); } //-------------------------------------------------------------------------------- // CV3AppLog::CheckBuf // // allocates the internal buffer to be atleast dwSize big. Does not do anything // if the the buffer is already big enough //-------------------------------------------------------------------------------- void CV3AppLog::CheckBuf(DWORD dwSize) { if (m_dwBufLen >= dwSize) return; SafeHeapFree(m_pFieldBuf); m_dwBufLen = dwSize + 16; m_pFieldBuf = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, m_dwBufLen); } //-------------------------------------------------------------------------------- // CV3AppLog::SetLogFile // // sets the log file name. Use this function if you did not specify the file name // in the ctor //-------------------------------------------------------------------------------- void CV3AppLog::SetLogFile(LPCTSTR pszLogFileName) { SafeHeapFree(m_pszLogFN); if (pszLogFileName != NULL) { m_pszLogFN = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH * sizeof (TCHAR)); if (NULL != m_pszLogFN) { HRESULT hr; hr = StringCchCopyEx(m_pszLogFN, MAX_PATH, pszLogFileName, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) { SafeHeapFree(m_pszLogFN); m_pszLogFN = NULL; } } } } //-------------------------------------------------------------------------------- // CV3AppLog::StartReading // // Reads the entire log in memory so we can read lines. Following is an example: // // CV3AppLog V3His("C:\\wuhistv3.log"); // V3His.StartReading(); // while (V3His.ReadLine()) // // do something; // V3His.StopReading(); //-------------------------------------------------------------------------------- void CV3AppLog::StartReading() { if (NULL != m_pszLogFN) { m_dwFileSize = 0; m_dwFileOfs = 0; SafeHeapFree(m_pFileBuf); HANDLE hFile = CreateFile(m_pszLogFN, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return; m_dwFileSize = GetFileSize(hFile, NULL); if (m_dwFileSize >0) { m_pFileBuf = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, m_dwFileSize+1); if (NULL == m_pFileBuf) { m_dwFileSize = 0; } else { DWORD dwBytes; if (!ReadFile(hFile, m_pFileBuf, m_dwFileSize, &dwBytes, NULL) || dwBytes != m_dwFileSize) { SafeHeapFree(m_pFileBuf); m_dwFileSize = 0; } } } CloseHandle(hFile); } } //-------------------------------------------------------------------------------- // CV3AppLog::ReadLine // // reads a line from the memory buffer where the entire file was loaded // moves the internal pointer to the next line. //-------------------------------------------------------------------------------- BOOL CV3AppLog::ReadLine() { DWORD dwOrgOfs; if (m_dwFileSize == 0 || m_dwFileOfs >= m_dwFileSize || (NULL == m_pFileBuf)) return FALSE; // setup the start of field parsing m_pLine = &m_pFileBuf[m_dwFileOfs]; dwOrgOfs = m_dwFileOfs; while (m_dwFileOfs < m_dwFileSize && m_pFileBuf[m_dwFileOfs] != '\r') m_dwFileOfs++; if ((m_dwFileOfs - dwOrgOfs) > 2048) { // self imposed limit of 2048 chars in a line // we consider a file with a longer line of text an invalid log file m_dwFileOfs = m_dwFileSize; m_pLine = NULL; return FALSE; } // this is where we have the \r (13), we replace it with a 0 to create // end of string here m_pFileBuf[m_dwFileOfs] = '\0'; // point the ofset to next line m_dwFileOfs += 2; // allocate enough memory to parse out fields when CopyNextField is called CheckBuf(m_dwFileOfs - dwOrgOfs - 2); if (NULL == m_pFieldBuf) { return FALSE; } return TRUE; } //-------------------------------------------------------------------------------- // CV3AppLog::CopyNextField // // parses out the current line separated by the LOG_FIELD_SEPARATOR // and copies the string to pszBuf upto cBufSize long field and moves internal // pointer to next field. When the end of line is reached, returns a blank string // // RETURNS: TRUE if more fields are left, FALSE otherwise // // NOTES: Once you get a field you cannot get it again. //-------------------------------------------------------------------------------- BOOL CV3AppLog::CopyNextField(LPSTR pszBuf, int cBufSize) { BOOL bMoreFields = FALSE; if (m_pLine == NULL || *m_pLine == '\0') { //there are no more fields m_pFieldBuf[0] = '\0'; m_pLine = NULL; } else { LPCSTR p = strstr(m_pLine, LOG_FIELD_SEPARATOR); if (p != NULL) { DWORD cch; // this will fail if the size of the field is > 4GB. But it should be // very unlikely that this will ever happen... cch = (DWORD)(DWORD_PTR)(p - m_pLine); if (cch >= m_dwBufLen) cch = m_dwBufLen - 1; // copy the field to buffer but there are still more fields // this is safe because we made sure above that the max amount of data // copied will be ARRAYSIZE(buffer) - 1 giving us room for the NULL at the end CopyMemory(m_pFieldBuf, m_pLine, cch * sizeof(m_pFieldBuf[0])); m_pFieldBuf[cch] = '\0'; m_pLine = const_cast(p + strlen(LOG_FIELD_SEPARATOR)); bMoreFields = TRUE; } else { // this is the last field, there are no more fields // don't care if this fails- it will always truncate the string which is // exactly what we want (void)StringCchCopyExA(m_pFieldBuf, m_dwBufLen, m_pLine, NULL, NULL, MISTSAFE_STRING_FLAGS); m_pLine = NULL; } } // don't care if this fails- it will always truncate the string which is exactly what // we want (void)StringCchCopyExA(pszBuf, cBufSize, m_pFieldBuf, NULL, NULL, MISTSAFE_STRING_FLAGS); return bMoreFields; } //-------------------------------------------------------------------------------- // CV3AppLog::StopReading // // free up memory from allocated in StartReading //-------------------------------------------------------------------------------- void CV3AppLog::StopReading() { SafeHeapFree(m_pFileBuf); m_dwFileSize = 0; }