Leaked source code of windows server 2003
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.
 
 
 
 
 
 

670 lines
20 KiB

/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
vssapi.cpp
Abstract:
Contains the exported DLL functions for VssAPI.dll.
BUGBUG: Uses code that currently sets the SE handler. Since the SEH is process
wide, this can/will effect the user of this DLL. Need to fix.
Author:
reuvenl 5/01/2002
Revision History:
Name Date Comments
reuvenl 5/01/2002 Created from old wrtrshim.cpp
--*/
#include "stdafx.h"
/*
** ATL
*/
CComModule _Module;
#include <atlcom.h>
#include "vs_sec.hxx"
#include "vs_reg.hxx"
#include "ntddsnap.h"
BEGIN_OBJECT_MAP(ObjectMap)
END_OBJECT_MAP()
////////////////////////////////////////////////////////////////////////
// Standard foo for file name aliasing. This code block must be after
// all includes of VSS header files.
//
#ifdef VSS_FILE_ALIAS
#undef VSS_FILE_ALIAS
#endif
#define VSS_FILE_ALIAS "VSSAPICP"
// the name of the Volume Snapshot Service
const LPCWSTR wszVssvcServiceName = L"VSS";
static ULONG g_ulThreadAttaches = 0;
static ULONG g_ulThreadDetaches = 0;
static CBsCritSec g_cCritSec;
static GUID g_guidSnapshotInProgress = GUID_NULL;
static IVssShim *g_pIShim = NULL; // Used by the simulate functions.
/*
**++
**
** Routine Description:
**
** The DllMain entry point for this DLL. Note that this must be called by the
** CRT DLL Start function since the CRT must be initialized.
**
**
** Arguments:
** hInstance
** dwReason
** lpReserved
**
**
** Return Value:
**
** TRUE - Successful function execution
** FALSE - Error when executing the function
**
**--
*/
BOOL APIENTRY DllMain (IN HINSTANCE hInstance,
IN DWORD dwReason,
IN LPVOID lpReserved)
{
BOOL bSuccessful = TRUE;
UNREFERENCED_PARAMETER (hInstance);
UNREFERENCED_PARAMETER (lpReserved);
if (DLL_PROCESS_ATTACH == dwReason)
{
try
{
/*
** Set the correct tracing context. This is an inproc DLL
*/
g_cDbgTrace.SetContextNum (VSS_CONTEXT_DELAYED_DLL);
}
catch (...)
{
/*
** Can't trace from here so just ASSERT() (checked builds only)
*/
bSuccessful = FALSE;
BS_ASSERT (bSuccessful && "FAILED to initialise tracing sub-system");
}
}
if (bSuccessful)
{
try
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
BsDebugTrace (0,
DEBUG_TRACE_VSSAPI,
(L"VssAPI: DllMain - DLL_PROCESS_ATTACH called, %s",
lpReserved ? L"Static load" : L"Dynamic load"));
/*
** Don't need to know when threads start and stop - Wrong
**
** DisableThreadLibraryCalls (hInstance);
*/
_Module.Init (ObjectMap, hInstance);
break;
case DLL_PROCESS_DETACH:
BsDebugTrace (0,
DEBUG_TRACE_VSSAPI,
(L"VssAPI: DllMain - DLL_PROCESS_DETACH called %s",
lpReserved ? L"during process termination" : L"by FreeLibrary"));
_Module.Term();
break;
case DLL_THREAD_ATTACH:
g_ulThreadAttaches++;
if (0 == (g_ulThreadAttaches % 1000))
{
BsDebugTrace (0,
DEBUG_TRACE_VSSAPI,
(L"VssAPI: DllMain thread attaches = %u, detaches = %u, outstanding = %u",
g_ulThreadAttaches,
g_ulThreadDetaches,
g_ulThreadAttaches - g_ulThreadDetaches));
}
break;
case DLL_THREAD_DETACH:
g_ulThreadDetaches++;
if (0 == (g_ulThreadDetaches % 1000))
{
BsDebugTrace (0,
DEBUG_TRACE_VSSAPI,
(L"VssAPI: DllMain thread attaches = %u, detaches = %u, outstanding = %u",
g_ulThreadAttaches,
g_ulThreadDetaches,
g_ulThreadAttaches - g_ulThreadDetaches));
}
break;
default:
BsDebugTrace (0,
DEBUG_TRACE_VSSAPI,
(L"VssAPI: DllMain got unexpected reason code, lpReserved: %sNULL",
dwReason,
lpReserved ? L"non-" : L""));
break;
}
}
catch (...)
{
BsDebugTraceAlways (0,
DEBUG_TRACE_VSSAPI,
(L"VssAPI: DllMain - Error, unknown exception caught"));
bSuccessful = FALSE;
}
}
return (bSuccessful);
} /* DllMain () */
/*
**++
**
** Routine Description:
**
** The exported function that is called to simulate a snapshot creation to allow
** backup to drive the shim writers rather than having the snapshot co-ordinator
** do so.
**
**
** Arguments:
**
** guidSnapshotSetId Identifier used to identify the simulated prepare/freeze
** ulOptionFlags Options required for this freeze selected from the following list:-
** VSS_SW_BOOTABLE_STATE
**
** ulVolumeCount Number of volumes in the volume array
** ppwszVolumeNamesArray Array of pointer to volume name strings
** hCompletionEvent Handle to an event which will be set when the asynchronous freeze completes
** phrCompletionStatus Pointer to an HRESULT which will receive the completion status when the
** asynchronous freeze completes
**
**
** Return Value:
**
** Any HRESULT from the Snapshot writer PrepareForFreeze or Freeze functions.
**
**--
*/
__declspec(dllexport) HRESULT APIENTRY SimulateSnapshotFreeze (
IN GUID guidSnapshotSetId,
IN ULONG ulOptionFlags,
IN ULONG ulVolumeCount,
IN LPWSTR *ppwszVolumeNamesArray,
OUT IVssAsync **ppAsync )
{
CVssFunctionTracer ft (VSSDBG_VSSAPI, L"VssAPI::SimulateSnapshotFreeze");
BOOL bSucceeded;
try
{
CBsAutoLock cAutoLock (g_cCritSec);
BOOL bPrivilegesSufficient = FALSE;
bPrivilegesSufficient = IsProcessBackupOperator ();
ft.ThrowIf (!bPrivilegesSufficient,
VSSDBG_VSSAPI,
E_ACCESSDENIED,
L"FAILED as insufficient privileges to call shim");
//
// Most parameter checks should be done here in the VssApi DLL and not in the
// IVssCoordinator::SimulateSnapshotFreeze method since the shim DLL can be
// changed independently from the service. The service is just a forwarding
// agent to get SimulateSnapshotFreezeInternal called within one of the
// service's threads.
//
ft.ThrowIf ((ulOptionFlags & ~VSS_SW_BOOTABLE_STATE) != 0,
VSSDBG_VSSAPI,
E_INVALIDARG,
L"FAILED as illegal option flags set");
ft.ThrowIf (!((ulOptionFlags & VSS_SW_BOOTABLE_STATE) || (ulVolumeCount > 0)),
VSSDBG_VSSAPI,
E_INVALIDARG,
L"FAILED as need either BootableState or a volume list");
ft.ThrowIf ((ulVolumeCount > 0) && (NULL == ppwszVolumeNamesArray),
VSSDBG_VSSAPI,
E_INVALIDARG,
L"FAILED as need at least a one volume in the list if not bootable state");
ft.ThrowIf ((GUID_NULL == guidSnapshotSetId),
VSSDBG_VSSAPI,
E_INVALIDARG,
L"FAILED as supplied SnapshotSetId should not be GUID_NULL");
ft.ThrowIf ((NULL == ppAsync),
VSSDBG_VSSAPI,
E_INVALIDARG,
L"FAILED as supplied ppAsync parameter is NULL");
*ppAsync = NULL;
/*
** Try to scan all the volume names in an attempt to trigger
** an access violation to catch it here rather than in an
** unfortunate spot later on. It also gives us the
** opportinutiy to do some very basic validity checks.
*/
for (ULONG ulIndex = 0; ulIndex < ulVolumeCount; ulIndex++)
{
ft.ThrowIf (NULL == ppwszVolumeNamesArray [ulIndex],
VSSDBG_VSSAPI,
E_INVALIDARG,
L"FAILED as NULL value in volume array");
ft.ThrowIf (wcslen (L"C:") > wcslen (ppwszVolumeNamesArray [ulIndex]),
VSSDBG_VSSAPI,
E_INVALIDARG,
L"FAILED as volume name too short");
}
/*
** Now we need to connect to the VssSvc service's IVssCoordinator object
** and make the simulate freeze happen.
*/
ft.ThrowIf ( g_pIShim != NULL,
VSSDBG_VSSAPI,
VSS_E_SNAPSHOT_SET_IN_PROGRESS,
L"SimulateSnapshotThaw() must first be called by this process before calling SimulateSnapshotFreeze() again." );
ft.LogVssStartupAttempt();
ft.CoCreateInstanceWithLog(
VSSDBG_VSSAPI,
CLSID_VSSCoordinator,
L"Coordinator",
CLSCTX_ALL,
IID_IVssShim,
(IUnknown**)&(g_pIShim));
ft.CheckForError(VSSDBG_VSSAPI, L"CoCreateInstance( CLSID_VSSCoordinator, IID_IVssShim)");
BS_ASSERT( g_pIShim != NULL );
g_guidSnapshotInProgress = guidSnapshotSetId;
/*
** Now call the simulate freeze method in the coordinator
*/
ft.hr = g_pIShim->SimulateSnapshotFreeze(
guidSnapshotSetId,
ulOptionFlags,
ulVolumeCount,
ppwszVolumeNamesArray,
ppAsync );
ft.CheckForError(VSSDBG_VSSAPI, L"IVssShim::SimulateSnapshotFreeze()");
/*
** The simulate freeze operation is now running in a thread in VssSvc.
*/
}
VSS_STANDARD_CATCH (ft);
return (ft.hr);
} /* SimulateSnapshotFreeze () */
/*
**++
**
** Routine Description:
**
** The exported function that is called to simulate a snapshot thaw to allow
** backup to drive the shim writers rather than having the snapshot co-ordinator
** do so.
**
**
** Arguments:
**
** guidSnapshotSetId Identifier used to identify the simulated prepare/freeze
**
**
** Return Value:
**
** Any HRESULT from the Snapshot writer Thaw functions.
**
**--
*/
__declspec(dllexport) HRESULT APIENTRY SimulateSnapshotThaw (
IN GUID guidSnapshotSetId )
{
CVssFunctionTracer ft (VSSDBG_VSSAPI, L"VssAPI::SimulateSnapshotThaw");
BOOL bPrivilegesSufficient = FALSE;
HRESULT hrBootableState = NOERROR;
HRESULT hrSimulateOnly = NOERROR;
try
{
CBsAutoLock cAutoLock (g_cCritSec);
bPrivilegesSufficient = IsProcessBackupOperator ();
ft.ThrowIf (!bPrivilegesSufficient,
VSSDBG_VSSAPI,
E_ACCESSDENIED,
L"FAILED as inssuficient privileges to call shim");
/*
** We need to make sure a prior SimulateSnapshotFreeze happened.
*/
ft.ThrowIf ( g_pIShim == NULL,
VSSDBG_VSSAPI,
VSS_E_BAD_STATE,
L"Called SimulateSnapshotThaw() without first calling SimulateSnapshotFreeze()" );
ft.ThrowIf ( g_guidSnapshotInProgress != guidSnapshotSetId,
VSSDBG_VSSAPI,
VSS_E_BAD_STATE,
L"Mismatch between guidSnapshotSetId and the one passed into SimulateSnapshotFreeze()" );
/*
** Now call the simulate thaw method in the coordinator
*/
ft.hr = g_pIShim->SimulateSnapshotThaw( guidSnapshotSetId );
/*
** Regardless of the outcome of the SimulateSnapshotThaw, get rid of the shim interface.
*/
g_pIShim->Release();
g_pIShim = NULL;
g_guidSnapshotInProgress = GUID_NULL;
ft.CheckForError(VSSDBG_VSSAPI, L"IVssShim::SimulateSnapshotThaw()");
}
VSS_STANDARD_CATCH (ft);
return (ft.hr);
} /* SimulateSnapshotThaw () */
/*
**++
**
** Routine Description:
**
** The exported function that is called to check if a volume is snapshotted
**
**
** Arguments:
**
** IN VSS_PWSZ pwszVolumeName - The volume to be checked.
** OUT BOOL * pbSnapshotsPresent - Returns TRUE if the volume is snapshotted.
**
**
** Return Value:
**
** Any HRESULT from the IVssCoordinator::IsVolumeSnapshotted.
**
**--
*/
__declspec(dllexport) HRESULT APIENTRY IsVolumeSnapshotted (
IN VSS_PWSZ pwszVolumeName,
OUT BOOL * pbSnapshotsPresent,
OUT LONG * plSnapshotCompatibility
)
{
CVssFunctionTracer ft (VSSDBG_VSSAPI, L"VssAPI::IsVolumeSnapshotted");
BOOL bPrivilegesSufficient = FALSE;
SC_HANDLE shSCManager = NULL;
SC_HANDLE shSCService = NULL;
DWORD dwOldState = 0;
try
{
// Zero out the out parameter
::VssZeroOut(pbSnapshotsPresent);
::VssZeroOut(plSnapshotCompatibility);
bPrivilegesSufficient = IsProcessAdministrator ();
ft.ThrowIf (!bPrivilegesSufficient,
VSSDBG_VSSAPI,
E_ACCESSDENIED,
L"FAILED as insufficient privileges to call shim");
ft.ThrowIf ( (pwszVolumeName == NULL) || (pbSnapshotsPresent == NULL) ||
(plSnapshotCompatibility == NULL),
VSSDBG_VSSAPI,
E_INVALIDARG,
L"FAILED as invalid parameters");
CBsAutoLock cAutoLock (g_cCritSec);
//
// Check to see if VSSVC is running. If not ,we are supposing that no snapshots are present on the system.
//
// Connect to the local service control manager
shSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT);
if (!shSCManager)
ft.TranslateGenericError(VSSDBG_VSSAPI, HRESULT_FROM_WIN32(GetLastError()),
L"OpenSCManager(NULL,NULL,SC_MANAGER_CONNECT)");
// Get a handle to the service
shSCService = OpenService (shSCManager, wszVssvcServiceName, SERVICE_QUERY_STATUS);
if (!shSCService)
ft.TranslateGenericError(VSSDBG_VSSAPI, HRESULT_FROM_WIN32(GetLastError()),
L" OpenService (shSCManager, \'%s\', SERVICE_QUERY_STATUS)", wszVssvcServiceName);
// Now query the service to see what state it is in at the moment.
SERVICE_STATUS sSStat;
if (!QueryServiceStatus (shSCService, &sSStat))
ft.TranslateGenericError(VSSDBG_VSSAPI, HRESULT_FROM_WIN32(GetLastError()),
L"QueryServiceStatus (shSCService, &sSStat)");
// BUG 250943: Only if the service is running then check to see if there are any snapsnots
if (sSStat.dwCurrentState == SERVICE_RUNNING) {
// Create the coordinator interface
CComPtr<IVssCoordinator> pCoord;
// The service is already started, but...
// We still log here in order to make our code more robust.
ft.LogVssStartupAttempt();
// Create the instance.
ft.CoCreateInstanceWithLog(
VSSDBG_VSSAPI,
CLSID_VSSCoordinator,
L"Coordinator",
CLSCTX_ALL,
IID_IVssCoordinator,
(IUnknown**)&(pCoord));
if (ft.HrFailed())
ft.TranslateGenericError(VSSDBG_VSSAPI, ft.hr, L"CoCreateInstance(CLSID_VSSCoordinator)");
BS_ASSERT(pCoord);
// Call IsVolumeSnapshotted on the coordinator
ft.hr = pCoord->IsVolumeSnapshotted(
GUID_NULL,
pwszVolumeName,
pbSnapshotsPresent,
plSnapshotCompatibility);
}
else
{
// If the service is not running, then try to see if we have only MS Software Provider installed
// Open the "Providers" key. Throw an error if the key does not exist.
CVssRegistryKey keyProviders;
if (!keyProviders.Open( HKEY_LOCAL_MACHINE, L"%s\\%s", x_wszVSSKey, x_wszVSSKeyProviders))
ft.TranslateGenericError(VSSDBG_VSSAPI, ft.hr, L"RegOpenKeyExW(%ld,%s\\%s,...) = ERROR_FILE_NOT_FOUND",
HKEY_LOCAL_MACHINE, x_wszVSSKey, x_wszVSSKeyProviders);
// Attach an enumerator to the subkeys the subkeys
CVssRegistryKeyIterator iter;
iter.Attach(keyProviders);
BS_ASSERT(!iter.IsEOF());
// Get the number of subkeys. If different than one, the we sould go with the standard path
// If it is only one, this is the MS software provider (since it is always registered)
if (iter.GetSubkeysCount() != 1)
{
// Create the instance.
CComPtr<IVssCoordinator> pCoord;
ft.CoCreateInstanceWithLog(
VSSDBG_VSSAPI,
CLSID_VSSCoordinator,
L"Coordinator",
CLSCTX_ALL,
IID_IVssCoordinator,
(IUnknown**)&(pCoord));
if (ft.HrFailed())
ft.TranslateGenericError(VSSDBG_VSSAPI, ft.hr, L"CoCreateInstance(CLSID_VSSCoordinator)");
BS_ASSERT(pCoord);
// Call IsVolumeSnapshotted on the coordinator
ft.hr = pCoord->IsVolumeSnapshotted(
GUID_NULL,
pwszVolumeName,
pbSnapshotsPresent,
plSnapshotCompatibility);
}
else
{
// Getting the volume name
WCHAR wszVolumeNameInternal[x_nLengthOfVolMgmtVolumeName + 1];
if (!::GetVolumeNameForVolumeMountPointW( pwszVolumeName,
wszVolumeNameInternal, ARRAY_LEN(wszVolumeNameInternal)))
ft.Throw( VSSDBG_VSSAPI, VSS_E_OBJECT_NOT_FOUND,
L"GetVolumeNameForVolumeMountPoint(%s,...) "
L"failed with error code 0x%08lx", pwszVolumeName, GetLastError());
BS_ASSERT(::wcslen(wszVolumeNameInternal) != 0);
BS_ASSERT(::IsVolMgmtVolumeName( wszVolumeNameInternal ));
// Check if the volume is fixed (i.e. no CD-ROM, no removable)
UINT uDriveType = ::GetDriveTypeW(wszVolumeNameInternal);
if ( uDriveType != DRIVE_FIXED)
ft.Throw( VSSDBG_VSSAPI, VSS_E_VOLUME_NOT_SUPPORTED,
L"Encountering a non-fixed volume (%s) - %ud",
pwszVolumeName, uDriveType);
// Open the volume. Throw "object not found" if needed.
CVssIOCTLChannel volumeIChannel;
ft.hr = volumeIChannel.Open(ft, wszVolumeNameInternal, true, false, VSS_ICHANNEL_LOG_NONE, 0);
if (ft.HrFailed())
ft.Throw( VSSDBG_VSSAPI, VSS_E_VOLUME_NOT_SUPPORTED,
L"Volume (%s) not supported for snapshots 0x%08lx",
pwszVolumeName, ft.hr);
// Check to see if there are existing snapshots
ft.hr = volumeIChannel.Call(ft, IOCTL_VOLSNAP_QUERY_NAMES_OF_SNAPSHOTS, false);
if (ft.HrFailed())
ft.Throw( VSSDBG_VSSAPI, VSS_E_VOLUME_NOT_SUPPORTED,
L"Volume (%s) not supported for snapshots 0x%08lx",
pwszVolumeName, ft.hr);
// Get the length of snapshot names multistring
ULONG ulMultiszLen;
volumeIChannel.Unpack(ft, &ulMultiszLen);
// If the multistring is empty, then ulMultiszLen is necesarily 2
// (i.e. two l"\0' characters)
// Then mark the volume as snapshotted.
if (ulMultiszLen != x_nEmptyVssMultiszLen)
{
(*pbSnapshotsPresent) = TRUE;
// Bug 500069: Allow DEFRAG on Babbage snapshotted volumes
(*plSnapshotCompatibility) = (/*VSS_SC_DISABLE_DEFRAG|*/VSS_SC_DISABLE_CONTENTINDEX);
}
}
}
} VSS_STANDARD_CATCH (ft);
// Close handles
if (NULL != shSCService) CloseServiceHandle (shSCService);
if (NULL != shSCManager) CloseServiceHandle (shSCManager);
// Convert the "volume not supported into S_OK.
if (ft.hr == VSS_E_VOLUME_NOT_SUPPORTED)
ft.hr = S_OK;
return (ft.hr);
} /* IsVolumeSnapshotted () */
/*
**++
**
** Routine Description:
**
** This routine is used to free the contents of hte VSS_SNASPHOT_PROP structure
**
**
** Arguments:
**
** IN VSS_SNAPSHOT_PROP* pProp
**
**--
*/
__declspec(dllexport) void APIENTRY VssFreeSnapshotProperties (
IN VSS_SNAPSHOT_PROP* pProp
)
{
CVssFunctionTracer ft (VSSDBG_VSSAPI, L"VssAPI::VssFreeSnapshotProperties");
if (pProp) {
::CoTaskMemFree(pProp->m_pwszSnapshotDeviceObject);
::CoTaskMemFree(pProp->m_pwszOriginalVolumeName);
::CoTaskMemFree(pProp->m_pwszOriginatingMachine);
::CoTaskMemFree(pProp->m_pwszServiceMachine);
::CoTaskMemFree(pProp->m_pwszExposedName);
::CoTaskMemFree(pProp->m_pwszExposedPath);
}
} /* VssFreeSnapshotProperties () */