188 lines
6.9 KiB
C++
188 lines
6.9 KiB
C++
/////////////////////////////////////////////////////////////////////////
|
|
// Copyright © 2006 Microsoft Corporation. All rights reserved.
|
|
//
|
|
// This file may contain preliminary information or inaccuracies,
|
|
// and may not correctly represent any associated Microsoft
|
|
// Product as commercially released. All Materials are provided entirely
|
|
// “AS IS.” To the extent permitted by law, MICROSOFT MAKES NO
|
|
// WARRANTY OF ANY KIND, DISCLAIMS ALL EXPRESS, IMPLIED AND STATUTORY
|
|
// WARRANTIES, AND ASSUMES NO LIABILITY TO YOU FOR ANY DAMAGES OF
|
|
// ANY TYPE IN CONNECTION WITH THESE MATERIALS OR ANY INTELLECTUAL PROPERTY IN THEM.
|
|
//
|
|
|
|
|
|
// Main header
|
|
#include "stdafx.h"
|
|
|
|
|
|
// Expose the given shadow copy set as a mount point or drive letter
|
|
void VssClient::ExposeSnapshotLocally(VSS_ID snapshotID, wstring path)
|
|
{
|
|
FunctionTracer ft(DBG_INFO);
|
|
|
|
ft.WriteLine(L"- Exposing shadow copy " WSTR_GUID_FMT L" under the path '%s'",
|
|
GUID_PRINTF_ARG(snapshotID), path.c_str());
|
|
|
|
// Make sure that the expose operation is valid for this snapshot.
|
|
// Get the shadow copy properties
|
|
VSS_SNAPSHOT_PROP Snap;
|
|
HRESULT hr = m_pVssObject->GetSnapshotProperties(snapshotID, &Snap);
|
|
if (hr == VSS_E_OBJECT_NOT_FOUND)
|
|
{
|
|
ft.WriteLine(L"\nERROR: there is no snapshot with the given ID");
|
|
throw(E_INVALIDARG);
|
|
}
|
|
|
|
// Automatically call VssFreeSnapshotProperties on this structure at the end of scope
|
|
CAutoSnapPointer snapAutoCleanup(&Snap);
|
|
|
|
// Client Accessible snapshots are not exposable
|
|
if (Snap.m_lSnapshotAttributes & VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE)
|
|
{
|
|
ft.WriteLine(L"\nERROR: the snapshot ID identifies a Client Accessible snapshot which cannot be exposed");
|
|
throw(E_INVALIDARG);
|
|
}
|
|
|
|
// Client Accessible snapshots are not exposable
|
|
if ((Snap.m_pwszExposedName != NULL) || (Snap.m_pwszExposedPath != NULL))
|
|
{
|
|
ft.WriteLine(L"\nERROR: Client-accessible (SFSF) snapshots cannot be exposed.");
|
|
throw(E_INVALIDARG);
|
|
}
|
|
|
|
//
|
|
// Check if the path parameter is valid
|
|
//
|
|
|
|
// If this looks like a drive letter then make sure that the drive letter is not in use
|
|
if ((path.length() == 2) && path[1] == L':')
|
|
{
|
|
ft.WriteLine(L"- Checking if '%s' is a valid drive letter ...", path.c_str());
|
|
|
|
wstring device(MAX_PATH, L'\0');
|
|
if (0 != QueryDosDeviceW( path.c_str(), WString2Buffer(device), (DWORD)device.length()))
|
|
{
|
|
ft.WriteLine(L"\nERROR: the second parameter to -el [%s] is a drive letter already in use!", path.c_str());
|
|
throw(E_INVALIDARG);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Append a backslash
|
|
if (path[path.length() - 1] != L'\\')
|
|
path += L'\\';
|
|
|
|
ft.WriteLine(L"- Checking if '%s' is a valid empty directory ...", path.c_str());
|
|
|
|
// Make sure this is a directory
|
|
DWORD dwAttributes = GetFileAttributes(path.c_str());
|
|
if ((dwAttributes == INVALID_FILE_ATTRIBUTES) || ((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0))
|
|
{
|
|
ft.WriteLine(L"\nERROR: the second parameter to -el [%s] is not a valid directory!", path.c_str());
|
|
throw(E_INVALIDARG);
|
|
}
|
|
|
|
// Make sure that this directory is empty
|
|
WIN32_FIND_DATA FindFileData;
|
|
wstring pattern = path + L'*';
|
|
HANDLE hFind = FindFirstFile( pattern.c_str(), &FindFileData);
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
CHECK_WIN32_ERROR(GetLastError(), L"FindFirstFile");
|
|
|
|
// Automatically calls FindClose at the end of scope
|
|
CAutoSearchHandle autoHandle(hFind);
|
|
|
|
// Enumerate all the files/subdirectories
|
|
while (true)
|
|
{
|
|
wstring fileName = FindFileData.cFileName;
|
|
if ((fileName != wstring(L".")) && (fileName != wstring(L"..")))
|
|
{
|
|
ft.WriteLine(L"\nERROR: the second parameter to -el [%s] is not an empty directory!", path.c_str());
|
|
throw(E_INVALIDARG);
|
|
}
|
|
|
|
if (!FindNextFile(hFind, &FindFileData))
|
|
{
|
|
if (GetLastError() == ERROR_NO_MORE_FILES)
|
|
break;
|
|
|
|
CHECK_WIN32_ERROR(GetLastError(), L"FindNextFile");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Expose locally the shadow copy set
|
|
LPWSTR pwszExposed = NULL;
|
|
CHECK_COM(m_pVssObject->ExposeSnapshot(snapshotID, NULL,
|
|
VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY, (VSS_PWSZ)path.c_str(), &pwszExposed));
|
|
|
|
// Automatically call CoTaskMemFree on this pointer at the end of scope
|
|
CAutoComPointer ptrAutoCleanup(pwszExposed);
|
|
|
|
ft.WriteLine(L"- Shadow copy exposed as '%s'", pwszExposed);
|
|
}
|
|
|
|
|
|
|
|
// Expose the given shadow copy set as a share
|
|
void VssClient::ExposeSnapshotRemotely(VSS_ID snapshotID, wstring shareName, wstring pathFromRoot)
|
|
{
|
|
FunctionTracer ft(DBG_INFO);
|
|
|
|
ft.WriteLine(L"- Exposing shadow copy " WSTR_GUID_FMT L" under the share '%s' (path from root: '%s')",
|
|
GUID_PRINTF_ARG(snapshotID), shareName.c_str(), pathFromRoot.c_str());
|
|
|
|
// Make sure that the expose operation is valid for this snapshot.
|
|
// Get the shadow copy properties
|
|
VSS_SNAPSHOT_PROP Snap;
|
|
HRESULT hr = m_pVssObject->GetSnapshotProperties(snapshotID, &Snap);
|
|
if (hr == VSS_E_OBJECT_NOT_FOUND)
|
|
{
|
|
ft.WriteLine(L"\nERROR: there is no snapshot with the given ID");
|
|
throw(E_INVALIDARG);
|
|
}
|
|
|
|
// Automatically call VssFreeSnapshotProperties on this structure at the end of scope
|
|
CAutoSnapPointer snapAutoCleanup(&Snap);
|
|
|
|
// Client Accessible snapshots are not exposable
|
|
if (Snap.m_lSnapshotAttributes & VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE)
|
|
{
|
|
ft.WriteLine(L"\nERROR: the snapshot ID identifies a Client Accessible snapshot which cannot be exposed");
|
|
throw(E_INVALIDARG);
|
|
}
|
|
|
|
// Client Accessible snapshots are not exposable
|
|
if ((Snap.m_pwszExposedName != NULL) || (Snap.m_pwszExposedPath != NULL))
|
|
{
|
|
ft.WriteLine(L"\nERROR: Client-accessible (SFSF) snapshots cannot be exposed.");
|
|
throw(E_INVALIDARG);
|
|
}
|
|
|
|
// Note: a true reqestor should also check here if
|
|
// - the remote share name is valid (i.e. unused)
|
|
// - the path from root is valid
|
|
|
|
// The path from root represents where to put the share on the snapshot volume.
|
|
// If the share is on root, then use a NULL argument
|
|
LPWSTR pwszPathFromRoot = NULL;
|
|
if (pathFromRoot.length() != 0)
|
|
pwszPathFromRoot = (VSS_PWSZ)pathFromRoot.c_str();
|
|
|
|
// Expose locally the shadow copy set
|
|
LPWSTR pwszExposed = NULL;
|
|
CHECK_COM(m_pVssObject->ExposeSnapshot(snapshotID,
|
|
pwszPathFromRoot,
|
|
VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY,
|
|
(VSS_PWSZ)shareName.c_str(),
|
|
&pwszExposed));
|
|
|
|
// Automatically call CoTaskMemFree on this pointer at the end of scope
|
|
CAutoComPointer ptrAutoCleanup(pwszExposed);
|
|
|
|
ft.WriteLine(L"- Shadow copy exposed as '%s'", pwszExposed);
|
|
}
|
|
|
|
|