/* **++ ** ** Copyright (c) 2000-2001 Microsoft Corporation ** ** ** Module Name: ** ** util.cpp ** ** ** Abstract: ** ** Sample program to ** - obtain and display the Writer metadata. ** - create a snapshot set ** ** Author: ** ** Adi Oltean [aoltean] 05-Dec-2000 ** ** The sample is based on the Metasnap test program written by Michael C. Johnson. ** ** ** Revision History: ** **-- */ /////////////////////////////////////////////////////////////////////////////// // Includes #include "vsreq.h" /////////////////////////////////////////////////////////////////////////////// // Print usage void CVssSampleRequestor::PrintUsage() { wprintf( L"\nUsage:\n" L" vsreq [-b] [-s] [-x ] []\n" L"\nOptions:\n" L" -b Backup includes bootable & system state.\n" L" -s Enable component selection.\n" L" -x Generate an XML file containing the backup metadata\n" L" Specifies the volumes to be part of the snapshot set\n" L" The volumes in the list must be distinct and \n" L" must be separated by space. A volume must be \n" L" terminated with a trailing backslask (for example C:\\).\n" L"\n" L"\nExample:\n" L" The following command will create a snapshot set\n" L" on the volumes mounted under c:\\ and d:\\\n" L"\n" L" vsreq c:\\ d:\\ \n" L"\n" L" The following command will create a snapshot set on the volumes \n" L" that contain selected components and also the volume c:\\\n" L" Also, the backup will contain bootable and system state.\n" L" The XML results will be stored in file.xml\n" L"\n" L" vsreq -b -s -x file.xml c:\\ \n" ); throw(2); } void CVssSampleRequestor::ParseCommandLine( IN INT nArgsCount, IN WCHAR ** ppwszArgsArray ) { if (nArgsCount == 0) PrintUsage(); // For each argument in the command line bool bParsingVolumes = false; INT nCurrentArg = nArgsCount; WCHAR ** ppwszCurrentArg = ppwszArgsArray; for(; nCurrentArg--; ppwszCurrentArg++) { if (!bParsingVolumes) { // Check for Bootable & system state option if (!m_bBootableSystemState && !wcscmp(*ppwszCurrentArg, L"-b")) { m_bBootableSystemState = true; continue; } // Check for Selected components option if (!m_bComponentSelectionEnabled && !wcscmp(*ppwszCurrentArg, L"-s")) { m_bComponentSelectionEnabled = true; continue; } // Check for Xml file option if (!m_pwszXmlFile && !wcscmp(*ppwszCurrentArg, L"-x")) { if (nCurrentArg-- == 0) return PrintUsage(); ppwszCurrentArg++; m_pwszXmlFile = *ppwszCurrentArg; continue; } } // We suppose that the next arguments are the volumes bParsingVolumes = true; // Add the volume to the list of snapshotting volumes // Make sure that the volume name is valid bool bAdded = false; if (!AddVolume(*ppwszCurrentArg, bAdded)) { wprintf(L"\nError while parsing the command line:\n" L"\t%s is not a valid option or a mount point [0x%08lx]\n\n", *ppwszCurrentArg, GetLastError() ); PrintUsage(); } // Check if the same volume is added twice if (!bAdded) { wprintf(L"\nError while parsing the command line:\n" L"\tThe volume %s is specified twice\n\n", *ppwszCurrentArg ); PrintUsage(); } } // Check if we added at least one volume if ((m_nVolumesCount == 0) && !m_bComponentSelectionEnabled) { wprintf(L"\nError while parsing the command line:\n" L"\t- You should specify at least one volume or enable component selection\n\n"); PrintUsage(); } } // Add the given volume by the contained path void CVssSampleRequestor::AddVolumeForComponent( IN IVssWMFiledesc* pFileDesc ) { // Get the component path CComBSTR bstrPath; CHECK_SUCCESS(pFileDesc->GetPath(&bstrPath)); // Trying to find the volume that will contain the path. WCHAR wszExpandedPath[MAX_TEXT_BUFFER]; if (!ExpandEnvironmentStringsW(bstrPath, wszExpandedPath, MAX_TEXT_BUFFER)) Error( 1, L"\nExpandEnvironmentStringsW(%s, wszExpandedPath, MAX_TEXT_BUFFER) failed with [0x%08lx]\n", bstrPath, GetLastError()); // Eliminate one by one the terminating folder names, until we reach an existing path. // Then get the volume name for that path WCHAR wszMountPoint[MAX_TEXT_BUFFER]; while(true) { if (GetVolumePathNameW(wszExpandedPath, wszMountPoint, MAX_TEXT_BUFFER)) break; if (GetLastError() != ERROR_FILE_NOT_FOUND) Error( 1, L"\nGetVolumePathNameW(%s, wszMountPoint, MAX_TEXT_BUFFER) failed with [0x%08lx]\n", wszExpandedPath, GetLastError()); WCHAR* pwszLastBackslashIndex = wcsrchr(wszExpandedPath, L'\\'); if (!pwszLastBackslashIndex) Error( 1, L"\nCannot find anymore a backslash in path %s. \n" L"The original path %s seems invalid.\n", wszExpandedPath, bstrPath); // Eliminate the last folder name pwszLastBackslashIndex[0] = L'\0'; } // Add the volume, if possible bool bAdded = false; if (!AddVolume( wszMountPoint, bAdded )) Error( 1, L"\nUnexpected error: cannot add volume %s to the snapshot set.\n", wszMountPoint); wprintf (L" [Volume %s (that contains the file) %s marked as a candidate for snapshot]\n", wszMountPoint, bAdded? L"is": L"is already"); } // Add the given volume in the list of potential candidates for snapshots // - Returns "false" if the volume does not correspond to a real mount point // (and GetLastError() will contain the correct Win32 error code) // - Sets "true" in the bAdded parameter if the volume is actually added bool CVssSampleRequestor::AddVolume( IN WCHAR* pwszVolume, OUT bool & bAdded ) { // Initialize [out] parameters bAdded = false; // Check if the volume represents a real mount point WCHAR wszVolumeName[MAX_TEXT_BUFFER]; if (!GetVolumeNameForVolumeMountPoint(pwszVolume, wszVolumeName, MAX_TEXT_BUFFER)) return false; // Invalid volume // Check if the volume is already added. for (INT nIndex = 0; nIndex < m_nVolumesCount; nIndex++) if (!wcscmp(wszVolumeName, m_ppwszVolumeNamesList[nIndex])) return true; // Volume already added. Stop here. // Check if we exceeded the maximum number of volumes if (m_nVolumesCount == MAX_VOLUMES) Error( 1, L"Maximum number of volumes exceeded"); // Create a copy of the volume WCHAR* pwszNewVolume = _wcsdup(pwszVolume); if (pwszNewVolume == NULL) Error( 1, L"Memory allocation error"); // Create a copy of the volume name WCHAR* pwszNewVolumeName = _wcsdup(wszVolumeName); if (pwszNewVolumeName == NULL) { free(pwszNewVolume); Error( 1, L"Memory allocation error"); } // Add the volume in our internal list of snapshotted volumes m_ppwszVolumesList[m_nVolumesCount] = pwszNewVolume; m_ppwszVolumeNamesList[m_nVolumesCount] = pwszNewVolumeName; m_nVolumesCount++; bAdded = true; return true; } // This function displays the formatted message at the console and throws // The passed return code will be returned by vsreq.exe void CVssSampleRequestor::Error( IN INT nReturnCode, IN const WCHAR* pwszMsgFormat, IN ... ) { va_list marker; va_start( marker, pwszMsgFormat ); vwprintf( pwszMsgFormat, marker ); va_end( marker ); // throw that return code. throw(nReturnCode); } /////////////////////////////////////////////////////////////////////////////// // Utility functions // Print a file description object void CVssSampleRequestor::PrintFiledesc (IVssWMFiledesc *pFiledesc, LPCWSTR wszDescription) { CComBSTR bstrPath; CComBSTR bstrFilespec; CComBSTR bstrAlternate; bool bRecursive; CHECK_SUCCESS(pFiledesc->GetPath(&bstrPath)); CHECK_SUCCESS(pFiledesc->GetFilespec (&bstrFilespec)); CHECK_NOFAIL(pFiledesc->GetRecursive(&bRecursive)); CHECK_NOFAIL(pFiledesc->GetAlternateLocation(&bstrAlternate)); wprintf (L"%s\n" L" Path = %s\n" L" Filespec = %s\n" L" Recursive = %s\n", wszDescription, bstrPath, bstrFilespec, bRecursive ? L"yes" : L"no"); if (bstrAlternate && wcslen (bstrAlternate) > 0) wprintf(L" Alternate Location = %s\n", bstrAlternate); } // Convert a usage type into a string LPCWSTR CVssSampleRequestor::GetStringFromUsageType (VSS_USAGE_TYPE eUsageType) { LPCWSTR pwszRetString = L"UNDEFINED"; switch (eUsageType) { case VSS_UT_BOOTABLESYSTEMSTATE: pwszRetString = L"BootableSystemState"; break; case VSS_UT_SYSTEMSERVICE: pwszRetString = L"SystemService"; break; case VSS_UT_USERDATA: pwszRetString = L"UserData"; break; case VSS_UT_OTHER: pwszRetString = L"Other"; break; default: break; } return (pwszRetString); } // Convert a source type into a string LPCWSTR CVssSampleRequestor::GetStringFromSourceType (VSS_SOURCE_TYPE eSourceType) { LPCWSTR pwszRetString = L"UNDEFINED"; switch (eSourceType) { case VSS_ST_TRANSACTEDDB: pwszRetString = L"TransactionDb"; break; case VSS_ST_NONTRANSACTEDDB: pwszRetString = L"NonTransactionDb"; break; case VSS_ST_OTHER: pwszRetString = L"Other"; break; default: break; } return (pwszRetString); } // Convert a restore method into a string LPCWSTR CVssSampleRequestor::GetStringFromRestoreMethod (VSS_RESTOREMETHOD_ENUM eRestoreMethod) { LPCWSTR pwszRetString = L"UNDEFINED"; switch (eRestoreMethod) { case VSS_RME_RESTORE_IF_NOT_THERE: pwszRetString = L"RestoreIfNotThere"; break; case VSS_RME_RESTORE_IF_CAN_REPLACE: pwszRetString = L"RestoreIfCanReplace"; break; case VSS_RME_STOP_RESTORE_START: pwszRetString = L"StopRestoreStart"; break; case VSS_RME_RESTORE_TO_ALTERNATE_LOCATION: pwszRetString = L"RestoreToAlternateLocation"; break; case VSS_RME_RESTORE_AT_REBOOT: pwszRetString = L"RestoreAtReboot"; break; case VSS_RME_CUSTOM: pwszRetString = L"Custom"; break; default: break; } return (pwszRetString); } // Convert a writer restore method into a string LPCWSTR CVssSampleRequestor::GetStringFromWriterRestoreMethod (VSS_WRITERRESTORE_ENUM eWriterRestoreMethod) { LPCWSTR pwszRetString = L"UNDEFINED"; switch (eWriterRestoreMethod) { case VSS_WRE_NEVER: pwszRetString = L"RestoreNever"; break; case VSS_WRE_IF_REPLACE_FAILS: pwszRetString = L"RestoreIfReplaceFailsI"; break; case VSS_WRE_ALWAYS: pwszRetString = L"RestoreAlways"; break; default: break; } return (pwszRetString); } // Convert a component type into a string LPCWSTR CVssSampleRequestor::GetStringFromComponentType (VSS_COMPONENT_TYPE eComponentType) { LPCWSTR pwszRetString = L"UNDEFINED"; switch (eComponentType) { case VSS_CT_DATABASE: pwszRetString = L"Database"; break; case VSS_CT_FILEGROUP: pwszRetString = L"FileGroup"; break; default: break; } return (pwszRetString); } // Convert a failure type into a string LPCWSTR CVssSampleRequestor::GetStringFromFailureType(HRESULT hrStatus) { LPCWSTR pwszFailureType = L""; switch (hrStatus) { case VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT: pwszFailureType = L"VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT"; break; case VSS_E_WRITERERROR_OUTOFRESOURCES: pwszFailureType = L"VSS_E_WRITERERROR_OUTOFRESOURCES"; break; case VSS_E_WRITERERROR_TIMEOUT: pwszFailureType = L"VSS_E_WRITERERROR_TIMEOUT"; break; case VSS_E_WRITERERROR_NONRETRYABLE: pwszFailureType = L"VSS_E_WRITERERROR_NONRETRYABLE"; break; case VSS_E_WRITERERROR_RETRYABLE: pwszFailureType = L"VSS_E_WRITERERROR_RETRYABLE"; break; case VSS_E_BAD_STATE: pwszFailureType = L"VSS_E_BAD_STATE"; break; case VSS_E_PROVIDER_ALREADY_REGISTERED: pwszFailureType = L"VSS_E_PROVIDER_ALREADY_REGISTERED"; break; case VSS_E_PROVIDER_NOT_REGISTERED: pwszFailureType = L"VSS_E_PROVIDER_NOT_REGISTERED"; break; case VSS_E_PROVIDER_VETO: pwszFailureType = L"VSS_E_PROVIDER_VETO"; break; case VSS_E_PROVIDER_IN_USE: pwszFailureType = L"VSS_E_PROVIDER_IN_USE"; break; case VSS_E_OBJECT_NOT_FOUND: pwszFailureType = L"VSS_E_OBJECT_NOT_FOUND"; break; case VSS_S_ASYNC_PENDING: pwszFailureType = L"VSS_S_ASYNC_PENDING"; break; case VSS_S_ASYNC_FINISHED: pwszFailureType = L"VSS_S_ASYNC_FINISHED"; break; case VSS_S_ASYNC_CANCELLED: pwszFailureType = L"VSS_S_ASYNC_CANCELLED"; break; case VSS_E_VOLUME_NOT_SUPPORTED: pwszFailureType = L"VSS_E_VOLUME_NOT_SUPPORTED"; break; case VSS_E_VOLUME_NOT_SUPPORTED_BY_PROVIDER: pwszFailureType = L"VSS_E_VOLUME_NOT_SUPPORTED_BY_PROVIDER"; break; case VSS_E_OBJECT_ALREADY_EXISTS: pwszFailureType = L"VSS_E_OBJECT_ALREADY_EXISTS"; break; case VSS_E_UNEXPECTED_PROVIDER_ERROR: pwszFailureType = L"VSS_E_UNEXPECTED_PROVIDER_ERROR"; break; case VSS_E_CORRUPT_XML_DOCUMENT: pwszFailureType = L"VSS_E_CORRUPT_XML_DOCUMENT"; break; case VSS_E_INVALID_XML_DOCUMENT: pwszFailureType = L"VSS_E_INVALID_XML_DOCUMENT"; break; case VSS_E_MAXIMUM_NUMBER_OF_VOLUMES_REACHED: pwszFailureType = L"VSS_E_MAXIMUM_NUMBER_OF_VOLUMES_REACHED"; break; case VSS_E_FLUSH_WRITES_TIMEOUT: pwszFailureType = L"VSS_E_FLUSH_WRITES_TIMEOUT"; break; case VSS_E_HOLD_WRITES_TIMEOUT: pwszFailureType = L"VSS_E_HOLD_WRITES_TIMEOUT"; break; case VSS_E_UNEXPECTED_WRITER_ERROR: pwszFailureType = L"VSS_E_UNEXPECTED_WRITER_ERROR"; break; case VSS_E_SNAPSHOT_SET_IN_PROGRESS: pwszFailureType = L"VSS_E_SNAPSHOT_SET_IN_PROGRESS"; break; case VSS_E_MAXIMUM_NUMBER_OF_SNAPSHOTS_REACHED: pwszFailureType = L"VSS_E_MAXIMUM_NUMBER_OF_SNAPSHOTS_REACHED"; break; case VSS_E_WRITER_INFRASTRUCTURE: pwszFailureType = L"VSS_E_WRITER_INFRASTRUCTURE"; break; case VSS_E_WRITER_NOT_RESPONDING: pwszFailureType = L"VSS_E_WRITER_NOT_RESPONDING"; break; case VSS_E_WRITER_ALREADY_SUBSCRIBED: pwszFailureType = L"VSS_E_WRITER_ALREADY_SUBSCRIBED"; break; case NOERROR: default: break; } return (pwszFailureType); } // Convert a writer status into a string LPCWSTR CVssSampleRequestor::GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus) { LPCWSTR pwszRetString = L"UNDEFINED"; switch (eWriterStatus) { case VSS_WS_STABLE: pwszRetString = L"STABLE"; break; case VSS_WS_WAITING_FOR_FREEZE: pwszRetString = L"WAITING_FOR_FREEZE"; break; case VSS_WS_WAITING_FOR_THAW: pwszRetString = L"WAITING_FOR_THAW"; break; case VSS_WS_WAITING_FOR_BACKUP_COMPLETE:pwszRetString = L"VSS_WS_WAITING_FOR_BACKUP_COMPLETE"; break; case VSS_WS_FAILED_AT_IDENTIFY: pwszRetString = L"FAILED_AT_IDENTIFY"; break; case VSS_WS_FAILED_AT_PREPARE_BACKUP: pwszRetString = L"FAILED_AT_PREPARE_BACKUP";break; case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT: pwszRetString = L"VSS_WS_FAILED_AT_PREPARE_SNAPSHOT"; break; case VSS_WS_FAILED_AT_FREEZE: pwszRetString = L"FAILED_AT_FREEZE"; break; case VSS_WS_FAILED_AT_THAW: pwszRetString = L"FAILED_AT_THAW"; break; default: break; } return (pwszRetString); }