/*++ © 1998 Seagate Software, Inc. All rights reserved Module Name: RmsServr.cpp Abstract: Implementation of CRmsServer Author: Brian Dodd [brian] 15-Nov-1996 Revision History: --*/ #include "stdafx.h" //#include //using namespace std ; //#pragma warning (disable : 4786) //using namespace std ; #include #include #include "RmsServr.h" #include "rsbuild.h" #include "wsb.h" #include "ntverp.h" #define PERSIST_CHECK_VALUE 0x526f6e57 #if 0 #define DebugPrint(a) { \ CWsbStringPtr out = a; \ out.Prepend(L": "); \ out.Prepend(WsbLongAsString(GetCurrentThreadId())); \ OutputDebugString((WCHAR *) out); \ } #else #define DebugPrint(a) #endif // DBG // This is made global so that anybody in the context of the server has // quick access to it IRmsServer *g_pServer = 0; ///////////////////////////////////////////////////////////////////////////// // CComObjectRoot HRESULT CRmsServer::FinalConstruct(void) /*++ Routine Description: This method does some initialization of the object that is necessary after construction. Arguments: None. Return Value: S_OK Anything returned by CWsbPersistStream::FinalConstruct(). --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::FinalConstruct"), OLESTR("")); // Zeroing global variable g_pServer = 0; CComQIPtr pObject = this; try { WsbAssertPointer( pObject ); CWsbBstrPtr tmpString; WsbAssertHr( CWsbPersistStream::FinalConstruct() ); WsbAffirmHr( ChangeState( RmsServerStateStarting )); // Figure out where to store information and initialize trace. // Setup the collections WsbAssertHr(CoCreateInstance( CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER, IID_IWsbIndexedCollection, (void **)&m_pCartridges )); WsbAssertHr(CoCreateInstance( CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER, IID_IWsbIndexedCollection, (void **)&m_pActiveCartridges )); WsbAssertHr(CoCreateInstance( CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER, IID_IWsbIndexedCollection, (void **)&m_pDataMovers )); WsbAssertHr(CoCreateInstance( CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER, IID_IWsbIndexedCollection, (void **)&m_pLibraries )); WsbAssertHr(CoCreateInstance( CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER, IID_IWsbIndexedCollection, (void **)&m_pMediaSets )); WsbAssertHr(CoCreateInstance( CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER, IID_IWsbIndexedCollection, (void **)&m_pRequests )); WsbAssertHr(CoCreateInstance( CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER, IID_IWsbIndexedCollection, (void **)&m_pClients )); WsbAssertHr(CoCreateInstance( CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER, IID_IWsbIndexedCollection, (void **)&m_pUnconfiguredDevices )); // Create NTMS object WsbAssertHr(CoCreateInstance( CLSID_CRmsNTMS, 0, CLSCTX_SERVER, IID_IRmsNTMS, (void **)&m_pNTMS )); // Get the name of the computer on which we running. CWsbStringPtr serverNameString; WsbAffirmHr( WsbGetComputerName( serverNameString )); m_ServerName = serverNameString; m_HardDrivesUsed = 0; m_LockReference = 0; WsbAffirmHr( ChangeState( RmsServerStateStarted )); } WsbCatchAndDo(hr, pObject->Disable( hr ); ); WsbTraceOut(OLESTR("CRmsServer::FinalConstruct"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } HRESULT CRmsServer::FinalRelease(void) /*++ Routine Description: This method does some uninitialization of the object that is necessary before destrucruction. Arguments: None. Return Value: S_OK --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::FinalRelease"), OLESTR("")); try { WsbAffirmHr( ChangeState( RmsServerStateStopping )); CWsbPersistStream::FinalRelease(); WsbAffirmHr( ChangeState( RmsServerStateStopped )); #ifdef WSB_TRACK_MEMORY (void) WsbObjectTracePointers(WSB_OTP_SEQUENCE | WSB_OTP_STATISTICS | WSB_OTP_ALLOCATED); (void) WsbObjectTraceTypes(); #endif } WsbCatch(hr); WsbTraceOut(OLESTR("CRmsServer::FinalRelease"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } STDMETHODIMP CRmsServer::InitializeInAnotherThread(void) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::InitializeInAnotherThread"), OLESTR("")); try { DWORD threadId; HANDLE hThread; WsbAffirmHandle(hThread = CreateThread(NULL, 1024, CRmsServer::InitializationThread, this, 0, &threadId)); CloseHandle(hThread); } WsbCatch(hr); WsbTraceOut(OLESTR("CRmsServer::InitializeInAnotherThread"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } DWORD WINAPI CRmsServer::InitializationThread( IN LPVOID pv) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::InitializationThread"), OLESTR("")); try { WsbAssertPointer(pv); CRmsServer *pServer = (CRmsServer*)pv; WsbAffirmHr(pServer->Initialize()); } WsbCatch(hr); WsbTraceOut(OLESTR("CRmsServer::InitializationThread"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } STDMETHODIMP CRmsServer::Initialize(void) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::Initialize"), OLESTR("")); CComQIPtr pObject = this; DWORD fixedDriveEnabled = RMS_DEFAULT_FIXED_DRIVE; DWORD size; OLECHAR tmpString[256]; if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_FIXED_DRIVE, tmpString, 256, &size))) { // Get the value. fixedDriveEnabled = wcstol(tmpString, NULL, 10); } DWORD opticalEnabled = RMS_DEFAULT_OPTICAL; if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_OPTICAL, tmpString, 256, &size))) { // Get the value. opticalEnabled = wcstol(tmpString, NULL, 10); } DWORD tapeEnabled = RMS_DEFAULT_TAPE; if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_TAPE, tmpString, 256, &size))) { // Get the value. tapeEnabled = wcstol(tmpString, NULL, 10); } DWORD dvdEnabled = RMS_DEFAULT_DVD; if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_DVD, tmpString, 256, &size))) { // Get the value. dvdEnabled = wcstol(tmpString, NULL, 10); } WsbTraceAlways(OLESTR("Fixed Drive Media Enabled: %ls\n"), WsbBoolAsString((BOOL)fixedDriveEnabled)); WsbTraceAlways(OLESTR("Optical Media Enabled: %ls\n"), WsbBoolAsString((BOOL)opticalEnabled)); WsbTraceAlways(OLESTR("Tape Media Enabled: %ls\n"), WsbBoolAsString((BOOL)tapeEnabled)); WsbTraceAlways(OLESTR("DVD Media Enabled: %ls\n"), WsbBoolAsString((BOOL)dvdEnabled)); try { if (0 == g_pServer) { // Set global variable for quick access (if not set yet) WsbAffirmHr(((IUnknown*)(IRmsServer *)this)->QueryInterface(IID_IRmsServer, (void**) &g_pServer)); // We don't want the reference count bumped for this global so release it here. g_pServer->Release(); } // initializing WsbAssertPointer( pObject ); CWsbStringPtr tmpString; WsbAffirmHr( ChangeState( RmsServerStateInitializing )); hr = IsNTMSInstalled(); if ( S_OK == hr ) { try { // Perform any initialization required for using NTMS subsystem. WsbAffirmHr( m_pNTMS->Initialize() ); } WsbCatch (hr); hr = S_OK; if (fixedDriveEnabled) { // Scan for drives. WsbAffirmHr( ScanForDrives() ); } // Resolve the devices detected by the scan. WsbAffirmHr( resolveUnconfiguredDevices() ); // Auto configure the remaining devices. WsbAffirmHr( autoConfigureDevices() ); // Try to dismount all of our medias, ignore errors HRESULT hrDismountAll = S_OK; try { CComPtr pEnumSets; CComPtr pMediaSet; CComPtr pObject; GUID mediaSetId; WsbAffirmHr(m_pMediaSets->Enum(&pEnumSets)); WsbAssertPointer(pEnumSets); hrDismountAll = pEnumSets->First(IID_IRmsMediaSet, (void **)&pMediaSet); while (S_OK == hrDismountAll) { WsbAffirmHr(pMediaSet->QueryInterface(IID_IRmsComObject, (void**) &pObject)); WsbAffirmHr(pObject->GetObjectId(&mediaSetId)); WsbAffirmHr(m_pNTMS->DismountAll(mediaSetId)); hrDismountAll = pEnumSets->Next(IID_IRmsMediaSet, (void **)&pMediaSet); } if (hrDismountAll == WSB_E_NOTFOUND) { hrDismountAll = S_OK; } else { WsbAffirmHr(hrDismountAll); } } WsbCatch(hrDismountAll); } else if ( RMS_E_NOT_CONFIGURED_FOR_NTMS == hr ) { hr = S_OK; // Scan for devices. WsbAffirmHr( ScanForDevices() ); if (fixedDriveEnabled) { // Scan for drives. WsbAffirmHr( ScanForDrives() ); } // Resolve the devices detected by the scan. WsbAffirmHr( resolveUnconfiguredDevices() ); // Auto configure the remaining devices. WsbAffirmHr( autoConfigureDevices() ); } else { // Some other NTMS connection failure (NTMS not installed, configured, or running) hr = S_OK; if (fixedDriveEnabled) { // Scan for drives. WsbAffirmHr( ScanForDrives() ); // Resolve the devices detected by the scan. WsbAffirmHr( resolveUnconfiguredDevices() ); // Auto configure the remaining devices. WsbAffirmHr( autoConfigureDevices() ); } } // Enable RMS process for backup operations. WsbAffirmHr( enableAsBackupOperator() ); // Save the configuration information. WsbAffirmHr( SaveAll() ); WsbAffirmHr( ChangeState( RmsServerStateReady )); WsbTraceAlways(OLESTR("RMS is ready.\n")); } WsbCatchAndDo(hr, pObject->Disable( hr ); ); WsbTraceOut(OLESTR("CRmsServer::Initialize"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } STDMETHODIMP CRmsServer::IsNTMSInstalled(void) { return m_pNTMS->IsInstalled(); } STDMETHODIMP CRmsServer::GetNTMS( OUT IRmsNTMS **ptr) /*++ Implements: IRmsServer::GetNTMS --*/ { HRESULT hr = E_FAIL; try { WsbAssertPointer( ptr ); *ptr = m_pNTMS; m_pNTMS->AddRef(); hr = S_OK; } WsbCatch( hr ); return hr; } // // Rms no longer save independently its own .col file, but only the NTMS database // STDMETHODIMP CRmsServer::SaveAll(void) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::SaveAll"), OLESTR("")); static BOOL saving = FALSE; try { WsbAffirm(!saving, S_FALSE); saving = TRUE; hr = m_pNTMS->ExportDatabase(); saving = FALSE; } WsbCatch(hr); WsbTraceOut(OLESTR("CRmsServer::SaveAll"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } STDMETHODIMP CRmsServer::Unload(void) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::Unload"), OLESTR("")); try { // We only need to release what may have gotten set/created by // a failed Load attempt. if (m_pCartridges) { WsbAffirmHr(m_pCartridges->RemoveAllAndRelease()); } if (m_pLibraries) { WsbAffirmHr(m_pLibraries->RemoveAllAndRelease()); } if (m_pMediaSets) { WsbAffirmHr(m_pMediaSets->RemoveAllAndRelease()); } if (m_pRequests) { WsbAffirmHr(m_pRequests->RemoveAllAndRelease()); } if (m_pClients) { WsbAffirmHr(m_pClients->RemoveAllAndRelease()); } } WsbCatch(hr); WsbTraceOut(OLESTR("CRmsServer::Unload"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } STDMETHODIMP CRmsServer::GetClassID( OUT CLSID* pClsid) /*++ Implements: IPersist::GetClassId --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::GetClassID"), OLESTR("")); try { WsbAssert(0 != pClsid, E_POINTER); *pClsid = CLSID_CRmsServer; } WsbCatch(hr); WsbTraceOut(OLESTR("CRmsServer::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid)); return hr; } STDMETHODIMP CRmsServer::GetSizeMax( OUT ULARGE_INTEGER* /*pcbSize*/) /*++ Implements: IPersistStream::GetSizeMax --*/ { HRESULT hr = E_NOTIMPL; // ULONG serverNameLen; // ULARGE_INTEGER cartridgesLen; // ULARGE_INTEGER librariesLen; // ULARGE_INTEGER mediaSetsLen; // ULARGE_INTEGER requestsLen; // ULARGE_INTEGER clientsLen; // ULARGE_INTEGER unconfiguredDevicesLen; // WsbTraceIn(OLESTR("CRmsServer::GetSizeMax"), OLESTR("")); // try { // WsbAssert(0 != pcbSize, E_POINTER); // m_pCartridges-> GetSizeMax (&cartridgesLen); // set up size of CRmsServer // pcbSize->QuadPart = WsbPersistSizeOf(ULONG) + // length of serverName // cartridgesLen.QuadPart; // m_pCartridges // } WsbCatch(hr); // WsbTraceOut(OLESTR("CRmsServer::GetSizeMax"), OLESTR("hr = <%ls>, Size = <%ls>"), WsbHrAsString(hr), WsbPtrToUliAsString(pcbSize)); return hr; } STDMETHODIMP CRmsServer::Load( IN IStream* pStream) /*++ Implements: IPersistStream::Load --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::Load"), OLESTR("")); // // Check if the global pointer is already set - if not, update it // (Today, Load is the only method that is executed before Initialize) // if (0 == g_pServer) { // Set global variable for quick access (if not set yet) WsbAffirmHr(((IUnknown*)(IRmsServer *)this)->QueryInterface(IID_IRmsServer, (void**) &g_pServer)); // We don't want the reference count bumped for this global so release it here. g_pServer->Release(); } // // Lock down the server while we are loading. // InterlockedIncrement( &m_LockReference ); // // The Load reverts the state, which is undesired for the server object. // Save away the original status information // BOOL bTemp = m_IsEnabled; LONG lTemp = m_State; HRESULT hrTemp = m_StatusCode; try { WsbAssertPointer(pStream); CComPtr pPersistStream; WsbAffirmHr(CRmsComObject::Load(pStream)); // Load the collections WsbAffirmHr(m_pMediaSets->QueryInterface(IID_IPersistStream, (void**) &pPersistStream)); WsbAffirmHr(pPersistStream->Load(pStream)); pPersistStream = 0; WsbAffirmHr(m_pCartridges->QueryInterface(IID_IPersistStream, (void**) &pPersistStream)); WsbAffirmHr(pPersistStream->Load(pStream)); pPersistStream = 0; WsbAffirmHr(m_pLibraries->QueryInterface(IID_IPersistStream, (void**) &pPersistStream)); WsbAffirmHr(pPersistStream->Load(pStream)); pPersistStream = 0; WsbAffirmHr(m_pRequests->QueryInterface(IID_IPersistStream, (void**) &pPersistStream)); WsbAffirmHr(pPersistStream->Load(pStream)); pPersistStream = 0; WsbAffirmHr(m_pClients->QueryInterface(IID_IPersistStream, (void**) &pPersistStream)); WsbAffirmHr(pPersistStream->Load(pStream)); pPersistStream = 0; // Check that we got everything ULONG check_value; WsbAffirmHr(WsbLoadFromStream(pStream, &check_value)); WsbAffirm(check_value == PERSIST_CHECK_VALUE, E_UNEXPECTED); } WsbCatch(hr); // Reset the object status information to their original settings. m_IsEnabled = bTemp; m_State = lTemp; m_StatusCode = hrTemp; // // Unlock the server. // InterlockedDecrement( &m_LockReference ); WsbTraceOut(OLESTR("CRmsServer::Load"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } STDMETHODIMP CRmsServer::Save( IN IStream* pStream, IN BOOL clearDirty) /*++ Implements: IPersistStream::Save --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::Save"), OLESTR("clearDirty = <%ls>"), WsbBoolAsString(clearDirty)); try { CComPtr pPersistStream; WsbAssertPointer(pStream); WsbAffirmHr(CRmsComObject::Save(pStream, clearDirty)); // Save the collections WsbAffirmHr(m_pMediaSets->QueryInterface(IID_IPersistStream, (void**) &pPersistStream)); WsbAffirmHr(pPersistStream->Save(pStream, clearDirty)); pPersistStream = 0; WsbAffirmHr(m_pCartridges->QueryInterface(IID_IPersistStream, (void**) &pPersistStream)); WsbAffirmHr(pPersistStream->Save(pStream, clearDirty)); pPersistStream = 0; WsbAffirmHr(m_pLibraries->QueryInterface(IID_IPersistStream, (void**) &pPersistStream)); WsbAffirmHr(pPersistStream->Save(pStream, clearDirty)); pPersistStream = 0; WsbAffirmHr(m_pRequests->QueryInterface(IID_IPersistStream, (void**) &pPersistStream)); WsbAffirmHr(pPersistStream->Save(pStream, clearDirty)); pPersistStream = 0; WsbAffirmHr(m_pClients->QueryInterface(IID_IPersistStream, (void**) &pPersistStream)); WsbAffirmHr(pPersistStream->Save(pStream, clearDirty)); pPersistStream = 0; // Put this at the end as a check during load ULONG check_value = PERSIST_CHECK_VALUE; WsbAffirmHr(WsbSaveToStream(pStream, check_value)); // Do we need to clear the dirty bit? if (clearDirty) { m_isDirty = FALSE; } } WsbCatch(hr); WsbTraceOut(OLESTR("CRmsServer::Save"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } ///////////////////////////////////////////////////////////////////////////// // IRmsServer STDMETHODIMP CRmsServer::GetServerName( OUT BSTR *pName) /*++ Implements: IRmsServer::GetServerName --*/ { WsbAssertPointer(pName); m_ServerName.CopyToBstr(pName); return S_OK; } STDMETHODIMP CRmsServer::GetCartridges( OUT IWsbIndexedCollection **ptr) /*++ Implements: IRmsServer::GetCartridges --*/ { HRESULT hr = S_OK; try { WsbAssertPointer(ptr); *ptr = m_pCartridges; m_pCartridges->AddRef(); } WsbCatch(hr) return hr; } STDMETHODIMP CRmsServer::GetActiveCartridges( OUT IWsbIndexedCollection **ptr) /*++ Implements: IRmsServer::GetActiveCartridges --*/ { HRESULT hr = S_OK; try { WsbAssertPointer(ptr); *ptr = m_pActiveCartridges; m_pActiveCartridges->AddRef(); } WsbCatch(hr) return hr; } STDMETHODIMP CRmsServer::GetDataMovers( OUT IWsbIndexedCollection **ptr) /*++ Implements: IRmsServer::GetDataMovers --*/ { HRESULT hr = S_OK; try { WsbAssertPointer(ptr); *ptr = m_pDataMovers; m_pDataMovers->AddRef(); } WsbCatch(hr) return hr; } STDMETHODIMP CRmsServer::SetActiveCartridge( IN IRmsCartridge *ptr) /*++ Implements: IRmsServer::SetActiveCartridge --*/ { HRESULT hr = S_OK; try { if (m_pActiveCartridge) { m_pActiveCartridge = 0; } m_pActiveCartridge = ptr; } WsbCatch(hr) return hr; } STDMETHODIMP CRmsServer::GetLibraries( OUT IWsbIndexedCollection **ptr) /*++ Implements: IRmsServer::GetLibraries --*/ { HRESULT hr = S_OK; try { WsbAssertPointer(ptr); *ptr = m_pLibraries; m_pLibraries->AddRef(); } WsbCatch(hr) return hr; } STDMETHODIMP CRmsServer::GetMediaSets( OUT IWsbIndexedCollection **ptr) /*++ Implements: IRmsServer::GetMediaSets --*/ { HRESULT hr = S_OK; try { WsbAssertPointer(ptr); // We need to reinit NTMS to account for PNP devices. (void) m_pNTMS->Initialize(); *ptr = m_pMediaSets; m_pMediaSets->AddRef(); } WsbCatch(hr) return hr; } STDMETHODIMP CRmsServer::GetRequests( OUT IWsbIndexedCollection **ptr) /*++ Implements: IRmsServer::GetRequests --*/ { HRESULT hr = S_OK; try { WsbAssertPointer(ptr); *ptr = m_pRequests; m_pRequests->AddRef(); } WsbCatch(hr) return hr; } STDMETHODIMP CRmsServer::GetClients( OUT IWsbIndexedCollection **ptr) /*++ Implements: IRmsServer::GetClients --*/ { HRESULT hr = S_OK; try { WsbAssertPointer(ptr); *ptr = m_pClients; m_pClients->AddRef(); } WsbCatch(hr) return hr; } STDMETHODIMP CRmsServer::GetUnconfiguredDevices( OUT IWsbIndexedCollection **ptr) /*++ Implements: IRmsServer::GetUnconfiguredDevices --*/ { HRESULT hr = S_OK; try { WsbAssertPointer(ptr); *ptr = m_pUnconfiguredDevices; m_pUnconfiguredDevices->AddRef(); } WsbCatch(hr) return hr; } STDMETHODIMP CRmsServer::ScanForDevices(void) /*++ Implements: IRmsServer::ScanForDevices --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::ScanForDevices"), OLESTR("")); HANDLE portHandle = INVALID_HANDLE_VALUE; LONGLONG trace = 0; try { // WsbAssertPointer( g_pTrace ); BOOL status; DWORD accessMode = GENERIC_READ; DWORD shareMode = FILE_SHARE_READ; UCHAR portData[2048]; OLECHAR string[25]; ULONG returned; int portNumber = 0; // BOOL traceTimeStamp; // BOOL traceCount; // BOOL traceThreadId; // WsbAssertHr( g_pTrace->GetTraceSettings( &trace )); // WsbAssertHr( g_pTrace->SetTraceOff( WSB_TRACE_BIT_ALL )); // WsbAssertHr( g_pTrace->GetOutputFormat( &traceTimeStamp, &traceCount, &traceThreadId )); // WsbAssertHr( g_pTrace->SetOutputFormat( FALSE, FALSE, FALSE )); WsbTraceAlways( OLESTR("\n\n----- Begin Device Scan ---------------------------------------------------------------\n\n") ); // // Go to each SCSI adapter connected to the system and build // out the device list. // do { swprintf( string, OLESTR("\\\\.\\Scsi%d:"), portNumber ); portHandle = CreateFile( string, accessMode, shareMode, NULL, OPEN_EXISTING, 0, NULL ); if ( portHandle == INVALID_HANDLE_VALUE ) { break; // we're done } // // Get the inquiry data. // WsbAffirmStatus( DeviceIoControl( portHandle, IOCTL_SCSI_GET_INQUIRY_DATA, NULL, 0, portData, sizeof(portData), &returned, FALSE )); status = CloseHandle( portHandle ); portHandle = INVALID_HANDLE_VALUE; WsbAffirmStatus( status ); WsbAffirmHrOk( processInquiryData( portNumber, portData ) ); portNumber++; } while ( 1 ); WsbTraceAlways( OLESTR("\n\n----- End Device Scan -----------------------------------------------------------------\n\n") ); // WsbAssertHr( g_pTrace->SetOutputFormat( traceTimeStamp, traceCount, traceThreadId )); // WsbAssertHr( g_pTrace->SetTraceOn( trace )); hr = S_OK; } WsbCatchAndDo( hr, // if (g_pTrace) { // WsbAssertHr( g_pTrace->SetTraceOn( trace )); WsbTraceAlways( OLESTR("\n\n !!!!! ERROR !!!!! Device Scan Terminated.\n\n") ); // } if ( portHandle != INVALID_HANDLE_VALUE ) { CloseHandle( portHandle ); } ); WsbTraceOut(OLESTR("CRmsServer::ScanForDevices"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } STDMETHODIMP CRmsServer::ScanForDrives(void) /*++ Implements: IRmsServer::ScanForDrives --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::ScanForDrives"), OLESTR("")); try { // // Build out device objects for various drive types: fixed drives, removables, and CD-ROM. // These are all supported by the system, and have drive letters associated with them. // // Use best effort to dectect drives. If anything fails we just go on to the next one. // Get the unconfigured device list CComPtr pDevices; WsbAssertHr( this->GetUnconfiguredDevices( &pDevices )); // Get the drive letters const DWORD bufSize = 256; // 26*4 + 1 = 105 is all we really need OLECHAR driveLetters[bufSize]; DWORD len; // See if there are drives for us to support if ( getHardDrivesToUseFromRegistry( driveLetters, &len ) != S_OK ) { len = GetLogicalDriveStrings( bufSize, driveLetters ); } UINT type; // For each drive letter see if it is something managed // by RMS. m_HardDrivesUsed = 0; for ( DWORD i = 0; i < len; i += 4 ) { // drive letters have the form "A:\" try { type = GetDriveType( &driveLetters[i] ); switch ( type ) { case DRIVE_REMOVABLE: { WsbTrace( OLESTR("Removable Drive Detected: %C\n"), driveLetters[i] ); CComPtr pDevice; WsbAffirmHr( CoCreateInstance( CLSID_CRmsDrive, 0, CLSCTX_SERVER, IID_IRmsDevice, (void **)&pDevice )); CWsbBstrPtr name = &(driveLetters[i]); WsbAffirmHr( pDevice->SetDeviceName( name )); WsbAffirmHr( pDevice->SetDeviceType( RmsDeviceRemovableDisk )); // // Don't add it if it was already detected in the SCSI device scan // CComQIPtr pObject = pDevice; WsbAssertPointer( pObject ); WsbAffirmHr( pObject->SetFindBy( RmsFindByDeviceName )); if ( S_OK == pDevices->Contains( pDevice ) ) { break; } WsbAffirmHr( pDevices->Add( pDevice )); pDevice = 0; } break; case DRIVE_FIXED: { CWsbBstrPtr name = &(driveLetters[i]); WCHAR volumeName[32]; DWORD volumeSerialNumber; DWORD filenameLength; DWORD fileSystemFlags; WCHAR fileSystemName[32]; WsbAffirmStatus(GetVolumeInformation( (WCHAR *)name, volumeName, 32, &volumeSerialNumber, &filenameLength, &fileSystemFlags, fileSystemName, 32)); WsbTrace( OLESTR("Fixed Drive Detected : %ls <%ls/%d> [len=%d, flags=0x%08x] %ls\n"), (WCHAR *)name, volumeName, volumeSerialNumber, filenameLength, fileSystemFlags, fileSystemName ); // // Use any volume with name starting with RStor, Remote Stor, RemoteStor, RS // if ( (0 == _wcsnicmp(volumeName, L"RS", 2)) || (0 == _wcsnicmp(volumeName, L"Remote Stor", 11)) || (0 == _wcsnicmp(volumeName, L"RemoteStor", 10))) { CComPtr pDevice; WsbAffirmHr( CoCreateInstance( CLSID_CRmsDrive, 0, CLSCTX_SERVER, IID_IRmsDevice, (void **)&pDevice )); WsbAffirmHr( pDevice->SetDeviceName( name )); WsbAffirmHr( pDevice->SetDeviceType( RmsDeviceFixedDisk )); WsbAffirmHr( pDevices->Add( pDevice )); pDevice = 0; m_HardDrivesUsed++; WsbTrace( OLESTR(" %ls added to Collection of unconfigured devices.\n"), (WCHAR *)name ); } } break; case DRIVE_CDROM: { WsbTrace( OLESTR("CD-ROM Drive Detected : %C\n"), driveLetters[i] ); CComPtr pDevice; WsbAffirmHr( CoCreateInstance( CLSID_CRmsDrive, 0, CLSCTX_SERVER, IID_IRmsDevice, (void **)&pDevice )); CWsbBstrPtr name = &(driveLetters[i]); WsbAffirmHr( pDevice->SetDeviceName( name )); WsbAffirmHr( pDevice->SetDeviceType( RmsDeviceCDROM )); WsbAffirmHr( pDevices->Add( pDevice )); pDevice = 0; } break; case DRIVE_UNKNOWN: case DRIVE_REMOTE: case DRIVE_RAMDISK: default: break; } // switch drive types } WsbCatchAndDo(hr, hr = S_OK; // Best effort ); } // for each drive } WsbCatchAndDo( hr, WsbTraceAlways( OLESTR("\n\n !!!!! ERROR !!!!! Drive Scan Terminated.\n\n") ); hr = S_OK; // Best effort ); WsbTraceOut(OLESTR("CRmsServer::ScanForDrives"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } HRESULT CRmsServer::processInquiryData( IN int portNumber, IN UCHAR *pDataBuffer) /*++ Routine Description: Builds RMS device objects from adapter port scan data. Arguments: portNumber - The adapter port to be processed. pDataBuffer - The adapter port data. Return Value: S_OK --*/ { HRESULT hr = E_FAIL; try { PSCSI_ADAPTER_BUS_INFO adapterInfo; PSCSI_INQUIRY_DATA inquiryData; OLECHAR deviceString[25]; CComPtr pDevice; CComPtr pDevices; WsbAffirmHr( this->GetUnconfiguredDevices( &pDevices )); adapterInfo = (PSCSI_ADAPTER_BUS_INFO) pDataBuffer; WsbTraceAlways( OLESTR("Port: %d\n"), portNumber ); WsbTraceAlways( OLESTR("Bus TID LUN Claimed String Inquiry Header Other\n") ); WsbTraceAlways( OLESTR("--- --- --- ------- ---------------------------- ----------------------- --------------\n") ); for ( UCHAR i = 0; i < adapterInfo->NumberOfBuses; i++) { inquiryData = (PSCSI_INQUIRY_DATA) (pDataBuffer + adapterInfo->BusData[i].InquiryDataOffset); while (adapterInfo->BusData[i].InquiryDataOffset) { WsbTraceAlways( OLESTR(" %d %d %3d %s %.28S "), i, inquiryData->TargetId, inquiryData->Lun, (inquiryData->DeviceClaimed) ? "Y" : "N", &inquiryData->InquiryData[8] ); for ( UCHAR j = 0; j < 8; j++) { WsbTraceAlways( OLESTR("%02X "), inquiryData->InquiryData[j] ); } WsbTraceAlways( OLESTR("%d %3d "), inquiryData->InquiryDataLength, inquiryData->NextInquiryDataOffset ); switch ( inquiryData->InquiryData[0] & 0x1f ) { case DIRECT_ACCESS_DEVICE: // // Is this a SCSI removable disk? (Fixed drives are dealt with later in the scan) // if ( (inquiryData->InquiryData[1] & 0x80) && inquiryData->InquiryData[2] & 0x02) { // // The device is a SCSI removable hard drive, So... // Create the Drive object and add it to the collection of unconfigured devices. // try { if ( inquiryData->DeviceClaimed ) { WsbAffirmHr( CoCreateInstance(CLSID_CRmsDrive, NULL, CLSCTX_SERVER, IID_IRmsDevice, (void**) &pDevice)); WsbAffirmHr( pDevice->SetDeviceAddress( (BYTE)portNumber, i, inquiryData->TargetId, inquiryData->Lun )); WsbAffirmHr( pDevice->SetDeviceType( RmsDeviceRemovableDisk )); WsbAffirmHr( pDevice->SetDeviceInfo( &inquiryData->InquiryData[0], 36 )); // // find drive letter // try { WsbAffirmHr( findDriveLetter( (UCHAR)portNumber, i, inquiryData->TargetId, inquiryData->Lun, deviceString )) WsbTraceAlways( OLESTR("%ls"), deviceString ); WsbAffirmHr( pDevice->SetDeviceName( deviceString )); WsbAffirmHr(pDevices->Add( pDevice )); } WsbCatch(hr); pDevice = 0; } } WsbCatch(hr); } break; case SEQUENTIAL_ACCESS_DEVICE: // // Create the Drive object and add it // to the collection of unconfigured devices. // try { if ( inquiryData->DeviceClaimed ) { WsbAffirmHr( CoCreateInstance(CLSID_CRmsDrive, NULL, CLSCTX_SERVER, IID_IRmsDevice, (void**) &pDevice)); WsbAffirmHr( pDevice->SetDeviceAddress( (BYTE)portNumber, i, inquiryData->TargetId, inquiryData->Lun )); WsbAffirmHr( pDevice->SetDeviceType( RmsDeviceTape )); WsbAffirmHr( pDevice->SetDeviceInfo( &inquiryData->InquiryData[0], 36 )); // // Find tape name // try { WsbAffirmHr( getDeviceName( (UCHAR)portNumber, i, inquiryData->TargetId, inquiryData->Lun, deviceString )); WsbTraceAlways( OLESTR("%ls"), deviceString ); // Create the name to use when creating a handle CWsbBstrPtr name = deviceString; name.Prepend( OLESTR("\\\\.\\") ); WsbAffirmHr( pDevice->SetDeviceName( name )); WsbAffirmHr(pDevices->Add( pDevice )); } WsbCatch(hr); pDevice = 0; } } WsbCatch(hr); break; case WRITE_ONCE_READ_MULTIPLE_DEVICE: // // Supported as OPTICAL_DEVICE only // break; case READ_ONLY_DIRECT_ACCESS_DEVICE: // // we'll deal with CD-ROM later in the scan... // break; case OPTICAL_DEVICE: // // Create the Drive object and add it // to the collection of unconfigured devices. // try { if ( inquiryData->DeviceClaimed ) { WsbAffirmHr( CoCreateInstance(CLSID_CRmsDrive, NULL, CLSCTX_SERVER, IID_IRmsDevice, (void**) &pDevice)); WsbAffirmHr( pDevice->SetDeviceAddress( (BYTE)portNumber, i, inquiryData->TargetId, inquiryData->Lun )); WsbAffirmHr( pDevice->SetDeviceType( RmsDeviceOptical )); WsbAffirmHr( pDevice->SetDeviceInfo( &inquiryData->InquiryData[0], 36 )); // // Find drive letter // try { WsbAffirmHr( findDriveLetter( (UCHAR)portNumber, i, inquiryData->TargetId, inquiryData->Lun, deviceString )) WsbTraceAlways( OLESTR("%ls"), deviceString ); WsbAffirmHr( pDevice->SetDeviceName( deviceString )); WsbAffirmHr(pDevices->Add( pDevice )); } WsbCatch(hr); pDevice = 0; } } WsbCatch(hr); break; case MEDIUM_CHANGER: // // Create the Medium Changer object and add it // to the collection of unconfigured devices. // try { if ( inquiryData->DeviceClaimed ) { WsbAffirmHr( CoCreateInstance(CLSID_CRmsMediumChanger, NULL, CLSCTX_SERVER, IID_IRmsDevice, (void**) &pDevice)); WsbAffirmHr( pDevice->SetDeviceAddress( (BYTE)portNumber, i, inquiryData->TargetId, inquiryData->Lun )); WsbAffirmHr( pDevice->SetDeviceType( RmsDeviceChanger )); WsbAffirmHr( pDevice->SetDeviceInfo( &inquiryData->InquiryData[0], 36 )); // // Find library name // try { WsbAffirmHr( getDeviceName( (UCHAR)portNumber, i, inquiryData->TargetId, inquiryData->Lun, deviceString )); WsbTraceAlways( OLESTR("%ls"), deviceString ); // Create the name to use when creating a handle CWsbBstrPtr name = deviceString; name.Prepend( OLESTR("\\\\.\\") ); WsbAffirmHr( pDevice->SetDeviceName( name )); WsbAffirmHr(pDevices->Add( pDevice )); } WsbCatch(hr); } pDevice = 0; } WsbCatch(hr); break; } // switch device type WsbTraceAlways( OLESTR("\n") ); if (inquiryData->NextInquiryDataOffset == 0) { break; } inquiryData = (PSCSI_INQUIRY_DATA) (pDataBuffer + inquiryData->NextInquiryDataOffset); } // for each device } // for each bus WsbTraceAlways( OLESTR("\n\n") ); hr = S_OK; } WsbCatch(hr); return hr; } HRESULT CRmsServer::findDriveLetter( IN UCHAR portNo, IN UCHAR pathNo, IN UCHAR id, IN UCHAR lun, OUT OLECHAR *driveString) /*++ Routine Description: Find associated drive letter for defined parameters. Arguments: portNo - input port number. pathNo - input path number. id - input id. lun - input logical unit number. driveString - pointer to drive letter string to return. Return Value: S_OK - Success --*/ { HRESULT hr = E_FAIL; const DWORD bufSize = 256; // 26*4 + 1 = 105 is all we really need OLECHAR driveLetters[bufSize]; BOOL status; DWORD accessMode = 0, // just get some drive properties. shareMode = FILE_SHARE_READ; HANDLE driveHandle = INVALID_HANDLE_VALUE; SCSI_ADDRESS address; DWORD returned; OLECHAR string[25]; UINT uiType; try { // first find which drives are mapped. DWORD len = GetLogicalDriveStrings( bufSize, driveLetters ); for ( DWORD i = 0; (i < len) && (hr != S_OK); i += 4 ) { // drive letters have the form "A:\" uiType = GetDriveType( &driveLetters[i] ); switch ( uiType ) { case DRIVE_REMOVABLE: // // get the SCSI address of the device and see if it's a match. // swprintf( string, OLESTR("\\\\.\\%C:"), driveLetters[i] ); driveHandle = CreateFile( string, accessMode, shareMode, NULL, OPEN_EXISTING, 0, NULL); WsbAffirmHandle( driveHandle ); // // Get the address structure. // status = DeviceIoControl( driveHandle, IOCTL_SCSI_GET_ADDRESS, NULL, 0, &address, sizeof(SCSI_ADDRESS), &returned, FALSE ); if (!status ) { // // asking for the SCSI address is not always a valid request for // all types of drives, so getting an error here means we're // not talking to a SCSI device... so skip it. // break; // out of switch } // // Let's check the SCSI address and see if we get a match. // if ( (address.PortNumber == portNo) && (address.PathId == pathNo) && (address.TargetId == id) && (address.Lun == lun)) { // its a match... wcscpy( driveString, &driveLetters[i] ); hr = S_OK; } break; // out of switch } // switch // // Cleanup // if ( driveHandle != INVALID_HANDLE_VALUE ) { status = CloseHandle( driveHandle ); driveHandle = INVALID_HANDLE_VALUE; WsbAffirmStatus( status ); } } // for each drive letter } WsbCatchAndDo( hr, if ( driveHandle != INVALID_HANDLE_VALUE ) { CloseHandle(driveHandle); } ); return hr; } HRESULT CRmsServer::getDeviceName( IN UCHAR portNo, IN UCHAR pathNo, IN UCHAR id, IN UCHAR lun, OUT OLECHAR *deviceName) /*++ Routine Description: Get device name from selected parameters. Arguments: portNo - port number. pathNo - path number. id - id. lun - logical unit number. deviceName - pointer to returned device name. Return Value: S_OK - Success --*/ { HRESULT hr = S_FALSE; OLECHAR string[256]; DWORD len; OLECHAR name[25]; // just go to the registry and get the DeviceName swprintf( string, OLESTR("HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port %d\\Scsi Bus %d\\Target Id %d\\Logical Unit Id %d"), portNo, pathNo, id, lun ); hr = WsbGetRegistryValueString( NULL, string, OLESTR("DeviceName"), name, sizeof(name), &len ); if ( S_OK == hr ) { wcscpy( deviceName, name ); } return hr; } HRESULT CRmsServer::resolveUnconfiguredDevices(void) /*++ This method goes through the unconfigured device list, which is created by the ScanForDevices() method, and determines if a device has already been configured. If a device is already configured, it is removed from the unconfigured device list. --*/ { HRESULT hr = E_FAIL; WsbTraceIn(OLESTR("CRmsServer::resolveUnconfiguredDevices"), OLESTR("")); BOOL tracingPlatform = 0; try { CComPtr pDevices; CComPtr pLibs; CComPtr pDevice; CComPtr pEnumDevices; CComPtr pEnumLibs; RmsDevice type; BOOL deviceIsConfigured = FALSE; // WsbAssertPointer( g_pTrace ); // WsbAffirmHr( g_pTrace->GetTraceSetting( WSB_TRACE_BIT_PLATFORM, &tracingPlatform )); WsbAssertHr( GetLibraries( &pLibs ) ); WsbAffirmHr( pLibs->Enum( &pEnumLibs )); WsbAssertPointer( pEnumLibs ); WsbAssertHr( GetUnconfiguredDevices( &pDevices )); WsbAffirmHr( pDevices->Enum( &pEnumDevices )); WsbAssertPointer( pEnumDevices ); // start off with the first unconfigured device. hr = pEnumDevices->First( IID_IRmsDevice, (void **)&pDevice ); while ( S_OK == hr ) { try { CComPtr pLib; deviceIsConfigured = FALSE; // // If a device is already in a library, then it is configured and // should be removed from the list of unconfigured devices. // // To test if a device is in a library we simply go to each library // and try to find the device. // WsbAffirmHr( pDevice->GetDeviceType( (LONG *) &type ) ); WsbTrace(OLESTR("CRmsServer::resolveUnconfiguredDevices: external loop: device type = %ld\n"), (LONG)type); CComPtr pChangers; CComPtr pDrives; CComQIPtr pObject = pDevice; WsbAssertPointer( pObject ); // Set up search method for the changer WsbAffirmHr( pObject->SetFindBy( RmsFindByDeviceInfo )); // start off with the first library. hr = pEnumLibs->First( IID_IRmsLibrary, (void **)&pLib ); while ( S_OK == hr ) { try { WsbTrace(OLESTR("CRmsServer::resolveUnconfiguredDevices: internal loop: device type = %ld\n"), (LONG)type); switch ( type ) { case RmsDeviceChanger: { CComQIPtr pChanger = pDevice; WsbAffirmHr( pLib->GetChangers( &pChangers ) ); WsbAffirmHrOk( pChangers->Contains( pChanger )); deviceIsConfigured = TRUE; } break; default: { CComQIPtr pDrive = pDevice; WsbAffirmHr( pLib->GetDrives( &pDrives ) ); WsbAffirmHrOk( pDrives->Contains( pDrive )); deviceIsConfigured = TRUE; } break; } } WsbCatch(hr); if ( deviceIsConfigured ) { WsbAffirmHr( pDevices->RemoveAndRelease( pDevice )); break; } pLib = 0; hr = pEnumLibs->Next( IID_IRmsLibrary, (void **)&pLib ); } } WsbCatch(hr); pDevice = 0; if ( deviceIsConfigured ) hr = pEnumDevices->This( IID_IRmsDevice, (void **)&pDevice ); else hr = pEnumDevices->Next( IID_IRmsDevice, (void **)&pDevice ); } // if ( !tracingPlatform ) // WsbAffirmHr( g_pTrace->SetTraceOff( WSB_TRACE_BIT_PLATFORM ) ); hr = S_OK; } WsbCatch(hr); // WsbCatchAndDo( hr, // if (g_pTrace) { // if ( !tracingPlatform ) // g_pTrace->SetTraceOff( WSB_TRACE_BIT_PLATFORM ); // } // ); WsbTraceOut(OLESTR("CRmsServer::resolveUnconfiguredDevices"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } HRESULT CRmsServer::autoConfigureDevices(void) /*++ This method automatically configures supported devices for RMS. The algorythm simply goes through the list of unconfigured devices and adds them to the appropriate library. Eventually, we need to be smart about when to bypass the auto-config step in favor of adminstrative overrides, but for now we'll automatically configure everything we can. --*/ { // // for each device in the unconfigured list, check if it was previously configured, // if it is not add it to a library; otherwise delete it from the list of unconfigured devices. // HRESULT hr = E_FAIL; WsbTraceIn(OLESTR("CRmsServer::autoConfigureDevices"), OLESTR("")); try { CComPtr pDevices; CComPtr pLibs; CComPtr pCarts; CComPtr pDevice; CComPtr pEnumDevices; RmsDevice type; BOOL deviceWasConfigured; WsbAssertHr( GetUnconfiguredDevices( &pDevices )); WsbAssertHr( GetLibraries( &pLibs )); WsbAssertHr( GetCartridges( &pCarts )); WsbAffirmHr( pDevices->Enum( &pEnumDevices )); WsbAssertPointer( pEnumDevices ); // first find all the changer devices hr = pEnumDevices->First( IID_IRmsDevice, (void **)&pDevice ); while ( S_OK == hr ) { try { deviceWasConfigured = FALSE; WsbAffirmHr( pDevice->GetDeviceType( (LONG *) &type )); WsbTrace(OLESTR("CRmsServer::autoConfigureDevices: first loop: device type = %ld\n"), (LONG)type); switch ( type ) { case RmsDeviceChanger: { CComPtr pChangers; CComPtr pDrives; CComPtr pMediaSets; CComPtr pLib; CComPtr pMediaSet; CComQIPtr pChanger = pDevice; WsbAssertPointer( pChanger ); CComQIPtr pChangerElmt = pChanger; WsbAssertPointer( pChanger ); // Create a Library object WsbAffirmHr( CoCreateInstance( CLSID_CRmsLibrary, 0, CLSCTX_SERVER, IID_IRmsLibrary, (void **)&pLib )); // Fill in library info WsbAffirmHr( pLib->SetName( RMS_DEFAULT_OPTICAL_LIBRARY_NAME )); WsbAffirmHr( pLib->SetMediaSupported( RmsMedia8mm /*RmsMediaOptical*/ )); // Add the library to the server's collection WsbAffirmHr( pLibs->Add( pLib )); // Create a media set WsbAffirmHr( CoCreateInstance( CLSID_CRmsMediaSet, 0, CLSCTX_SERVER, IID_IRmsMediaSet, (void **)&pMediaSet )); // Fill in media set info WsbAffirmHr( pMediaSet->SetName( RMS_DEFAULT_OPTICAL_MEDIASET_NAME )); WsbAffirmHr( pMediaSet->SetMediaSupported( RmsMedia8mm /*RmsMediaOptical*/ )); WsbAffirmHr( pMediaSet->SetMediaSetType( RmsMediaSetLibrary ) ); // Add the media set the libary's collection WsbAssertHr( pLib->GetMediaSets( &pMediaSets )); WsbAssertPointer( pMediaSets ); WsbAffirmHr( pMediaSets->Add( pMediaSet )); pMediaSets = 0; // Add the media set the server's collection WsbAssertHr( GetMediaSets( &pMediaSets ) ); WsbAssertPointer( pMediaSets ); WsbAffirmHr( pMediaSets->Add( pMediaSet )); // Add the changer device to the library's collection WsbAffirmHr( pLib->GetChangers( &pChangers )); WsbAssertPointer( pChangers ); WsbAffirmHr( pChangers->Add( pChanger )); // Set the changer's element information GUID libId; WsbAffirmHr( pLib->GetLibraryId( &libId )); WsbAffirmHr( pChangerElmt->SetLocation( RmsElementChanger, libId, GUID_NULL, 0, 0, 0, 0, FALSE)); WsbAffirmHr( pChangerElmt->SetMediaSupported( RmsMedia8mm /*RmsMediaOptical*/ )); // Initialize the changer device WsbAffirmHr( pChanger->Initialize() ); deviceWasConfigured = TRUE; } break; default: break; } } WsbCatch(hr); pDevice = 0; if ( deviceWasConfigured ) hr = pEnumDevices->This( IID_IRmsDevice, (void **)&pDevice ); else hr = pEnumDevices->Next( IID_IRmsDevice, (void **)&pDevice ); } // any remaining devices are stand alone drives. hr = pEnumDevices->First( IID_IRmsDevice, (void **)&pDevice ); while ( S_OK == hr ) { try { deviceWasConfigured = FALSE; WsbAffirmHr( hr = pDevice->GetDeviceType( (LONG *) &type )); WsbTrace(OLESTR("CRmsServer::autoConfigureDevices: second loop: device type = %ld\n"), (LONG)type); switch ( type ) { case RmsDeviceFixedDisk: // find the fixed disk library and add this drive. { CComPtr pDrives; CComPtr pMediaSets; CComPtr pFixedLib; CComPtr pFixedMediaSet; CComPtr pFindLib; CComPtr pCart; GUID libId = GUID_NULL; GUID mediaSetId = GUID_NULL; ULONG driveNo; CComQIPtr pDriveElmt = pDevice; WsbAssertPointer( pDriveElmt ); CComQIPtr pDrive = pDevice; WsbAssertPointer( pDrive ); WsbAffirmHr( CoCreateInstance( CLSID_CRmsLibrary, 0, CLSCTX_SERVER, IID_IRmsLibrary, (void **)&pFindLib )); // Set up the find template WsbAffirmHr( pFindLib->SetMediaSupported( RmsMediaFixed )); CComQIPtr pObject = pFindLib; WsbAffirmHr( pObject->SetFindBy( RmsFindByMediaSupported )); // Find the library hr = pLibs->Find( pFindLib, IID_IRmsLibrary, (void **)&pFixedLib ); if ( WSB_E_NOTFOUND == hr ) { // We don't have a fixed drive library yet, so create one... WsbAffirmHr( CoCreateInstance( CLSID_CRmsLibrary, 0, CLSCTX_SERVER, IID_IRmsLibrary, (void **)&pFixedLib )); WsbAffirmHr( pFixedLib->SetName( RMS_DEFAULT_FIXEDDRIVE_LIBRARY_NAME )); WsbAffirmHr( pFixedLib->SetMediaSupported( RmsMediaFixed )); WsbAffirmHr( pLibs->Add( pFixedLib )); CComPtr pMediaSet; WsbAffirmHr( CoCreateInstance( CLSID_CRmsMediaSet, 0, CLSCTX_SERVER, IID_IRmsMediaSet, (void **)&pMediaSet )); WsbAffirmHr( pMediaSet->SetName( RMS_DEFAULT_FIXEDDRIVE_MEDIASET_NAME )); WsbAffirmHr( pMediaSet->SetMediaSupported( RmsMediaFixed )); WsbAffirmHr( pMediaSet->SetMediaSetType( RmsMediaSetLibrary ) ); // Add the media set the libary's collection WsbAssertHr( pFixedLib->GetMediaSets( &pMediaSets )); WsbAssertPointer( pMediaSets ); WsbAffirmHr( pMediaSets->Add( pMediaSet )); pMediaSets = 0; // Add the media set the server's collection WsbAssertHr( GetMediaSets( &pMediaSets ) ); WsbAssertPointer( pMediaSets ); WsbAffirmHr( pMediaSets->Add( pMediaSet )); DWORD num; WsbAffirmHr( pMediaSets->GetEntries( &num )); pMediaSets = 0; WsbTrace(OLESTR("CRmsServer::autoConfigureDevices - type %d CRmsMediaSet created.\n"), RmsMediaFixed); WsbTrace(OLESTR("CRmsServer::autoConfigureDevices - Number of sets = %d.\n"), num); } // Add the drive to the library WsbAssertHr( pFixedLib->GetDrives( &pDrives )); WsbAffirmHr( pDrives->Add( pDevice )); WsbAffirmHr( pDrives->GetEntries( &driveNo )); // Remove the drive form the unconfigured list WsbAffirmHr( pDevices->RemoveAndRelease( pDevice )); deviceWasConfigured = TRUE; // Get library information WsbAssertHr( pFixedLib->GetMediaSets( &pMediaSets )); WsbAffirmHr( pFixedLib->GetLibraryId( &libId )); WsbAffirmHr( pMediaSets->First( IID_IRmsMediaSet, (void **)&pFixedMediaSet )); WsbAffirmHr( pFixedMediaSet->GetMediaSetId( &mediaSetId )); // Set the location WsbAffirmHr( pDriveElmt->SetLocation( RmsElementDrive, libId, mediaSetId, driveNo-1, 0, 0, 0, 0 )); // Set the kind of media supported WsbAffirmHr( pDriveElmt->SetMediaSupported( RmsMediaFixed )); // Create a cartridge for the media in the drive. WsbAffirmHr( CoCreateInstance( CLSID_CRmsCartridge, 0, CLSCTX_SERVER, IID_IRmsCartridge, (void **)&pCart )); WsbAffirmHr( pCart->SetLocation( RmsElementDrive, libId, mediaSetId, driveNo-1, 0, 0, 0, 0 )); WsbAffirmHr( pCart->SetHome( RmsElementDrive, libId, mediaSetId, driveNo-1, 0, 0, 0, 0 )); WsbAffirmHr( pCart->SetStatus( RmsStatusScratch )); WsbAffirmHr( pCart->SetType( RmsMediaFixed )); // Add the drive to the Cartridge object. WsbAffirmHr( pCart->SetDrive( pDrive )); // Add the cartridge to the cartridge collection WsbAffirmHr( pCarts->Add( pCart )); } break; case RmsDeviceRemovableDisk: // find manual library and add this stand alone drive. break; case RmsDeviceTape: // find manual tape library and add this stand alone drive. { CComPtr pDrives; CComPtr pMediaSets; CComPtr pTapeLib; CComPtr pTapeMediaSet; CComPtr pFindLib; CComPtr pCart; GUID libId = GUID_NULL; GUID mediaSetId = GUID_NULL; ULONG driveNo; CComQIPtr pDriveElmt = pDevice; WsbAssertPointer( pDriveElmt ); CComQIPtr pDrive = pDevice; WsbAssertPointer( pDrive ); WsbAffirmHr( CoCreateInstance( CLSID_CRmsLibrary, 0, CLSCTX_SERVER, IID_IRmsLibrary, (void **)&pFindLib )); // Set up the find template WsbAffirmHr( pFindLib->SetMediaSupported( RmsMedia4mm )); CComQIPtr pObject = pFindLib; WsbAffirmHr( pObject->SetFindBy( RmsFindByMediaSupported )); // Find the library hr = pLibs->Find( pFindLib, IID_IRmsLibrary, (void **)&pTapeLib ); if ( WSB_E_NOTFOUND == hr ) { // We don't have a manual tape library yet, so create one... WsbAffirmHr( CoCreateInstance( CLSID_CRmsLibrary, 0, CLSCTX_SERVER, IID_IRmsLibrary, (void **)&pTapeLib )); WsbAffirmHr( pTapeLib->SetName( RMS_DEFAULT_TAPE_LIBRARY_NAME )); WsbAffirmHr( pTapeLib->SetMediaSupported( RmsMedia4mm )); WsbAffirmHr( pLibs->Add( pTapeLib )); CComPtr pMediaSet; WsbAffirmHr( CoCreateInstance( CLSID_CRmsMediaSet, 0, CLSCTX_SERVER, IID_IRmsMediaSet, (void **)&pMediaSet )); WsbAffirmHr( pMediaSet->SetName( RMS_DEFAULT_TAPE_MEDIASET_NAME )); WsbAffirmHr( pMediaSet->SetMediaSupported( RmsMedia4mm )); WsbAffirmHr( pMediaSet->SetMediaSetType( RmsMediaSetLibrary ) ); // Add the media set the library's collection WsbAssertHr( pTapeLib->GetMediaSets( &pMediaSets )); WsbAssertPointer( pMediaSets ); WsbAffirmHr( pMediaSets->Add( pMediaSet )); pMediaSets = 0; // Add the media set the server's collection WsbAssertHr( GetMediaSets( &pMediaSets ) ); WsbAssertPointer( pMediaSets ); WsbAffirmHr( pMediaSets->Add( pMediaSet )); pMediaSets = 0; WsbTrace(OLESTR("CRmsServer::autoConfigureDevices - type %d CRmsMediaSet created.\n"), RmsMedia4mm); } // Add the drive to the library WsbAssertHr( pTapeLib->GetDrives( &pDrives )); WsbAffirmHr( pDrives->Add( pDevice )); WsbAffirmHr( pDrives->GetEntries( &driveNo )); // Remove the drive form the unconfigured list WsbAffirmHr( pDevices->RemoveAndRelease( pDevice )); deviceWasConfigured = TRUE; // Get library information WsbAssertHr( pTapeLib->GetMediaSets( &pMediaSets )); WsbAffirmHr( pTapeLib->GetLibraryId( &libId )); WsbAffirmHr( pMediaSets->First( IID_IRmsMediaSet, (void **)&pTapeMediaSet )); WsbAffirmHr( pTapeMediaSet->GetMediaSetId( &mediaSetId )); // Set the location WsbAffirmHr( pDriveElmt->SetLocation( RmsElementDrive, libId, mediaSetId, driveNo-1, 0, 0, 0, 0 )); // Set the kind of media supported WsbAffirmHr( pDriveElmt->SetMediaSupported( RmsMedia4mm )); // Create a cartridge for the media in the drive. // TODO: it may be empty. WsbAffirmHr( CoCreateInstance( CLSID_CRmsCartridge, 0, CLSCTX_SERVER, IID_IRmsCartridge, (void **)&pCart )); WsbAffirmHr( pCart->SetLocation( RmsElementDrive, libId, mediaSetId, driveNo-1, 0, 0, 0, 0 )); WsbAffirmHr( pCart->SetHome( RmsElementDrive, libId, mediaSetId, driveNo-1, 0, 0, 0, 0 )); WsbAffirmHr( pCart->SetStatus( RmsStatusScratch )); WsbAffirmHr( pCart->SetType( RmsMedia4mm )); // Add the drive to the Cartridge object. WsbAffirmHr( pCart->SetDrive( pDrive )); // Add the cartridge to the cartridge collection WsbAffirmHr( pCarts->Add( pCart )); } break; case RmsDeviceCDROM: case RmsDeviceWORM: case RmsDeviceOptical: // find manual library and add this stand alone drive. break; default: break; } } WsbCatch(hr); pDevice = 0; if ( deviceWasConfigured ) hr = pEnumDevices->This( IID_IRmsDevice, (void **)&pDevice ); else hr = pEnumDevices->Next( IID_IRmsDevice, (void **)&pDevice ); } hr = S_OK; } WsbCatch(hr); WsbTraceOut(OLESTR("CRmsServer::autoConfigureDevices"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } // Maximum number of retries for allocating and mounting a scratch piece of media #define MAX_RETRIES 2 STDMETHODIMP CRmsServer::MountScratchCartridge( OUT GUID *pCartId, IN REFGUID fromMediaSet, IN REFGUID prevSideId, IN OUT LONGLONG *pFreeSpace, IN LONG blockingFactor, IN BSTR displayName, IN OUT IRmsDrive **ppDrive, OUT IRmsCartridge **ppCartridge, OUT IDataMover **ppDataMover, IN DWORD dwOptions) /*++ Implements: IRmsServer::MountScratchCartridge Notes: The default flag for mounting (in dwOptions) is blocking, i.e. waiting for the Mount to finish even if the media is offline, the drive is not ready, etc. Calling with flag set to non-blocking indicates performing the Mount only if everything is available immediately. --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::MountScratchCartridge"), OLESTR("<%ls> <%ls> <%ls>"), WsbQuickString(WsbGuidAsString(fromMediaSet)), WsbQuickString(WsbPtrToLonglongAsString(pFreeSpace)), WsbQuickString(WsbPtrToStringAsString((WCHAR **)&displayName))); CWsbBstrPtr cartridgeName = ""; CWsbBstrPtr cartridgeDesc = ""; GUID cartId = GUID_NULL; CWsbBstrPtr label; try { WsbAssertPointer(pCartId); WsbAssertPointer(displayName); WsbAssert(wcslen((WCHAR *)displayName) > 0, E_INVALIDARG); WsbAffirmHrOk( IsReady() ); DWORD retry = 0; CComPtr pDrive; CComPtr pCart[MAX_RETRIES]; CComPtr pMover; // Decrease max-retries to 1 if short-timeout or non-blocking is specified // or if we want to allocate a specific side DWORD maxRetries = MAX_RETRIES; BOOL bShortTimeout = ( (dwOptions & RMS_SHORT_TIMEOUT) || (dwOptions & RMS_ALLOCATE_NO_BLOCK) ) ? TRUE : FALSE; if (bShortTimeout || (GUID_NULL != prevSideId)) { maxRetries = 1; } WsbTrace(OLESTR("Try to allocate and mount a scratch media %lu times\n"), maxRetries); // Get the media set CComPtr pMediaSet; WsbAffirmHr(CreateObject(fromMediaSet, CLSID_CRmsMediaSet, IID_IRmsMediaSet, RmsOpenExisting, (void **) &pMediaSet)); try { // Allocate from the specified media set WsbAffirmHr(pMediaSet->Allocate(prevSideId, pFreeSpace, displayName, dwOptions, &pCart[retry])); // We want to try the scratch mount twice, but do not deallocate the first until we // grab the second cartridge so we'll get a different cartridge. If both fail, drop out. do { //Clear these,in case we're retrying. pDrive = NULL; pMover = NULL; try { cartId = GUID_NULL; cartridgeName = ""; cartridgeDesc = ""; WsbAffirmHr(pCart[retry]->GetCartridgeId(&cartId)); // for the log message cartridgeName.Free(); WsbAffirmHr(pCart[retry]->GetName(&cartridgeName)); // for the log message cartridgeDesc.Free(); WsbAffirmHr(pCart[retry]->GetDescription(&cartridgeDesc)); // for the log message // Mount the cartridge. WsbAffirmHr(pCart[retry]->Mount(&pDrive, dwOptions)); try { // Set blockingFactor before we create the DataMover (only for a non-fixed block size media) if (blockingFactor > 0) { HRESULT hrBlock = pCart[retry]->IsFixedBlockSize(); WsbAffirmHr(hrBlock); if (hrBlock == S_FALSE) { WsbTrace(OLESTR("MountScratchCartridge: Setting block size on scratch media to %ld\n"), blockingFactor); WsbAffirmHr(pCart[retry]->SetBlockSize(blockingFactor)); } } // Create a data mover for the application. WsbAffirmHr(pCart[retry]->CreateDataMover(&pMover)); // Write out the On Media Label. label.Free(); WsbAffirmHr(pMover->FormatLabel(displayName, &label)); WsbAffirmHr(pMover->WriteLabel(label)); // Mark the media private before returning. WsbAffirmHr(pCart[retry]->SetStatus(RmsStatusPrivate)); // Since we don't have a DB, we need to persist the current state here. WsbAffirmHr(SaveAll()); // // Fill in the return arguments. // WsbAssertHr(pCart[retry]->GetCartridgeId(pCartId)); *ppDrive = pDrive; pDrive->AddRef(); *ppCartridge = pCart[retry]; pCart[retry]->AddRef(); *ppDataMover = pMover; pMover->AddRef(); // We're done, so break out. break; } WsbCatchAndDo(hr, // Best effort dismount... DWORD dwDismountOptions = RMS_DISMOUNT_IMMEDIATE; pCart[retry]->Dismount(dwDismountOptions); WsbThrow(hr); ) } WsbCatchAndDo(hr, retry++; // Check the exact error code: // Alllow another retry only if the error may be media-related BOOL bContinue = TRUE; switch (hr) { case RMS_E_SCRATCH_NOT_FOUND: case RMS_E_CANCELLED: case RMS_E_REQUEST_REFUSED: case RMS_E_CARTRIDGE_UNAVAILABLE: // timeout during Mount case HRESULT_FROM_WIN32(ERROR_DEVICE_NOT_AVAILABLE): case HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE): case HRESULT_FROM_WIN32(ERROR_RESOURCE_DISABLED): // disabled drives case HRESULT_FROM_WIN32(ERROR_DATABASE_FULL): // Prevent another retry bContinue = FALSE; break; default: break; } if (bContinue && (retry < maxRetries)) { WsbLogEvent(RMS_MESSAGE_SCRATCH_MOUNT_RETRY, sizeof(GUID), (void *) &cartId, (WCHAR *) displayName, WsbHrAsString(hr), NULL); // Allocate from the specified media set hr = pMediaSet->Allocate(prevSideId, pFreeSpace, displayName, dwOptions, &pCart[retry]); // Deallocate the previous retry media set pMediaSet->Deallocate(pCart[(retry-1)]); // Make sure the allocate worked, if not, throw. WsbAffirmHr(hr); } else { // If were on the last retry, deallocate the last media set and E_ABORT pMediaSet->Deallocate(pCart[(retry-1)]); WsbThrow(hr); } ) } while (retry < maxRetries); } WsbCatch(hr) } WsbCatch(hr) if ( SUCCEEDED(hr) ) { WsbLogEvent(RMS_MESSAGE_CARTRIDGE_MOUNTED, sizeof(GUID), (void *) &cartId, (WCHAR *) cartridgeName, (WCHAR *) cartridgeDesc, NULL); } else { BOOL bShortTimeout = ( (dwOptions & RMS_SHORT_TIMEOUT) || (dwOptions & RMS_ALLOCATE_NO_BLOCK) ) ? TRUE : FALSE; // In case of short-timeout or non-blocking mode, log message with low severity if (bShortTimeout) { WsbLogEvent(RMS_MESSAGE_EXPECTED_SCRATCH_MOUNT_FAILED, sizeof(GUID), (void *) &cartId, (WCHAR *) displayName, WsbHrAsString(hr), NULL); } else { WsbLogEvent(RMS_MESSAGE_SCRATCH_MOUNT_FAILED, sizeof(GUID), (void *) &cartId, (WCHAR *) displayName, WsbHrAsString(hr), NULL); } } WsbTraceOut(OLESTR("CRmsServer::MountScratchCartridge"), OLESTR("hr = <%ls>, name/desc = <%ls/%ls>, cartId = %ls"), WsbHrAsString(hr), (WCHAR *) cartridgeName, (WCHAR *) cartridgeDesc, WsbQuickString(WsbGuidAsString(cartId))); return hr; } STDMETHODIMP CRmsServer::MountCartridge( IN REFGUID cartId, IN OUT IRmsDrive **ppDrive, OUT IRmsCartridge **ppCartridge, OUT IDataMover **ppDataMover, IN DWORD dwOptions OPTIONAL, IN DWORD threadId OPTIONAL) /*++ Implements: IRmsServer::MountCartridge Notes: The default flag for mounting (in dwOptions) is blocking, i.e. waiting for the Mount to finish even if the media is offline, the drive is not ready, etc. Calling with flag set to non-blocking indicates performing the Mount only if everything is available immediately. --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::MountCartridge"), OLESTR("<%ls>"), WsbGuidAsString(cartId)); CWsbBstrPtr cartridgeName = ""; CWsbBstrPtr cartridgeDesc = ""; try { WsbAffirmHrOk( IsReady() ); CComPtr pDrive; CComPtr pCart; CComPtr pMover; WsbAffirmHr(FindCartridgeById(cartId, &pCart)); cartridgeName.Free(); WsbAffirmHr(pCart->GetName(&cartridgeName)); // for the log message cartridgeDesc.Free(); WsbAffirmHr(pCart->GetDescription(&cartridgeDesc)); // for the log message WsbAffirmHr(pCart->Mount(&pDrive, dwOptions, threadId)); try { WsbAffirmHr(pCart->CreateDataMover(&pMover)); // // Fill in the return arguments. // *ppDrive = pDrive; pDrive->AddRef(); *ppCartridge = pCart; pCart->AddRef(); *ppDataMover = pMover; pMover->AddRef(); } WsbCatchAndDo(hr, // Best effort dismount... DWORD dwDismountOptions = RMS_DISMOUNT_IMMEDIATE; pCart->Dismount(dwDismountOptions); WsbThrow(hr); ) } WsbCatch(hr) if ( SUCCEEDED(hr) ) { WsbLogEvent(RMS_MESSAGE_CARTRIDGE_MOUNTED, sizeof(GUID), (void *) &cartId, (WCHAR *) cartridgeName, (WCHAR *) cartridgeDesc, NULL); } else { BOOL bShortTimeout = ( dwOptions & RMS_SHORT_TIMEOUT ) ? TRUE : FALSE; // In case of short timeout, log message with low severity if (bShortTimeout) { WsbLogEvent(RMS_MESSAGE_EXPECTED_MOUNT_FAILED, sizeof(GUID), (void *) &cartId, (WCHAR *) cartridgeName, (WCHAR *) cartridgeDesc, WsbHrAsString(hr), NULL); } else { WsbLogEvent(RMS_MESSAGE_MOUNT_FAILED, sizeof(GUID), (void *) &cartId, (WCHAR *) cartridgeName, (WCHAR *) cartridgeDesc, WsbHrAsString(hr), NULL); } } WsbTraceOut(OLESTR("CRmsServer::MountCartridge"), OLESTR("hr = <%ls>, name/desc = <%ls/%ls>, cartId = %ls"), WsbHrAsString(hr), (WCHAR *) cartridgeName, (WCHAR *) cartridgeDesc, WsbQuickString(WsbGuidAsString(cartId))); return hr; } STDMETHODIMP CRmsServer::DismountCartridge( IN REFGUID cartId, IN DWORD dwOptions) /*++ Implements: IRmsServer::DismountCartridge Notes: The default flag for dismounting (in dwOptions) is not set for immediate dismount, i.e. delaying the Dismount for a configurable amount of time. Setting the flag for immediate dismount indicates performing Dismount immediately with no delay. --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::DismountCartridge"), OLESTR("<%ls>"), WsbGuidAsString(cartId)); CWsbBstrPtr cartridgeName = ""; CWsbBstrPtr cartridgeDesc = ""; try { // // Allow dismount when ready or in transition... // to handle in-progress duplicate operations. // HRESULT hrReady = IsReady(); WsbAffirm((S_OK == hrReady) || (RMS_E_NOT_READY_SERVER_SUSPENDING == hrReady), hrReady); CComPtr pCart; WsbAffirmHr(FindCartridgeById(cartId, &pCart)); cartridgeName.Free(); WsbAffirmHr(pCart->GetName(&cartridgeName)); // for the log message cartridgeDesc.Free(); WsbAffirmHr(pCart->GetDescription(&cartridgeDesc)); // for the log message WsbAffirmHr(pCart->Dismount(dwOptions)); } WsbCatch(hr) if ( SUCCEEDED(hr) ) { WsbLogEvent(RMS_MESSAGE_CARTRIDGE_DISMOUNTED, sizeof(GUID), (void *) &cartId, (WCHAR *) cartridgeName, (WCHAR *) cartridgeDesc, NULL); } else { WsbLogEvent(RMS_MESSAGE_DISMOUNT_FAILED, sizeof(GUID), (void *) &cartId, (WCHAR *) cartridgeName, (WCHAR *) cartridgeDesc, WsbHrAsString(hr), NULL); } WsbTraceOut(OLESTR("CRmsServer::DismountCartridge"), OLESTR("hr = <%ls>, name/desc = <%ls/%ls>, cartId = %ls"), WsbHrAsString(hr), (WCHAR *) cartridgeName, (WCHAR *) cartridgeDesc, WsbQuickString(WsbGuidAsString(cartId))); return hr; } STDMETHODIMP CRmsServer::DuplicateCartridge( IN REFGUID originalCartId, IN REFGUID firstSideId, IN OUT GUID *pCopyCartId, IN REFGUID copySetId, IN BSTR copyName, OUT LONGLONG *pFreeSpace, OUT LONGLONG *pCapacity, IN DWORD options) /*++ Implements: IRmsServer::DuplicateCartridge --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::DuplicateCartridge"), OLESTR("<%ls> <%ls> <%ls> <%ls> <%d>"), WsbQuickString(WsbGuidAsString(originalCartId)), WsbQuickString(WsbPtrToGuidAsString(pCopyCartId)), WsbQuickString(WsbGuidAsString(copySetId)), WsbQuickString(WsbPtrToStringAsString((WCHAR **)©Name)), options); CComPtr pMover1; CComPtr pMover2; GUID newCartId = GUID_NULL; LONGLONG freeSpace = 0; LONGLONG capacity = 0; try { WsbAffirmHrOk( IsReady() ); WsbAssertPointer( pCopyCartId ); // Mount the Copy first and then the original CComPtr pDrive1; CComPtr pCart1; CComPtr pDrive2; CComPtr pCart2; LONG blockSize1=0, blockSize2=0; // Serialize mounts for media copies DWORD dwMountOptions = RMS_SERIALIZE_MOUNT; // mount copy if ( *pCopyCartId != GUID_NULL ) { WsbAffirmHr(MountCartridge(*pCopyCartId, &pDrive2, &pCart2, &pMover2, dwMountOptions)); } else { GUID mediaSetId = copySetId; CComPtr pCart; WsbAffirmHr(FindCartridgeById(originalCartId, &pCart)); WsbAffirmHr(pCart->GetBlockSize(&blockSize1)); if ( mediaSetId == GUID_NULL ) { WsbAffirmHr(pCart->GetMediaSetId(&mediaSetId)); } // Get capacity of original media and adjust by fudge factor LONGLONG capacity=0; CComQIPtr pInfo = pCart; WsbAffirmHr(pInfo->GetCapacity(&capacity)); LONG fudge = RMS_DEFAULT_MEDIA_COPY_TOLERANCE; DWORD size; OLECHAR tmpString[256]; if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_MEDIA_COPY_TOLERANCE, tmpString, 256, &size))) { // Get the value. fudge = wcstol(tmpString, NULL, 10); } capacity -= (capacity * fudge) / 100; WsbAffirmHr(MountScratchCartridge( &newCartId, mediaSetId, firstSideId, &capacity, blockSize1, copyName, &pDrive2, &pCart2, &pMover2, dwMountOptions )); } // Mount original (in a non-blocking manner) dwMountOptions |= RMS_MOUNT_NO_BLOCK; WsbAffirmHr(MountCartridge(originalCartId, &pDrive1, &pCart1, &pMover1, dwMountOptions)); // Verify matching block size (only for a non-fixed block size media) HRESULT hrBlock = pCart1->IsFixedBlockSize(); WsbAffirmHr(hrBlock); if (hrBlock == S_FALSE) { if (blockSize1 == 0) { // didn't get it yet... WsbAffirmHr(pCart1->GetBlockSize(&blockSize1)); } WsbAffirmHr(pCart2->GetBlockSize(&blockSize2)); WsbAssert(blockSize1 == blockSize2, E_UNEXPECTED); } WsbAffirmHr(pMover1->Duplicate(pMover2, options, NULL, NULL)); // Now get stats to return to caller. WsbAffirmHr(pMover2->GetLargestFreeSpace(&freeSpace, &capacity)); if (pFreeSpace) { *pFreeSpace = freeSpace; } if (pCapacity) { *pCapacity = capacity; } } WsbCatch(hr) if ( pMover1 ) { DismountCartridge(originalCartId); } if ( pMover2 ) { // We always perform immediate dismount to the copy media // (We may need to recycle a new copy in case of an error + there's no benefit in a deferred // dismount for the copy-media - we don't expect the copy-media to be needed again soon) DWORD dwDismountOptions = RMS_DISMOUNT_IMMEDIATE; if (newCartId == GUID_NULL) { // this is the case of an existing copy DismountCartridge(*pCopyCartId, dwDismountOptions); } else { // this is the case of a scratch copy DismountCartridge(newCartId, dwDismountOptions); // if mounting of original failed, we always recycle the scratch copy if (((options & RMS_DUPLICATE_RECYCLEONERROR) || (pMover1 == NULL)) && (S_OK != hr)) { // // If we failed and a scratch mount was performed // we need to recycle the cartridge since the calling // app can't be depended upon to do this. // RecycleCartridge(newCartId, 0); } else { *pCopyCartId = newCartId; } } } WsbTraceOut(OLESTR("CRmsServer::DuplicateCartridge"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } STDMETHODIMP CRmsServer::RecycleCartridge( IN REFGUID cartId, IN DWORD options) /*++ Implements: IRmsServer::RecycleCartridge --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::RecycleCartridge"), OLESTR("<%ls> <%d>"), WsbGuidAsString(cartId), options); CWsbBstrPtr cartridgeName = ""; CWsbBstrPtr cartridgeDesc = ""; try { // // Allow recycle when ready or in transition... // to handle in-progress duplicate operations. // HRESULT hrReady = IsReady(); WsbAffirm((S_OK == hrReady) || (RMS_E_NOT_READY_SERVER_SUSPENDING == hrReady), hrReady); CComPtr pCart; GUID mediaSetId; CComPtr pMediaSet; WsbAffirmHr(FindCartridgeById(cartId, &pCart)); cartridgeName.Free(); WsbAffirmHr(pCart->GetName(&cartridgeName)); // for the log message cartridgeDesc.Free(); WsbAffirmHr(pCart->GetDescription(&cartridgeDesc)); // for the log message // Now go to the media set to deallocate WsbAffirmHr(pCart->GetMediaSetId(&mediaSetId)); WsbAffirmHr(CreateObject(mediaSetId, CLSID_CRmsMediaSet, IID_IRmsMediaSet, RmsOpenExisting, (void **) &pMediaSet)); WsbAffirmHr(pMediaSet->Deallocate(pCart)); } WsbCatch(hr) if ( SUCCEEDED(hr) ) { WsbLogEvent(RMS_MESSAGE_CARTRIDGE_RECYCLED, sizeof(GUID), (void *) &cartId, (WCHAR *) cartridgeName, (WCHAR *) cartridgeDesc, NULL); } else { WsbLogEvent(RMS_MESSAGE_CARTRIDGE_RECYCLE_FAILED, sizeof(GUID), (void *) &cartId, (WCHAR *) cartridgeName, (WCHAR *) cartridgeDesc, WsbHrAsString(hr), NULL); } WsbTraceOut(OLESTR("CRmsServer::RecycleCartridge"), OLESTR("hr = <%ls>, name/desc = <%ls/%ls>, cartId = %ls"), WsbHrAsString(hr), (WCHAR *) cartridgeName, (WCHAR *) cartridgeDesc, WsbQuickString(WsbGuidAsString(cartId))); return hr; } STDMETHODIMP CRmsServer::FindLibraryById( IN REFGUID libId, OUT IRmsLibrary **pLib) /*++ Implements: IRmsServer::FindLibraryById --*/ { HRESULT hr = E_FAIL; CComPtr pFindLib; try { WsbAssertPointer( pLib ); // Create a cartridge template WsbAffirmHr( CoCreateInstance( CLSID_CRmsLibrary, 0, CLSCTX_SERVER, IID_IRmsLibrary, (void **)&pFindLib )); // Fill in the find template CComQIPtr pObject = pFindLib; WsbAffirmHr( pObject->SetObjectId( libId )); WsbAffirmHr( pObject->SetFindBy( RmsFindByObjectId )); // Find the cartridge WsbAffirmHr( m_pLibraries->Find( pFindLib, IID_IRmsLibrary, (void **)pLib )); hr = S_OK; } WsbCatchAndDo(hr, if ( WSB_E_NOTFOUND == hr) hr = RMS_E_LIBRARY_NOT_FOUND; WsbTrace(OLESTR("CRmsServer::FindLibraryById - %ls Not Found. hr = <%ls>\n"),WsbGuidAsString(libId),WsbHrAsString(hr)); ); return hr; } STDMETHODIMP CRmsServer::FindCartridgeById( IN REFGUID cartId, OUT IRmsCartridge **ppCart) /*++ Implements: IRmsServer::FindCartridgeById --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::FindCartridgeById"), OLESTR("%ls"), WsbGuidAsString(cartId)); try { WsbAssertPointer(ppCart); // // The search algorithms attempts to avoid unnecessary throws that // clutter the trace file. Each media management subsystem is tried. // // First check the most active cartridge. hr = RMS_E_CARTRIDGE_NOT_FOUND; if (m_pActiveCartridge) { GUID activeId; WsbAffirmHr( m_pActiveCartridge->GetCartridgeId(&activeId)); if (activeId == cartId) { *ppCart = m_pActiveCartridge; m_pActiveCartridge->AddRef(); hr = S_OK; } } if (hr != S_OK ) { // // Try native RMS // try { hr = S_OK; CComPtr pFindCart; // Create a cartridge template WsbAffirmHr(CoCreateInstance(CLSID_CRmsCartridge, 0, CLSCTX_SERVER, IID_IRmsCartridge, (void **)&pFindCart)); // Fill in the find template CComQIPtr pObject = pFindCart; WsbAffirmHr( pObject->SetObjectId(cartId)); WsbAffirmHr( pObject->SetFindBy(RmsFindByObjectId)); // Try to find the cartridge in the collection of active cartridges. hr = m_pActiveCartridges->Find(pFindCart, IID_IRmsCartridge, (void **)ppCart); WsbAffirm(S_OK == hr || WSB_E_NOTFOUND == hr, hr); if (WSB_E_NOTFOUND == hr) { // Find the cartridge in the collection of cartridges hr = m_pCartridges->Find(pFindCart, IID_IRmsCartridge, (void **)ppCart); WsbAffirm(S_OK == hr || WSB_E_NOTFOUND == hr, hr); if (WSB_E_NOTFOUND == hr) { hr = RMS_E_CARTRIDGE_NOT_FOUND; } } } WsbCatch(hr); } if ( hr != S_OK ) { // // Try NTMS // try { hr = S_OK; hr = IsNTMSInstalled(); if ( S_OK == hr ) { hr = m_pNTMS->FindCartridge(cartId, ppCart); WsbAffirm(S_OK == hr || RMS_E_CARTRIDGE_NOT_FOUND == hr, hr); } else { switch(hr) { case RMS_E_NOT_CONFIGURED_FOR_NTMS: case RMS_E_NTMS_NOT_REGISTERED: // Normal errors hr = RMS_E_CARTRIDGE_NOT_FOUND; break; default: // Unexpected Error! WsbThrow(hr); break; } } } WsbCatch(hr); } } WsbCatchAndDo(hr, CWsbStringPtr idString = cartId; WsbLogEvent(RMS_MESSAGE_CARTRIDGE_NOT_FOUND, 0, NULL, (WCHAR *) idString, WsbHrAsString(hr), NULL); hr = RMS_E_CARTRIDGE_NOT_FOUND; ); WsbTraceOut(OLESTR("CRmsServer::FindCartridgeById"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } STDMETHODIMP CRmsServer::CreateObject( IN REFGUID objectId, IN REFCLSID rclsid, IN REFIID riid, IN DWORD dwCreate, OUT void **ppvObj) /*++ Implements: IRmsServer::CreateObject --*/ { HRESULT hr = E_FAIL; try { WsbAssertPointer( ppvObj ); WsbAssert( NULL == *ppvObj, E_INVALIDARG ); CComPtr pCollection; CComPtr pCollectable; if ( objectId != GUID_NULL ) { CComPtr pFindObject; // Create an object template WsbAffirmHr( CoCreateInstance( rclsid, 0, CLSCTX_SERVER, IID_IRmsComObject, (void **)&pFindObject )); WsbAffirmHr( pFindObject->SetObjectId( objectId )); WsbAffirmHr( pFindObject->SetFindBy( RmsFindByObjectId )); // The only kinds created must support: IRmsComObject (for the object Id), // and IWsbCollectable (to be added to a collection). // See if the object is already in a collection. try { if ( CLSID_CRmsCartridge == rclsid ) { pCollection = m_pCartridges; WsbAffirmHrOk( m_pCartridges->Find( pFindObject, IID_IWsbCollectable, (void **) &pCollectable ) ); } else if ( CLSID_CRmsLibrary == rclsid ) { pCollection = m_pLibraries; WsbAffirmHrOk( m_pLibraries->Find( pFindObject, IID_IWsbCollectable, (void **) &pCollectable ) ); } else if ( CLSID_CRmsMediaSet == rclsid ) { pCollection = m_pMediaSets; WsbAffirmHrOk( m_pMediaSets->Find( pFindObject, IID_IWsbCollectable, (void **) &pCollectable ) ); } else if ( CLSID_CRmsRequest == rclsid ) { pCollection = m_pRequests; WsbAffirmHrOk( m_pRequests->Find( pFindObject, IID_IWsbCollectable, (void **) &pCollectable ) ); } else if ( CLSID_CRmsClient == rclsid ) { pCollection = m_pClients; WsbAffirmHrOk( m_pClients->Find( pFindObject, IID_IWsbCollectable, (void **) &pCollectable ) ); } else { WsbThrow( E_UNEXPECTED ); } hr = S_OK; } WsbCatch(hr); } else if ( RmsOpenExisting == dwCreate ) { // If we get GUID_NULL, we must going after a default object, and we only support this // with existing objects. This is only legal if the default media set registry key exists. if ( CLSID_CRmsMediaSet == rclsid ) { CWsbBstrPtr defaultMediaSetName = RMS_DEFAULT_MEDIASET; DWORD size; OLECHAR tmpString[256]; if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_DEFAULT_MEDIASET, tmpString, 256, &size))) { // Get the value. defaultMediaSetName = tmpString; } else { WsbAssert( objectId != GUID_NULL, E_INVALIDARG ); } CComPtr pFindObject; // Create an object template WsbAffirmHr( CoCreateInstance( rclsid, 0, CLSCTX_SERVER, IID_IRmsComObject, (void **)&pFindObject )); WsbAffirmHr( pFindObject->SetName( defaultMediaSetName )); WsbAffirmHr( pFindObject->SetFindBy( RmsFindByName )); pCollection = m_pMediaSets; WsbAffirmHrOk( m_pMediaSets->Find( pFindObject, IID_IWsbCollectable, (void **) &pCollectable ) ); WsbTrace(OLESTR("Using Default MediaSet <%ls>.\n"), (WCHAR *) defaultMediaSetName); hr = S_OK; } else { WsbThrow( E_INVALIDARG ); } } else { WsbThrow( E_UNEXPECTED ); } // If the object wasn't found we create it here, and add it to the appropriate collection. switch ( (RmsCreate)dwCreate ) { case RmsOpenExisting: if ( S_OK == hr ) { WsbAffirmHr( pCollectable->QueryInterface( riid, ppvObj ) ); } else { WsbThrow( hr ); } break; case RmsOpenAlways: if ( WSB_E_NOTFOUND == hr ) { // Create the object WsbAffirmHr( CoCreateInstance( rclsid, 0, CLSCTX_SERVER, IID_IWsbCollectable, (void **) &pCollectable )); CComQIPtr pObject = pCollectable; WsbAffirmPointer( pObject ); WsbAffirmHr( pObject->SetObjectId( objectId ) ); // Before we add the collection, make sure the interface is supported. WsbAffirmHr( pCollectable->QueryInterface( riid, ppvObj )); WsbAffirmPointer( pCollection ); WsbAffirmHr( pCollection->Add( pCollectable ) ); } else if ( S_OK == hr ) { WsbAffirmHr( pCollectable->QueryInterface( riid, ppvObj ) ); } else { WsbThrow( hr ); } break; case RmsCreateNew: if ( WSB_E_NOTFOUND == hr ) { // Create the object WsbAffirmHr( CoCreateInstance( rclsid, 0, CLSCTX_SERVER, IID_IWsbCollectable, (void **) &pCollectable )); CComQIPtr pObject = pCollectable; WsbAffirmPointer( pObject ); WsbAffirmHr( pObject->SetObjectId( objectId ) ); // Before we add the collection, make sure the interface is supported. WsbAffirmHr( pCollectable->QueryInterface( riid, ppvObj ) ); WsbAffirmPointer( pCollection ); WsbAffirmHr( pCollection->Add( pCollectable ) ); } else if ( S_OK == hr ) { WsbThrow( RMS_E_ALREADY_EXISTS ); } else { WsbThrow( hr ); } break; default: WsbThrow( E_UNEXPECTED ); break; } hr = S_OK; } WsbCatchAndDo( hr, if ( WSB_E_NOTFOUND == hr) hr = RMS_E_NOT_FOUND; WsbTrace(OLESTR("!!!!! ERROR !!!!! CRmsServer::CreateObject: %ls; hr = <%ls>\n"),WsbGuidAsString(objectId),WsbHrAsString(hr)); ); return hr; } HRESULT CRmsServer::getHardDrivesToUseFromRegistry( OUT OLECHAR *pDrivesToUse, OUT DWORD *pLen) /*++ --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::GetHardpDrivesToUseFromRegistry"),OLESTR("")); try { WsbAssert(0 != pDrivesToUse, E_POINTER); WsbAssert(0 != pLen, E_POINTER); DWORD sizeGot; OLECHAR tmpString[1000]; *pLen = 0; pDrivesToUse[0] = OLECHAR('\0'); pDrivesToUse[1] = OLECHAR('\0'); // // Get the default value // WsbAffirmHr(WsbEnsureRegistryKeyExists (NULL, RMS_REGISTRY_STRING)); WsbAffirmHr(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_HARD_DRIVES_TO_USE, tmpString, RMS_DIR_LEN, &sizeGot)); // We are doing some string manipulation here to match the Win32 call // GetLogicalDriveStrings. It returns a string of drives separated by // Nulls with a double NULL at the end. For example: if we want to use // the C and E drives the string should be: C:\E:\ // and len would be 8. DWORD myCharCount = 0; sizeGot = wcslen(tmpString); for (DWORD i = 0; i < sizeGot; i++) { swprintf((OLECHAR *)&pDrivesToUse[myCharCount], OLESTR("%c:\\"), tmpString[i]); myCharCount = ((i + 1)* 4); } pDrivesToUse[myCharCount] = OLECHAR('\0'); if (myCharCount != 0) { *pLen = myCharCount + 1; } } WsbCatch(hr); WsbTraceOut(OLESTR("CRmsServer::GetHardpDrivesToUseFromRegistry"), OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return hr; } HRESULT CRmsServer::enableAsBackupOperator(void) /*++ Routine Description: This routine enables backup operator privilege for the process. This is required to insure that RMS has full access to all resources on the system, primarily with regard to the data mover. Arguments: None. Return Values: S_OK - Success. --*/ { HRESULT hr = E_FAIL; try { HANDLE pHandle; LUID backupValue; HANDLE tokenHandle; TOKEN_PRIVILEGES newState; DWORD lErr; pHandle = GetCurrentProcess(); WsbAffirmStatus(OpenProcessToken(pHandle, MAXIMUM_ALLOWED, &tokenHandle)); // // adjust backup token privileges // WsbAffirmStatus(LookupPrivilegeValueW(NULL, L"SeBackupPrivilege", &backupValue)); newState.PrivilegeCount = 1; newState.Privileges[0].Luid = backupValue; newState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; WsbAffirmStatus(AdjustTokenPrivileges(tokenHandle, FALSE, &newState, (DWORD)0, NULL, NULL)); // // Note that AdjustTokenPrivileges may return success even if it did not assign all privileges. // We check last error here to insure everything was set. // if ( (lErr = GetLastError()) != ERROR_SUCCESS ) { // Not backup user or some other error // // TODO: Should we fail here or just log something? // WsbLogEvent( RMS_MESSAGE_SERVICE_UNABLE_TO_SET_BACKUP_PRIVILEGE, 0, NULL, WsbHrAsString(HRESULT_FROM_WIN32(lErr)), NULL ); } WsbAffirmStatus(LookupPrivilegeValueW(NULL, L"SeRestorePrivilege", &backupValue)); newState.PrivilegeCount = 1; newState.Privileges[0].Luid = backupValue; newState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; WsbAffirmStatus(AdjustTokenPrivileges(tokenHandle, FALSE, &newState, (DWORD)0, NULL, NULL)); // // Note that AdjustTokenPrivileges may return success even if it did not assign all privileges. // We check last error here to insure everything was set. // if ( (lErr = GetLastError()) != ERROR_SUCCESS ) { // Not backup user or some other error // // TODO: Should we fail here or just log something? // WsbLogEvent( RMS_MESSAGE_SERVICE_UNABLE_TO_SET_RESTORE_PRIVILEGE, 0, NULL, WsbHrAsString(HRESULT_FROM_WIN32(lErr)), NULL ); } CloseHandle( tokenHandle ); hr = S_OK; } WsbCatch( hr ); return hr; } STDMETHODIMP CRmsServer::ChangeState( IN LONG newState) /*++ Implements: IRmsServer::CreateObject --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::ChangeState"), OLESTR("<%d>"), newState); try { CComQIPtr pObject = this; WsbAssertPointer( pObject ); switch ((RmsServerState) newState) { case RmsServerStateStarting: case RmsServerStateStarted: case RmsServerStateInitializing: case RmsServerStateReady: case RmsServerStateStopping: case RmsServerStateStopped: case RmsServerStateSuspending: case RmsServerStateSuspended: case RmsServerStateResuming: WsbAffirmHr(pObject->SetState(newState)); break; default: WsbAssert(0, E_UNEXPECTED); break; } } WsbCatch(hr); WsbTraceOut(OLESTR("CRmsServer::ChangeState"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } HRESULT CRmsServer::IsReady(void) /*++ Implements: IRmsServer::IsReady --*/ { HRESULT hr = S_OK; try { BOOL isEnabled; HRESULT status; RmsServerState state; CComQIPtr pObject = this; WsbAssertPointer( pObject ); WsbAffirm(m_LockReference == 0, RMS_E_NOT_READY_SERVER_LOCKED); WsbAffirmHr( isEnabled = pObject->IsEnabled()); WsbAffirmHr( pObject->GetState( (LONG *)&state )); WsbAffirmHr( pObject->GetStatusCode( &status )); if ( S_OK == isEnabled ) { if ( RmsServerStateReady == state ) { hr = S_OK; } else { if ( S_OK == status ) { switch ( state ) { case RmsServerStateStarting: WsbThrow(RMS_E_NOT_READY_SERVER_STARTING); break; case RmsServerStateStarted: WsbThrow(RMS_E_NOT_READY_SERVER_STARTED); break; case RmsServerStateInitializing: WsbThrow(RMS_E_NOT_READY_SERVER_INITIALIZING); break; case RmsServerStateStopping: WsbThrow(RMS_E_NOT_READY_SERVER_STOPPING); break; case RmsServerStateStopped: WsbThrow(RMS_E_NOT_READY_SERVER_STOPPED); break; case RmsServerStateSuspending: WsbThrow(RMS_E_NOT_READY_SERVER_SUSPENDING); break; case RmsServerStateSuspended: WsbThrow(RMS_E_NOT_READY_SERVER_SUSPENDED); break; case RmsServerStateResuming: WsbThrow(RMS_E_NOT_READY_SERVER_RESUMING); break; default: WsbThrow(E_UNEXPECTED); break; } } else { WsbThrow(status); } } } else { if ( S_OK == status ) { WsbThrow(RMS_E_NOT_READY_SERVER_DISABLED); } else { WsbThrow(status); } } } WsbCatch(hr); return hr; } HRESULT CRmsServer::ChangeSysState( IN OUT HSM_SYSTEM_STATE* pSysState ) /*++ Implements: IHsmSystemState::ChangeSysState(). --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::ChangeSysState"), OLESTR("State = %lx"), pSysState->State); try { if ((pSysState->State & HSM_STATE_SHUTDOWN) || (pSysState->State & HSM_STATE_SUSPEND)) { // // Shutdown or Suspend operations // // For power mangement support we need to release // all device handles, and the NTMS (RSM) session handle. // // To accomplish this we simply disable each cartridge, // then disable NTMS. // // The fallout from this gets everything in the power ready state. // WsbAffirmHr(ChangeState(RmsServerStateSuspending)); // // Suspend operations with NMTS. This will cancel any in-progress mounts. // WsbAffirmHr(m_pNTMS->Suspend()); // // Disable each of the active cartridges // CComPtr pEnumCartridges; CComPtr pEnumDataMovers; CComPtr pObject; CComPtr pCart; CComPtr pMover; CComPtr pDrive; WsbAffirmHr( m_pActiveCartridges->Enum( &pEnumCartridges )); WsbAssertPointer( pEnumCartridges ); // // Disable each cartridge. // hr = pEnumCartridges->First( IID_IRmsComObject, (void **)&pObject ); while (S_OK == hr) { try { WsbAffirmHr(pObject->Disable(RMS_E_NOT_READY_SERVER_SUSPENDING)); } WsbCatch(hr); pObject = 0; hr = pEnumCartridges->Next( IID_IRmsComObject, (void **)&pObject ); } hr = S_OK; /* Tracking DataMovers is only partially implemented. // // Cancel I/O requests. // WsbAffirmHr( m_pDataMovers->Enum( &pEnumDataMovers )); WsbAssertPointer( pEnumDataMovers ); hr = pEnumDataMovers->First( IID_IDataMover, (void **)&pMover ); while (S_OK == hr) { try { WsbAffirmHr(pMover->Cancel()); } WsbCatch(hr); pMover = 0; hr = pEnumDataMovers->Next( IID_IDataMover, (void **)&pMover ); } hr = S_OK; */ // // Unload all drives. // hr = pEnumCartridges->First( IID_IRmsCartridge, (void **)&pCart ); while (S_OK == hr) { try { WsbAffirmHr(pCart->GetDrive(&pDrive)); WsbAffirmHr(pDrive->UnloadNow()); } WsbCatch(hr); pDrive = 0; pCart = 0; // // We use "->This" since the UnloadNow() method will wait // until the active cartridge is dismount, and removed // from the active cartridge list. // hr = pEnumCartridges->This( IID_IRmsCartridge, (void **)&pCart ); } hr = S_OK; // // Suspend operations with NMTS. This will close the NTMS handle in // case it was reopend for dismounts during shutdown. // WsbAffirmHr(m_pNTMS->Suspend()); WsbAffirmHr(ChangeState(RmsServerStateSuspended)); } else if (pSysState->State & HSM_STATE_RESUME) { // // Resume operations // WsbAffirmHr(ChangeState(RmsServerStateResuming)); WsbAffirmHr(m_pNTMS->Resume()); CComPtr pEnumCartridges; CComPtr pObject; WsbAffirmHr( m_pActiveCartridges->Enum( &pEnumCartridges )); WsbAssertPointer( pEnumCartridges ); // // Enable each of the active cartridges // hr = pEnumCartridges->First( IID_IRmsComObject, (void **)&pObject ); while (S_OK == hr) { try { WsbAffirmHr(pObject->Enable()); } WsbCatch(hr); pObject = 0; hr = pEnumCartridges->Next( IID_IRmsComObject, (void **)&pObject ); } hr = S_OK; WsbAffirmHr(ChangeState(RmsServerStateReady)); } } WsbCatch(hr); WsbTraceOut(OLESTR("CRmsServer::ChangeSysState"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CRmsServer::GetNofAvailableDrives( IN REFGUID fromMediaSet, OUT DWORD* pdwNofDrives ) /*++ Implements: IRmsServer::GetNofAvailableDrives(). --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::GetNofAvailableDrives"), OLESTR("")); try { WsbAssertPointer(pdwNofDrives); *pdwNofDrives = 0; // Get the media set CComPtr pMediaSet; WsbAffirmHr(CreateObject(fromMediaSet, CLSID_CRmsMediaSet, IID_IRmsMediaSet, RmsOpenExisting, (void **) &pMediaSet)); // Check if the media set is of fixed drives LONG mediaType; WsbAffirmHr(pMediaSet->GetMediaSupported(&mediaType)); if (RmsMediaFixed == mediaType) { // Count fixed drives // We take a shortcut here and just use number of drives that were counted // during initialization. (FindCartridgeStatusById can give current state) *pdwNofDrives = m_HardDrivesUsed; } else { // Just use NTMS // TEMPORARY - We might want RmsNtms to use media-set info as well, // in order not to count both tape and optical drives on a system that has both WsbAffirmHr(m_pNTMS->GetNofAvailableDrives(pdwNofDrives)); } } WsbCatch(hr); WsbTrace(OLESTR("CRmsServer::GetNofAvailableDrives: Number of enabled drives is %lu\n"), *pdwNofDrives); WsbTraceOut(OLESTR("CRmsServer::GetNofAvailableDrives"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CRmsServer::FindCartridgeStatusById( IN REFGUID cartId, OUT DWORD* pdwStatus ) /*++ Implements: IRmsServer::FindCartridgeStatusById(). --*/ { HRESULT hr = S_OK; CComPtr pCart; CComPtr pFindCart; WsbTraceIn(OLESTR("CRmsServer::FindCartridgeStatusById"), OLESTR("cartId = %ls"), WsbGuidAsString(cartId)); try { WsbAssertPointer(pdwStatus); *pdwStatus = 0; // Try native RMS, Currently this should succeed only if media is a fixed drive WsbAffirmHr(CoCreateInstance(CLSID_CRmsCartridge, 0, CLSCTX_SERVER, IID_IRmsCartridge, (void **)&pFindCart)); CComQIPtr pObject = pFindCart; WsbAffirmHr(pObject->SetObjectId(cartId)); WsbAffirmHr(pObject->SetFindBy(RmsFindByObjectId)); hr = m_pCartridges->Find(pFindCart, IID_IRmsCartridge, (void **)&pCart); WsbAffirm(S_OK == hr || WSB_E_NOTFOUND == hr, hr); if (WSB_E_NOTFOUND == hr) { hr = RMS_E_CARTRIDGE_NOT_FOUND; } // Search in RSM if (S_OK != hr) { hr = IsNTMSInstalled(); if (S_OK == hr) { hr = m_pNTMS->FindCartridge(cartId, &pCart); WsbAffirm(S_OK == hr || RMS_E_CARTRIDGE_NOT_FOUND == hr, hr); } else { switch(hr) { case RMS_E_NOT_CONFIGURED_FOR_NTMS: case RMS_E_NTMS_NOT_REGISTERED: // Normal errors hr = RMS_E_CARTRIDGE_NOT_FOUND; break; default: // Unexpected Error! WsbThrow(hr); break; } } } // if media found... if (S_OK == hr) { // Check media type LONG mediaType; WsbAffirmHr(pCart->GetType(&mediaType)); if (RmsMediaFixed != mediaType) { // RSM media // set flags CComQIPtr pObject = pCart; WsbAffirmPointer(pObject); if (S_OK == pObject->IsEnabled()) { (*pdwStatus) |= RMS_MEDIA_ENABLED; } if (S_OK == pCart->IsAvailable()) { (*pdwStatus) |= RMS_MEDIA_AVAILABLE; } LONG lLocationType; GUID Dum1,Dum2; LONG lDum3, lDum4, lDum5, lDum6; BOOL bDum7; WsbAffirmHr(pCart->GetLocation(&lLocationType, &Dum1, &Dum2, &lDum3, &lDum4, &lDum5, &lDum6, &bDum7)); switch (lLocationType) { case RmsElementUnknown: case RmsElementShelf: case RmsElementOffSite: // media is offline... break; default: (*pdwStatus) |= RMS_MEDIA_ONLINE; break; } } else { // Fixed drive - just try to access the volume and see if it's still valid // If so, set all flags, otherwise, set none CComPtr pDrive; CWsbBstrPtr driveName; WCHAR fileSystemType[MAX_PATH]; // Get drive name (volume name for fixed drives) to check WsbAffirmHr(pCart->GetDrive(&pDrive)); CComQIPtr pDevice = pDrive; WsbAssertPointer(pDevice); WsbAffirmHr(pDevice->GetDeviceName(&driveName)); if (GetVolumeInformation((WCHAR *)driveName, NULL, 0, NULL, NULL, NULL, fileSystemType, MAX_PATH) ) { if (0 == wcscmp(L"NTFS", fileSystemType)) { // Volume is ready for migration - set all flags (*pdwStatus) |= (RMS_MEDIA_ENABLED | RMS_MEDIA_ONLINE | RMS_MEDIA_AVAILABLE); } else { // Not NTFS - don't use that volume WsbTrace(OLESTR("CRmsServer::FindCartridgeStatusById: Fixed volume %ls is formatted to %ls\n"), (WCHAR *)driveName, fileSystemType); } } else { // Volume is not available - don't use it WsbTrace(OLESTR("CRmsServer::FindCartridgeStatusById: GetVolumeInformation returned %lu for Fixed volume %ls\n"), GetLastError(), (WCHAR *)driveName); } } } } WsbCatch(hr); WsbTrace(OLESTR("CRmsServer::FindCartridgeStatusById: Status bits are %lX\n"), *pdwStatus); WsbTraceOut(OLESTR("CRmsServer::FindCartridgeStatusById"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CRmsServer::IsMultipleSidedMedia( IN REFGUID mediaSetId ) /*++ Implements: IRmsServer::IsMultipleSidedMedia Notes: Currently, optical & DVD media types are reported as multiple sided media Tapes and fixed disks would fall in the default - one side media --*/ { HRESULT hr = S_FALSE; WsbTraceIn(OLESTR("CRmsServer::IsMultipleSidedMedia"), OLESTR("")); try { // Multiple sided is currently determined if the media set is optical or not // This may change to include other media types of according two other characteristics CComPtr pMediaSet; LONG mediaType; if (mediaSetId != GUID_NULL) { // if input media set is non-null, check this data-set. WsbAffirmHr(CreateObject(mediaSetId, CLSID_CRmsMediaSet, IID_IRmsMediaSet, RmsOpenAlways, (void **)&pMediaSet)); WsbAffirmHr(pMediaSet->GetMediaSupported(&mediaType)); if ((RmsMediaOptical == mediaType) || (RmsMediaDVD == mediaType)) { hr = S_OK; } } else { // Otherwise, enumerate the collection seeking for any media set that might have two sides CComPtr pEnumSets; WsbAffirmHr(m_pMediaSets->Enum(&pEnumSets)); WsbAssertPointer(pEnumSets); hr = pEnumSets->First(IID_IRmsMediaSet, (void **)&pMediaSet); while (S_OK == hr) { WsbAffirmHr(pMediaSet->GetMediaSupported(&mediaType)); if ((RmsMediaOptical == mediaType) || (RmsMediaDVD == mediaType)) { hr = S_OK; break; } hr = pEnumSets->Next(IID_IRmsMediaSet, (void **)&pMediaSet); if (hr == WSB_E_NOTFOUND) { hr = S_FALSE; } else { WsbAffirmHr(hr); } } } } WsbCatch(hr); WsbTraceOut(OLESTR("CRmsServer::IsMultipleSidedMedia"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return hr; } HRESULT CRmsServer::CheckSecondSide( IN REFGUID firstSideId, OUT BOOL *pbValid, OUT GUID *pSecondSideId ) /*++ Implements: IRmsServer::CheckSecondSide(). Notes: It is not expected that this utility is called on a single sided media. If it does, it would return invalid second side for tape and would fail on fixed disks. --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CRmsServer::CheckSecondSide"), OLESTR("")); try { // just use NTMS (RmsServer collections are not used today!) WsbAffirmHr(m_pNTMS->CheckSecondSide(firstSideId, pbValid, pSecondSideId)); } WsbCatch(hr); WsbTrace(OLESTR("CRmsServer::CheckSecondSide: Valid second side: %ls, id=<%ls>\n"), WsbBoolAsString(*pbValid), WsbGuidAsString(*pSecondSideId)); WsbTraceOut(OLESTR("CRmsServer::CheckSecondSide"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); }