windows-nt/Source/XPSP1/NT/admin/pchealth/sr/enumlogs/respoint.cpp

802 lines
20 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/******************************************************************************
*
* Copyright (c) 2000 Microsoft Corporation
*
* Module Name:
* respoint.cpp
*
* Abstract:
* CRestorePoint, CRestorePointEnum class functions
*
* Revision History:
* Brijesh Krishnaswami (brijeshk) 03/17/2000
* created
*
*****************************************************************************/
#include "precomp.h"
#include "srapi.h"
#ifdef THIS_FILE
#undef THIS_FILE
#endif
static char __szTraceSourceFile[] = __FILE__;
#define THIS_FILE __szTraceSourceFile
// constructors
// use this constructor to read in an existing rp
// then need to call Read() to initialize rp members
CRestorePoint::CRestorePoint()
{
m_pRPInfo = NULL;
lstrcpy(m_szRPDir, L"");
m_itCurChgLogEntry = m_ChgLogList.end();
m_fForward = TRUE;
m_fDefunct = FALSE;
}
// initialize
BOOL
CRestorePoint::Load(RESTOREPOINTINFOW *prpinfo)
{
if (prpinfo)
{
if (! m_pRPInfo)
{
m_pRPInfo = (RESTOREPOINTINFOW *) SRMemAlloc(sizeof(RESTOREPOINTINFOW));
if (! m_pRPInfo)
return FALSE;
}
CopyMemory(m_pRPInfo, prpinfo, sizeof(RESTOREPOINTINFOW));
}
return TRUE;
}
// destructor
// call FindClose here
// if no enumeration was done, this is a no-op
CRestorePoint::~CRestorePoint()
{
if (m_pRPInfo)
SRMemFree(m_pRPInfo);
FindClose();
}
// return first/last change log entry in this restore point
// assumes Read() has already been called
DWORD
CRestorePoint::FindFirstChangeLogEntry(
LPWSTR pszDrive,
BOOL fForward,
CChangeLogEntry& cle)
{
DWORD dwRc = ERROR_SUCCESS;
WCHAR szChgLogPrefix[MAX_PATH];
WIN32_FIND_DATA FindData;
INT64 llSeqNum;
WCHAR szPath[MAX_PATH];
TENTER("CRestorePoint::FindFirstChangeLogEntry");
m_fForward = fForward;
lstrcpy(m_szDrive, pszDrive);
// read the first/last change log in this restore point
// all entries inside a change log will always be read in forward order
MakeRestorePath(szPath, m_szDrive, m_szRPDir);
wsprintf(szChgLogPrefix, L"%s\\%s", szPath, s_cszChangeLogPrefix);
if (! m_FindFile._FindFirstFile(szChgLogPrefix,
s_cszChangeLogSuffix,
&FindData,
m_fForward,
FALSE))
{
TRACE(0, "No changelog in %S", szPath);
dwRc = ERROR_NO_MORE_ITEMS;
goto done;
}
lstrcat(szPath, L"\\");
lstrcat(szPath, FindData.cFileName);
// build list of entries in increasing order of sequence number
dwRc = BuildList(szPath);
if (ERROR_SUCCESS != dwRc)
{
TRACE(0, "! BuildList : %ld", dwRc);
goto done;
}
TRACE(0, "Enumerating %S in %S", FindData.cFileName, m_szRPDir);
// if there was no entry in this change log, go to the next
if (m_ChgLogList.empty())
{
dwRc = FindNextChangeLogEntry(cle);
goto done;
}
// get the first/last entry
if (m_fForward)
{
m_itCurChgLogEntry = m_ChgLogList.begin();
}
else
{
m_itCurChgLogEntry = m_ChgLogList.end();
m_itCurChgLogEntry--;
}
// read in the change log entry into the object
cle.Load(*m_itCurChgLogEntry, m_szRPDir);
done:
TLEAVE();
return dwRc;
}
// return next/prev change log entry in this restore point
// assumes Read() has already been called
DWORD
CRestorePoint::FindNextChangeLogEntry(
CChangeLogEntry& cle)
{
DWORD dwRc = ERROR_SUCCESS;
WCHAR szPath[MAX_PATH];
WCHAR szChangeLogPath[MAX_PATH];
WCHAR szChgLogPrefix[MAX_PATH];
WIN32_FIND_DATA FindData;
INT64 llSeqNum;
TENTER("CRestorePoint::FindNextChangeLogEntry");
// go to the next entry in the list
m_fForward ? m_itCurChgLogEntry++ : m_itCurChgLogEntry--;
// check if we've reached the end of this change log
// end is the same for both forward and reverse enumeration
if (m_itCurChgLogEntry == m_ChgLogList.end())
{
// if so, read the next change log into memory
// nuke the current list
FindClose();
MakeRestorePath(szPath, m_szDrive, m_szRPDir);
wsprintf(szChgLogPrefix, L"%s\\%s", szPath, s_cszChangeLogPrefix);
while (m_ChgLogList.empty())
{
if (FALSE == m_FindFile._FindNextFile(szChgLogPrefix,
s_cszChangeLogSuffix,
&FindData))
{
dwRc = ERROR_NO_MORE_ITEMS;
TRACE(0, "No more change logs");
goto done;
}
lstrcpy(szChangeLogPath, szPath);
lstrcat(szChangeLogPath, L"\\");
lstrcat(szChangeLogPath, FindData.cFileName);
dwRc = BuildList(szChangeLogPath);
if (ERROR_SUCCESS != dwRc)
{
TRACE(0, "BuildList : error=%ld", dwRc);
goto done;
}
TRACE(0, "Enumerating %S in %S", FindData.cFileName, m_szRPDir);
}
// get the first/last entry
if (m_fForward)
{
m_itCurChgLogEntry = m_ChgLogList.begin();
}
else
{
m_itCurChgLogEntry = m_ChgLogList.end();
m_itCurChgLogEntry--;
}
}
// read in the change log entry fields into the object
cle.Load(*m_itCurChgLogEntry, m_szRPDir);
done:
TLEAVE();
return dwRc;
}
DWORD
CRestorePoint::BuildList(
LPWSTR pszChgLog)
{
DWORD dwRc = ERROR_INTERNAL_ERROR;
HANDLE hChgLog = INVALID_HANDLE_VALUE;
DWORD dwRead;
DWORD dwEntrySize;
PVOID pBlob = NULL;
SR_LOG_ENTRY* pEntry = NULL;
PSR_LOG_HEADER pLogHeader = NULL;
DWORD cbSize;
TENTER("CChangeLogEntry::BuildList");
if (FALSE==IsFileOwnedByAdminOrSystem(pszChgLog))
{
// this is not a valid log.
// ignore this log and go to the next one
TRACE(0, "Change log %S not owned by admin or system", pszChgLog);
dwRc = ERROR_SUCCESS;
goto done;
}
hChgLog = CreateFile(pszChgLog, // file name
GENERIC_READ, // access mode
FILE_SHARE_READ, // share mode
NULL, // SD
OPEN_EXISTING, // how to create
FILE_ATTRIBUTE_NORMAL, // file attributes
NULL);
if (INVALID_HANDLE_VALUE == hChgLog)
{
dwRc = GetLastError();
TRACE(0, "! CreateFile on %S : %ld", pszChgLog, dwRc);
goto done;
}
// read header size
if (FALSE == ReadFile(hChgLog,
&cbSize,
sizeof(DWORD),
&dwRead,
NULL) || dwRead == 0 || cbSize == 0)
{
// if the file could not be read,
// assume that it is a 0-sized log, and go to the next log
dwRc = GetLastError();
TRACE(0, "Zero sized log : %ld", pszChgLog, dwRc);
dwRc = ERROR_SUCCESS;
goto done;
}
pLogHeader = (SR_LOG_HEADER *) SRMemAlloc(cbSize);
if (! pLogHeader)
{
TRACE(0, "Out of memory");
goto done;
}
// read header
pLogHeader->Header.RecordSize = cbSize;
if (FALSE == ReadFile(hChgLog,
(PVOID) ( ((BYTE *) pLogHeader) + sizeof(DWORD)),
cbSize - sizeof(DWORD),
&dwRead,
NULL))
{
dwRc = GetLastError();
TRACE(0, "! ReadFile on %S : %ld", pszChgLog, dwRc);
goto done;
}
// check log's integrity
if( pLogHeader->LogVersion != SR_LOG_VERSION ||
pLogHeader->MagicNum != SR_LOG_MAGIC_NUMBER )
{
TRACE(0, "! LogHeader for %S : invalid or corrupt", pszChgLog);
goto done;
}
// now read the entries
do
{
// get the size of the entry
if (FALSE == ReadFile(hChgLog, &dwEntrySize, sizeof(DWORD), &dwRead, NULL))
{
TRACE(0, "ReadFile failed, error=%ld", GetLastError());
break;
}
if (0 == dwRead) // end of file
{
TRACE(0, "End of file");
dwRc = ERROR_NO_MORE_ITEMS;
break;
}
if (dwRead != sizeof(DWORD)) // error reading entry
{
TRACE(0, "Readfile could not read a DWORD");
break;
}
if (0 == dwEntrySize) // reached the last entry
{
TRACE(0, "No more entries");
dwRc = ERROR_NO_MORE_ITEMS;
break;
}
// get the entry itself
pEntry = (SR_LOG_ENTRY *) SRMemAlloc(dwEntrySize);
if (! pEntry)
{
TRACE(0, "Out of memory");
break;
}
pEntry->Header.RecordSize = dwEntrySize;
// skip the size field
pBlob = (PVOID) ((PBYTE) pEntry + sizeof(dwEntrySize));
if (FALSE == ReadFile(hChgLog, pBlob, dwEntrySize - sizeof(dwEntrySize), &dwRead, NULL))
{
TRACE(0, "! ReadFile on %S : %ld", pszChgLog, GetLastError());
break;
}
if (dwRead != dwEntrySize - sizeof(dwEntrySize)) // error reading entry
{
TRACE(0, "! Readfile: ToRead=%ld, Read=%ld bytes",
dwEntrySize - sizeof(dwEntrySize), dwRead);
break;
}
// insert entry into list
dwRc = InsertEntryIntoList(pEntry);
} while (ERROR_SUCCESS == dwRc);
if (ERROR_NO_MORE_ITEMS == dwRc)
{
dwRc = ERROR_SUCCESS;
}
done:
if (INVALID_HANDLE_VALUE != hChgLog)
CloseHandle(hChgLog);
SRMemFree(pLogHeader);
TLEAVE();
return dwRc;
}
// release memory and empty the list
DWORD CRestorePoint::FindClose()
{
// nuke the list
for (m_itCurChgLogEntry = m_ChgLogList.begin();
m_itCurChgLogEntry != m_ChgLogList.end();
m_itCurChgLogEntry++)
{
SRMemFree(*m_itCurChgLogEntry);
}
m_ChgLogList.clear();
return ERROR_SUCCESS;
}
// insert change log entry into list
DWORD
CRestorePoint::InsertEntryIntoList(
SR_LOG_ENTRY* pEntry)
{
TENTER("CRestorePoint::InsertEntryIntoList");
m_ChgLogList.push_back(pEntry);
TLEAVE();
return ERROR_SUCCESS;
}
// populate members
DWORD
CRestorePoint::ReadLog()
{
DWORD dwRc = ERROR_SUCCESS;
WCHAR szLog[MAX_PATH];
WCHAR szSystemDrive[MAX_PATH];
DWORD dwRead;
TENTER("CRestorePoint::ReadLog");
// construct path of rp.log
GetSystemDrive(szSystemDrive);
MakeRestorePath(szLog, szSystemDrive, m_szRPDir);
lstrcat(szLog, L"\\");
lstrcat(szLog, s_cszRestorePointLogName);
HANDLE hFile = CreateFile (szLog, // file name
GENERIC_READ, // file access
FILE_SHARE_READ, // share mode
NULL, // SD
OPEN_EXISTING, // how to create
0, // file attributes
NULL); // handle to template file
if (INVALID_HANDLE_VALUE == hFile)
{
dwRc = GetLastError();
trace(0, "! CreateFile on %S : %ld", szLog, dwRc);
goto done;
}
// read the restore point info
if (! m_pRPInfo)
{
m_pRPInfo = (RESTOREPOINTINFOW *) SRMemAlloc(sizeof(RESTOREPOINTINFOW));
if (! m_pRPInfo)
{
dwRc = ERROR_OUTOFMEMORY;
trace(0, "SRMemAlloc failed");
goto done;
}
}
if (FALSE == ReadFile(hFile, m_pRPInfo, sizeof(RESTOREPOINTINFOW), &dwRead, NULL) ||
dwRead != sizeof(RESTOREPOINTINFOW))
{
dwRc = GetLastError();
trace(0, "! ReadFile on %S : %ld", szLog, dwRc);
goto done;
}
m_fDefunct = (m_pRPInfo->dwRestorePtType == CANCELLED_OPERATION);
// read the creation time
if (FALSE == ReadFile(hFile, &m_Time, sizeof(m_Time), &dwRead, NULL) ||
dwRead != sizeof(m_Time))
{
dwRc = GetLastError();
trace(0, "! ReadFile on %S : %ld", szLog, dwRc);
goto done;
}
done:
if (INVALID_HANDLE_VALUE != hFile)
CloseHandle(hFile);
TLEAVE();
return dwRc;
}
DWORD
CRestorePoint::WriteLog()
{
DWORD dwRc = ERROR_SUCCESS;
WCHAR szLog[MAX_PATH];
WCHAR szSystemDrive[MAX_PATH];
DWORD dwWritten;
HANDLE hFile = INVALID_HANDLE_VALUE;
TENTER("CRestorePoint::WriteLog");
if (! m_pRPInfo)
{
ASSERT(0);
dwRc = ERROR_INTERNAL_ERROR;
goto done;
}
// set the creation time to the current time
GetSystemTimeAsFileTime(&m_Time);
// construct path of rp.log
GetSystemDrive(szSystemDrive);
MakeRestorePath(szLog, szSystemDrive, m_szRPDir);
lstrcat(szLog, L"\\");
lstrcat(szLog, s_cszRestorePointLogName);
hFile = CreateFile (szLog, // file name
GENERIC_WRITE, // file access
0, // share mode
NULL, // SD
CREATE_ALWAYS, // how to create
FILE_FLAG_WRITE_THROUGH, // file attributes
NULL); // handle to template file
if (INVALID_HANDLE_VALUE == hFile)
{
dwRc = GetLastError();
trace(0, "! CreateFile on %S : %ld", szLog, dwRc);
goto done;
}
// write the restore point info
if (FALSE == WriteFile(hFile, m_pRPInfo, sizeof(RESTOREPOINTINFOW), &dwWritten, NULL))
{
dwRc = GetLastError();
trace(0, "! WriteFile on %S : %ld", szLog, dwRc);
goto done;
}
// write the creation time
if (FALSE == WriteFile(hFile, &m_Time, sizeof(m_Time), &dwWritten, NULL))
{
dwRc = GetLastError();
trace(0, "! WriteFile on %S : %ld", szLog, dwRc);
goto done;
}
done:
if (INVALID_HANDLE_VALUE != hFile)
CloseHandle(hFile);
TLEAVE();
return dwRc;
}
BOOL
CRestorePoint::DeleteLog()
{
WCHAR szLog[MAX_PATH];
WCHAR szSystemDrive[MAX_PATH];
GetSystemDrive(szSystemDrive);
MakeRestorePath(szLog, szSystemDrive, m_szRPDir);
lstrcat(szLog, L"\\");
lstrcat(szLog, s_cszRestorePointLogName);
return DeleteFile(szLog);
}
DWORD
CRestorePoint::Cancel()
{
if (m_pRPInfo)
{
m_pRPInfo->dwRestorePtType = CANCELLED_OPERATION;
return WriteLog();
}
else
{
ASSERT(0);
return ERROR_INTERNAL_ERROR;
}
}
DWORD
CRestorePoint::GetNum()
{
return GetID(m_szRPDir);
}
// read the size of the restore point folder from file
DWORD CRestorePoint::ReadSize (const WCHAR *pwszDrive, INT64 *pllSize)
{
DWORD dwErr = ERROR_SUCCESS;
DWORD cbRead = 0;
WCHAR wcsPath[MAX_PATH];
MakeRestorePath(wcsPath, pwszDrive, m_szRPDir);
lstrcat(wcsPath, L"\\");
lstrcat (wcsPath, s_cszRestorePointSize);
HANDLE hFile = CreateFileW ( wcsPath, // file name
GENERIC_READ, // file access
FILE_SHARE_READ, // share mode
NULL, // SD
OPEN_EXISTING, // how to create
0, // file attributes
NULL); // handle to template file
if (INVALID_HANDLE_VALUE == hFile)
{
dwErr = GetLastError();
return dwErr;
}
if (FALSE == ReadFile (hFile, (BYTE *) pllSize, sizeof(*pllSize),
&cbRead, NULL))
{
dwErr = GetLastError();
}
CloseHandle (hFile);
return dwErr;
}
// write the size of the restore point folder to file
DWORD CRestorePoint::WriteSize (const WCHAR *pwszDrive, INT64 llSize)
{
DWORD dwErr = ERROR_SUCCESS;
DWORD cbWritten = 0;
WCHAR wcsPath[MAX_PATH];
MakeRestorePath(wcsPath, pwszDrive, m_szRPDir);
lstrcat(wcsPath, L"\\");
lstrcat (wcsPath, s_cszRestorePointSize);
HANDLE hFile = CreateFileW ( wcsPath, // file name
GENERIC_WRITE, // file access
0, // share mode
NULL, // SD
CREATE_ALWAYS, // how to create
0, // file attributes
NULL); // handle to template file
if (INVALID_HANDLE_VALUE == hFile)
{
dwErr = GetLastError();
return dwErr;
}
if (FALSE == WriteFile (hFile, (BYTE *) &llSize, sizeof(llSize),
&cbWritten, NULL))
{
dwErr = GetLastError();
}
CloseHandle (hFile);
return dwErr;
}
// populate a changelogentry object
void
CChangeLogEntry::Load(SR_LOG_ENTRY *pentry, LPWSTR pszRPDir)
{
PSR_LOG_DEBUG_INFO pDebugRec = NULL;
_pentry = pentry;
_pszPath1 = _pszPath2 = _pszTemp = _pszProcess = _pszShortName = NULL;
_pbAcl = NULL;
_cbAcl = 0;
_fAclInline = FALSE;
lstrcpy(_pszRPDir, pszRPDir);
BYTE *pRec = (PBYTE) & _pentry->SubRecords;
//
// get source path
//
_pszPath1 = (LPWSTR) (pRec + sizeof(RECORD_HEADER));
//
// get temp path if exists
//
if (_pentry->EntryFlags & ENTRYFLAGS_TEMPPATH)
{
pRec += RECORD_SIZE(pRec);
_pszTemp = (LPWSTR) (pRec + sizeof(RECORD_HEADER));
}
//
// get second path if exists
//
if (_pentry->EntryFlags & ENTRYFLAGS_SECONDPATH)
{
pRec += RECORD_SIZE(pRec);
_pszPath2 = (LPWSTR) (pRec + sizeof(RECORD_HEADER));
}
//
// get acl info if exists
//
if (_pentry->EntryFlags & ENTRYFLAGS_ACLINFO)
{
pRec += RECORD_SIZE(pRec);
if (RECORD_TYPE(pRec) == RecordTypeAclInline)
{
_fAclInline = TRUE;
}
_pbAcl = (BYTE *) (pRec + sizeof(RECORD_HEADER));
_cbAcl = RECORD_SIZE(pRec) - sizeof(RECORD_HEADER);
}
//
// get debug info if exists
//
if (_pentry->EntryFlags & ENTRYFLAGS_DEBUGINFO)
{
pRec += RECORD_SIZE(pRec);
pDebugRec = (PSR_LOG_DEBUG_INFO) pRec;
_pszProcess = (LPWSTR) (pDebugRec->ProcessName);
}
//
// get shortname if exists
//
if (_pentry->EntryFlags & ENTRYFLAGS_SHORTNAME)
{
pRec += RECORD_SIZE(pRec);
_pszShortName = (LPWSTR) (pRec + sizeof(RECORD_HEADER));
}
return;
}
// this function will check if any filepath length exceeds
// the max length that restore supports
// if so, it will return FALSE
BOOL
CChangeLogEntry::CheckPathLengths()
{
if (_pszPath1 && lstrlen(_pszPath1) > SR_MAX_FILENAME_PATH-1)
return FALSE;
if (_pszPath2 && lstrlen(_pszPath2) > SR_MAX_FILENAME_PATH-1)
return FALSE;
if (_pszTemp && lstrlen(_pszTemp) > SR_MAX_FILENAME_PATH-1)
return FALSE;
return TRUE;
}