You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
624 lines
18 KiB
624 lines
18 KiB
#include "stdafx.hxx"
|
|
#include "vs_idl.hxx"
|
|
#include "vswriter.h"
|
|
#include "vsbackup.h"
|
|
#include "compont.h"
|
|
#include <debug.h>
|
|
#include <cwriter.h>
|
|
#include <lmshare.h>
|
|
#include <lmaccess.h>
|
|
#include <time.h>
|
|
|
|
//
|
|
// CWriterComponentsSelection class
|
|
//
|
|
|
|
CWriterComponentsSelection::CWriterComponentsSelection()
|
|
{
|
|
m_WriterId = GUID_NULL;
|
|
m_uNumComponents = 0;
|
|
m_uNumSubcomponents = 0;
|
|
m_ppwszComponentLogicalPaths = NULL;
|
|
m_ppwszSubcomponentLogicalPaths = NULL;
|
|
}
|
|
|
|
CWriterComponentsSelection::~CWriterComponentsSelection()
|
|
{
|
|
if ((m_uNumComponents > 0) && (m_ppwszComponentLogicalPaths != NULL))
|
|
{
|
|
for (UINT i=0; i<m_uNumComponents; i++)
|
|
{
|
|
if (m_ppwszComponentLogicalPaths[i] != NULL)
|
|
{
|
|
free(m_ppwszComponentLogicalPaths[i]);
|
|
m_ppwszComponentLogicalPaths[i] = NULL;
|
|
}
|
|
}
|
|
|
|
free(m_ppwszComponentLogicalPaths);
|
|
m_ppwszComponentLogicalPaths = NULL;
|
|
m_uNumComponents = 0;
|
|
}
|
|
|
|
if ((m_uNumSubcomponents > 0) && (m_ppwszSubcomponentLogicalPaths != NULL))
|
|
{
|
|
for (UINT i=0; i<m_uNumSubcomponents; i++)
|
|
{
|
|
if (m_ppwszSubcomponentLogicalPaths[i] != NULL)
|
|
{
|
|
free(m_ppwszSubcomponentLogicalPaths[i]);
|
|
m_ppwszSubcomponentLogicalPaths[i] = NULL;
|
|
}
|
|
}
|
|
|
|
free(m_ppwszSubcomponentLogicalPaths);
|
|
m_ppwszSubcomponentLogicalPaths = NULL;
|
|
m_uNumSubcomponents = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CWriterComponentsSelection::SetWriter
|
|
(
|
|
IN VSS_ID WriterId
|
|
)
|
|
{
|
|
m_WriterId = WriterId;
|
|
}
|
|
|
|
HRESULT CWriterComponentsSelection::AddSelectedComponent
|
|
(
|
|
IN WCHAR* pwszComponentLogicalPath
|
|
)
|
|
{
|
|
return AddSelected(pwszComponentLogicalPath, m_ppwszComponentLogicalPaths, m_uNumComponents);
|
|
}
|
|
|
|
HRESULT CWriterComponentsSelection::AddSelectedSubcomponent
|
|
(
|
|
IN WCHAR* pwszSubcomponentLogicalPath
|
|
)
|
|
{
|
|
return AddSelected(pwszSubcomponentLogicalPath, m_ppwszSubcomponentLogicalPaths, m_uNumSubcomponents);
|
|
}
|
|
|
|
HRESULT CWriterComponentsSelection::AddSelected
|
|
(
|
|
IN WCHAR* pwszLogicalPath,
|
|
WCHAR**& pwszLogicalPaths,
|
|
UINT& uSize
|
|
)
|
|
{
|
|
if (m_WriterId == GUID_NULL)
|
|
{
|
|
// Don't allow adding components to NULL writer...
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
if (pwszLogicalPath == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// A more clever implementation would allocate memory in chuncks, but this is just a test program...
|
|
PWCHAR *ppwzTemp = (PWCHAR *) realloc(pwszLogicalPaths, (uSize+1) * sizeof (PWCHAR));
|
|
if (ppwzTemp != NULL)
|
|
{
|
|
pwszLogicalPaths = ppwzTemp;
|
|
pwszLogicalPaths[uSize] = NULL;
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
pwszLogicalPaths[uSize] = (PWCHAR) malloc((wcslen(pwszLogicalPath) + 1) * sizeof (WCHAR));
|
|
if (pwszLogicalPaths[uSize] != NULL)
|
|
{
|
|
wcscpy(pwszLogicalPaths[uSize], pwszLogicalPath);
|
|
uSize++;
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
BOOL CWriterComponentsSelection::IsComponentSelected
|
|
(
|
|
IN WCHAR* pwszComponentLogicalPath,
|
|
IN WCHAR* pwszComponentName
|
|
)
|
|
{
|
|
return IsSelected(pwszComponentLogicalPath, pwszComponentName,
|
|
m_ppwszComponentLogicalPaths, m_uNumComponents);
|
|
}
|
|
|
|
BOOL CWriterComponentsSelection::IsSubcomponentSelected
|
|
(
|
|
IN WCHAR* pwszSubcomponentLogicalPath,
|
|
IN WCHAR* pwszSubcomponentName
|
|
)
|
|
{
|
|
return IsSelected(pwszSubcomponentLogicalPath, pwszSubcomponentName,
|
|
m_ppwszSubcomponentLogicalPaths, m_uNumSubcomponents);
|
|
}
|
|
|
|
BOOL CWriterComponentsSelection::IsSelected(IN WCHAR* pwszLogicalPath, IN WCHAR* pwszName,
|
|
IN WCHAR** pwszLogicalPaths, IN UINT uSize)
|
|
{
|
|
if (m_WriterId == GUID_NULL)
|
|
{
|
|
// Don't allow query for NULL writer...
|
|
return FALSE;
|
|
}
|
|
if (uSize <= 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// A component matches if:
|
|
// 1. The selection criteria is on the logical-path of the leaf component OR
|
|
// 2. The selection criteria is <full-logical-path>\<component-name>
|
|
// 3. The selction criteria is component-name (only if logical-path is NULL)
|
|
|
|
for (UINT i=0; i<uSize; i++)
|
|
{
|
|
DWORD dwLen;
|
|
|
|
if (pwszLogicalPaths[i] == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
dwLen = (DWORD)wcslen(pwszLogicalPaths[i]);
|
|
|
|
if (pwszLogicalPath != NULL)
|
|
{
|
|
// Case 1.
|
|
if (_wcsnicmp(pwszLogicalPaths[i], pwszLogicalPath, dwLen) == 0 &&
|
|
pwszName == NULL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// Case 2.
|
|
if (pwszName == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
WCHAR* pwszTemp = wcsrchr(pwszLogicalPaths[i], L'\\');
|
|
if (pwszTemp == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
if ((pwszTemp != pwszLogicalPaths[i]) && (*(pwszTemp+1) != '\0'))
|
|
{
|
|
dwLen = (DWORD)(pwszTemp - pwszLogicalPaths[i]);
|
|
if ( (dwLen == wcslen(pwszLogicalPath)) &&
|
|
(_wcsnicmp(pwszLogicalPaths[i], pwszLogicalPath, dwLen) == 0) &&
|
|
(wcscmp(pwszTemp+1, pwszName) == 0) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Case 3.
|
|
if (pwszName == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
if (_wcsnicmp(pwszLogicalPaths[i], pwszName, dwLen) == 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// CWritersSelection class
|
|
//
|
|
|
|
CWritersSelection::CWritersSelection()
|
|
{
|
|
m_lRef = 0;
|
|
}
|
|
|
|
CWritersSelection::~CWritersSelection()
|
|
{
|
|
// Cleanup the Map
|
|
for(int nIndex = 0; nIndex < m_WritersMap.GetSize(); nIndex++)
|
|
{
|
|
CWriterComponentsSelection* pComponentsSelection = m_WritersMap.GetValueAt(nIndex);
|
|
if (pComponentsSelection)
|
|
{
|
|
delete pComponentsSelection;
|
|
}
|
|
}
|
|
|
|
m_WritersMap.RemoveAll();
|
|
}
|
|
|
|
CWritersSelection* CWritersSelection::CreateInstance()
|
|
{
|
|
CWritersSelection* pObj = new CWritersSelection;
|
|
|
|
return pObj;
|
|
}
|
|
|
|
STDMETHODIMP CWritersSelection::QueryInterface(
|
|
IN REFIID iid,
|
|
OUT void** pp
|
|
)
|
|
{
|
|
if (pp == NULL)
|
|
return E_INVALIDARG;
|
|
if (iid != IID_IUnknown)
|
|
return E_NOINTERFACE;
|
|
|
|
AddRef();
|
|
IUnknown** pUnk = reinterpret_cast<IUnknown**>(pp);
|
|
(*pUnk) = static_cast<IUnknown*>(this);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
ULONG CWritersSelection::AddRef()
|
|
{
|
|
return ::InterlockedIncrement(&m_lRef);
|
|
}
|
|
|
|
|
|
ULONG CWritersSelection::Release()
|
|
{
|
|
LONG l = ::InterlockedDecrement(&m_lRef);
|
|
if (l == 0)
|
|
delete this; // We assume that we always allocate this object on the heap!
|
|
return l;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CWritersSelection::BuildChosenComponents
|
|
(
|
|
WCHAR *pwszComponentsFileName
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
DWORD dwBytesToRead = 0;
|
|
DWORD dwBytesRead;
|
|
|
|
// Create the file
|
|
hFile = CreateFile(pwszComponentsFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
wprintf(L"Invalid components file, CreateFile returned = %lu\n", dwLastError);
|
|
return HRESULT_FROM_WIN32(dwLastError);
|
|
}
|
|
|
|
if ((dwBytesToRead = GetFileSize(hFile, NULL)) <= 0)
|
|
{
|
|
CloseHandle(hFile);
|
|
DWORD dwLastError = GetLastError();
|
|
wprintf(L"Invalid components file, GetFileSize returned = %lu\n", dwLastError);
|
|
return HRESULT_FROM_WIN32(dwLastError);
|
|
}
|
|
|
|
if (dwBytesToRead > 0x100000)
|
|
{
|
|
CloseHandle(hFile);
|
|
wprintf(L"Invalid components file, Provide a file with a size of less than 1 MB\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
char * pcBuffer = (PCHAR) malloc (dwBytesToRead);
|
|
if (! pcBuffer)
|
|
{
|
|
CloseHandle(hFile);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Read the components info
|
|
if (! ReadFile(hFile, (LPVOID)pcBuffer, dwBytesToRead, &dwBytesRead, NULL))
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
CloseHandle(hFile);
|
|
free (pcBuffer);
|
|
wprintf(L"Invalid components file, ReadFile returned = %lu\n", dwLastError);
|
|
return HRESULT_FROM_WIN32(dwLastError);
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
|
|
if (dwBytesToRead != dwBytesRead)
|
|
{
|
|
free (pcBuffer);
|
|
wprintf(L"Components selection file is supposed to have %lu bytes but only %lu bytes are read\n", dwBytesToRead, dwBytesRead);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Allocate a buffer to work with
|
|
WCHAR * pwcBuffer = (PWCHAR) malloc ((dwBytesToRead+1) * sizeof(WCHAR));
|
|
if (! pwcBuffer)
|
|
{
|
|
free (pcBuffer);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Simple pasring, assume ANSI, Format:
|
|
// "writer1-id": "component1.1-name", "component1.2-name",... ; "writer2-id": "component2.1-name", ...
|
|
CWriterComponentsSelection* pWriterComponents = NULL;
|
|
|
|
try
|
|
{
|
|
VSS_ID WriterId = GUID_NULL;
|
|
BOOL bBeforeWriter = TRUE;
|
|
BOOL bBeforeComponents = TRUE;
|
|
BOOL bInString = FALSE;
|
|
char* pcStart = NULL;
|
|
|
|
for (char* pcCurrent = pcBuffer; pcCurrent < (pcBuffer+dwBytesToRead); pcCurrent++)
|
|
{
|
|
switch (*pcCurrent)
|
|
{
|
|
case ':':
|
|
if (bBeforeWriter && !bInString)
|
|
{
|
|
bBeforeWriter = FALSE;
|
|
}
|
|
else if (bBeforeComponents && !bInString)
|
|
{
|
|
bBeforeComponents = FALSE;
|
|
}
|
|
else if (!bInString)
|
|
{
|
|
throw(E_FAIL);
|
|
}
|
|
break;
|
|
|
|
case ';':
|
|
if (bBeforeWriter || bInString)
|
|
{
|
|
throw(E_FAIL);
|
|
}
|
|
else
|
|
{
|
|
// If we have a valid writer - add it to the map
|
|
if ((pWriterComponents != NULL) && (WriterId != GUID_NULL))
|
|
{
|
|
if (!m_WritersMap.Add(WriterId, pWriterComponents))
|
|
{
|
|
delete pWriterComponents;
|
|
throw E_OUTOFMEMORY;
|
|
}
|
|
|
|
pWriterComponents = NULL;
|
|
WriterId = GUID_NULL;
|
|
}
|
|
|
|
bBeforeWriter = TRUE;
|
|
}
|
|
break;
|
|
|
|
case ',':
|
|
if (bBeforeWriter || bInString)
|
|
{
|
|
throw(E_FAIL);
|
|
}
|
|
break;
|
|
|
|
case '"':
|
|
if (! bInString)
|
|
{
|
|
// Mark string-start for later
|
|
pcStart = pcCurrent + 1;
|
|
}
|
|
else if (pcStart == pcCurrent)
|
|
{
|
|
// empty string - skip it
|
|
}
|
|
else
|
|
{
|
|
// String ends - convert to WCHAR and process
|
|
DWORD dwSize = (DWORD)mbstowcs(pwcBuffer, pcStart, pcCurrent - pcStart);
|
|
pwcBuffer[dwSize] = NULL;
|
|
if (dwSize <= 0)
|
|
{
|
|
throw(E_FAIL);
|
|
}
|
|
|
|
if (bBeforeWriter)
|
|
{
|
|
// If before-writer - must be a writer GUID
|
|
HRESULT hrConvert = CLSIDFromString(pwcBuffer, &WriterId);
|
|
if ((! SUCCEEDED(hrConvert)) && (hrConvert != REGDB_E_WRITEREGDB))
|
|
{
|
|
wprintf(L"A writer id in the components selection file is in invalid GUID format\n");
|
|
throw(E_FAIL);
|
|
}
|
|
|
|
if (pWriterComponents != NULL)
|
|
{
|
|
// Previous writer info was not ended correctly
|
|
throw(E_FAIL);
|
|
}
|
|
|
|
pWriterComponents = new CWriterComponentsSelection;
|
|
if (pWriterComponents == NULL)
|
|
{
|
|
throw(E_OUTOFMEMORY);
|
|
}
|
|
pWriterComponents->SetWriter(WriterId);
|
|
}
|
|
else if (bBeforeComponents)
|
|
{
|
|
// Must be a component logical-path , name or logical-path\name
|
|
if (pWriterComponents != NULL)
|
|
{
|
|
pWriterComponents->AddSelectedComponent(pwcBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Must be a component logical-path , name or logical-path\name
|
|
if (pWriterComponents != NULL)
|
|
{
|
|
pWriterComponents->AddSelectedSubcomponent(pwcBuffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Flip in-string flag
|
|
bInString = (! bInString);
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
break;
|
|
|
|
case '\n':
|
|
case '\t':
|
|
case '\r':
|
|
if (bInString)
|
|
{
|
|
throw(E_FAIL);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
if (! bInString)
|
|
{
|
|
throw(E_FAIL);
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
catch (HRESULT hrParse)
|
|
{
|
|
hr = hrParse;
|
|
|
|
if (hr == E_FAIL)
|
|
{
|
|
wprintf(L"Invalid format of components selection file\n");
|
|
}
|
|
|
|
if (pWriterComponents != NULL)
|
|
{
|
|
// Error int he middle of writer-components creation (not added to the map yet...)
|
|
delete pWriterComponents;
|
|
}
|
|
}
|
|
|
|
free (pcBuffer);
|
|
free (pwcBuffer);
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL CWritersSelection::IsComponentSelected
|
|
(
|
|
IN VSS_ID WriterId,
|
|
IN WCHAR* pwszComponentLogicalPath,
|
|
IN WCHAR* pwszComponentName
|
|
)
|
|
{
|
|
CWriterComponentsSelection* pWriterComponents = m_WritersMap.Lookup(WriterId);
|
|
if (pWriterComponents == NULL)
|
|
{
|
|
// No component is selected for this writer
|
|
return FALSE;
|
|
}
|
|
|
|
// There are components selected for this writer, check if this specific one is selected
|
|
return pWriterComponents->IsComponentSelected(pwszComponentLogicalPath, pwszComponentName);
|
|
}
|
|
|
|
BOOL CWritersSelection::IsSubcomponentSelected
|
|
(
|
|
IN VSS_ID WriterId,
|
|
IN WCHAR* pwszComponentLogicalPath,
|
|
IN WCHAR* pwszComponentName
|
|
)
|
|
{
|
|
CWriterComponentsSelection* pWriterComponents = m_WritersMap.Lookup(WriterId);
|
|
if (pWriterComponents == NULL)
|
|
{
|
|
// No component is selected for this writer
|
|
return FALSE;
|
|
}
|
|
|
|
// There are subccomponents selected for this writer, check if this specific one is selected
|
|
return pWriterComponents->IsSubcomponentSelected(pwszComponentLogicalPath, pwszComponentName);
|
|
}
|
|
|
|
const WCHAR* const * CWritersSelection::GetComponents
|
|
(
|
|
IN VSS_ID WriterId
|
|
)
|
|
{
|
|
CWriterComponentsSelection* pWriterComponents = m_WritersMap.Lookup(WriterId);
|
|
if (pWriterComponents == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return pWriterComponents->GetComponents();
|
|
}
|
|
|
|
const WCHAR* const * CWritersSelection::GetSubcomponents
|
|
(
|
|
IN VSS_ID WriterId
|
|
)
|
|
{
|
|
CWriterComponentsSelection* pWriterComponents = m_WritersMap.Lookup(WriterId);
|
|
if (pWriterComponents == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return pWriterComponents->GetSubcomponents();
|
|
}
|
|
|
|
const UINT CWritersSelection::GetComponentsCount
|
|
(
|
|
IN VSS_ID WriterId
|
|
)
|
|
{
|
|
CWriterComponentsSelection* pWriterComponents = m_WritersMap.Lookup(WriterId);
|
|
if (pWriterComponents == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return pWriterComponents->GetComponentsCount();
|
|
}
|
|
|
|
const UINT CWritersSelection::GetSubcomponentsCount
|
|
(
|
|
IN VSS_ID WriterId
|
|
)
|
|
{
|
|
CWriterComponentsSelection* pWriterComponents = m_WritersMap.Lookup(WriterId);
|
|
if (pWriterComponents == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return pWriterComponents->GetSubcomponentsCount();
|
|
}
|
|
|
|
|