Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5208 lines
168 KiB

  1. /*++
  2. Copyright (c) 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. hsmServ.cpp
  5. Abstract:
  6. This component provides the functions to access the HSM
  7. IHsmServer interfaces.
  8. Author:
  9. Cat Brant [cbrant] 24-Jan-1997
  10. Revision History:
  11. Chris Timmes [ctimmes] 11-Sep-1997
  12. - renamed COM method FindStoragePoolById() to FindHSMStoragePoolByMediaSetId()
  13. to better reflect its purpose. Also created new COM method
  14. FindHsmStoragePoolById(). Action required since the Engine maintains 2
  15. sets of (original/master) secondary storage media set ids (GUIDs). First,
  16. the Engine maintains its own 'media set' id, called a Storage Pool id, which
  17. is only maintained by the Engine. Second, the Engine also maintains the NT
  18. Media Services (NTMS) id, called the Media Set id, which comes from NTMS and
  19. is passed to the Engine by RMS (the Remote Storage Subsystem). (Note that the
  20. concept of a Storage Pool encompasses more info than that of a Media Set.)
  21. These 2 lookup functions allow for lookup by either id.
  22. Chris Timmes [ctimmes] 22-Sep-1997
  23. - added new COM methods FindMediaIdByDisplayName() and RecreateMaster(). Changes
  24. made to enable Copy Set usage. Code written to be both Sakkara and Phoenix
  25. compatible.
  26. Chris Timmes [ctimmes] 21-Oct-1997
  27. - added new COM method MarkMediaForRecreation(). Change made to allow
  28. RecreateMaster() to be invokable directly from RsLaunch (without going through
  29. the UI).
  30. Chris Timmes [ctimmes] 18-Nov-1997
  31. - added new COM method CreateTask(). Change made to move NT Task Scheduler task
  32. creation code from the UI to the Engine. Change required to allow Remote
  33. Storage system to run under LocalSystem account. CreateTask() is a generic
  34. method callable by anyone wanting to create any supported type of Remote Storage
  35. task in Task Scheduler.
  36. --*/
  37. #include "stdafx.h"
  38. #include "HsmServ.h"
  39. #include "HsmConn.h"
  40. #include "metalib.h"
  41. #include "task.h"
  42. #include "wsbdb.h"
  43. #include "rsbuild.h"
  44. #include "wsb.h"
  45. #include "ntverp.h" // for GetNtProductVersion() and GetNtProductBuild()
  46. #include "Rms.h"
  47. #include "rsevents.h"
  48. #include "HsmEng.h"
  49. #define WSB_TRACE_IS WSB_TRACE_BIT_HSMENG
  50. #define HSM_PERSIST_FILE "\\RsEng.col"
  51. #define RMS_WIN2K_PERSIST_FILE "\\RsSub.col"
  52. #define DEFAULT_COPYFILES_USER_LIMIT 10
  53. BOOL g_HsmSaveInProcess = FALSE;
  54. /////////////////////////////////////////////////////////////////////////////
  55. //
  56. // Non-member function initially called for autosave thread
  57. static DWORD HsmengStartAutosave(
  58. void* pVoid
  59. )
  60. {
  61. return(((CHsmServer*) pVoid)->Autosave());
  62. }
  63. // Non-member function run in a separate thread to call CheckManagedResources
  64. static DWORD HsmengStartCheckManagedResources(
  65. void* pVoid
  66. )
  67. {
  68. DWORD result;
  69. result = ((CHsmServer*) pVoid)->CheckManagedResources();
  70. return(result);
  71. }
  72. HRESULT
  73. CHsmServer::Autosave(
  74. void
  75. )
  76. /*++
  77. Routine Description:
  78. Implements an autosave loop.
  79. Arguments:
  80. None.
  81. Return Value:
  82. Doesn't matter.
  83. --*/
  84. {
  85. HRESULT hr = S_OK;
  86. ULONG l_autosaveInterval = m_autosaveInterval;
  87. BOOL exitLoop = FALSE;
  88. WsbTraceIn(OLESTR("CHsmServer::Autosave"), OLESTR(""));
  89. try {
  90. while (m_autosaveInterval && (! exitLoop)) {
  91. // Wait for termination event, if timeout occurs, check if we can perform Autosave
  92. switch (WaitForSingleObject(m_terminateEvent, l_autosaveInterval)) {
  93. case WAIT_OBJECT_0:
  94. // Need to terminate
  95. WsbTrace(OLESTR("CHsmServer::Autosave: signaled to terminate\n"));
  96. exitLoop = TRUE;
  97. break;
  98. case WAIT_TIMEOUT:
  99. // Check if backup need to be performed
  100. WsbTrace(OLESTR("CHsmServer::Autosave: Autosave awakened\n"));
  101. // Don't do this if we're suspended
  102. if (!m_Suspended) {
  103. // Save data
  104. // NOTE: Because this is a separate thread, there is the possibility
  105. // of a conflict if the main thread is changing some data at the same
  106. // time we're trying to save it.
  107. // If a save is already happening, just skip this one and
  108. // go back to sleep
  109. hr = SaveAll();
  110. // If the save fails, increase the sleep time to avoid filling
  111. // the event log
  112. if (!SUCCEEDED(hr)) {
  113. if ((MAX_AUTOSAVE_INTERVAL / 2) < l_autosaveInterval) {
  114. l_autosaveInterval = MAX_AUTOSAVE_INTERVAL;
  115. } else {
  116. l_autosaveInterval *= 2;
  117. }
  118. } else {
  119. l_autosaveInterval = m_autosaveInterval;
  120. }
  121. }
  122. break; // end of timeout case
  123. case WAIT_FAILED:
  124. default:
  125. WsbTrace(OLESTR("CHsmServer::Autosave: WaitForSingleObject returned error %lu\n"), GetLastError());
  126. exitLoop = TRUE;
  127. break;
  128. } // end of switch
  129. } // end of while
  130. } WsbCatch(hr);
  131. WsbTraceOut(OLESTR("CHsmServer::Autosave"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  132. return(hr);
  133. }
  134. HRESULT
  135. CHsmServer::GetAutosave(
  136. OUT ULONG* pMilliseconds
  137. )
  138. /*++
  139. Implements:
  140. CHsmServer::GetAutosave().
  141. --*/
  142. {
  143. HRESULT hr = S_OK;
  144. WsbTraceIn(OLESTR("CHsmServer::GetAutosave"), OLESTR(""));
  145. try {
  146. WsbAssert(0 != pMilliseconds, E_POINTER);
  147. *pMilliseconds = m_autosaveInterval;
  148. } WsbCatch(hr);
  149. WsbTraceOut(OLESTR("CHsmServer::GetAutosave"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  150. return(hr);
  151. }
  152. HRESULT
  153. CHsmServer::SetAutosave(
  154. IN ULONG milliseconds
  155. )
  156. /*++
  157. Implements:
  158. CHsmServer::SetAutosave().
  159. --*/
  160. {
  161. HRESULT hr = S_OK;
  162. WsbTraceIn(OLESTR("CHsmServer::SetAutosave"), OLESTR("milliseconds = <%ls>"), WsbPtrToUlongAsString( &milliseconds ) );
  163. try {
  164. // Don't do anything if interval isn't changing
  165. if (milliseconds != m_autosaveInterval) {
  166. // Close the current thread
  167. if (m_autosaveThread) {
  168. StopAutosaveThread();
  169. }
  170. m_autosaveInterval = milliseconds;
  171. // Start/restart the autosave thread
  172. if (m_autosaveInterval) {
  173. DWORD threadId;
  174. WsbAffirm((m_autosaveThread = CreateThread(0, 0, HsmengStartAutosave, (void*) this, 0, &threadId))
  175. != 0, HRESULT_FROM_WIN32(GetLastError()));
  176. }
  177. }
  178. } WsbCatch(hr);
  179. WsbTraceOut(OLESTR("CHsmServer::SetAutosave"), OLESTR("hr = <%ls> m_runInterval = <%ls>"), WsbHrAsString(hr), WsbPtrToUlongAsString( &m_autosaveInterval ) );
  180. return(hr);
  181. }
  182. HRESULT CHsmServer::GetID(
  183. GUID *phid
  184. )
  185. {
  186. if( !phid )
  187. return E_INVALIDARG;
  188. *phid = m_hId;
  189. return S_OK;
  190. }
  191. HRESULT CHsmServer::GetId(
  192. GUID *phid
  193. )
  194. {
  195. return (GetID(phid));
  196. }
  197. HRESULT CHsmServer::SetId(
  198. GUID id
  199. )
  200. {
  201. m_hId = id;
  202. return S_OK;
  203. }
  204. HRESULT
  205. CHsmServer::GetDbPath(
  206. OUT OLECHAR** pPath,
  207. IN ULONG bufferSize
  208. )
  209. /*++
  210. Implements:
  211. IHsmServer::GetDbPath().
  212. --*/
  213. {
  214. HRESULT hr = S_OK;
  215. try {
  216. WsbAssert(0 != pPath, E_POINTER);
  217. WsbAffirmHr(m_dbPath.CopyTo(pPath, bufferSize));
  218. } WsbCatch(hr);
  219. return(hr);
  220. }
  221. HRESULT
  222. CHsmServer::GetDbPathAndName(
  223. OUT OLECHAR** pPath,
  224. IN ULONG bufferSize
  225. )
  226. /*++
  227. Implements:
  228. IHsmServer::GetDbPathAndName().
  229. --*/
  230. {
  231. HRESULT hr = S_OK;
  232. CWsbStringPtr tmpString;
  233. try {
  234. WsbAssert(0 != pPath, E_POINTER);
  235. tmpString = m_dbPath;
  236. WsbAffirmHr(tmpString.Append(HSM_PERSIST_FILE));
  237. WsbAffirmHr(tmpString.CopyTo(pPath, bufferSize));
  238. } WsbCatch(hr);
  239. return(hr);
  240. }
  241. HRESULT
  242. CHsmServer::GetIDbPath(
  243. OUT OLECHAR** pPath,
  244. IN ULONG bufferSize
  245. )
  246. /*++
  247. Routine Description:
  248. Returns the path (directory) for the Engine IDB files
  249. Arguments:
  250. pPath - address of pointer to buffer
  251. bufferSize - size of buffer (or zero)
  252. Return Value:
  253. S_OK - On success
  254. --*/
  255. {
  256. HRESULT hr = S_OK;
  257. try {
  258. CWsbStringPtr temp;
  259. WsbAssert(0 != pPath, E_POINTER);
  260. temp = m_dbPath;
  261. temp.Append(OLESTR("\\"));
  262. temp.Append(ENG_DB_DIRECTORY);
  263. WsbAffirmHr(temp.CopyTo(pPath, bufferSize));
  264. } WsbCatch(hr);
  265. return(hr);
  266. }
  267. HRESULT CHsmServer::GetName (
  268. OLECHAR **ppName
  269. )
  270. {
  271. HRESULT hr = S_OK;
  272. try {
  273. WsbAssert(0 != ppName, E_POINTER);
  274. WsbAffirmHr(m_name.CopyTo(ppName));
  275. } WsbCatch( hr );
  276. return (hr);
  277. }
  278. HRESULT CHsmServer::GetRegistryName (
  279. OLECHAR **pName,
  280. ULONG bufferSize
  281. )
  282. {
  283. HRESULT hr = S_OK;
  284. try {
  285. CWsbStringPtr tmpString;
  286. WsbAssert(0 != pName, E_POINTER);
  287. tmpString = HSM_ENGINE_REGISTRY_NAME;
  288. WsbAffirmHr(tmpString.CopyTo(pName, bufferSize));
  289. } WsbCatch( hr );
  290. return (hr);
  291. }
  292. HRESULT CHsmServer::GetHsmExtVerHi (
  293. SHORT * /*pExtVerHi*/
  294. )
  295. {
  296. return( E_NOTIMPL );
  297. }
  298. HRESULT CHsmServer::GetHsmExtVerLo (
  299. SHORT * /*pExtVerLo*/
  300. )
  301. {
  302. return( E_NOTIMPL );
  303. }
  304. HRESULT CHsmServer::GetHsmExtRev (
  305. SHORT * /*pExtRev*/
  306. )
  307. {
  308. return( E_NOTIMPL );
  309. };
  310. HRESULT CHsmServer::GetManagedResources(
  311. IWsbIndexedCollection **ppCollection
  312. )
  313. {
  314. HRESULT hr = S_OK;
  315. WsbTraceIn(OLESTR("CHsmServer::GetManagedResources"),OLESTR(""));
  316. //
  317. // If the resources have been loaded, return the pointer. Otherwise,
  318. // fail.
  319. try {
  320. WsbAssert(0 != ppCollection, E_POINTER);
  321. *ppCollection = m_pManagedResources;
  322. WsbAffirm(m_pManagedResources != 0, E_FAIL);
  323. m_pManagedResources->AddRef();
  324. } WsbCatch(hr);
  325. WsbTraceOut(OLESTR("CHsmServer::GetManagedResources"),OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  326. return (hr);
  327. }
  328. HRESULT CHsmServer::SaveMetaData(
  329. void
  330. )
  331. {
  332. HRESULT hr = S_OK;
  333. WsbTraceIn(OLESTR("CHsmServer::SaveMetaData"), OLESTR(""));
  334. //
  335. // Force a save of all metadata
  336. //
  337. try {
  338. if (m_pSegmentDatabase != 0) {
  339. WsbAffirmHr(StoreSegmentInformation());
  340. }
  341. } WsbCatch(hr);
  342. WsbTraceOut(OLESTR("CHsmServer::SaveMetaData"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  343. return (hr);
  344. }
  345. HRESULT CHsmServer::LoadPersistData(
  346. void
  347. )
  348. {
  349. HRESULT hr = S_OK;
  350. WsbTraceIn(OLESTR("CHsmServer::LoadPersistData"), OLESTR(""));
  351. //
  352. // Create persistent collections and attempt to load from file
  353. //
  354. try {
  355. CComPtr<IWsbServer> pWsbServer;
  356. CWsbStringPtr tmpString;
  357. // Create the collections
  358. WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER,
  359. IID_IWsbIndexedCollection, (void **)&m_pJobs ));
  360. WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER,
  361. IID_IWsbIndexedCollection, (void **)&m_pJobDefs ));
  362. WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER,
  363. IID_IWsbIndexedCollection, (void **)&m_pPolicies ));
  364. WsbAffirmHr(CoCreateInstance(CLSID_CHsmManagedResourceCollection, 0, CLSCTX_SERVER,
  365. IID_IWsbIndexedCollection, (void **)&m_pManagedResources ));
  366. WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER,
  367. IID_IWsbIndexedCollection, (void **)&m_pStoragePools ));
  368. WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER,
  369. IID_IWsbIndexedCollection, (void **)&m_pMessages ));
  370. // Try to read from the persistence file
  371. // Note: currently Engine doesn't verify the service id in the Registry
  372. // If Engine would ever start without an Fsa in the HSM server process -
  373. // this should be changed
  374. WsbAffirmHr(((IUnknown*) (IHsmServer*) this)->QueryInterface(IID_IWsbServer,
  375. (void**) &pWsbServer));
  376. WsbAffirmHr(WsbServiceSafeInitialize(pWsbServer, FALSE, TRUE, &m_persistWasCreated));
  377. } WsbCatch(hr);
  378. WsbTraceOut(OLESTR("CHsmServer::LoadPersistData"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  379. return (hr);
  380. }
  381. HRESULT CHsmServer::SavePersistData(
  382. void
  383. )
  384. {
  385. HRESULT hr = S_OK;
  386. WsbTraceIn(OLESTR("CHsmServer::SavePersistData"), OLESTR(""));
  387. if (FALSE == g_HsmSaveInProcess) {
  388. g_HsmSaveInProcess = TRUE;
  389. //
  390. // Force a save of all non-meta persistent data
  391. //
  392. hr = InternalSavePersistData();
  393. g_HsmSaveInProcess = FALSE;
  394. } else {
  395. WsbTrace( OLESTR("Save already occurring - so wait"));
  396. while (TRUE == g_HsmSaveInProcess) {
  397. //
  398. // Sleep a half a second then see if flag
  399. // is cleared. We want to wait until the
  400. // save is done before returning.
  401. //
  402. Sleep(500);
  403. }
  404. }
  405. WsbTraceOut(OLESTR("CHsmServer::SavePersistData"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  406. return (hr);
  407. }
  408. HRESULT
  409. CHsmServer::FindHsmStoragePoolById(
  410. IN GUID StoragePoolId,
  411. OUT IHsmStoragePool** ppStoragePool
  412. )
  413. /*++
  414. Implements:
  415. IHsmServer::FindHsmStoragePoolById().
  416. Routine Description:
  417. This routine implements the COM method for looking up an HSM (Engine)
  418. Storage Pool object by the HSM Storage Pool id (a GUID). If found, a
  419. COM interface pointer to that object is returned.
  420. After using the Engine's stored pointer to an indexed collection of valid
  421. storage pools to obtain an iterator (enumerator) to the collection, the
  422. code searches the collection. For each record it obtains that Storage
  423. Pool's interface pointer, which it uses to get that pool's id. Once
  424. it finds the record whose Storage Pool id matches the HSM pool id
  425. passed in, it returns the interface pointer .
  426. Note that with Sakkara there is only 1 storage pool, so a match should be
  427. found on the first (and only) record. However, the code is written to
  428. allow for future enhancements where there may be more than 1 storage pool.
  429. Arguments:
  430. StoragePoolId - The HSM id (GUID) - as opposed to the NTMS id - for the
  431. Storage Pool whose interface pointer is to be returned by this method.
  432. ppStoragePool - a pointer to the Storage Pool Interface Pointer which will
  433. be returned by this method.
  434. Return Value:
  435. S_OK - The call succeeded (the specified storage pool record was found and
  436. its interface pointer was returned to the caller.
  437. Any other value - The call failed. Generally this should only happen if
  438. a matching storage pool record is not found in the storage pool
  439. indexed collection (this error will return HR = 81000001, 'search
  440. of a collection failed', aka WSB_E_NOTFOUND).
  441. --*/
  442. {
  443. // since this code is currently only used by the CopyMedia routines,
  444. // reset the Tracing bit
  445. #undef WSB_TRACE_IS
  446. #define WSB_TRACE_IS WSB_TRACE_BIT_COPYMEDIA
  447. HRESULT hr = S_OK;
  448. GUID poolId = GUID_NULL;
  449. CComPtr<IWsbEnum> pEnum;
  450. CComPtr<IHsmStoragePool> pStoragePool;
  451. WsbTraceIn(OLESTR("CHsmServer::FindHsmStoragePoolById"),
  452. OLESTR("StoragePoolId = <%ls>"), WsbGuidAsString(StoragePoolId));
  453. try {
  454. // ensure the OUT parameter pointer is valid
  455. WsbAssert(0 != ppStoragePool, E_POINTER);
  456. // null out the interface pointer so garbage is not returned
  457. *ppStoragePool = 0;
  458. // obtain an iterator (enumerator) to the indexed storage pool collection
  459. // from the engine's stored storage pool pointer.
  460. WsbAffirmHr(m_pStoragePools->Enum(&pEnum));
  461. // get the first record in the collection. Get that storage pool's id (GUID).
  462. WsbAffirmHr(pEnum->First(IID_IHsmStoragePool, (void**) &pStoragePool));
  463. WsbAffirmHr(pStoragePool->GetId(&poolId));
  464. // if the ids (GUIDs) don't match, iterate through the collection until
  465. // a match is found. Note that no match being found will cause an error
  466. // to be thrown when the Next() call is made after reaching the end of the
  467. // collection.
  468. while (poolId != StoragePoolId) {
  469. pStoragePool.Release();
  470. WsbAffirmHr(pEnum->Next(IID_IHsmStoragePool, (void**) &pStoragePool));
  471. WsbAffirmHr(pStoragePool->GetId(&poolId));
  472. }
  473. // Match found: return requested interface pointer after increasing COM
  474. // ref count
  475. *ppStoragePool = pStoragePool;
  476. if (pStoragePool != 0) {
  477. (*ppStoragePool)->AddRef();
  478. }
  479. } WsbCatch(hr);
  480. WsbTraceOut(OLESTR("CHsmServer::FindHsmStoragePoolById"),
  481. OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  482. return(hr);
  483. // leaving CopyMedia code, so reset Tracing bit to the Hsm Engine
  484. #undef WSB_TRACE_IS
  485. #define WSB_TRACE_IS WSB_TRACE_BIT_HSMENG
  486. }
  487. HRESULT
  488. CHsmServer::FindHsmStoragePoolByMediaSetId(
  489. IN GUID RmsMediaSetId,
  490. OUT IHsmStoragePool** ppStoragePool
  491. )
  492. /*++
  493. Implements:
  494. IHsmServer::FindHsmStoragePoolByMediaSetId().
  495. Routine Description:
  496. This routine implements the COM method for looking up an HSM (Engine)
  497. Storage Pool object by the remote media subsystem Media Set id (a GUID which
  498. comes from NTMS in the case where tape is used as secondary storage). If found,
  499. a COM interface pointer to that object is returned.
  500. After using the Engine's stored pointer to an indexed collection of valid
  501. storage pools to obtain an iterator (enumerator) to the collection, the
  502. code searches the collection. For each record it obtains that Storage
  503. Pool's interface pointer, which it uses to get that pool's media set id.
  504. Once it finds the record whose Media Set (Storage Pool) id matches the media
  505. set id passed in, it returns that record's interface pointer.
  506. Note that with Sakkara there is only 1 storage pool, so a match should be
  507. found on the first (and only) record. However, the code is written to
  508. allow for future enhancements where there may be more than 1 storage pool.
  509. Arguments:
  510. MediaSetId - The Remote Storage Subsystem id (GUID) - as opposed to the Engine's
  511. local HSM id - for the Storage Pool (referred to by the subsystem as a
  512. Media Set) whose interface pointer is to be returned by this method.
  513. ppStoragePool - a pointer to the Storage Pool Interface Pointer which will
  514. be returned by this method.
  515. Return Value:
  516. S_OK - The call succeeded (the specified storage pool record was found and
  517. its interface pointer was returned to the caller).
  518. Any other value - The call failed. Generally this should only happen if
  519. a matching storage pool record is not found in the storage pool
  520. indexed collection (this error will return HR = 81000001, 'search
  521. of a collection failed', aka WSB_E_NOTFOUND).
  522. --*/
  523. {
  524. // since this code is currently only used by the CopyMedia routines,
  525. // reset the Tracing bit
  526. #undef WSB_TRACE_IS
  527. #define WSB_TRACE_IS WSB_TRACE_BIT_COPYMEDIA
  528. HRESULT hr = S_OK;
  529. GUID mediaSetId = GUID_NULL;
  530. CWsbBstrPtr mediaSetName;
  531. CComPtr<IWsbEnum> pEnum;
  532. CComPtr<IHsmStoragePool> pStoragePool;
  533. WsbTraceIn(OLESTR("CHsmServer::FindHsmStoragePoolByMediaSetId"),
  534. OLESTR("RmsMediaSetId = <%ls>"), WsbGuidAsString(RmsMediaSetId));
  535. try {
  536. // ensure OUT parameter is valid
  537. WsbAssert(0 != ppStoragePool, E_POINTER);
  538. // null out the returned interface pointer so garbage is not returned
  539. *ppStoragePool = 0;
  540. // obtain an iterator (enumerator) to the indexed storage pool collection
  541. WsbAffirmHr(m_pStoragePools->Enum(&pEnum));
  542. // Get first record in the collection and its Remote Storage Subsystem
  543. // Media Set GUID using its interface pointer.
  544. WsbAffirmHr(pEnum->First(IID_IHsmStoragePool, (void**) &pStoragePool));
  545. WsbAffirmHr(pStoragePool->GetMediaSet(&mediaSetId, &mediaSetName));
  546. // if the ids (GUIDs) don't match, iterate through the collection until
  547. // a match is found. Note that no match being found will cause an error
  548. // to be thrown when the Next() call is made after reaching the end of the
  549. // collection.
  550. while (mediaSetId != RmsMediaSetId) {
  551. pStoragePool.Release();
  552. WsbAffirmHr(pEnum->Next(IID_IHsmStoragePool, (void**) &pStoragePool));
  553. mediaSetName.Free();
  554. WsbAffirmHr(pStoragePool->GetMediaSet(&mediaSetId, &mediaSetName));
  555. }
  556. // Match found: return the requested interface pointer after increasing COM
  557. // ref count.
  558. *ppStoragePool = pStoragePool;
  559. if (pStoragePool != 0) {
  560. (*ppStoragePool)->AddRef();
  561. }
  562. } WsbCatch(hr);
  563. WsbTraceOut(OLESTR("CHsmServer::FindHsmStoragePoolByMediaSetId"),
  564. OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  565. return(hr);
  566. // leaving CopyMedia code, so reset Tracing bit to the Hsm Engine
  567. #undef WSB_TRACE_IS
  568. #define WSB_TRACE_IS WSB_TRACE_BIT_HSMENG
  569. }
  570. HRESULT
  571. CHsmServer::FindMediaIdByDescription(
  572. IN OLECHAR* description,
  573. OUT GUID* pMediaId
  574. )
  575. /*++
  576. Implements:
  577. IHsmServer::FindMediaIdByDescription().
  578. Routine Description:
  579. This routine implements the COM method for looking up the secondary storage
  580. master media's id (a GUID) by its description (display name). Both the id and
  581. description are fields stored in the Engine's MediaInfo database. (The MediaInfo
  582. database is actually a separate entity stored within the Engine's Segment database.)
  583. After opening the Engine's Segment database and getting the MediaInfo entity,
  584. the routine loops through the MediaInfo records to find the one whose Description
  585. matches that passed into this method. When it finds the matching record
  586. it gets and returns that record's media id. Any error conditions encountered
  587. result in the appropriate error HRESULT being thrown and returned to the caller.
  588. Arguments:
  589. description - Originally called the media's 'name', then the 'display name', later
  590. clarified to be the media's 'description', this is what is displayed in the
  591. UI to identify the Remote Storage secondary storage (master) media.
  592. pMediaId - a pointer to the media's id (a GUID) for that media whose description
  593. matches the one passed in as the first argument above.
  594. Return Value:
  595. S_OK - The call succeeded (the specified media record was found and a pointer to
  596. its id was returned to the caller.
  597. E_POINTER - Returned if an invalid pointer was passed in as the 'pMediaId' argument.
  598. WSB_E_NOTFOUND - Value 81000001. Returned if no media info record was found whose
  599. description matched the one passed in.
  600. Any other value - The call failed because one of the Remote Storage API calls
  601. contained internally in this method failed. The error value returned is
  602. specific to the API call which failed.
  603. --*/
  604. {
  605. // since this code is currently only used by the CopyMedia routines,
  606. // reset the Tracing bit from this source module's default setting
  607. #undef WSB_TRACE_IS
  608. #define WSB_TRACE_IS WSB_TRACE_BIT_COPYMEDIA
  609. HRESULT hr = S_OK;
  610. CWsbStringPtr mediaDescription;
  611. CComPtr<IWsbDbSession> pDbSession;
  612. CComPtr<IMediaInfo> pMediaInfo;
  613. WsbTraceIn( OLESTR("CHsmServer::FindMediaIdByDescription"),
  614. OLESTR("description = <%ls>"), description );
  615. try {
  616. // ensure OUT parameter is valid
  617. WsbAssert( pMediaId != 0, E_POINTER );
  618. // null out the returned value so garbage is not returned
  619. *pMediaId = GUID_NULL;
  620. // open Engine's Segment database
  621. WsbAffirmHr(m_pSegmentDatabase->Open(&pDbSession));
  622. try {
  623. // get an interface pointer to the MediaInfo entity (records) in the
  624. // Segment database.
  625. WsbAffirmHr(m_pSegmentDatabase->GetEntity( pDbSession, HSM_MEDIA_INFO_REC_TYPE,
  626. IID_IMediaInfo, (void**) &pMediaInfo ));
  627. // Get the first media record and its description
  628. WsbAffirmHr( pMediaInfo->First() );
  629. WsbAffirmHr( pMediaInfo->GetDescription( &mediaDescription, 0 ) );
  630. // Iterate through all media records until a record is found with a matching
  631. // description. Since an architectural feature of HSM is that all
  632. // descriptions (display names) are unique, even across storage pools,
  633. // a match means we found the media record we want. Note that no match
  634. // being found will cause an error to be thrown when the Next() call is
  635. // made after reaching the last media record.
  636. // check for description (display name) match (CASE INSENSITIVE)
  637. while ( _wcsicmp( description, mediaDescription ) != 0 ) {
  638. WsbAffirmHr( pMediaInfo->Next() );
  639. WsbAffirmHr( pMediaInfo->GetDescription( &mediaDescription, 0 ));
  640. }
  641. // We found the record we want. Get that media's id for return
  642. WsbAffirmHr( pMediaInfo->GetId( pMediaId ));
  643. } WsbCatch (hr); // 'try' to get MediaInfo entity and main processing body
  644. // close the database
  645. WsbAffirmHr( m_pSegmentDatabase->Close( pDbSession ));
  646. } WsbCatch (hr); // 'try' to open the Segment database
  647. // Done. Interface pointers used above are singly assigned smart pointers so
  648. // don't explicitly Release() them. They will do auto-garbage collection.
  649. WsbTraceOut(OLESTR("CHsmServer::FindMediaIdByDescription"),
  650. OLESTR("hr = <%ls>, media id = <%ls>"),
  651. WsbHrAsString(hr), WsbGuidAsString(*pMediaId));
  652. return(hr);
  653. // leaving CopyMedia code, reset Tracing bit to Hsm Engine (default for this module)
  654. #undef WSB_TRACE_IS
  655. #define WSB_TRACE_IS WSB_TRACE_BIT_HSMENG
  656. }
  657. HRESULT
  658. CHsmServer::FindStoragePoolByName(
  659. IN OLECHAR* name,
  660. OUT IHsmStoragePool** ppStoragePool
  661. )
  662. /*++
  663. Implements:
  664. IHsmServer::FindStoragePoolByName().
  665. --*/
  666. {
  667. // since this code is currently only used by the CopyMedia routines,
  668. // reset the Tracing bit
  669. #undef WSB_TRACE_IS
  670. #define WSB_TRACE_IS WSB_TRACE_BIT_COPYMEDIA
  671. HRESULT hr = S_OK;
  672. GUID id;
  673. CWsbStringPtr storagePoolName;
  674. CComPtr<IWsbCollection> pCollection;
  675. CComPtr<IWsbEnum> pEnum;
  676. CComPtr<IHsmStoragePool> pStoragePool;
  677. WsbTraceIn(OLESTR("CHsmServer::FindStoragePoolByName"), OLESTR("name = <%ls>"), name);
  678. try {
  679. WsbAssert(0 != ppStoragePool, E_POINTER);
  680. *ppStoragePool = 0;
  681. WsbAffirmHr(m_pStoragePools->QueryInterface(IID_IWsbCollection, (void**) &pCollection));
  682. WsbAffirmHr(pCollection->Enum(&pEnum));
  683. WsbAffirmHr(pEnum->First(IID_IHsmStoragePool, (void**) &pStoragePool));
  684. WsbAffirmHr(pStoragePool->GetMediaSet(&id, &storagePoolName));
  685. while (_wcsicmp(name, storagePoolName) != 0) {
  686. pStoragePool = 0;
  687. WsbAffirmHr(pEnum->Next(IID_IHsmStoragePool, (void**) &pStoragePool));
  688. storagePoolName.Free();
  689. WsbAffirmHr(pStoragePool->GetMediaSet(&id, &storagePoolName));
  690. }
  691. *ppStoragePool = pStoragePool;
  692. if (pStoragePool != 0) {
  693. (*ppStoragePool)->AddRef();
  694. }
  695. } WsbCatch(hr);
  696. WsbTraceOut(OLESTR("CHsmServer::FindStoragePoolByName"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  697. return(hr);
  698. // leaving CopyMedia code, so reset Tracing bit to the Hsm Engine
  699. #undef WSB_TRACE_IS
  700. #define WSB_TRACE_IS WSB_TRACE_BIT_HSMENG
  701. }
  702. HRESULT CHsmServer::GetStoragePools(
  703. IWsbIndexedCollection **ppCollection
  704. )
  705. {
  706. HRESULT hr = S_OK;
  707. //
  708. // If the pools have been loaded, return the pointer. Otherwise,
  709. // fail.
  710. try {
  711. WsbAssert(0 != ppCollection, E_POINTER);
  712. *ppCollection = m_pStoragePools;
  713. WsbAffirm(m_pStoragePools != 0, E_FAIL);
  714. m_pStoragePools->AddRef();
  715. } WsbCatch(hr);
  716. return (hr);
  717. }
  718. HRESULT CHsmServer::GetOnlineInformation(
  719. IWsbIndexedCollection **ppCollection
  720. )
  721. {
  722. HRESULT hr = S_OK;
  723. //
  724. // If the online information has been loaded, return it
  725. // Otherwise, fail.
  726. try {
  727. WsbAssert(0 != ppCollection, E_POINTER);
  728. *ppCollection = m_pOnlineInformation;
  729. WsbAffirm(m_pOnlineInformation != 0, E_FAIL);
  730. m_pOnlineInformation->AddRef();
  731. } WsbCatch(hr);
  732. return (hr);
  733. }
  734. HRESULT CHsmServer::GetMountingMedias(
  735. IWsbIndexedCollection **ppCollection
  736. )
  737. {
  738. HRESULT hr = S_OK;
  739. try {
  740. WsbAssert(0 != ppCollection, E_POINTER);
  741. *ppCollection = m_pMountingMedias;
  742. WsbAffirm(m_pMountingMedias != 0, E_FAIL);
  743. m_pMountingMedias->AddRef();
  744. } WsbCatch(hr);
  745. return (hr);
  746. }
  747. HRESULT CHsmServer::GetMessages(
  748. IWsbIndexedCollection **ppCollection
  749. )
  750. {
  751. HRESULT hr = S_OK;
  752. //
  753. // If messages have been loaded, return them.
  754. // Otherwise, fail.
  755. try {
  756. WsbAssert(0 != ppCollection, E_POINTER);
  757. *ppCollection = m_pMessages;
  758. WsbAffirm(m_pMessages != 0, E_FAIL);
  759. m_pMessages->AddRef();
  760. } WsbCatch(hr);
  761. return (hr);
  762. }
  763. HRESULT CHsmServer::GetUsrToNotify(
  764. IWsbIndexedCollection** /*ppCollection*/
  765. )
  766. {
  767. return E_NOTIMPL;
  768. }
  769. HRESULT CHsmServer::GetJobs(
  770. IWsbIndexedCollection **ppCollection
  771. )
  772. {
  773. HRESULT hr = S_OK;
  774. //
  775. // If the jobs have been loaded, return the pointer. Otherwise,
  776. // fail.
  777. try {
  778. WsbAssert(0 != ppCollection, E_POINTER);
  779. *ppCollection = m_pJobs;
  780. WsbAffirm(m_pJobs != 0, E_FAIL);
  781. m_pJobs->AddRef();
  782. } WsbCatch(hr);
  783. return (hr);
  784. }
  785. HRESULT
  786. CHsmServer::FindJobByName(
  787. IN OLECHAR* name,
  788. OUT IHsmJob** ppJob
  789. )
  790. /*++
  791. Implements:
  792. IHsmServer::FindJobByName().
  793. --*/
  794. {
  795. HRESULT hr = S_OK;
  796. CWsbStringPtr jobName;
  797. CComPtr<IWsbCollection> pCollection;
  798. CComPtr<IWsbEnum> pEnum;
  799. CComPtr<IHsmJob> pJob;
  800. WsbTraceIn(OLESTR("CHsmServer::FindJobByName"), OLESTR("name = <%ls>"), name);
  801. try {
  802. WsbAssert(0 != ppJob, E_POINTER);
  803. *ppJob = 0;
  804. WsbAffirmHr(m_pJobs->QueryInterface(IID_IWsbCollection, (void**) &pCollection));
  805. WsbAffirmHr(pCollection->Enum(&pEnum));
  806. hr = pEnum->First(IID_IHsmJob, (void**) &pJob);
  807. while (S_OK == hr) {
  808. WsbAffirmHr(pJob->GetName(&jobName, 0));
  809. WsbTrace(OLESTR("CHsmServer::FindJobByName: name = <%ls>\n"),
  810. jobName);
  811. if (_wcsicmp(name, jobName) == 0) break;
  812. pJob = 0;
  813. hr = pEnum->Next(IID_IHsmJob, (void**) &pJob);
  814. }
  815. if (S_OK == hr) {
  816. *ppJob = pJob;
  817. if (pJob != 0) {
  818. (*ppJob)->AddRef();
  819. }
  820. }
  821. } WsbCatch(hr);
  822. WsbTraceOut(OLESTR("CHsmServer::FindJobByName"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  823. return(hr);
  824. }
  825. HRESULT CHsmServer::GetJobDefs(
  826. IWsbIndexedCollection **ppCollection
  827. )
  828. {
  829. HRESULT hr = S_OK;
  830. //
  831. // If the job definitions have been loaded, return the pointer. Otherwise,
  832. // fail.
  833. try {
  834. WsbAssert(0 != ppCollection, E_POINTER);
  835. *ppCollection = m_pJobDefs;
  836. WsbAffirm(m_pJobDefs != 0, E_FAIL);
  837. m_pJobDefs->AddRef();
  838. } WsbCatch(hr);
  839. return (hr);
  840. }
  841. HRESULT CHsmServer::GetMediaRecs(
  842. IWsbIndexedCollection **ppCollection
  843. )
  844. {
  845. HRESULT hr = S_OK;
  846. WsbTraceIn(OLESTR("CHsmServer::GetMediaRecs"), OLESTR(""));
  847. try {
  848. HRESULT hr2;
  849. CComPtr<IWsbIndexedCollection> pCol;
  850. CComPtr<IWsbDbSession> pDbSes;
  851. CComPtr<IWsbDbEntity> pRec;
  852. WsbAffirm(m_pSegmentDatabase != 0, E_FAIL);
  853. WsbAssert(0 != ppCollection, E_POINTER);
  854. WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER,
  855. IID_IWsbIndexedCollection, (void **)&pCol ));
  856. WsbAffirmHr(m_pSegmentDatabase->Open(&pDbSes));
  857. WsbAffirmHr(m_pSegmentDatabase->GetEntity(pDbSes, HSM_MEDIA_INFO_REC_TYPE,
  858. IID_IWsbDbEntity, (void**)&pRec));
  859. // Loop over records in DB and copy to collection
  860. hr2 = pRec->First();
  861. while(S_OK == hr2) {
  862. CComPtr<IMediaInfo> pCopy;
  863. CComPtr<IMediaInfo> pOrig;
  864. GUID MediaId;
  865. GUID MediaSubsystemId;
  866. GUID StoragePoolId;
  867. LONGLONG FreeBytes;
  868. LONGLONG Capacity;
  869. HRESULT LastError;
  870. short NextRemoteDataSet;
  871. OLECHAR * pDescription = NULL;
  872. HSM_JOB_MEDIA_TYPE Type;
  873. OLECHAR * pName = NULL;
  874. BOOL ReadOnly;
  875. FILETIME Update;
  876. LONGLONG LogicalValidBytes;
  877. BOOL Recreate;
  878. // Create a copy for the collection
  879. WsbAffirmHr(CoCreateInstance(CLSID_CMediaInfo, NULL, CLSCTX_ALL,
  880. IID_IMediaInfo, (void**) &pCopy));
  881. // Copy data
  882. WsbAffirmHr(pRec->QueryInterface(IID_IMediaInfo, (void**)&pOrig));
  883. WsbAffirmHr(pOrig->GetMediaInfo(&MediaId, &MediaSubsystemId,
  884. &StoragePoolId, &FreeBytes, &Capacity, &LastError, &NextRemoteDataSet,
  885. &pDescription, 0, &Type, &pName, 0, &ReadOnly, &Update, &LogicalValidBytes,
  886. &Recreate));
  887. WsbTrace(OLESTR("CHsmServer::GetMediaRecs: after GetMediaInfo\n"));
  888. WsbAffirmHr(pCopy->SetMediaInfo(MediaId, MediaSubsystemId,
  889. StoragePoolId, FreeBytes, Capacity, LastError, NextRemoteDataSet,
  890. pDescription, Type, pName, ReadOnly, Update, LogicalValidBytes,
  891. Recreate));
  892. WsbTrace(OLESTR("CHsmServer::GetMediaRecs: after SetMediaInfo\n"));
  893. if (pDescription) {
  894. WsbFree(pDescription);
  895. pDescription = NULL;
  896. }
  897. if (pName) {
  898. WsbFree(pName);
  899. pName = NULL;
  900. }
  901. WsbAffirmHr(pCol->Add(pCopy));
  902. hr2 = pRec->Next();
  903. }
  904. WsbAffirm(WSB_E_NOTFOUND == hr2, hr2);
  905. *ppCollection = pCol;
  906. pCol->AddRef();
  907. } WsbCatch(hr);
  908. WsbTraceOut(OLESTR("CHsmServer::GetMediaRecs"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  909. return (hr);
  910. }
  911. HRESULT CHsmServer::GetPolicies(
  912. IWsbIndexedCollection **ppCollection
  913. )
  914. {
  915. HRESULT hr = S_OK;
  916. //
  917. // If the policies have been loaded, return the pointer. Otherwise,
  918. // fail.
  919. try {
  920. WsbAssert(0 != ppCollection, E_POINTER);
  921. *ppCollection = m_pPolicies;
  922. WsbAffirm(m_pPolicies != 0, E_FAIL);
  923. m_pPolicies->AddRef();
  924. } WsbCatch(hr);
  925. return (hr);
  926. }
  927. HRESULT CHsmServer::GetActions(
  928. IWsbIndexedCollection** /*ppCollection*/
  929. )
  930. {
  931. return E_NOTIMPL;
  932. }
  933. HRESULT CHsmServer::GetCriteria(
  934. IWsbIndexedCollection** /*ppCollection*/
  935. )
  936. {
  937. return E_NOTIMPL;
  938. }
  939. HRESULT CHsmServer::GetSegmentDb(
  940. IWsbDb **ppDb
  941. )
  942. {
  943. HRESULT hr = S_OK;
  944. //
  945. // If the segment table has been created, return the pointer. Otherwise,
  946. // fail.
  947. try {
  948. WsbAssert(0 != ppDb, E_POINTER);
  949. WsbAffirm(m_pSegmentDatabase != 0, E_FAIL);
  950. *ppDb = m_pSegmentDatabase;
  951. m_pSegmentDatabase->AddRef();
  952. } WsbCatch(hr);
  953. return (hr);
  954. }
  955. HRESULT CHsmServer::GetHsmFsaTskMgr(
  956. IHsmFsaTskMgr **ppHsmFsaTskMgr
  957. )
  958. {
  959. HRESULT hr = S_OK;
  960. //
  961. // If the Task Manager has been created, return the pointer. Otherwise,
  962. // fail.
  963. try {
  964. WsbAssert(0 != ppHsmFsaTskMgr, E_POINTER);
  965. *ppHsmFsaTskMgr = m_pHsmFsaTskMgr;
  966. WsbAffirm(m_pHsmFsaTskMgr != 0, E_FAIL);
  967. m_pHsmFsaTskMgr->AddRef();
  968. } WsbCatch(hr);
  969. return (hr);
  970. }
  971. HRESULT
  972. CHsmServer::CreateInstance (
  973. REFCLSID rclsid,
  974. REFIID riid,
  975. void **ppv
  976. )
  977. {
  978. HRESULT hr = S_OK;
  979. hr = CoCreateInstance( rclsid, NULL, CLSCTX_SERVER, riid, ppv );
  980. return hr;
  981. }
  982. HRESULT CHsmServer::FinalConstruct(
  983. )
  984. {
  985. HRESULT hr = S_OK;
  986. WsbTraceIn(OLESTR("CHsmServer::FinalConstruct"), OLESTR(""));
  987. //
  988. // Initialize member data
  989. //
  990. m_pRssWriter = NULL;
  991. m_savingEvent = NULL;
  992. m_terminateEvent = NULL;
  993. m_hId = GUID_NULL;
  994. m_initializationCompleted = FALSE;
  995. m_persistWasCreated = FALSE;
  996. m_mediaCount = 0;
  997. m_copyfilesUserLimit = DEFAULT_COPYFILES_USER_LIMIT;
  998. m_autosaveThread = 0;
  999. m_CheckManagedResourcesThread = 0;
  1000. m_cancelCopyMedia = FALSE;
  1001. m_inCopyMedia = FALSE;
  1002. m_Suspended = FALSE;
  1003. m_JobsEnabled = TRUE;
  1004. InitializeCriticalSectionAndSpinCount(&m_JobDisableLock, 1000);
  1005. InitializeCriticalSectionAndSpinCount(&m_MountingMediasLock, 1000);
  1006. try {
  1007. WsbAffirmHr(CWsbPersistable::FinalConstruct( ));
  1008. } WsbCatch(hr);
  1009. WsbTraceOut(OLESTR("CHsmServer::FinalConstruct"), OLESTR("hr = <%ls>\n"), WsbHrAsString(hr));
  1010. return( hr );
  1011. }
  1012. void CHsmServer::FinalRelease(
  1013. )
  1014. {
  1015. WsbTraceIn(OLESTR("CHsmServer::FinalRelease"), OLESTR(""));
  1016. if (TRUE == m_initializationCompleted) {
  1017. HSM_SYSTEM_STATE SysState;
  1018. SysState.State = HSM_STATE_SHUTDOWN;
  1019. ChangeSysState(&SysState);
  1020. } else {
  1021. WsbTrace(OLESTR("CHsmServer::FinalRelease not saving persistent information.\n"));
  1022. }
  1023. // Let the parent class do his thing.
  1024. CWsbPersistable::FinalRelease();
  1025. DeleteCriticalSection(&m_JobDisableLock);
  1026. DeleteCriticalSection(&m_MountingMediasLock);
  1027. // Free String members
  1028. // Note: Member objects held in smart-pointers are freed when the
  1029. // smart-pointer destructor is being called (as part of this object destruction)
  1030. m_name.Free();
  1031. m_dir.Free();
  1032. m_dbPath.Free();
  1033. if (m_terminateEvent != NULL) {
  1034. CloseHandle(m_terminateEvent);
  1035. m_terminateEvent = NULL;
  1036. }
  1037. // Cleanup the writer
  1038. m_pRssWriter->Terminate();
  1039. delete m_pRssWriter;
  1040. m_pRssWriter = NULL;
  1041. // Clean up database system
  1042. m_pDbSys->Terminate();
  1043. if (m_savingEvent != NULL) {
  1044. CloseHandle(m_savingEvent);
  1045. m_savingEvent = NULL;
  1046. }
  1047. WsbTraceOut(OLESTR("CHsmServer::FinalRelease"), OLESTR(""));
  1048. }
  1049. HRESULT
  1050. CHsmServer::GetClassID(
  1051. OUT CLSID* pClsid
  1052. )
  1053. /*++
  1054. Implements:
  1055. IPersist::GetClassID().
  1056. --*/
  1057. {
  1058. HRESULT hr = S_OK;
  1059. WsbTraceIn(OLESTR("CHsmServer::GetClassID"), OLESTR(""));
  1060. try {
  1061. WsbAssert(0 != pClsid, E_POINTER);
  1062. *pClsid = CLSID_HsmServer;
  1063. } WsbCatch(hr);
  1064. WsbTraceOut(OLESTR("CHsmServer::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid));
  1065. return(hr);
  1066. }
  1067. HRESULT CHsmServer::Init(
  1068. void
  1069. )
  1070. {
  1071. HRESULT hr = S_OK;
  1072. WsbTraceIn(OLESTR("CHsmServer::Init"),OLESTR(""));
  1073. try {
  1074. CComPtr<IPersistFile> pPersistFile;
  1075. DWORD threadId;
  1076. CWsbStringPtr tmpString;
  1077. LUID backupValue;
  1078. HANDLE tokenHandle;
  1079. TOKEN_PRIVILEGES newState;
  1080. DWORD lErr;
  1081. HANDLE pHandle;
  1082. // Get our Name
  1083. WsbAffirmHr(WsbGetComputerName(m_name));
  1084. // Set the build and database parameters
  1085. WsbAffirmHr(WsbGetMetaDataPath(m_dbPath));
  1086. m_databaseVersion = ENGINE_CURRENT_DB_VERSION;
  1087. m_buildVersion = RS_BUILD_VERSION;
  1088. // Set the autosave parameters.
  1089. m_autosaveInterval = DEFAULT_AUTOSAVE_INTERVAL;
  1090. m_autosaveThread = 0;
  1091. // Enable the backup operator privilege. This is required to insure that we
  1092. // have full access to all resources on the system.
  1093. pHandle = GetCurrentProcess();
  1094. WsbAffirmStatus(OpenProcessToken(pHandle, MAXIMUM_ALLOWED, &tokenHandle));
  1095. // adjust backup token privileges
  1096. WsbAffirmStatus(LookupPrivilegeValueW(NULL, L"SeBackupPrivilege", &backupValue));
  1097. newState.PrivilegeCount = 1;
  1098. newState.Privileges[0].Luid = backupValue;
  1099. newState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  1100. WsbAffirmStatus(AdjustTokenPrivileges(tokenHandle, FALSE, &newState, (DWORD)0, NULL, NULL));
  1101. // Note that AdjustTokenPrivileges may return success even if it did not assign all privileges.
  1102. // We check last error here to insure everything was set.
  1103. if ((lErr = GetLastError()) != ERROR_SUCCESS) {
  1104. // Not backup user or some other error
  1105. //
  1106. // TODO: Should we fail here or just log something?
  1107. WsbLogEvent( HSM_MESSAGE_SERVICE_UNABLE_TO_SET_BACKUP_PRIVILEGE, 0, NULL,
  1108. WsbHrAsString(HRESULT_FROM_WIN32(lErr)), NULL );
  1109. }
  1110. WsbAffirmStatus(LookupPrivilegeValueW(NULL, L"SeRestorePrivilege", &backupValue));
  1111. newState.PrivilegeCount = 1;
  1112. newState.Privileges[0].Luid = backupValue;
  1113. newState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  1114. WsbAffirmStatus(AdjustTokenPrivileges(tokenHandle, FALSE, &newState, (DWORD)0, NULL, NULL));
  1115. // Note that AdjustTokenPrivileges may return success even if it did not assign all privileges.
  1116. // We check last error here to insure everything was set.
  1117. if ((lErr = GetLastError()) != ERROR_SUCCESS) {
  1118. // Not backup user or some other error
  1119. //
  1120. // TODO: Should we fail here or just log something?
  1121. WsbLogEvent( HSM_MESSAGE_SERVICE_UNABLE_TO_SET_RESTORE_PRIVILEGE, 0, NULL,
  1122. WsbHrAsString(HRESULT_FROM_WIN32(lErr)), NULL );
  1123. }
  1124. CloseHandle(tokenHandle);
  1125. // Create the Writer
  1126. m_pRssWriter = new CRssJetWriter;
  1127. WsbAffirm(NULL != m_pRssWriter, E_OUTOFMEMORY);
  1128. // Create the event that synchronize saving of persistent data with snapshots
  1129. WsbAffirmHandle(m_savingEvent = CreateEvent(NULL, FALSE, TRUE, HSM_ENGINE_STATE_EVENT));
  1130. //
  1131. // Create one instance of the Media Server Interface
  1132. // (It must be created before the persistent data is loaded.
  1133. //
  1134. WsbTrace(OLESTR("Creating Rsm Server member.\n"));
  1135. WsbAffirmHr(CoCreateInstance(CLSID_CRmsServer, NULL, CLSCTX_SERVER,
  1136. IID_IRmsServer, (void**)&m_pHsmMediaMgr));
  1137. //
  1138. // Load the persistent information
  1139. //
  1140. WsbTrace(OLESTR("Loading Persistent Information.\n"));
  1141. WsbAffirmHr(LoadPersistData());
  1142. // Create mounting-medias collection - Note: this collection is not persistent!
  1143. WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, 0, CLSCTX_SERVER,
  1144. IID_IWsbIndexedCollection, (void **)&m_pMountingMedias));
  1145. // Initialize the Media Server object
  1146. WsbAffirmHr(m_pHsmMediaMgr->InitializeInAnotherThread());
  1147. // Initialize the IDB system for this process
  1148. WsbAffirmHr(CoCreateInstance(CLSID_CWsbDbSys, NULL, CLSCTX_SERVER,
  1149. IID_IWsbDbSys, (void**) &m_pDbSys));
  1150. WsbAffirmHr(GetIDbPath(&tmpString, 0));
  1151. WsbAffirmHr(m_pDbSys->Init(tmpString, IDB_SYS_INIT_FLAG_FULL_LOGGING));
  1152. // Start automatic backup of DBs
  1153. WsbAffirmHr(m_pDbSys->Backup(NULL, IDB_BACKUP_FLAG_AUTO));
  1154. // Initialize Rss Writer
  1155. WsbAffirmHr(m_pRssWriter->Init());
  1156. WsbTrace(OLESTR("Loading Segment Information.\n"));
  1157. WsbAffirmHr(LoadSegmentInformation());
  1158. WsbAffirmHr(CreateDefaultJobs());
  1159. WsbTrace(OLESTR("CreateDefaultJobs OK\n"));
  1160. //
  1161. // Create one instance of the Hsm Task Manager Interface and one instance
  1162. // of the Hsm Fsa Task Manager Interface
  1163. //
  1164. WsbTrace(OLESTR("Creating Task Manager.\n"));
  1165. WsbAffirmHr(CoCreateInstance( CLSID_CHsmTskMgr, 0, CLSCTX_SERVER,
  1166. IID_IHsmFsaTskMgr, (void **)&m_pHsmFsaTskMgr ));
  1167. WsbAffirmHr(m_pHsmFsaTskMgr->Init((IUnknown*) (IHsmServer*) this));
  1168. //
  1169. // Tell the world that we are here
  1170. //
  1171. // Currently, avoid publishing HSM in the AD - if this becomes necessary,
  1172. // remove the comments from the following code
  1173. //
  1174. /*** WsbAffirmHr(HsmPublish (HSMCONN_TYPE_HSM, m_name, m_hId, m_name, CLSID_HsmServer ));
  1175. WsbTrace(OLESTR("Published OK\n")); ***/
  1176. // Create termination event for auto-backup thread
  1177. WsbAffirmHandle((m_terminateEvent = CreateEvent(NULL, FALSE, FALSE, NULL)));
  1178. // If the autosave interval is non-zero, start the autosave thread
  1179. if (m_autosaveInterval) {
  1180. ULONG interval = m_autosaveInterval;
  1181. WsbAffirm(0 == m_autosaveThread, E_FAIL);
  1182. m_autosaveInterval = 0;
  1183. // Trick SetAutosave into starting the thread
  1184. WsbAffirmHr(SetAutosave(interval));
  1185. }
  1186. m_initializationCompleted = TRUE;
  1187. // Start a thread that will check on the managed resources. This is done
  1188. // as a separate thread because the Resource code can call back into this
  1189. // process and hang the FSA and the Engine since the Engine code hasn't
  1190. // gotten to it's message loop yet.
  1191. WsbAffirm((m_CheckManagedResourcesThread = CreateThread(0, 0, HsmengStartCheckManagedResources,
  1192. (void*) this, 0, &threadId)) != 0, HRESULT_FROM_WIN32(GetLastError()));
  1193. } WsbCatch( hr );
  1194. WsbTraceOut(OLESTR("CHsmServer::Init"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1195. return( hr );
  1196. }
  1197. HRESULT
  1198. CHsmServer::GetSizeMax(
  1199. OUT ULARGE_INTEGER* pSize
  1200. )
  1201. /*++
  1202. Implements:
  1203. IPersistStream::GetSizeMax().
  1204. --*/
  1205. {
  1206. HRESULT hr = S_OK;
  1207. WsbTraceIn(OLESTR("CHsmServer::GetSizeMax"), OLESTR(""));
  1208. try {
  1209. WsbAssert(0 != pSize, E_POINTER);
  1210. pSize->QuadPart = 2000000;
  1211. } WsbCatch( hr );
  1212. WsbTraceOut(OLESTR("CHsmServer::GetSizeMax"), OLESTR("hr = <%ls>, size = <%ls>"),
  1213. WsbHrAsString(hr), WsbPtrToUliAsString(pSize));
  1214. return( hr );
  1215. }
  1216. HRESULT
  1217. CHsmServer::Load(
  1218. IN IStream* pStream
  1219. )
  1220. /*++
  1221. Implements:
  1222. IPersistStream::Load().
  1223. --*/
  1224. {
  1225. HRESULT hr = S_OK;
  1226. WsbTraceIn(OLESTR("CHsmServer::Load"), OLESTR(""));
  1227. try {
  1228. WsbAssert(0 != pStream, E_POINTER);
  1229. //
  1230. // Make sure these are in the same order as Save
  1231. //
  1232. // Make sure this is the right version of the database to load
  1233. //
  1234. ULONG tmpDatabaseVersion;
  1235. WsbAffirmHr(WsbLoadFromStream(pStream, &tmpDatabaseVersion));
  1236. if (tmpDatabaseVersion == ENGINE_WIN2K_DB_VERSION) {
  1237. // We are upgrading from an older version of the database
  1238. WsbLogEvent( HSM_MESSAGE_DATABASE_VERSION_UPGRADE, 0, NULL, WsbQuickString(WsbPtrToUlongAsString(&m_databaseVersion)),
  1239. WsbQuickString(WsbPtrToUlongAsString(&tmpDatabaseVersion)), NULL );
  1240. } else if (tmpDatabaseVersion != m_databaseVersion) {
  1241. //
  1242. // The database version this server is expecting does not
  1243. // match that of the saved database - so error out.
  1244. WsbLogEvent( HSM_MESSAGE_DATABASE_VERSION_MISMATCH, 0, NULL, WsbQuickString(WsbPtrToUlongAsString(&m_databaseVersion)),
  1245. WsbQuickString(WsbPtrToUlongAsString(&tmpDatabaseVersion)), NULL );
  1246. WsbThrow(HSM_E_DATABASE_VERSION_MISMATCH);
  1247. }
  1248. //
  1249. // Now read in the build version but don't do anything with it. It is in the
  1250. // databases for dump programs to display
  1251. //
  1252. ULONG tmpBuildVersion;
  1253. WsbAffirmHr(WsbLoadFromStream(pStream, &tmpBuildVersion));
  1254. WsbAffirmHr(WsbLoadFromStream(pStream, &m_hId));
  1255. WsbAffirmHr(WsbLoadFromStream(pStream, &m_autosaveInterval));
  1256. if (tmpDatabaseVersion == ENGINE_WIN2K_DB_VERSION) {
  1257. LONGLONG mediaCount;
  1258. WsbAffirmHr(WsbLoadFromStream(pStream, &mediaCount));
  1259. m_mediaCount = (LONG)mediaCount;
  1260. m_copyfilesUserLimit = DEFAULT_COPYFILES_USER_LIMIT;
  1261. } else {
  1262. WsbAffirmHr(WsbLoadFromStream(pStream, &m_mediaCount));
  1263. WsbAffirmHr(WsbLoadFromStream(pStream, &m_copyfilesUserLimit));
  1264. }
  1265. WsbTrace(OLESTR("Loading Jobs.\n"));
  1266. WsbAffirmHr(LoadJobs(pStream));
  1267. WsbTrace(OLESTR("Loading Job Definitions.\n"));
  1268. WsbAffirmHr(LoadJobDefs(pStream));
  1269. WsbTrace(OLESTR("Loading Policies.\n"));
  1270. WsbAffirmHr(LoadPolicies(pStream));
  1271. WsbTrace(OLESTR("Loading Managed Resources.\n"));
  1272. WsbAffirmHr(LoadManagedResources(pStream));
  1273. WsbTrace(OLESTR("Loading Storage Pools.\n"));
  1274. WsbAffirmHr(LoadStoragePools(pStream));
  1275. WsbTrace(OLESTR("Loading Messages.\n"));
  1276. WsbAffirmHr(LoadMessages(pStream));
  1277. WsbTrace(OLESTR("Loading Media Manager objects.\n"));
  1278. if (tmpDatabaseVersion == ENGINE_WIN2K_DB_VERSION) {
  1279. // Special procedure for upgrading a Win2K media manager data, which is located in a separate file
  1280. CComPtr<IHsmUpgradeRmsDb> pUpgrade;
  1281. CComPtr<IPersistFile> pServerPersist;
  1282. CWsbStringPtr rmsDbName;
  1283. WsbAffirmHr(CoCreateInstance(CLSID_CHsmUpgradeRmsDb, NULL, CLSCTX_SERVER,
  1284. IID_IHsmUpgradeRmsDb, (void**)&pUpgrade));
  1285. WsbAffirmHr(pUpgrade->Init(m_pHsmMediaMgr));
  1286. WsbAffirmHr(pUpgrade->QueryInterface(IID_IPersistFile, (void **)&pServerPersist));
  1287. rmsDbName = m_dbPath;
  1288. WsbAffirmHr(rmsDbName.Append(RMS_WIN2K_PERSIST_FILE));
  1289. hr = WsbSafeLoad(rmsDbName, pServerPersist, FALSE);
  1290. if (WSB_E_NOTFOUND == hr) {
  1291. // In case of upgrade, the Rms database must be there
  1292. hr = WSB_E_SERVICE_MISSING_DATABASES;
  1293. }
  1294. WsbAffirmHr(hr);
  1295. } else {
  1296. CComPtr<IPersistStream> pIStream;
  1297. WsbAffirmHr(m_pHsmMediaMgr->QueryInterface(IID_IPersistStream, (void **)&pIStream));
  1298. WsbAffirmHr(pIStream->Load(pStream));
  1299. }
  1300. } WsbCatch(hr);
  1301. WsbTraceOut(OLESTR("CHsmServer::Load"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1302. return(hr);
  1303. }
  1304. HRESULT
  1305. CHsmServer::Save(
  1306. IN IStream* pStream,
  1307. IN BOOL clearDirty
  1308. )
  1309. /*++
  1310. Implements:
  1311. IPersistStream::Save().
  1312. --*/
  1313. {
  1314. HRESULT hr = S_OK;
  1315. WsbTraceIn(OLESTR("CHsmServer::Save"), OLESTR("clearDirty = <%ls>"), WsbBoolAsString(clearDirty));
  1316. try {
  1317. WsbAssert(0 != pStream, E_POINTER);
  1318. // Make sure these are in the same order as Load
  1319. WsbAffirmHr(WsbSaveToStream(pStream, m_databaseVersion));
  1320. WsbAffirmHr(WsbSaveToStream(pStream, m_buildVersion));
  1321. WsbAffirmHr(WsbSaveToStream(pStream, m_hId));
  1322. WsbAffirmHr(WsbSaveToStream(pStream, m_autosaveInterval));
  1323. WsbAffirmHr(WsbSaveToStream(pStream, m_mediaCount));
  1324. WsbAffirmHr(WsbSaveToStream(pStream, m_copyfilesUserLimit));
  1325. WsbTrace(OLESTR("Storing Jobs.\n"));
  1326. WsbAffirmHr(StoreJobs(pStream));
  1327. WsbTrace(OLESTR("Storing Job Definitions.\n"));
  1328. WsbAffirmHr(StoreJobDefs(pStream));
  1329. WsbTrace(OLESTR("Storing Policies.\n"));
  1330. WsbAffirmHr(StorePolicies(pStream));
  1331. WsbTrace(OLESTR("Storing Managed Resources.\n"));
  1332. WsbAffirmHr(StoreManagedResources(pStream));
  1333. WsbTrace(OLESTR("Storing Storage Pools.\n"));
  1334. WsbAffirmHr(StoreStoragePools(pStream));
  1335. WsbTrace(OLESTR("Storing Messages.\n"));
  1336. WsbAffirmHr(StoreMessages(pStream));
  1337. WsbTrace(OLESTR("Storing Media Manager objects.\n"));
  1338. CComPtr<IPersistStream> pIStream;
  1339. WsbAffirmHr(m_pHsmMediaMgr->QueryInterface(IID_IPersistStream, (void **)&pIStream));
  1340. WsbAffirmHr(pIStream->Save(pStream, clearDirty));
  1341. // If we got it saved and we were asked to clear the dirty bit, then
  1342. // do so now.
  1343. if (clearDirty) {
  1344. m_isDirty = FALSE;
  1345. }
  1346. } WsbCatch(hr);
  1347. WsbTraceOut(OLESTR("CHsmServer::Save"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1348. return(hr);
  1349. }
  1350. STDMETHODIMP
  1351. CHsmServer::SaveAll(
  1352. void
  1353. )
  1354. /*++
  1355. Implements:
  1356. IwsbServer::SaveAll
  1357. Return Value:
  1358. S_OK - Success
  1359. S_FALSE - Already saving
  1360. Other - Error
  1361. --*/
  1362. {
  1363. HRESULT hr = S_OK;
  1364. WsbTraceIn(OLESTR("CHsmServer::SaveAll"), OLESTR(""));
  1365. try {
  1366. WsbAffirm(!g_HsmSaveInProcess, S_FALSE);
  1367. g_HsmSaveInProcess = TRUE;
  1368. hr = InternalSavePersistData();
  1369. g_HsmSaveInProcess = FALSE;
  1370. // call Media Server SaveAll
  1371. WsbAffirmHr(m_pHsmMediaMgr->SaveAll());
  1372. } WsbCatch(hr);
  1373. WsbTraceOut(OLESTR("CHsmServer::SaveAll"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1374. return(hr);
  1375. }
  1376. HRESULT
  1377. CHsmServer::GetNextMedia(
  1378. LONG *pNextMedia
  1379. )
  1380. /*++
  1381. Implements:
  1382. IHsmServer::GetNextMedia().
  1383. --*/
  1384. {
  1385. HRESULT hr = S_OK;
  1386. WsbTraceIn(OLESTR("CHsmServer::GetNextMedia"), OLESTR(""));
  1387. try {
  1388. WsbAssert(0 != pNextMedia, E_POINTER);
  1389. // Always increment media count
  1390. // If prior scratch mount failed, the mounting component should save the id that
  1391. // it got on the first call
  1392. // NOTE: One possible consequence is that if a job fails mounting scratch (one time
  1393. // or more) and gives up, one increment has already done, hence skipping one number.
  1394. *pNextMedia = InterlockedIncrement(&m_mediaCount);
  1395. //
  1396. // We want to make sure we never reuse this count so
  1397. // save it now
  1398. //
  1399. WsbAffirmHr(SavePersistData());
  1400. } WsbCatch(hr);
  1401. WsbTraceOut(OLESTR("CHsmServer::GetNextMedia"), OLESTR("hr = <%ls>, nextMedia = <%ls>"),
  1402. WsbHrAsString(hr), WsbPtrToLongAsString(pNextMedia));
  1403. return(hr);
  1404. }
  1405. HRESULT
  1406. CHsmServer::CreateTask(
  1407. IN const OLECHAR * jobName,
  1408. IN const OLECHAR * jobParameters,
  1409. IN const OLECHAR * jobComments,
  1410. IN const TASK_TRIGGER_TYPE jobTriggerType,
  1411. IN const WORD jobStartHour,
  1412. IN const WORD jobStartMinute,
  1413. IN const BOOL scheduledJob
  1414. )
  1415. /*++
  1416. Implements:
  1417. IHsmServer::CreateTask().
  1418. Routine Description:
  1419. This routine implements the Engine's COM method for creating a task (aka job) in the
  1420. NT Task Scheduler. If the task is to be run on a scheduled basis, that schedule
  1421. will be set. If the task is a disabled task (does not run on a scheduled basis),
  1422. it will be run at the end of this method.
  1423. The method creates a Task Scheduler object, which is first used to delete any old
  1424. task with the same name as the one about to be created, and then to create the new
  1425. task (aka job). The rest of the method deals with setting the various fields in
  1426. the NT Task Scheduler needed to run the job. The logic is straight forward, except
  1427. possibly for the code dealing with the Task Trigger.
  1428. The Task Trigger is a struct defined in the 'mstask.idl' file (nt\public\sdk\inc)
  1429. which is used to set the schedule for a scheduled task. (Note it is not used for
  1430. a disabled, or non-scheduled, job, since that type of job only runs once (at the end
  1431. of this method).) While a number of scheduling options are defined, this method
  1432. only supports 5 of the 8 defined. See 'jobTriggerType' in the 'Arguments' section,
  1433. and 'E_INVALIDARG' in the 'Return Value' section below for a listing of which options
  1434. are, and are not, supported. Also note that a filled-out Task Trigger structure can
  1435. not be passed to this method as an argument since a Task Trigger is non-marshallable
  1436. (by virtue of containing a simple union field). (This is why 3 of the fields
  1437. contained within the Task Trigger struct are passed as args.)
  1438. Note that this method does not create a job object in the HSM Engine. If a job
  1439. needs to be created, it is the caller's responsibility to do so.
  1440. Arguments:
  1441. jobName - The fully formatted task name as it will appear in the NT Task Scheduler UI.
  1442. It is the caller's responsibility to build/format this string prior to
  1443. calling this method. Can not be NULL.
  1444. jobParameters - The fully formatted parameter string for the program the task will
  1445. invoke. For Sakkara the invoked program is RsLaunch. 'jobParameters'
  1446. is the string added to the RsLaunch command line which specifies the
  1447. Remote Storage job to run (e.g., 'run manage'). Can not be NULL.
  1448. jobComments - The fully formatted comments string as it will appear in the NT Task
  1449. Scheduler UI. Can be null.
  1450. jobTriggerType - The value which specifies to the Task Scheduler the frequency with
  1451. which to run a scheduled task. For scheduled tasks, used to build the
  1452. Task Trigger structure. (Not used for non-scheduled (one time only)
  1453. tasks.) Supported values are 'TASK_TIME_TRIGGER_ONCE',
  1454. 'TASK_TIME_TRIGGER_DAILY', 'TASK_TIME_TRIGGER_ON_IDLE',
  1455. 'TASK_TIME_TRIGGER_AT_SYSTEMSTART', and 'TASK_TIME_TRIGGER_AT_LOGON'.
  1456. See return value 'E_INVALIDARG' below for a list of non-supported options.
  1457. jobStartHour - The value which specifies to the Task Scheduler the hour at which to
  1458. start a scheduled task. For scheduled tasks, used to build the Task
  1459. Trigger structure. (Not used for non-scheduled (one time only) tasks.)
  1460. jobStartMinute - The value which specifies to the Task Scheduler the minutes past
  1461. the hour at which to start a scheduled task. For scheduled tasks, used
  1462. to build the Task Trigger structure. (Not used for non-scheduled (one
  1463. time only) tasks.)
  1464. scheduledJob - A Boolean which indicates whether or not the task to be created is to
  1465. run as a scheduled task, or as a one time only task. One time only tasks
  1466. are run immediately at the end of this method.
  1467. Return Value:
  1468. S_OK - The call succeeded (the specified task was created (and run, in the case of
  1469. one time only tasks) in NT Task Scheduler).
  1470. E_INVALIDARG - Either an invalid (not supported by this method) or non-existent
  1471. 'jobTriggerType' value was passed into this method. Non-supported values
  1472. are 'TASK_TIME_TRIGGER_WEEKLY', 'TASK_TIME_TRIGGER_MONTHLYDATE', and
  1473. 'TASK_TIME_TRIGGER_MONTHLYDOW'. Supported values are listed in argument
  1474. 'jobTriggerType' above.
  1475. E_POINTER - Either the 'jobName' or 'jobParameters' argument was passed as NULL.
  1476. Any other value - The call failed because one of the Remote Storage API calls
  1477. contained internally in this method failed. The error value returned is
  1478. specific to the API call which failed.
  1479. --*/
  1480. {
  1481. // The below 'define' statement is used to control conditional compilation of the code
  1482. // which sets the account info in NT Task Scheduler. Once Task Scheduler is fixed to
  1483. // not need a specific user name and password to run a task, simply remove or comment
  1484. // out this statement.
  1485. HRESULT hr = S_OK;
  1486. CComPtr<ITaskScheduler> pTaskScheduler;
  1487. CComPtr<ITask> pTask;
  1488. CComPtr<IPersistFile> pPersist;
  1489. DWORD TaskFlags;
  1490. WsbTraceIn(OLESTR("CHsmServer::CreateTask"),
  1491. OLESTR("jobName = <%ls>, jobParameters = <%ls>, jobComments = <%ls>, "
  1492. L"jobTriggerType = <%d>, jobStartHour = <%d>, jobStartMinute = <%d>, "
  1493. L"scheduledJob = <%ls>"), jobName, jobParameters, jobComments,
  1494. jobTriggerType, jobStartHour, jobStartMinute,
  1495. WsbBoolAsString( scheduledJob ) );
  1496. try {
  1497. WsbAffirmPointer( jobName );
  1498. WsbAffirmPointer( jobParameters );
  1499. // Create a Task Scheduler object, which defaults to pointing to this computer's
  1500. // NT Task Scheduler.
  1501. WsbAffirmHr( CoCreateInstance( CLSID_CTaskScheduler, 0, CLSCTX_SERVER,
  1502. IID_ITaskScheduler, (void **) &pTaskScheduler ) );
  1503. // Delete any old job with the same name from the scheduler, if it exists.
  1504. // Ignore error.
  1505. pTaskScheduler->Delete( jobName );
  1506. // Create the new job in the scheduler
  1507. WsbAffirmHr( pTaskScheduler->NewWorkItem( jobName, CLSID_CTask, IID_ITask,
  1508. (IUnknown**)&pTask ) );
  1509. CWsbStringPtr appName;
  1510. WsbAffirmHr(appName.LoadFromRsc(_Module.m_hInst, IDS_PRODUCT_NAME));
  1511. // Set the Creator field for the task
  1512. WsbAffirmHr( pTask->SetCreator( appName ) );
  1513. // Branch on whether or not the task is to run by schedule
  1514. if ( scheduledJob ) {
  1515. CComPtr<ITaskTrigger> pTrigger;
  1516. WORD triggerNumber;
  1517. TASK_TRIGGER taskTrigger;
  1518. SYSTEMTIME sysTime;
  1519. // create Trigger scheduling object for the job
  1520. WsbAffirmHr( pTask->CreateTrigger( &triggerNumber, &pTrigger ) );
  1521. // Zero out Task Trigger struct contents, then init its structure size field
  1522. memset( &taskTrigger, 0, sizeof( taskTrigger ) );
  1523. taskTrigger.cbTriggerSize = sizeof( taskTrigger );
  1524. // Set up schedule for the job in the Task Trigger struct
  1525. GetSystemTime( &sysTime );
  1526. taskTrigger.wBeginYear = sysTime.wYear;
  1527. taskTrigger.wBeginMonth = sysTime.wMonth;
  1528. taskTrigger.wBeginDay = sysTime.wDay;
  1529. taskTrigger.wStartHour = jobStartHour;
  1530. taskTrigger.wStartMinute = jobStartMinute;
  1531. taskTrigger.TriggerType = jobTriggerType;
  1532. // Finish setting schedule info based on case, reject non-supported cases
  1533. switch ( jobTriggerType )
  1534. {
  1535. case TASK_TIME_TRIGGER_DAILY:
  1536. {
  1537. taskTrigger.Type.Daily.DaysInterval = 1;
  1538. }
  1539. break;
  1540. // these are supported cases that need no further set up
  1541. case TASK_TIME_TRIGGER_ONCE:
  1542. case TASK_EVENT_TRIGGER_ON_IDLE:
  1543. case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
  1544. case TASK_EVENT_TRIGGER_AT_LOGON:
  1545. {
  1546. }
  1547. break;
  1548. // non-supported cases
  1549. case TASK_TIME_TRIGGER_WEEKLY:
  1550. case TASK_TIME_TRIGGER_MONTHLYDATE:
  1551. case TASK_TIME_TRIGGER_MONTHLYDOW:
  1552. {
  1553. WsbTrace(
  1554. OLESTR("(CreateTask) Job Trigger Type passed <%d> is invalid (see mstask.idl)\n"),
  1555. jobTriggerType );
  1556. WsbThrow( E_INVALIDARG );
  1557. }
  1558. break;
  1559. default:
  1560. {
  1561. WsbTrace(
  1562. OLESTR("(CreateTask) Nonexistent Job Trigger Type passed <%d> (see mstask.idl)\n"),
  1563. jobTriggerType );
  1564. WsbThrow( E_INVALIDARG );
  1565. }
  1566. }
  1567. // Set the job schedule
  1568. WsbAffirmHr( pTrigger->SetTrigger( &taskTrigger ) );
  1569. }
  1570. // Note that for Disabled (non-scheduled) tasks, there is no need to 'SetFlags()'
  1571. // on the task (pTask) to 'TASK_FLAG_DISABLED'. In fact, this method will hang
  1572. // for an undetermined reason if you do issue that call.
  1573. // Below steps finish creating an entry for NT Task Scheduler
  1574. // Set the program that the Scheduler is to run (for Sakkara this is RsLaunch)
  1575. WsbAffirmHr( pTask->SetApplicationName( WSB_FACILITY_LAUNCH_NAME ) );
  1576. // Put the job name in as the task parameter - for Sakkara this is how RsLaunch
  1577. // knows which job to run.
  1578. WsbAffirmHr( pTask->SetParameters( jobParameters ) );
  1579. // Set the comments field for the task
  1580. WsbAffirmHr( pTask->SetComment( jobComments ) );
  1581. // Set Task Scheduler account info by passing nulls
  1582. WsbAffirmHr( pTask->SetAccountInformation( OLESTR(""), NULL ) );
  1583. // Set the SYSTEM_REQUIRED flag to deal with standby/sleep mode
  1584. WsbAffirmHr(pTask->GetTaskFlags(&TaskFlags));
  1585. TaskFlags |= TASK_FLAG_SYSTEM_REQUIRED;
  1586. WsbAffirmHr(pTask->SetTaskFlags(TaskFlags));
  1587. // Save the scheduled task
  1588. WsbAffirmHr( pTask->QueryInterface( IID_IPersistFile, (void**)&pPersist ) );
  1589. WsbAffirmHr( pPersist->Save( 0, 0 ) );
  1590. // If this is not a scheduled job, run it now
  1591. if ( !scheduledJob ) {
  1592. WsbAffirmHr( pTask->Run() );
  1593. }
  1594. } WsbCatch( hr );
  1595. WsbTraceOut( L"CHsmServer::CreateTask", L"hr = <%ls>", WsbHrAsString( hr ) );
  1596. return( hr );
  1597. }
  1598. HRESULT
  1599. CHsmServer::CreateTaskEx(
  1600. IN const OLECHAR * jobName,
  1601. IN const OLECHAR * jobParameters,
  1602. IN const OLECHAR * jobComments,
  1603. IN const TASK_TRIGGER_TYPE jobTriggerType,
  1604. IN const SYSTEMTIME runTime,
  1605. IN const DWORD runOccurrence,
  1606. IN const BOOL scheduledJob
  1607. )
  1608. /*++
  1609. Implements:
  1610. IHsmServer::CreateTaskEx().
  1611. Routine Description:
  1612. This routine implements the Engine's COM method for creating a task (aka job) in the
  1613. NT Task Scheduler. If the task is to be run on a scheduled basis, that schedule
  1614. will be set. If the task is a disabled task (does not run on a scheduled basis),
  1615. it will be run at the end of this method.
  1616. The method creates a Task Scheduler object, which is first used to delete any old
  1617. task with the same name as the one about to be created, and then to create the new
  1618. task (aka job). The rest of the method deals with setting the various fields in
  1619. the NT Task Scheduler needed to run the job. The logic is straight forward, except
  1620. possibly for the code dealing with the Task Trigger.
  1621. The Task Trigger is a struct defined in the 'mstask.idl' file (nt\public\sdk\inc)
  1622. which is used to set the schedule for a scheduled task. (Note it is not used for
  1623. a disabled, or non-scheduled, job, since that type of job only runs once (at the end
  1624. of this method).) While a number of scheduling options are defined, this method
  1625. only supports 5 of the 8 defined. See 'jobTriggerType' in the 'Arguments' section,
  1626. and 'E_INVALIDARG' in the 'Return Value' section below for a listing of which options
  1627. are, and are not, supported. Also note that a filled-out Task Trigger structure can
  1628. not be passed to this method as an argument since a Task Trigger is non-marshallable
  1629. (by virtue of containing a simple union field). (This is why 3 of the fields
  1630. contained within the Task Trigger struct are passed as args.)
  1631. Note that this method does not create a job object in the HSM Engine. If a job
  1632. needs to be created, it is the caller's responsibility to do so.
  1633. Arguments:
  1634. jobName - The fully formatted task name as it will appear in the NT Task Scheduler UI.
  1635. It is the caller's responsibility to build/format this string prior to
  1636. calling this method. Can not be NULL.
  1637. jobParameters - The fully formatted parameter string for the program the task will
  1638. invoke. For Sakkara the invoked program is RsLaunch. 'jobParameters'
  1639. is the string added to the RsLaunch command line which specifies the
  1640. Remote Storage job to run (e.g., 'run manage'). Can not be NULL.
  1641. jobComments - The fully formatted comments string as it will appear in the NT Task
  1642. Scheduler UI. Can be null.
  1643. jobTriggerType - The value which specifies to the Task Scheduler the frequency with
  1644. which to run a scheduled task. For scheduled tasks, used to build the
  1645. Task Trigger structure. (Not used for non-scheduled (one time only)
  1646. tasks.) Supported values are 'TASK_TIME_TRIGGER_ONCE',
  1647. 'TASK_TIME_TRIGGER_DAILY', TASK_TIME_TRIGGER_WEEKLY ,
  1648. TASK_TIME_TRIGGER_MONTHLYDATE, 'TASK_TIME_TRIGGER_ON_IDLE',
  1649. 'TASK_TIME_TRIGGER_AT_SYSTEMSTART', and 'TASK_TIME_TRIGGER_AT_LOGON'.
  1650. See return value 'E_INVALIDARG' below for a list of non-supported options.
  1651. runTime - Time when the job should be scheduled
  1652. runOccurrence - Occurrence for the job should to be scheduled, relevant for several trigger types
  1653. scheduledJob - A Boolean which indicates whether or not the task to be created is to
  1654. run as a scheduled task, or as a one time only task. One time only tasks
  1655. are run immediately at the end of this method.
  1656. Return Value:
  1657. S_OK - The call succeeded (the specified task was created (and run, in the case of
  1658. one time only tasks) in NT Task Scheduler).
  1659. E_INVALIDARG - Either an invalid (not supported by this method) or non-existent
  1660. 'jobTriggerType' value was passed into this method. Non-supported values
  1661. are 'TASK_TIME_TRIGGER_WEEKLY', 'TASK_TIME_TRIGGER_MONTHLYDATE', and
  1662. 'TASK_TIME_TRIGGER_MONTHLYDOW'. Supported values are listed in argument
  1663. 'jobTriggerType' above.
  1664. E_POINTER - Either the 'jobName' or 'jobParameters' argument was passed as NULL.
  1665. Any other value - The call failed because one of the Remote Storage API calls
  1666. contained internally in this method failed. The error value returned is
  1667. specific to the API call which failed.
  1668. --*/
  1669. {
  1670. // The below 'define' statement is used to control conditional compilation of the code
  1671. // which sets the account info in NT Task Scheduler. Once Task Scheduler is fixed to
  1672. // not need a specific user name and password to run a task, simply remove or comment
  1673. // out this statement.
  1674. HRESULT hr = S_OK;
  1675. CComPtr<ITaskScheduler> pTaskScheduler;
  1676. CComPtr<ITask> pTask;
  1677. CComPtr<IPersistFile> pPersist;
  1678. DWORD TaskFlags;
  1679. WsbTraceIn(OLESTR("CHsmServer::CreateTaskEx"),
  1680. OLESTR("jobName = <%ls>, jobParameters = <%ls>, jobComments = <%ls>, "
  1681. L"jobTriggerType = <%d>, jobStartHour = <%d>, jobStartMinute = <%d>, "
  1682. L"scheduledJob = <%ls>"), jobName, jobParameters, jobComments,
  1683. jobTriggerType, runTime.wHour, runTime.wMinute,
  1684. WsbBoolAsString( scheduledJob ) );
  1685. try {
  1686. WsbAffirmPointer( jobName );
  1687. WsbAffirmPointer( jobParameters );
  1688. // Create a Task Scheduler object, which defaults to pointing to this computer's
  1689. // NT Task Scheduler.
  1690. WsbAffirmHr( CoCreateInstance( CLSID_CTaskScheduler, 0, CLSCTX_SERVER,
  1691. IID_ITaskScheduler, (void **) &pTaskScheduler ) );
  1692. // Delete any old job with the same name from the scheduler, if it exists.
  1693. // Ignore error.
  1694. pTaskScheduler->Delete( jobName );
  1695. // Create the new job in the scheduler
  1696. WsbAffirmHr( pTaskScheduler->NewWorkItem( jobName, CLSID_CTask, IID_ITask,
  1697. (IUnknown**)&pTask ) );
  1698. CWsbStringPtr appName;
  1699. WsbAffirmHr(appName.LoadFromRsc(_Module.m_hInst, IDS_PRODUCT_NAME));
  1700. // Set the Creator field for the task
  1701. WsbAffirmHr( pTask->SetCreator( appName ) );
  1702. // Branch on whether or not the task is to run by schedule
  1703. if ( scheduledJob ) {
  1704. CComPtr<ITaskTrigger> pTrigger;
  1705. WORD triggerNumber;
  1706. TASK_TRIGGER taskTrigger;
  1707. // create Trigger scheduling object for the job
  1708. WsbAffirmHr( pTask->CreateTrigger( &triggerNumber, &pTrigger ) );
  1709. // Zero out Task Trigger struct contents, then init its structure size field
  1710. memset( &taskTrigger, 0, sizeof( taskTrigger ) );
  1711. taskTrigger.cbTriggerSize = sizeof( taskTrigger );
  1712. // Set up schedule for the job in the Task Trigger struct
  1713. taskTrigger.wBeginYear = runTime.wYear;
  1714. taskTrigger.wBeginMonth = runTime.wMonth;
  1715. taskTrigger.wBeginDay = runTime.wDay;
  1716. taskTrigger.wStartHour = runTime.wHour;
  1717. taskTrigger.wStartMinute = runTime.wMinute;
  1718. taskTrigger.TriggerType = jobTriggerType;
  1719. // Finish setting schedule info based on case, reject non-supported cases
  1720. switch ( jobTriggerType )
  1721. {
  1722. case TASK_TIME_TRIGGER_DAILY:
  1723. {
  1724. taskTrigger.Type.Daily.DaysInterval = (WORD)runOccurrence;
  1725. }
  1726. break;
  1727. case TASK_TIME_TRIGGER_WEEKLY:
  1728. {
  1729. taskTrigger.Type.Weekly.WeeksInterval = (WORD)runOccurrence;
  1730. switch (runTime.wDayOfWeek) {
  1731. case 0:
  1732. taskTrigger.Type.Weekly.rgfDaysOfTheWeek = TASK_SUNDAY;
  1733. break;
  1734. case 1:
  1735. taskTrigger.Type.Weekly.rgfDaysOfTheWeek = TASK_MONDAY;
  1736. break;
  1737. case 2:
  1738. taskTrigger.Type.Weekly.rgfDaysOfTheWeek = TASK_TUESDAY;
  1739. break;
  1740. case 3:
  1741. taskTrigger.Type.Weekly.rgfDaysOfTheWeek = TASK_WEDNESDAY;
  1742. break;
  1743. case 4:
  1744. taskTrigger.Type.Weekly.rgfDaysOfTheWeek = TASK_THURSDAY;
  1745. break;
  1746. case 5:
  1747. taskTrigger.Type.Weekly.rgfDaysOfTheWeek = TASK_FRIDAY;
  1748. break;
  1749. case 6:
  1750. taskTrigger.Type.Weekly.rgfDaysOfTheWeek = TASK_SATURDAY;
  1751. break;
  1752. }
  1753. }
  1754. break;
  1755. case TASK_TIME_TRIGGER_MONTHLYDATE:
  1756. {
  1757. WsbAssert(runTime.wDay < 32, E_INVALIDARG);
  1758. taskTrigger.Type.MonthlyDate.rgfDays = (1 << (runTime.wDay-1));
  1759. taskTrigger.Type.MonthlyDate.rgfMonths = (TASK_JANUARY | TASK_FEBRUARY | TASK_MARCH |TASK_APRIL |
  1760. TASK_MAY | TASK_JUNE |TASK_JULY | TASK_AUGUST |
  1761. TASK_SEPTEMBER | TASK_OCTOBER | TASK_NOVEMBER | TASK_DECEMBER);
  1762. }
  1763. break;
  1764. case TASK_EVENT_TRIGGER_ON_IDLE:
  1765. {
  1766. WORD wIdle, wTemp;
  1767. WsbAffirmHr(pTask->GetIdleWait(&wIdle, &wTemp));
  1768. wIdle = (WORD)runOccurrence;
  1769. WsbAffirmHr(pTask->SetIdleWait(wIdle, wTemp));
  1770. }
  1771. // these are supported cases that need no further set up
  1772. case TASK_TIME_TRIGGER_ONCE:
  1773. case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
  1774. case TASK_EVENT_TRIGGER_AT_LOGON:
  1775. {
  1776. }
  1777. break;
  1778. // non-supported cases
  1779. case TASK_TIME_TRIGGER_MONTHLYDOW:
  1780. {
  1781. WsbTrace(
  1782. OLESTR("(CreateTaskEx) Job Trigger Type passed <%d> is invalid (see mstask.idl)\n"),
  1783. jobTriggerType );
  1784. WsbThrow( E_INVALIDARG );
  1785. }
  1786. break;
  1787. default:
  1788. {
  1789. WsbTrace(
  1790. OLESTR("(CreateTaskEx) Nonexistent Job Trigger Type passed <%d> (see mstask.idl)\n"),
  1791. jobTriggerType );
  1792. WsbThrow( E_INVALIDARG );
  1793. }
  1794. }
  1795. // Set the job schedule
  1796. WsbAffirmHr( pTrigger->SetTrigger( &taskTrigger ) );
  1797. }
  1798. // Note that for Disabled (non-scheduled) tasks, there is no need to 'SetFlags()'
  1799. // on the task (pTask) to 'TASK_FLAG_DISABLED'. In fact, this method will hang
  1800. // for an undetermined reason if you do issue that call.
  1801. // Below steps finish creating an entry for NT Task Scheduler
  1802. // Set the program that the Scheduler is to run (for Sakkara this is RsLaunch)
  1803. WsbAffirmHr( pTask->SetApplicationName( WSB_FACILITY_LAUNCH_NAME ) );
  1804. // Put the job name in as the task parameter - for Sakkara this is how RsLaunch
  1805. // knows which job to run.
  1806. WsbAffirmHr( pTask->SetParameters( jobParameters ) );
  1807. // Set the comments field for the task
  1808. WsbAffirmHr( pTask->SetComment( jobComments ) );
  1809. // Set Task Scheduler account info by passing nulls
  1810. WsbAffirmHr( pTask->SetAccountInformation( OLESTR(""), NULL ) );
  1811. // Set the SYSTEM_REQUIRED flag to deal with standby/sleep mode
  1812. WsbAffirmHr(pTask->GetTaskFlags(&TaskFlags));
  1813. TaskFlags |= TASK_FLAG_SYSTEM_REQUIRED;
  1814. WsbAffirmHr(pTask->SetTaskFlags(TaskFlags));
  1815. // Save the scheduled task
  1816. WsbAffirmHr( pTask->QueryInterface( IID_IPersistFile, (void**)&pPersist ) );
  1817. WsbAffirmHr( pPersist->Save( 0, 0 ) );
  1818. // If this is not a scheduled job, run it now
  1819. if ( !scheduledJob ) {
  1820. WsbAffirmHr( pTask->Run() );
  1821. }
  1822. } WsbCatch( hr );
  1823. WsbTraceOut( L"CHsmServer::CreateTaskEx", L"hr = <%ls>", WsbHrAsString( hr ) );
  1824. return( hr );
  1825. }
  1826. HRESULT
  1827. CHsmServer::CancelCopyMedia(
  1828. void
  1829. )
  1830. /*++
  1831. Implements:
  1832. IHsmServer::CancelCopyMedia().
  1833. Routine Description:
  1834. Cancel any active media copy operations (synchronize copy or recreate master).
  1835. Arguments:
  1836. None.
  1837. Return Value:
  1838. S_OK - The call succeeded.
  1839. S_FALSE - No media copy operation is active.
  1840. --*/
  1841. {
  1842. // since this code is currently only used by the CopyMedia routines,
  1843. // reset the Tracing bit
  1844. #undef WSB_TRACE_IS
  1845. #define WSB_TRACE_IS WSB_TRACE_BIT_COPYMEDIA
  1846. HRESULT hr = S_OK;
  1847. WsbTraceIn( OLESTR("CHsmServer::CancelCopyMedia"),
  1848. OLESTR("m_inCopyMedia = %ls, m_cancelCopyMedia = %ls"),
  1849. WsbQuickString(WsbBoolAsString(m_inCopyMedia)),
  1850. WsbQuickString(WsbBoolAsString(m_cancelCopyMedia)));
  1851. Lock();
  1852. if (m_inCopyMedia) {
  1853. m_cancelCopyMedia = TRUE;
  1854. } else {
  1855. hr = S_FALSE;
  1856. }
  1857. Unlock();
  1858. WsbTraceOut(OLESTR("CHsmServer::CancelCopyMedia"), OLESTR("hr = <%ls>"),
  1859. WsbHrAsString(hr));
  1860. return(hr);
  1861. // leaving CopyMedia code, so reset Tracing bit to the Hsm Engine
  1862. #undef WSB_TRACE_IS
  1863. #define WSB_TRACE_IS WSB_TRACE_BIT_HSMENG
  1864. }
  1865. HRESULT
  1866. CHsmServer::MarkMediaForRecreation(
  1867. IN REFGUID masterMediaId
  1868. )
  1869. /*++
  1870. Implements:
  1871. IHsmServer::MarkMediaForRecreation().
  1872. Routine Description:
  1873. This routine implements the Engine's COM method for marking a master media for re-creation
  1874. Should we mark such a media as Recall Only as well ?
  1875. Arguments:
  1876. masterMediaId - The id (GUID) for the master media to be marked.
  1877. Return Value:
  1878. S_OK - The call succeeded (the specified master media was marked).
  1879. Any other value - The call failed because one of the Remote Storage API calls
  1880. contained internally in this method failed. The error value returned is
  1881. specific to the API call which failed.
  1882. --*/
  1883. {
  1884. // since this code is currently only used by the CopyMedia routines,
  1885. // reset the Tracing bit
  1886. #undef WSB_TRACE_IS
  1887. #define WSB_TRACE_IS WSB_TRACE_BIT_COPYMEDIA
  1888. HRESULT hr = S_OK;
  1889. CComPtr<IMediaInfo> pMediaInfo;
  1890. CComPtr<IWsbDbSession> pDbSession;
  1891. WsbTraceIn( OLESTR("CHsmServer::MarkMediaForRecreation"),
  1892. OLESTR("masterMediaId = <%ls>"), WsbGuidAsString(masterMediaId) );
  1893. // no event logging since this method is presently for development use only
  1894. try {
  1895. // open the Engine's Segment database
  1896. WsbAffirmHr( m_pSegmentDatabase->Open( &pDbSession ));
  1897. try {
  1898. // get an interface pointer to the MediaInfo records (entity) in the
  1899. // Segment database
  1900. WsbAffirmHr( m_pSegmentDatabase->GetEntity( pDbSession,
  1901. HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
  1902. (void**) &pMediaInfo ));
  1903. // get the MediaInfo database record for the master media we will mark for
  1904. // re-creation
  1905. WsbAffirmHr( pMediaInfo->SetId( masterMediaId ));
  1906. WsbAffirmHr( pMediaInfo->FindEQ());
  1907. // mark this media for re-creation and as read only
  1908. WsbAffirmHr( pMediaInfo->SetRecreate( TRUE ) );
  1909. /*** WsbAffirmHr( pMediaInfo->RecreateMaster() ); TEMPORARY: Call this one instead for marking as Read Only as well ***/
  1910. // write updated record into the database
  1911. WsbAffirmHr( pMediaInfo->Write());
  1912. } WsbCatch(hr); // inner 'try' - get media info entity and process
  1913. WsbAffirmHr( m_pSegmentDatabase->Close(pDbSession));
  1914. } WsbCatch(hr); // 'try' to open the database
  1915. // processing is done. The singly-assigned smart interface pointers will auto-garbage
  1916. // collect themselves.
  1917. WsbTraceOut(OLESTR("CHsmServer::MarkMediaForRecreation"), OLESTR("hr = <%ls>"),
  1918. WsbHrAsString(hr));
  1919. return(hr);
  1920. // leaving CopyMedia code, so reset Tracing bit to the Hsm Engine
  1921. #undef WSB_TRACE_IS
  1922. #define WSB_TRACE_IS WSB_TRACE_BIT_HSMENG
  1923. }
  1924. HRESULT
  1925. CHsmServer::RecreateMaster(
  1926. IN REFGUID masterMediaId,
  1927. IN USHORT copySet
  1928. )
  1929. /*++
  1930. Implements:
  1931. IHsmServer::RecreateMaster().
  1932. Routine Description:
  1933. This routine implements the COM method for replacing (re-creating) a secondary
  1934. storage original (master) media. To replace the master, a duplicate is made of
  1935. the copy specified. The master record for that media in the Engine's
  1936. MediaInfo database is then updated to point to the 're-created' master (duplicated
  1937. media). For safety purposes all re-created masters are marked 'read only' if
  1938. the copy was not up to date with the original master.
  1939. Because of the potential for data loss (if the most recent copy is not up to date
  1940. with the original master which is being re-created), the user (System Administrator)
  1941. is urged to run a Validate job against the appropriate volume (via the UI) after
  1942. re-creating any master.
  1943. After opening the Segment database (a single database containing all Engine
  1944. database tables), getting the MediaInfo (remote storage master media) records
  1945. (entity) and connecting to the RMS subsystem, the method gets the media record
  1946. corresponding to the master to be re-created. It then checks that the specified
  1947. copy exists for that master. After ensuring the copy exists,
  1948. a 're-created master' is made by duplicating the that copy. The
  1949. database info for the media record is then updated to point to the newly 're-created'
  1950. master media. The method then cleans up (i.e., closes the database) and returns.
  1951. Arguments:
  1952. masterMediaId - The id (GUID) for the master media which is to be re-created.
  1953. copySet - The copyset number of the copy to use or zero, which means use the
  1954. most recent copy.
  1955. Return Value:
  1956. S_OK - The call succeeded (the specified master media was re-created from the
  1957. specified copy media).
  1958. HSM_E_RECREATE_FLAG_WRONGVALUE - Returned if the 'recreate' flag for the master
  1959. media record whose id was passed in, indicating it is to be recreated,
  1960. is not set properly. (The UI is supposed to set it to TRUE prior to
  1961. calling this method via RsLaunch.)
  1962. HSM_E_NO_COPIES_CONFIGURED - Returned if no copies have been configured or created
  1963. for the master which is to be recreated. Without a valid copy we can not
  1964. recreate a master secondary storage media.
  1965. HSM_E_NO_COPIES_EXIST - Returned if copies have been configured but they either
  1966. haven't been created yet, or had previously been created but the System
  1967. Administrator deleted them via UI action.
  1968. WSB_E_NOTFOUND - Value 81000001. Returned if no storage pool record was found whose
  1969. id matched the one contained in the media record.
  1970. HSM_E_BUSY - Another media copy operation was already in progress.
  1971. HSM_E_WORK_SKIPPED_CANCELLED - Operation was cancelled.
  1972. Any other value - The call failed because one of the Remote Storage API calls
  1973. contained internally in this method failed. The error value returned is
  1974. specific to the API call which failed.
  1975. --*/
  1976. {
  1977. // since this code is currently only used by the CopyMedia routines,
  1978. // reset the Tracing bit
  1979. #undef WSB_TRACE_IS
  1980. #define WSB_TRACE_IS WSB_TRACE_BIT_COPYMEDIA
  1981. HRESULT hr = S_OK;
  1982. HRESULT currentLastError = S_OK;
  1983. BOOL haveMasterMediaRecord = FALSE;
  1984. BOOL recreateMaster = FALSE;
  1985. BOOL currentRecallOnly = FALSE;
  1986. BOOL newRecallOnly = FALSE;
  1987. SHORT currentNextRemoteDataSet = 0;
  1988. SHORT copyNextRemoteDataSet = 0;
  1989. SHORT lastKnownGoodMasterNextRemoteDataSet = 0;
  1990. USHORT maxSets = 0;
  1991. GUID poolId = GUID_NULL;
  1992. GUID newMasterId = GUID_NULL;
  1993. GUID mediaSetId = GUID_NULL;
  1994. GUID currentMediaId = GUID_NULL;
  1995. GUID currentMediaSubsystemId = GUID_NULL;
  1996. GUID lastKnownGoodMasterId = GUID_NULL;
  1997. GUID copyMediaSubsystemId = GUID_NULL;
  1998. LONGLONG newFreeBytes = 0;
  1999. LONGLONG currentFreeBytes = 0;
  2000. LONGLONG currentLogicalValidBytes = 0;
  2001. LONGLONG newCapacity = 0;
  2002. LONGLONG currentCapacity = 0;
  2003. FILETIME copyUpdate;
  2004. FILETIME currentUpdate;
  2005. FILETIME lastKnownGoodMasterUpdate;
  2006. CComPtr<IHsmStoragePool> pPool;
  2007. CComPtr<IMediaInfo> pMediaInfo;
  2008. CComPtr<IRmsCartridge> pNewMasterMedia;
  2009. CComPtr<IRmsCartridge> pCopyMedia;
  2010. CComPtr<IWsbDbSession> pDbSession;
  2011. CWsbStringPtr currentName;
  2012. CWsbStringPtr currentDescription;
  2013. CWsbStringPtr copyDescription;
  2014. CWsbBstrPtr copyDescriptionAsBstr;
  2015. CWsbBstrPtr mediaSetName;
  2016. CWsbBstrPtr newName;
  2017. HSM_JOB_MEDIA_TYPE currentType;
  2018. WsbTraceIn( OLESTR("CHsmServer::RecreateMaster"), OLESTR("masterMediaId = <%ls>"),
  2019. WsbGuidAsString(masterMediaId) );
  2020. // log 'information' message
  2021. WsbLogEvent( HSM_MESSAGE_RECREATE_MASTER_START, 0, NULL, NULL );
  2022. try {
  2023. BOOL okToContinue = TRUE;
  2024. // Make sure we're not already busy & haven't been cancelled
  2025. Lock();
  2026. if (m_inCopyMedia) {
  2027. okToContinue = FALSE;
  2028. } else {
  2029. m_inCopyMedia = TRUE;
  2030. }
  2031. Unlock();
  2032. WsbAffirm(okToContinue, HSM_E_BUSY);
  2033. WsbAffirm(!m_cancelCopyMedia, HSM_E_WORK_SKIPPED_CANCELLED);
  2034. // open the Engine's Segment database
  2035. WsbAffirmHr( m_pSegmentDatabase->Open( &pDbSession ));
  2036. try {
  2037. // get an interface pointer to the MediaInfo records (entity) in the
  2038. // Segment database
  2039. WsbAffirmHr( m_pSegmentDatabase->GetEntity( pDbSession,
  2040. HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
  2041. (void**) &pMediaInfo ));
  2042. // get the MediaInfo db record for the master media we want to re-create
  2043. WsbAffirmHr( pMediaInfo->SetId( masterMediaId ));
  2044. WsbAffirmHr( pMediaInfo->FindEQ());
  2045. haveMasterMediaRecord = TRUE;
  2046. // to check if this master has in fact been marked for re-creation, get
  2047. // the re-created flag value
  2048. WsbAffirmHr( pMediaInfo->GetRecreate( &recreateMaster ));
  2049. // do not proceed if re-created flag is not set
  2050. if ( recreateMaster == FALSE ) {
  2051. // log 'error' message and exit
  2052. WsbLogEvent( HSM_MESSAGE_RECREATE_MASTER_INVALID_FLAG_VALUE,
  2053. 0, NULL, NULL );
  2054. WsbThrow( HSM_E_RECREATE_FLAG_WRONGVALUE );
  2055. }
  2056. // recreateMaster flag is TRUE, so proceed to re-create...
  2057. // Get the storage pool the master to be re-created belongs to. We'll
  2058. // use this pool to determine number of copy sets configured for this
  2059. // media, and to specify what storage pool the 'new' (re-created) master
  2060. // is to belong to.
  2061. WsbAffirmHr( pMediaInfo->GetStoragePoolId( &poolId ));
  2062. // Get the storage pool object.
  2063. hr = FindHsmStoragePoolById( poolId, &pPool );
  2064. if (S_OK != hr) {
  2065. // log the returned error and throw the error
  2066. WsbLogEvent( HSM_MESSAGE_SEARCH_STGPOOL_BY_HSMID_ERROR,
  2067. 0, NULL, WsbHrAsString(hr), NULL );
  2068. WsbThrow( hr );
  2069. }
  2070. // get the number of copy sets configured for this pool
  2071. WsbAffirmHr( pPool->GetNumMediaCopies( &maxSets ));
  2072. // if none have been configured by SysAdmin, error out
  2073. WsbAffirm( maxSets > 0, HSM_E_NO_COPIES_CONFIGURED );
  2074. // If the copySet number was specified, make sure it is valid
  2075. WsbAffirm(((copySet == 0) || (copySet <= maxSets)), E_INVALIDARG);
  2076. // If the copySet was not specified, determine
  2077. // which copy belonging to this master is most recent, otherwise
  2078. // get information about specified copy.
  2079. if (copySet == 0) {
  2080. USHORT mostRecentCopy = 0;
  2081. USHORT mostDataSets = 0;
  2082. FILETIME mostRecentCopyUpdate = WsbLLtoFT(0);
  2083. // set invalid value for validity testing (testing if any media
  2084. // copies exist)
  2085. mostRecentCopy = (USHORT)( maxSets + 1 );
  2086. // loop through the configured copy sets
  2087. for (copySet = 1; copySet <= maxSets; copySet++ ) {
  2088. //
  2089. // We use the NextDataSet count to determine most recent copy.
  2090. //
  2091. WsbAffirmHr(pMediaInfo->GetCopyNextRemoteDataSet(copySet,
  2092. &copyNextRemoteDataSet));
  2093. if (copyNextRemoteDataSet > mostDataSets) {
  2094. //
  2095. // We need to make sure this copy is available.
  2096. //
  2097. WsbAffirmHr(pMediaInfo->GetCopyMediaSubsystemId(copySet,
  2098. &copyMediaSubsystemId));
  2099. try {
  2100. //
  2101. // Check the copy to make sure it exists and is enabled.
  2102. //
  2103. WsbAffirm(copyMediaSubsystemId != GUID_NULL, E_FAIL);
  2104. WsbAffirmHr(m_pHsmMediaMgr->FindCartridgeById(copyMediaSubsystemId, &pCopyMedia));
  2105. CComQIPtr<IRmsComObject, &IID_IRmsComObject> pCartCom = pCopyMedia;
  2106. WsbAffirmPointer(pCartCom);
  2107. if( S_OK == pCartCom->IsEnabled( ) ) {
  2108. //
  2109. // This copy is more recent, and available, so save info
  2110. //
  2111. WsbAffirmHr(pMediaInfo->GetCopyUpdate(copySet, &copyUpdate));
  2112. // set the NextRemoteDataSet to this copy's count
  2113. mostDataSets = copyNextRemoteDataSet;
  2114. // capture copy number, and update time
  2115. mostRecentCopy = copySet;
  2116. mostRecentCopyUpdate = copyUpdate;
  2117. }
  2118. } WsbCatchAndDo(hr,
  2119. hr = S_OK;
  2120. );
  2121. }
  2122. } // end 'for' loop
  2123. // Check to be sure there was a copy. If not, error out.
  2124. WsbAffirm( ((maxSets + 1) > mostRecentCopy), HSM_E_NO_COPIES_EXIST );
  2125. copySet = mostRecentCopy;
  2126. copyUpdate = mostRecentCopyUpdate;
  2127. } else {
  2128. WsbAffirmHr(pMediaInfo->GetCopyMediaSubsystemId(copySet, &copyMediaSubsystemId));
  2129. WsbAffirm(copyMediaSubsystemId != GUID_NULL, HSM_E_NO_COPY_EXISTS);
  2130. WsbAffirmHr(pMediaInfo->GetCopyUpdate(copySet, &copyUpdate));
  2131. }
  2132. WsbTrace(OLESTR("Source for re-creation: copySet number = %d; version: %ls\n"),
  2133. copySet, WsbFiletimeAsString(FALSE, copyUpdate) );
  2134. // Check to see if we are going to loose data because of re-creating
  2135. // the master.
  2136. // !!! IMPORTANT NOTE - bmd !!!
  2137. //
  2138. // We need to handle the case where we are recreating multiple times
  2139. // from out of sync copies. The last known good master always holds the info
  2140. // of the master in its last known good state. We are looking at the update
  2141. // timestamp which represent the version of the master or copy. The dataset
  2142. // number may be one more than what is store with the last known good master
  2143. // because of the particular logic required to handle partial/incomplete data sets:
  2144. // a) either the data set was written, but not committed, or b) the data set was started,
  2145. // but data was actually written.
  2146. CWsbStringPtr name;
  2147. CWsbStringPtr description;
  2148. GUID unusedGuid1;
  2149. GUID unusedGuid2; // NOTE: Use multiples so the trace in GetLastKnownGoodMasterInfo works
  2150. LONGLONG unusedLL1;
  2151. LONGLONG unusedLL2; // NOTE: Use multiples so the trace in GetLastKnownGoodMasterInfo works
  2152. BOOL lastKnownGoodMasterRecallOnly;
  2153. HRESULT lastKnownGoodMasterLastError;
  2154. HSM_JOB_MEDIA_TYPE unusedJMT;
  2155. // Get date the original master was last updated, this is stored with
  2156. // the last known good master.
  2157. WsbAffirmHr(pMediaInfo->GetLastKnownGoodMasterInfo(
  2158. &unusedGuid1, &lastKnownGoodMasterId, &unusedGuid2,
  2159. &unusedLL1, &unusedLL2,
  2160. &lastKnownGoodMasterLastError, &description, 0, &unusedJMT, &name, 0,
  2161. &lastKnownGoodMasterRecallOnly,
  2162. &lastKnownGoodMasterUpdate,
  2163. &lastKnownGoodMasterNextRemoteDataSet));
  2164. name.Free( );
  2165. description.Free( );
  2166. // If the original master is newer than the most
  2167. // recent copy... (it should not be possible for the master
  2168. // to be older than a copy!)
  2169. if (CompareFileTime(&lastKnownGoodMasterUpdate, &copyUpdate) != 0) {
  2170. // ...we may lose data, so log it.
  2171. WsbLogEvent( HSM_MESSAGE_RECREATE_MASTER_COPY_OLD, 0, NULL, NULL );
  2172. }
  2173. // Set up done. Now get/build necessary parameters for the call
  2174. // to actually duplicate the most recent copy onto scratch media.
  2175. // This copy will be the re-created master.
  2176. WsbAffirmHr(pMediaInfo->GetCopyDescription(copySet, &copyDescription, 0));
  2177. copyDescriptionAsBstr = copyDescription; // auto-allocates the BSTR
  2178. // Something simple for now.
  2179. copyDescriptionAsBstr.Prepend(OLESTR("RM-"));
  2180. WsbAffirmHr(pMediaInfo->GetCopyMediaSubsystemId(copySet,
  2181. &copyMediaSubsystemId));
  2182. // get the media set the storage pool contains so we assign the
  2183. // re-created master to the proper media set
  2184. WsbAffirmHr( pPool->GetMediaSet( &mediaSetId, &mediaSetName ));
  2185. // Parameters built. Call HSM subsystem to copy the most recent copy
  2186. // onto scratch media
  2187. WsbAffirm(!m_cancelCopyMedia, HSM_E_WORK_SKIPPED_CANCELLED);
  2188. GUID firstSideId = GUID_NULL;
  2189. WsbAffirmHrOk(m_pHsmMediaMgr->DuplicateCartridge(copyMediaSubsystemId,
  2190. firstSideId, &newMasterId, mediaSetId,
  2191. copyDescriptionAsBstr,
  2192. &newFreeBytes, &newCapacity,
  2193. RMS_DUPLICATE_RECYCLEONERROR));
  2194. // now that a replacement master media has been created, prepare
  2195. // to update the master media info in the database
  2196. // first get an interface pointer to the new re-created master
  2197. WsbAffirmHr(m_pHsmMediaMgr->FindCartridgeById(newMasterId, &pNewMasterMedia));
  2198. // Get re-created master's label name. Note that if secondary
  2199. // storage is tape, this 'name' is the tape's bar code. For
  2200. // other media (e.g., optical) this is a name.
  2201. WsbAffirmHr(pNewMasterMedia->GetName(&newName));
  2202. // Get Next Remote Data Set value from the copy. Used by the Validate
  2203. // job to determine what bags are on a master, it will be carried
  2204. // forward to the re-created master.
  2205. WsbAffirmHr(pMediaInfo->GetCopyNextRemoteDataSet(copySet,
  2206. &copyNextRemoteDataSet));
  2207. // get current master media info since some fields will not change
  2208. WsbAffirmHr(pMediaInfo->GetMediaInfo( &currentMediaId,
  2209. &currentMediaSubsystemId,
  2210. &poolId, &currentFreeBytes,
  2211. &currentCapacity,
  2212. &currentLastError,
  2213. &currentNextRemoteDataSet,
  2214. &currentDescription, 0,
  2215. &currentType, &currentName, 0,
  2216. &currentRecallOnly,
  2217. &currentUpdate,
  2218. &currentLogicalValidBytes,
  2219. &recreateMaster ));
  2220. WsbTrace(OLESTR("Original Master next dataset, ver = %d, %ls\n"), currentNextRemoteDataSet, WsbFiletimeAsString(FALSE, currentUpdate));
  2221. WsbTrace(OLESTR("Copy next dataset, ver = %d, %ls\n"), copyNextRemoteDataSet, WsbFiletimeAsString(FALSE, copyUpdate));
  2222. WsbTrace(OLESTR("LastKnownGoodMaster next dataset, ver = %d, %ls\n"), lastKnownGoodMasterNextRemoteDataSet, WsbFiletimeAsString(FALSE, lastKnownGoodMasterUpdate));
  2223. //
  2224. // Initialize the state of the recreated master
  2225. //
  2226. newRecallOnly = lastKnownGoodMasterRecallOnly;
  2227. BOOL inSync = (CompareFileTime(&lastKnownGoodMasterUpdate, &copyUpdate) == 0) &&
  2228. (lastKnownGoodMasterNextRemoteDataSet == copyNextRemoteDataSet);
  2229. if (!inSync) {
  2230. // If the copy was not up to date, mark the new master as RecallOnly.
  2231. // Also clear free bytes since we won't know this value
  2232. newRecallOnly = TRUE;
  2233. newFreeBytes = 0;
  2234. } else {
  2235. // This is an in-sync copy... check LastKnownGoodMaster RecallOnly and LastError to
  2236. // determine how to mark the recreated master RecallOnly status. Since the current,
  2237. // maybe recreated from an incomplete copy, we must use information about the
  2238. // LastKnownGoodMaster to determine the new RecallOnly status.
  2239. if (lastKnownGoodMasterRecallOnly) {
  2240. if (S_OK == lastKnownGoodMasterLastError) {
  2241. // If media is RecallOnly and there is no error (i.e. the media is full, or
  2242. // was marked RecallOnly via tool), we leave the media RecallOnly.
  2243. newRecallOnly = TRUE;
  2244. } else {
  2245. // If the original master was RecallOnly because of an error, reset
  2246. // the RecallOnly bit, since we should now have corrected the problem.
  2247. newRecallOnly = FALSE;
  2248. }
  2249. }
  2250. }
  2251. //
  2252. // Now we need to determine what to do with the old media...
  2253. //
  2254. HRESULT hrRecycle;
  2255. if (inSync) {
  2256. // We recreated an in sync master. The old LastKnownGoodMaster will be
  2257. // overwritten with the new recreated master, so we can safely recycle
  2258. // the LastKnownGoodMaster media.
  2259. // If the cartridge cannot be found we assume it
  2260. // was already deallocated through the media manager UI.
  2261. hrRecycle = m_pHsmMediaMgr->RecycleCartridge( lastKnownGoodMasterId, 0 );
  2262. WsbAffirm( S_OK == hrRecycle || RMS_E_CARTRIDGE_NOT_FOUND == hrRecycle, hrRecycle );
  2263. // if the current media is not the same as the LastKnownGoodMaster, we
  2264. // can recyle the current media, as well. This happens when the
  2265. // current media was recreated from an incomplete (out-of-sync) copy.
  2266. if (lastKnownGoodMasterId != currentMediaSubsystemId) {
  2267. // If the cartridge cannot be found we assume it
  2268. // was already deallocated through the media manager UI.
  2269. hrRecycle = m_pHsmMediaMgr->RecycleCartridge( currentMediaSubsystemId, 0 );
  2270. WsbAffirm( S_OK == hrRecycle || RMS_E_CARTRIDGE_NOT_FOUND == hrRecycle, hrRecycle );
  2271. }
  2272. } else {
  2273. // We recreated from an out-of-sync copy. If the current media
  2274. // and the LastKnownGoodMaster are different, we recycle the current
  2275. // media, since this will be overwritten with the new recreated master.
  2276. // This handles the case where we recreate from an out of sync copy
  2277. // multiple times.
  2278. if (lastKnownGoodMasterId != currentMediaSubsystemId) {
  2279. // If the cartridge cannot be found we assume it
  2280. // was already deallocated through the media manager UI.
  2281. hrRecycle = m_pHsmMediaMgr->RecycleCartridge( currentMediaSubsystemId, 0 );
  2282. WsbAffirm( S_OK == hrRecycle || RMS_E_CARTRIDGE_NOT_FOUND == hrRecycle, hrRecycle );
  2283. }
  2284. }
  2285. // Reset master media info - use new values where needed and original
  2286. // values where appropriate. The copy's Next Remote
  2287. // Data Set value allows the Validate job to handle managed files
  2288. // that are 'lost' by re-creating with an out of date copy.
  2289. WsbAffirmHr(pMediaInfo->SetMediaInfo(currentMediaId, newMasterId,
  2290. poolId,
  2291. newFreeBytes,
  2292. newCapacity, S_OK,
  2293. copyNextRemoteDataSet,
  2294. currentDescription, currentType,
  2295. newName,
  2296. newRecallOnly,
  2297. copyUpdate,
  2298. currentLogicalValidBytes, FALSE));
  2299. if (inSync) {
  2300. // we've alread recycled the media, above.
  2301. WsbAffirmHr(pMediaInfo->UpdateLastKnownGoodMaster());
  2302. }
  2303. // write the updated media record into the database
  2304. WsbAffirmHr(pMediaInfo->Write());
  2305. } WsbCatch(hr); // inner 'try' - get media info entity and process
  2306. // if any error was thrown after getting the master media record reset
  2307. // the 'recreate master' state to off (FALSE) for safety and so it appears
  2308. // correctly in the UI
  2309. if (( haveMasterMediaRecord ) && ( hr != S_OK )) {
  2310. WsbAffirmHr( pMediaInfo->SetRecreate( FALSE ) );
  2311. WsbAffirmHr( pMediaInfo->Write() );
  2312. }
  2313. // close the database
  2314. WsbAffirmHr( m_pSegmentDatabase->Close(pDbSession) );
  2315. } WsbCatch(hr);
  2316. // processing is done. Singly-assigned smart interface pointers will
  2317. // auto-garbage collect themselves.
  2318. if (S_OK == hr) {
  2319. WsbLogEvent( HSM_MESSAGE_RECREATE_MASTER_END, 0, NULL, WsbHrAsString(hr), NULL );
  2320. } else {
  2321. WsbLogEvent( HSM_MESSAGE_RECREATE_MASTER_ERROR_END, 0, NULL, WsbHrAsString(hr), NULL );
  2322. }
  2323. // Reset flags
  2324. Lock();
  2325. if (m_inCopyMedia && HSM_E_BUSY != hr) {
  2326. m_inCopyMedia = FALSE;
  2327. m_cancelCopyMedia = FALSE;
  2328. }
  2329. Unlock();
  2330. WsbTraceOut(OLESTR("CHsmServer::RecreateMaster"), OLESTR("hr = <%ls>"),
  2331. WsbHrAsString(hr));
  2332. return(hr);
  2333. // leaving CopyMedia code, reset Tracing bit to the Hsm Engine
  2334. #undef WSB_TRACE_IS
  2335. #define WSB_TRACE_IS WSB_TRACE_BIT_HSMENG
  2336. }
  2337. HRESULT
  2338. CHsmServer::SynchronizeMedia(
  2339. IN GUID poolId,
  2340. IN USHORT copySet
  2341. )
  2342. /*++
  2343. Implements:
  2344. IHsmServer::SynchronizeMedia().
  2345. Routine Description:
  2346. This routine implements the COM method for updating a specified Copy Set.
  2347. All copy media in the Copy Set either out of date (aka not synchronized
  2348. with the master) or non-existent (either hasn't been made or has been
  2349. deleted by the SysAdmin) will be 'synchronized' by this method. Out of
  2350. date media are copied (from the master) and the MediaInfo database is
  2351. updated to reflect the new info.
  2352. After opening the Segment database (a single database containing all Engine
  2353. database tables), getting the MediaInfo (secondary storage master media) records
  2354. (entity) and connecting to the RMS subsystem, the method enters its main loop.
  2355. The loop iterates through all MediaInfo records. Those that belong to the specified
  2356. storage pool are processed. First a check is made to ensure that the copy set
  2357. requested to be updated is valid. If valid, and if that copy set's media is out of
  2358. sync with the master (meaning it is outdated), the copy media is then duplicated
  2359. from the master. (The copy media is actually 'updated', meaning only that
  2360. portion of the master that was not previously written to the copy is copied.)
  2361. Finally, that master's specified Copy Set media record is updated in the database.
  2362. The loop then iterates to the next MediaInfo record. After all MediaInfo
  2363. records have been processed the database is closed and the method returns.
  2364. Arguments:
  2365. poolId - The id (GUID) for the Storage Pool whose copy set specified in the
  2366. following parameter is to synchronized (aka updated). (Sakkara only
  2367. has one storage pool.)
  2368. copySet - the number of the copy set that is to be updated. (Sakkara allows
  2369. anywhere from 1 to 3 copy sets of secondary storage media, as configured
  2370. by the System Administrator.)
  2371. Return Value:
  2372. S_OK - The call succeeded (the specified copy set in the specified storage
  2373. pool was updated).
  2374. HSM_E_BUSY - Another media copy operation was already in progress.
  2375. HSM_E_WORK_SKIPPED_CANCELLED - Operation was cancelled.
  2376. Any other value - The call failed in either opening the Engine's Segment
  2377. database, in getting the MediaInfo database entity, or in connecting
  2378. to the RMS subsystem.
  2379. NOTE that any error thrown during this routine's main loop will be
  2380. logged to the Event Log, but will then be over-written to S_OK. That
  2381. record is skipped and the next record in the loop is processed. Due
  2382. to this it is possible that an out of sync copy set media will not be
  2383. updated.
  2384. --*/
  2385. {
  2386. // since this code is currently only used by the CopyMedia routines,
  2387. // reset the Tracing bit
  2388. #undef WSB_TRACE_IS
  2389. #define WSB_TRACE_IS WSB_TRACE_BIT_COPYMEDIA
  2390. HRESULT hr = S_OK;
  2391. USHORT maxSets = 0;
  2392. FILETIME mediaTime;
  2393. GUID mediaId = GUID_NULL;
  2394. GUID mediaSetId = GUID_NULL;
  2395. GUID copyPoolId = GUID_NULL;
  2396. HRESULT hrDup = S_OK;
  2397. BOOL atLeastOneCopyError = FALSE;
  2398. SHORT masterNextRemoteDataSet;
  2399. CComPtr<IHsmStoragePool> pPool;
  2400. CComPtr<IMediaInfo> pMediaInfo;
  2401. CComPtr<IRmsCartridge> pCopyMedia;
  2402. CComPtr<IWsbDbSession> pDbSession;
  2403. CWsbStringPtr mediaDescription;
  2404. WsbTraceIn(OLESTR("CHsmServer::SynchronizeMedia"),
  2405. OLESTR("poolId = <%ls>, copySet = <%d>"),
  2406. WsbGuidAsString(poolId), copySet);
  2407. // log 'information' message
  2408. WsbLogEvent( HSM_MESSAGE_SYNCHRONIZE_MEDIA_START, 0, NULL, NULL );
  2409. try {
  2410. wchar_t copySetAsString[20];
  2411. BOOLEAN done = FALSE;
  2412. BOOLEAN firstPass = TRUE;
  2413. BOOL okToContinue = TRUE;
  2414. // Make sure we're not already busy & haven't been cancelled
  2415. Lock();
  2416. if (m_inCopyMedia) {
  2417. okToContinue = FALSE;
  2418. } else {
  2419. m_inCopyMedia = TRUE;
  2420. }
  2421. Unlock();
  2422. WsbAffirm(okToContinue, HSM_E_BUSY);
  2423. WsbAffirm(!m_cancelCopyMedia, HSM_E_WORK_SKIPPED_CANCELLED);
  2424. // open the Engine's Segment database
  2425. WsbAffirmHr(m_pSegmentDatabase->Open(&pDbSession));
  2426. // get interface pointer to the MediaInfo records (entity) in the
  2427. // Segment database
  2428. WsbAffirmHr(m_pSegmentDatabase->GetEntity(pDbSession,
  2429. HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
  2430. (void**) &pMediaInfo));
  2431. WsbAffirm(!m_cancelCopyMedia, HSM_E_WORK_SKIPPED_CANCELLED);
  2432. // Convert copySet number to a sting for use later
  2433. _itow( copySet, copySetAsString, 10 );
  2434. // Main processing loop -- loop through all media at least once to
  2435. // check for out-of-date copies. Keep looping if any copies were
  2436. // skipped because the mount request timed out.
  2437. while (!done) {
  2438. LONG nTimedOut = 0;
  2439. // Iterate through the (master secondary storage) media looking for
  2440. // duplicate (copy) media in this copy set that either haven't been made
  2441. // or haven't been synchronized since the last time the master was updated.
  2442. for (hr = pMediaInfo->First(); SUCCEEDED(hr); hr = pMediaInfo->Next()) {
  2443. CWsbStringPtr copyDescription;
  2444. HRESULT copyError = S_OK;
  2445. GUID copyMediaId = GUID_NULL;
  2446. SHORT copyNextRemoteDataSet = 0;
  2447. CWsbStringPtr copyName;
  2448. FILETIME copyTime = WsbLLtoFT(0);
  2449. BOOL gotCopyInfo = FALSE;
  2450. BOOL updateMediaInfo = FALSE;
  2451. BOOLEAN mountingScratch = FALSE;
  2452. try {
  2453. WsbAffirm(!m_cancelCopyMedia, HSM_E_WORK_SKIPPED_CANCELLED);
  2454. // get the storage pool GUID of this master media (& its copies)
  2455. WsbAffirmHr(pMediaInfo->GetStoragePoolId(&copyPoolId));
  2456. // If the media is from the desired pool (or any pool) then check it.
  2457. // (Passing in a poolId of NULL has the effect of indicating the
  2458. // SysAdmin wants copy set 'x' in all storage pools updated in one
  2459. // operation. Note that Sakkara currently uses this technique
  2460. // when the 'Update Copyset x' command is issued via the UI
  2461. // (it launches RsLaunch with no pool id specified).)
  2462. if ((poolId == GUID_NULL) || (poolId == copyPoolId)) {
  2463. // Ensure the copy set requested for update is valid:
  2464. // Get the storage pool using the pool's HSM (not remote media
  2465. // subsystem) id (GUID).
  2466. hr = FindHsmStoragePoolById(copyPoolId, &pPool);
  2467. if (S_OK != hr) {
  2468. // log and throw the returned error (this media will be
  2469. // skipped)
  2470. WsbLogEvent( HSM_MESSAGE_SEARCH_STGPOOL_BY_HSMID_ERROR,
  2471. 0, NULL, WsbHrAsString(hr), NULL );
  2472. WsbThrow( hr );
  2473. }
  2474. // get the number of copy sets configured for this pool
  2475. WsbAffirmHr(pPool->GetNumMediaCopies(&maxSets));
  2476. // ensure requested copy set is valid
  2477. WsbAffirm(copySet <= maxSets, E_INVALIDARG);
  2478. // to determine if the copy set media needs to be updated
  2479. // get the date the master media was last updated,
  2480. // and the last dataset written to the media...
  2481. //
  2482. // !!! IMPORTANT NOTE !!!
  2483. // This is the current time and data set count. If a migrate
  2484. // is in progress this is NOT the final update time.
  2485. //
  2486. WsbAffirmHr(pMediaInfo->GetUpdate(&mediaTime));
  2487. WsbAffirmHr(pMediaInfo->GetNextRemoteDataSet(&masterNextRemoteDataSet));
  2488. // ...and get the date the copy media was last updated -
  2489. // for efficiency get all copy media info in 1 call
  2490. // (copyMediaId is used later).
  2491. WsbAffirmHr(pMediaInfo->GetCopyInfo(copySet, &copyMediaId,
  2492. &copyDescription, 0, &copyName, 0,
  2493. &copyTime, &copyError,
  2494. &copyNextRemoteDataSet));
  2495. gotCopyInfo = TRUE;
  2496. // If the copy media is out of date (copy's date last
  2497. // updated < master media's date last updated OR nextDataSet don't
  2498. // match), synchronize it.
  2499. //
  2500. // If this is not the first pass through the media records, we only
  2501. // want to retry copies that timed out.
  2502. if ((CompareFileTime( &copyTime, &mediaTime ) < 0 ||
  2503. copyNextRemoteDataSet != masterNextRemoteDataSet) &&
  2504. (firstPass ||
  2505. (RMS_E_TIMEOUT == copyError) ||
  2506. (RMS_E_SCRATCH_NOT_FOUND == copyError) ||
  2507. (RMS_E_CARTRIDGE_UNAVAILABLE == copyError))) {
  2508. CWsbBstrPtr mediaDescriptionAsBstr;
  2509. CWsbBstrPtr mediaSetName;
  2510. GUID copySecondSideId = GUID_NULL;
  2511. DWORD nofDrives = 0;
  2512. mountingScratch = FALSE;
  2513. // get media set id the storage pool contains so we assign
  2514. // the synchronized copy media to the proper media set
  2515. WsbAffirmHr(pPool->GetMediaSet( &mediaSetId, &mediaSetName ));
  2516. // since the duplication itself will be done by the remote
  2517. // media subsystem, get the subsystem GUID of the master
  2518. WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(&mediaId));
  2519. // build the description (display name) for the copy set
  2520. // media as a BSTR (required format for duplicate call)
  2521. WsbAffirmHr(pMediaInfo->GetDescription(&mediaDescription, 0));
  2522. // check if we have at least 2 enabled drives for synchronizing the media
  2523. // if not - abort
  2524. WsbAffirmHr(m_pHsmMediaMgr->GetNofAvailableDrives(mediaSetId, &nofDrives));
  2525. WsbAffirm(nofDrives > 1, HSM_E_NO_TWO_DRIVES);
  2526. // If no media has been allocated for this copy, we need
  2527. // to construct a media description string
  2528. if (GUID_NULL == copyMediaId) {
  2529. mountingScratch = TRUE;
  2530. mediaDescriptionAsBstr = mediaDescription;
  2531. mediaDescriptionAsBstr.Append(" (Copy ");
  2532. mediaDescriptionAsBstr.Append(copySetAsString);
  2533. mediaDescriptionAsBstr.Append(")");
  2534. WsbTrace(OLESTR("CHsmServer::SynchronizeMedia: scratch desc = %ls\n"),
  2535. mediaDescriptionAsBstr);
  2536. // In case of two-sided medias, we need to check whether the
  2537. // original has a second side which has an existing copy
  2538. // If so, we want to allocate the second side of this existing copy
  2539. if (S_OK == m_pHsmMediaMgr->IsMultipleSidedMedia(mediaSetId)) {
  2540. GUID secondSideId;
  2541. BOOL bValid;
  2542. // Get second side of original
  2543. WsbAffirmHr(m_pHsmMediaMgr->CheckSecondSide(mediaId, &bValid, &secondSideId));
  2544. if (bValid && (GUID_NULL != secondSideId)) {
  2545. CComPtr<IMediaInfo> pSecondSideInfo;
  2546. GUID idFromDb;
  2547. // Get second side record (if second side exists and allocated - it must be allocated by us!)
  2548. // Since the subsystem-id is not a key, we must traverse the table
  2549. WsbAffirmHr(m_pSegmentDatabase->GetEntity(pDbSession, HSM_MEDIA_INFO_REC_TYPE,
  2550. IID_IMediaInfo, (void**) &pSecondSideInfo));
  2551. for (hr = pSecondSideInfo->First(); SUCCEEDED(hr); hr = pSecondSideInfo->Next()) {
  2552. WsbAffirmHr(pSecondSideInfo->GetMediaSubsystemId(&idFromDb));
  2553. if (idFromDb == secondSideId) {
  2554. // Just set second side copy for allocation the other side of the as existing copy.cartridge
  2555. WsbAffirmHr(pSecondSideInfo->GetCopyMediaSubsystemId(copySet, &copySecondSideId));
  2556. break;
  2557. }
  2558. }
  2559. }
  2560. }
  2561. } else {
  2562. mediaDescriptionAsBstr = copyDescription;
  2563. }
  2564. // call remote media subsystem to copy the master
  2565. // onto the copy set media indicated
  2566. WsbAffirm(!m_cancelCopyMedia,
  2567. HSM_E_WORK_SKIPPED_CANCELLED);
  2568. // These two LONGLONGs are not used, but simply placeholders for the DuplicateCartridge
  2569. // function call (avoids passing null reference pointer errors).
  2570. LONGLONG FreeSpace = 0;
  2571. LONGLONG Capacity = 0;
  2572. hrDup = m_pHsmMediaMgr->DuplicateCartridge(mediaId,
  2573. copySecondSideId, &copyMediaId, mediaSetId,
  2574. mediaDescriptionAsBstr, &FreeSpace, &Capacity, 0);
  2575. WsbTrace(OLESTR("CHsmServer::SynchronizeMedia: DuplicateCartridge = <%ls>\n"),
  2576. WsbHrAsString(hrDup));
  2577. // Make sure the status get saved in DB
  2578. copyError = hrDup;
  2579. updateMediaInfo = TRUE;
  2580. //
  2581. // We need to refresh the mediaTime and next data set. This
  2582. // handles case were DuplicateCartridge was waiting on migrate to finish.
  2583. //
  2584. WsbAffirmHr(pMediaInfo->GetUpdate(&mediaTime));
  2585. WsbAffirmHr(pMediaInfo->GetNextRemoteDataSet(&masterNextRemoteDataSet));
  2586. // If we got a new piece of media, save the info about
  2587. // it in the DB.
  2588. // The DuplicateCartridge operation may fail after the media was
  2589. // allocated, so we need to record the copy media id in our databases
  2590. // no matter what. If copyMediaId is still GUID_NULL we know the
  2591. // failure occurred while allocating the media and skip this step.
  2592. if (mountingScratch && copyMediaId != GUID_NULL) {
  2593. CWsbBstrPtr mediaNameAsBstr;
  2594. // get the copy media
  2595. WsbAffirmHr(m_pHsmMediaMgr->FindCartridgeById(copyMediaId,
  2596. &pCopyMedia));
  2597. // Get the label name of the copy media that was just
  2598. // created. Note that if secondary storage is tape,
  2599. // this 'name' is the tape's bar code. For other media
  2600. // (e.g., optical) this is a name.
  2601. copyName.Free();
  2602. WsbAffirmHr(pCopyMedia->GetName(&mediaNameAsBstr));
  2603. copyName = mediaNameAsBstr;
  2604. // Save the description string
  2605. copyDescription = mediaDescriptionAsBstr;
  2606. }
  2607. // If the duplication succeeded, update the MediaInfo
  2608. // data
  2609. if (S_OK == hrDup) {
  2610. copyTime = mediaTime;
  2611. copyNextRemoteDataSet = masterNextRemoteDataSet;
  2612. // If the duplication failed because of a mount timeout,
  2613. // count it and we'll try again on the next pass
  2614. } else if ((RMS_E_TIMEOUT == hrDup) ||
  2615. (RMS_E_SCRATCH_NOT_FOUND == hrDup) ||
  2616. (RMS_E_CARTRIDGE_UNAVAILABLE == hrDup)) {
  2617. nTimedOut++;
  2618. } else {
  2619. WsbThrow(hrDup);
  2620. }
  2621. } // end 'if copy set media is out of date'
  2622. } // end 'if poolId is valid'
  2623. } WsbCatchAndDo(hr, // 'try' in the for loop
  2624. // If user cancelled, don't count it as an error, just exit
  2625. if (HSM_E_WORK_SKIPPED_CANCELLED == hr) {
  2626. WsbThrow(hr);
  2627. }
  2628. // If there are no 2 enabled drives, log a message but don't count it as a media error
  2629. if (HSM_E_NO_TWO_DRIVES == hr) {
  2630. WsbLogEvent(HSM_MESSAGE_SYNCHRONIZE_MEDIA_ABORT, 0, NULL,
  2631. copySetAsString, WsbHrAsString(hr), NULL);
  2632. WsbThrow(hr);
  2633. }
  2634. // If a piece of media fails during the 'for' loop log the error in
  2635. // the Event Log, then continue through loop to try the others.
  2636. atLeastOneCopyError = TRUE;
  2637. // Update the media info with the error
  2638. copyError = hr;
  2639. if (gotCopyInfo) {
  2640. updateMediaInfo = TRUE;
  2641. }
  2642. pMediaInfo->GetDescription( &mediaDescription, 0 );
  2643. WsbLogEvent( HSM_MESSAGE_SYNCHRONIZE_MEDIA_ERROR, 0, NULL,
  2644. copySetAsString, (OLECHAR*)mediaDescription,
  2645. WsbHrAsString( hr ), NULL );
  2646. );
  2647. // Update the MediaInfo record if anything changed
  2648. if (updateMediaInfo) {
  2649. // It may have been a while since we got the the media info
  2650. // record and some of the data could have changed (e.g. if a
  2651. // synchronize media job on a different copy set completed) so
  2652. // we re-read the record before the update and we do it inside
  2653. // a transaction to make sure it can't get changed while we're
  2654. // doing this
  2655. hr = S_OK;
  2656. WsbAffirmHr(pDbSession->TransactionBegin());
  2657. try {
  2658. // This FindEQ call will synchronize the data in our local
  2659. // MediaInfo record with what is in the DB
  2660. WsbAffirmHr(pMediaInfo->FindEQ());
  2661. // Update the copy media info - specifically the media id
  2662. // (if the copy media was just created), description,
  2663. // name (bar code for tape), date last updated (which
  2664. // is set to the master's date last updated) and the
  2665. // next remote dataset (conceptually same as next bag).
  2666. WsbAffirmHr(pMediaInfo->SetCopyInfo(copySet, copyMediaId,
  2667. copyDescription, copyName, copyTime, copyError,
  2668. copyNextRemoteDataSet));
  2669. // write the changes into the database
  2670. WsbAffirmHr(pMediaInfo->Write());
  2671. } WsbCatch(hr);
  2672. if (S_OK == hr) {
  2673. WsbAffirmHr(pDbSession->TransactionEnd());
  2674. } else {
  2675. WsbAffirmHr(pDbSession->TransactionCancel());
  2676. atLeastOneCopyError = TRUE;
  2677. //
  2678. // If the copy info could not be updated in the database and this is a new copy,
  2679. // we need to recycle the copy, otherwise, the RSS database is inconsistent
  2680. //
  2681. if (mountingScratch && copyMediaId != GUID_NULL) {
  2682. HRESULT hrRecycle = m_pHsmMediaMgr->RecycleCartridge( copyMediaId, 0 );
  2683. WsbTraceAlways(OLESTR("CHsmServer::SynchronizeMedia: Recycling copy cartridge after DB_update failure, hrRecycle = <%ls>\n"), WsbHrAsString(hrRecycle));
  2684. }
  2685. //
  2686. // Log a message on the error
  2687. //
  2688. mediaDescription = L"";
  2689. pMediaInfo->GetDescription( &mediaDescription, 0 );
  2690. WsbLogEvent( HSM_MESSAGE_SYNCHRONIZE_MEDIA_ERROR, 0, NULL,
  2691. copySetAsString, (OLECHAR*)mediaDescription,
  2692. WsbHrAsString( hr ), NULL );
  2693. //
  2694. // Make sure we don't continue the job if an unexpected database-update error occurs
  2695. //
  2696. WsbThrow(hr);
  2697. }
  2698. }
  2699. // Release the interface pointers that will be reassigned during the
  2700. // next iteration of the 'for' loop.
  2701. pPool = 0;
  2702. pCopyMedia = 0;
  2703. } // end 'for' loop
  2704. // We will fall out of the 'for' loop after processing all MediaInfo
  2705. // records. This is indicated by the Next() call returning WSB_E_NOTFOUND.
  2706. // Since this is normal, reset hr to indicate so.
  2707. if (WSB_E_NOTFOUND == hr) {
  2708. hr = S_OK;
  2709. }
  2710. if (0 == nTimedOut) {
  2711. done = TRUE;
  2712. }
  2713. firstPass = FALSE;
  2714. } // End of while loop
  2715. } WsbCatch(hr);
  2716. // Close the database (if it was opened)
  2717. if (pDbSession) {
  2718. m_pSegmentDatabase->Close(pDbSession);
  2719. }
  2720. // Report an error if any copy failed
  2721. if (S_OK == hr && atLeastOneCopyError) {
  2722. hr = HSM_E_MEDIA_COPY_FAILED;
  2723. }
  2724. WsbLogEvent( HSM_MESSAGE_SYNCHRONIZE_MEDIA_END, 0, NULL, WsbHrAsString(hr), NULL );
  2725. // Reset flags
  2726. Lock();
  2727. if (m_inCopyMedia && HSM_E_BUSY != hr) {
  2728. m_inCopyMedia = FALSE;
  2729. m_cancelCopyMedia = FALSE;
  2730. }
  2731. Unlock();
  2732. WsbTraceOut(OLESTR("CHsmServer::SynchronizeMedia"), OLESTR("hr = <%ls>"),
  2733. WsbHrAsString(hr));
  2734. return(hr);
  2735. // leaving CopyMedia code, reset Tracing bit to the Hsm Engine
  2736. #undef WSB_TRACE_IS
  2737. #define WSB_TRACE_IS WSB_TRACE_BIT_HSMENG
  2738. }
  2739. HRESULT
  2740. CHsmServer::CloseOutDb( void )
  2741. /*++
  2742. Implements:
  2743. IHsmServer::CloseOutDb().
  2744. --*/
  2745. {
  2746. HRESULT hr = S_OK;
  2747. WsbTraceIn(OLESTR("CHsmServer::CloseOutDb"), OLESTR(""));
  2748. try {
  2749. if (m_pDbSys != 0) {
  2750. WsbAffirmHr(m_pDbSys->Backup(NULL, 0));
  2751. }
  2752. } WsbCatch(hr);
  2753. WsbTraceOut(OLESTR("CHsmServer::CloseOutDb"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2754. return(hr);
  2755. }
  2756. HRESULT
  2757. CHsmServer::BackupSegmentDb( void )
  2758. /*++
  2759. Implements:
  2760. IHsmServer::BackupSegmentDb().
  2761. --*/
  2762. {
  2763. HRESULT hr = S_OK;
  2764. WsbTraceIn(OLESTR("CHsmServer::BackupSegmentDb"), OLESTR(""));
  2765. try {
  2766. if (m_pDbSys != 0) {
  2767. WsbAffirmHr(m_pDbSys->Backup(NULL, 0));
  2768. }
  2769. } WsbCatch(hr);
  2770. WsbTraceOut(OLESTR("CHsmServer::BackupSegmentDb"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2771. return(hr);
  2772. }
  2773. HRESULT
  2774. CHsmServer::ChangeSysState(
  2775. IN OUT HSM_SYSTEM_STATE* pSysState
  2776. )
  2777. /*++
  2778. Implements:
  2779. IHsmSystemState::ChangeSysState().
  2780. --*/
  2781. {
  2782. HRESULT hr = S_OK;
  2783. WsbTraceIn(OLESTR("CHsmServer::ChangeSysState"), OLESTR("State = %lx"),
  2784. pSysState->State);
  2785. try {
  2786. if (pSysState->State & HSM_STATE_SUSPEND) {
  2787. if (!m_Suspended) {
  2788. m_Suspended = TRUE;
  2789. // Pause the jobs
  2790. NotifyAllJobs(HSM_JOB_STATE_PAUSING);
  2791. // Save data
  2792. SavePersistData();
  2793. SaveMetaData();
  2794. }
  2795. } else if (pSysState->State & HSM_STATE_RESUME) {
  2796. m_Suspended = FALSE;
  2797. // Resume the jobs
  2798. NotifyAllJobs(HSM_JOB_STATE_RESUMING);
  2799. } else if (pSysState->State & HSM_STATE_SHUTDOWN) {
  2800. // Kill the CheckManagedResources thread
  2801. if (m_CheckManagedResourcesThread) {
  2802. // Could this cause a problem if the thread is in the middle
  2803. // of something?
  2804. TerminateThread(m_CheckManagedResourcesThread, 0);
  2805. CloseHandle(m_CheckManagedResourcesThread);
  2806. m_CheckManagedResourcesThread = 0;
  2807. }
  2808. // Close the autosave thread
  2809. StopAutosaveThread();
  2810. //
  2811. // Since MediaCopy operations do not run as standard jobs,
  2812. // the only way to cancel these is to suspend or shutdown RMS
  2813. // directly.
  2814. //
  2815. try {
  2816. CComPtr<IHsmSystemState> pISysState;
  2817. HSM_SYSTEM_STATE SysState;
  2818. WsbAffirmHr(m_pHsmMediaMgr->QueryInterface(IID_IHsmSystemState, (void**) &pISysState));
  2819. WsbAffirmPointer(pISysState);
  2820. SysState.State = HSM_STATE_SUSPEND;
  2821. WsbAffirmHr(pISysState->ChangeSysState(&SysState));
  2822. SysState.State = HSM_STATE_RESUME;
  2823. WsbAffirmHr(pISysState->ChangeSysState(&SysState));
  2824. } WsbCatch(hr);
  2825. // Cancel jobs
  2826. CancelAllJobs();
  2827. // Save data
  2828. SavePersistData();
  2829. SaveMetaData();
  2830. }
  2831. // Notify the task manager
  2832. if (m_pHsmFsaTskMgr) {
  2833. m_pHsmFsaTskMgr->ChangeSysState(pSysState);
  2834. }
  2835. // Notify the Media Server
  2836. try {
  2837. CComPtr<IHsmSystemState> pISysState;
  2838. WsbAffirmHr(m_pHsmMediaMgr->QueryInterface(IID_IHsmSystemState, (void**) &pISysState));
  2839. WsbAffirmPointer(pISysState);
  2840. WsbAffirmHr(pISysState->ChangeSysState(pSysState));
  2841. } WsbCatch(hr);
  2842. if (pSysState->State & HSM_STATE_SHUTDOWN) {
  2843. CloseOutDb();
  2844. // Release collections
  2845. if (m_pMountingMedias) {
  2846. m_pMountingMedias->RemoveAllAndRelease();
  2847. }
  2848. // Release collections
  2849. if (m_pJobs) {
  2850. m_pJobs->RemoveAllAndRelease();
  2851. }
  2852. if (m_pJobDefs) {
  2853. m_pJobDefs->RemoveAllAndRelease();
  2854. }
  2855. if (m_pPolicies) {
  2856. m_pPolicies->RemoveAllAndRelease();
  2857. }
  2858. if (m_pManagedResources) {
  2859. ULONG count;
  2860. CComPtr<IHsmManagedResourceCollection> pIMRC;
  2861. // We can't use RemoveAllAndRelease because the Remove function for
  2862. // this non-standard collection tells the FSA to unmanage the resource.
  2863. // Then when the FSA shuts down, the list of managed resources is empty.
  2864. // The next time the FSA starts up, it loads an empty list of managed
  2865. // resources, which is wrong. The method DeleteAllAndRelesae avoids
  2866. // this problem.
  2867. WsbAffirmHr(m_pManagedResources->QueryInterface(IID_IHsmManagedResourceCollection,
  2868. (void**) &pIMRC));
  2869. pIMRC->DeleteAllAndRelease();
  2870. pIMRC = 0;
  2871. WsbAffirmHr(m_pManagedResources->GetEntries(&count));
  2872. }
  2873. if (m_pStoragePools) {
  2874. m_pStoragePools->RemoveAllAndRelease();
  2875. }
  2876. if (m_pMessages) {
  2877. m_pMessages->RemoveAllAndRelease();
  2878. }
  2879. if (m_pOnlineInformation) {
  2880. m_pOnlineInformation->RemoveAllAndRelease();
  2881. }
  2882. // Dump object table info
  2883. WSB_OBJECT_TRACE_TYPES;
  2884. WSB_OBJECT_TRACE_POINTERS(WSB_OTP_STATISTICS | WSB_OTP_ALL);
  2885. m_initializationCompleted = FALSE;
  2886. }
  2887. } WsbCatch(hr);
  2888. WsbTraceOut(OLESTR("CHsmServer::ChangeSysState"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2889. return(hr);
  2890. }
  2891. STDMETHODIMP
  2892. CHsmServer::Unload(
  2893. void
  2894. )
  2895. /*++
  2896. Implements:
  2897. IwsbServer::Unload
  2898. Return Value:
  2899. S_OK - Success
  2900. Other - Error
  2901. --*/
  2902. {
  2903. HRESULT hr = S_OK;
  2904. WsbTraceIn(OLESTR("CHsmServer::Unload"), OLESTR(""));
  2905. try {
  2906. // We only need to release what may have gotten set/created by
  2907. // a failed Load attempt.
  2908. if (m_pJobs) {
  2909. m_pJobs->RemoveAllAndRelease();
  2910. }
  2911. if (m_pJobDefs) {
  2912. m_pJobDefs->RemoveAllAndRelease();
  2913. }
  2914. if (m_pPolicies) {
  2915. m_pPolicies->RemoveAllAndRelease();
  2916. }
  2917. if (m_pManagedResources) {
  2918. CComPtr<IHsmManagedResourceCollection> pIMRC;
  2919. // We can't use RemoveAllAndRelease because the Remove function for
  2920. // this non-standard collection tells the FSA to unmanage the resource.
  2921. // Then when the FSA shuts down, the list of managed resources is empty.
  2922. // The next time the FSA starts up, it loads an empty list of managed
  2923. // resources, which is wrong. The method DeleteAllAndRelesae avoids
  2924. // this problem.
  2925. WsbAffirmHr(m_pManagedResources->QueryInterface(IID_IHsmManagedResourceCollection,
  2926. (void**) &pIMRC));
  2927. pIMRC->DeleteAllAndRelease();
  2928. }
  2929. if (m_pStoragePools) {
  2930. m_pStoragePools->RemoveAllAndRelease();
  2931. }
  2932. if (m_pMessages) {
  2933. m_pMessages->RemoveAllAndRelease();
  2934. }
  2935. } WsbCatch(hr);
  2936. WsbTraceOut(OLESTR("CHsmServer::Unload"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2937. return(hr);
  2938. }
  2939. STDMETHODIMP
  2940. CHsmServer::DestroyObject(
  2941. void
  2942. )
  2943. /*++
  2944. Implements:
  2945. IWsbServer::DestroyObject
  2946. Return Value:
  2947. S_OK - Success
  2948. --*/
  2949. {
  2950. HRESULT hr = S_OK;
  2951. WsbTraceIn(OLESTR("CHsmServer::DestroyObject"), OLESTR(""));
  2952. CComObject<CHsmServer> *pEngDelete = (CComObject<CHsmServer> *)this;
  2953. delete pEngDelete;
  2954. WsbTraceOut(OLESTR("CHsmServer::DestroyObject"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2955. return(hr);
  2956. }
  2957. HRESULT
  2958. CHsmServer::CancelAllJobs( void )
  2959. /*++
  2960. Implements:
  2961. IHsmServer::CancelAllJobs().
  2962. --*/
  2963. {
  2964. HRESULT hr = S_OK;
  2965. HRESULT hr2 = S_OK;
  2966. BOOL foundRunningJob = FALSE;
  2967. CComPtr<IWsbCollection> pCollection;
  2968. CComPtr<IWsbEnum> pEnum;
  2969. CComPtr<IHsmJob> pJob;
  2970. WsbTraceIn(OLESTR("CHsmServer::CancelAllJobs"), OLESTR(""));
  2971. try {
  2972. //
  2973. // Set up for the loops
  2974. //
  2975. WsbAffirmHr(m_pJobs->QueryInterface(IID_IWsbCollection, (void**) &pCollection));
  2976. WsbAffirmHr(pCollection->Enum(&pEnum));
  2977. //
  2978. // Loop through all jobs and cancel any currently running jobs
  2979. //
  2980. pJob = 0;
  2981. for (hr = pEnum->First(IID_IHsmJob, (void**) &pJob);
  2982. SUCCEEDED(hr);
  2983. pJob = 0, hr = pEnum->Next(IID_IHsmJob, (void**) &pJob)) {
  2984. try {
  2985. WsbAffirmHrOk(pJob->IsActive());
  2986. foundRunningJob = TRUE;
  2987. WsbAffirmHr(pJob->Cancel(HSM_JOB_PHASE_ALL));
  2988. } WsbCatchAndDo(hr2, hr = S_OK;);
  2989. }
  2990. //
  2991. // Clean up end of scan return
  2992. //
  2993. if (WSB_E_NOTFOUND == hr) {
  2994. hr = S_OK;
  2995. }
  2996. //
  2997. // Cancel all mounting medias so all jobs can finish
  2998. //
  2999. CancelMountingMedias();
  3000. //
  3001. // Make sure all jobs are done
  3002. //
  3003. if (TRUE == foundRunningJob) {
  3004. pJob = 0;
  3005. for (hr = pEnum->First(IID_IHsmJob, (void**) &pJob);
  3006. SUCCEEDED(hr);
  3007. pJob = 0, hr = pEnum->Next(IID_IHsmJob, (void**) &pJob)) {
  3008. try {
  3009. WsbAffirmHrOk(pJob->IsActive());
  3010. WsbAffirmHr(pJob->WaitUntilDone());
  3011. } WsbCatchAndDo(hr2, hr = S_OK;);
  3012. }
  3013. }
  3014. //
  3015. // Clean up end of scan return
  3016. //
  3017. if (WSB_E_NOTFOUND == hr) {
  3018. hr = S_OK;
  3019. }
  3020. } WsbCatch(hr);
  3021. WsbTraceOut(OLESTR("CHsmServer::CancelAllJobs"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3022. return(hr);
  3023. }
  3024. HRESULT
  3025. CHsmServer::CheckManagedResources( void )
  3026. /*++
  3027. Implements:
  3028. IHsmServer::CheckManagedResources().
  3029. --*/
  3030. {
  3031. HRESULT hr = S_OK;
  3032. CComPtr<IWsbEnum> pEnum;
  3033. CComPtr<IHsmManagedResource> pMngdRes;
  3034. CComPtr<IUnknown> pFsaResUnknown;
  3035. CComPtr<IFsaResource> pFsaRes;
  3036. WsbTraceIn(OLESTR("CHsmServer::CheckManagedResources"), OLESTR(""));
  3037. try {
  3038. //
  3039. // Get an enumerator for the managed resource collection
  3040. //
  3041. WsbAffirmHr(m_pManagedResources->Enum(&pEnum));
  3042. //
  3043. // Scan through all managed resources and start the validation
  3044. // job for each
  3045. //
  3046. pMngdRes = 0;
  3047. for (hr = pEnum->First(IID_IHsmManagedResource,(void **)&pMngdRes );
  3048. SUCCEEDED(hr);
  3049. pMngdRes = 0, hr = pEnum->Next(IID_IHsmManagedResource, (void **)&pMngdRes)) {
  3050. try {
  3051. pFsaResUnknown = 0;
  3052. pFsaRes = 0;
  3053. WsbAffirmHr(pMngdRes->GetFsaResource((IUnknown **)&pFsaResUnknown));
  3054. WsbAffirmHr(pFsaResUnknown->QueryInterface(IID_IFsaResource, (void**) &pFsaRes));
  3055. if ((pFsaRes->IsActive() == S_OK) && (pFsaRes->IsAvailable() == S_OK)) {
  3056. WsbAffirmHr(pFsaRes->CheckForValidate(FALSE));
  3057. }
  3058. } WsbCatchAndDo(hr, hr = S_OK; );
  3059. }
  3060. if (WSB_E_NOTFOUND == hr) {
  3061. hr = S_OK;
  3062. }
  3063. } WsbCatch(hr);
  3064. // Release the thread (the thread should terminate on exit
  3065. // from the routine that called this routine)
  3066. CloseHandle(m_CheckManagedResourcesThread);
  3067. m_CheckManagedResourcesThread = 0;
  3068. WsbTraceOut(OLESTR("CHsmServer::CheckManagedResources"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3069. return(hr);
  3070. }
  3071. HRESULT
  3072. CHsmServer::GetBuildVersion(
  3073. ULONG *pBuildVersion
  3074. )
  3075. /*++
  3076. Implements:
  3077. IWsbServer::GetBuildVersion().
  3078. --*/
  3079. {
  3080. HRESULT hr = S_OK;
  3081. WsbTraceIn(OLESTR("CHsmServer::GetBuildVersion"), OLESTR(""));
  3082. try {
  3083. WsbAssertPointer(pBuildVersion);
  3084. *pBuildVersion = m_buildVersion;
  3085. } WsbCatch(hr);
  3086. WsbTraceOut(OLESTR("CHsmServer::GetBuildVersion"), OLESTR("hr = <%ls>, Version = <%ls)"),
  3087. WsbHrAsString(hr), RsBuildVersionAsString(m_buildVersion));
  3088. return ( hr );
  3089. }
  3090. HRESULT
  3091. CHsmServer::GetDatabaseVersion(
  3092. ULONG *pDatabaseVersion
  3093. )
  3094. /*++
  3095. Implements:
  3096. IWsbServer::GetDatabaseVersion().
  3097. --*/
  3098. {
  3099. HRESULT hr = S_OK;
  3100. WsbTraceIn(OLESTR("CHsmServer::GetDatabaseVersion"), OLESTR(""));
  3101. *pDatabaseVersion = m_databaseVersion;
  3102. WsbTraceOut(OLESTR("CHsmServer::GetDatabaseVersion"), OLESTR("hr = <%ls>, Version = <%ls)"),
  3103. WsbHrAsString(hr), WsbPtrToUlongAsString(pDatabaseVersion));
  3104. return ( hr );
  3105. }
  3106. HRESULT
  3107. CHsmServer::GetNtProductVersion (
  3108. OLECHAR **pNtProductVersion,
  3109. ULONG bufferSize
  3110. )
  3111. /*++
  3112. Implements:
  3113. IWsbServer::GetNtProductVersion().
  3114. --*/
  3115. {
  3116. HRESULT hr = S_OK;
  3117. try {
  3118. CWsbStringPtr tmpString;
  3119. WsbAssert(0 != pNtProductVersion, E_POINTER);
  3120. tmpString = VER_PRODUCTVERSION_STRING;
  3121. WsbAffirmHr(tmpString.CopyTo(pNtProductVersion, bufferSize));
  3122. } WsbCatch( hr );
  3123. return (hr);
  3124. }
  3125. HRESULT
  3126. CHsmServer::GetNtProductBuild(
  3127. ULONG *pNtProductBuild
  3128. )
  3129. /*++
  3130. Implements:
  3131. IWsbServer::GetNtProductBuild().
  3132. --*/
  3133. {
  3134. HRESULT hr = S_OK;
  3135. WsbTraceIn(OLESTR("CHsmServer::GetNtProductBuild"), OLESTR(""));
  3136. *pNtProductBuild = VER_PRODUCTBUILD;
  3137. WsbTraceOut(OLESTR("CHsmServer::GetNtProductBuild"), OLESTR("hr = <%ls>, Version = <%ls)"),
  3138. WsbHrAsString(hr), WsbLongAsString(VER_PRODUCTBUILD));
  3139. return ( hr );
  3140. }
  3141. HRESULT
  3142. CHsmServer::CheckAccess(
  3143. WSB_ACCESS_TYPE AccessType
  3144. )
  3145. /*++
  3146. Implements:
  3147. IWsbServer::CheckAccess().
  3148. --*/
  3149. {
  3150. WsbTraceIn(OLESTR("CHsmServer::CheckAccess"), OLESTR(""));
  3151. HRESULT hr = S_OK;
  3152. try {
  3153. //
  3154. // Do the impersonation
  3155. //
  3156. WsbAffirmHr( CoImpersonateClient() );
  3157. hr = WsbCheckAccess( AccessType );
  3158. CoRevertToSelf();
  3159. } WsbCatchAndDo( hr,
  3160. //
  3161. // Handle case where there is no COM context to check against
  3162. // in which case we are the service so any security is allowed.
  3163. //
  3164. if( ( hr == RPC_E_NO_CONTEXT ) || ( hr != RPC_E_CALL_COMPLETE ) ) {
  3165. hr = S_OK;
  3166. }
  3167. );
  3168. WsbTraceOut(OLESTR("CHsmServer::CheckAccess"), OLESTR("hr = <%ls>"), WsbHrAsString( hr ) );
  3169. return( hr );
  3170. }
  3171. HRESULT
  3172. CHsmServer::GetTrace(
  3173. OUT IWsbTrace ** ppTrace
  3174. )
  3175. /*++
  3176. Implements:
  3177. IWsbServer::GetTrace().
  3178. --*/
  3179. {
  3180. WsbTraceIn(OLESTR("CHsmServer::GetTrace"), OLESTR("ppTrace = <0x%p>"), ppTrace);
  3181. HRESULT hr = S_OK;
  3182. try {
  3183. WsbAffirmPointer(ppTrace);
  3184. *ppTrace = 0;
  3185. WsbAffirmPointer(m_pTrace);
  3186. *ppTrace = m_pTrace;
  3187. (*ppTrace)->AddRef();
  3188. } WsbCatch(hr);
  3189. WsbTraceOut(OLESTR("CHsmServer::GetTrace"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3190. return(hr);
  3191. }
  3192. HRESULT
  3193. CHsmServer::SetTrace(
  3194. OUT IWsbTrace * pTrace
  3195. )
  3196. /*++
  3197. Implements:
  3198. IWsbServer::SetTrace().
  3199. --*/
  3200. {
  3201. WsbTraceIn(OLESTR("CHsmServer::SetTrace"), OLESTR("pTrace = <0x%p>"), pTrace);
  3202. HRESULT hr = S_OK;
  3203. try {
  3204. WsbAffirmPointer(pTrace);
  3205. m_pTrace = pTrace;
  3206. } WsbCatch(hr);
  3207. WsbTraceOut(OLESTR("CHsmServer::SetTrace"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3208. return(hr);
  3209. }
  3210. HRESULT
  3211. CHsmServer::NotifyAllJobs( HSM_JOB_STATE jobState )
  3212. /*++
  3213. Routine Description:
  3214. Notify all jobs of a change in status.
  3215. Arguments:
  3216. jobState - New job state.
  3217. Return Value:
  3218. S_OK - Success
  3219. --*/
  3220. {
  3221. HRESULT hr = S_OK;
  3222. HRESULT hr2 = S_OK;
  3223. CComPtr<IWsbCollection> pCollection;
  3224. CComPtr<IWsbEnum> pEnum;
  3225. CComPtr<IHsmJob> pJob;
  3226. WsbTraceIn(OLESTR("CHsmServer::NotifyAllJobs"), OLESTR(""));
  3227. try {
  3228. //
  3229. // Set up for the loops
  3230. //
  3231. WsbAffirmHr(m_pJobs->QueryInterface(IID_IWsbCollection,
  3232. (void**) &pCollection));
  3233. WsbAffirmHr(pCollection->Enum(&pEnum));
  3234. //
  3235. // Loop through all jobs and notify any currently running jobs
  3236. //
  3237. pJob = 0;
  3238. for (hr = pEnum->First(IID_IHsmJob, (void**) &pJob);
  3239. SUCCEEDED(hr);
  3240. pJob = 0, hr = pEnum->Next(IID_IHsmJob, (void**) &pJob)) {
  3241. try {
  3242. if (S_OK == pJob->IsActive()) {
  3243. if (HSM_JOB_STATE_PAUSING == jobState) {
  3244. WsbAffirmHr(pJob->Pause(HSM_JOB_PHASE_ALL));
  3245. } else {
  3246. WsbAffirmHr(pJob->Resume(HSM_JOB_PHASE_ALL));
  3247. }
  3248. }
  3249. } WsbCatchAndDo(hr2, hr = S_OK;);
  3250. }
  3251. //
  3252. // Clean up end of scan return
  3253. //
  3254. if (WSB_E_NOTFOUND == hr) {
  3255. hr = S_OK;
  3256. }
  3257. } WsbCatch(hr);
  3258. WsbTraceOut(OLESTR("CHsmServer::NotifyAllJobs"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3259. return(hr);
  3260. }
  3261. //
  3262. // Retrieves the Media Manager object
  3263. //
  3264. HRESULT CHsmServer::GetHsmMediaMgr(
  3265. IRmsServer **ppHsmMediaMgr
  3266. )
  3267. {
  3268. HRESULT hr = S_OK;
  3269. // If the Media Manager has been created, return the pointer. Otherwise, fail.
  3270. try {
  3271. WsbAssert(0 != ppHsmMediaMgr, E_POINTER);
  3272. *ppHsmMediaMgr = m_pHsmMediaMgr;
  3273. WsbAffirm(m_pHsmMediaMgr != 0, E_FAIL);
  3274. m_pHsmMediaMgr->AddRef();
  3275. } WsbCatch(hr);
  3276. return (hr);
  3277. }
  3278. HRESULT
  3279. CHsmServer::GetCopyFilesUserLimit(
  3280. OUT ULONG* pLimit
  3281. )
  3282. /*++
  3283. Implements:
  3284. CHsmServer::GetCopyFilesUserLimit().
  3285. --*/
  3286. {
  3287. HRESULT hr = S_OK;
  3288. WsbTraceIn(OLESTR("CHsmServer::GetCopyFilesUserLimit"), OLESTR(""));
  3289. try {
  3290. WsbAssert(0 != pLimit, E_POINTER);
  3291. *pLimit = m_copyfilesUserLimit;
  3292. } WsbCatch(hr);
  3293. WsbTraceOut(OLESTR("CHsmServer::GetCopyFilesUserLimit"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3294. return(hr);
  3295. }
  3296. HRESULT
  3297. CHsmServer::SetCopyFilesUserLimit(
  3298. IN ULONG limit
  3299. )
  3300. /*++
  3301. Implements:
  3302. CHsmServer::SetCopyFilesUserLimit().
  3303. --*/
  3304. {
  3305. HRESULT hr = S_OK;
  3306. WsbTraceIn(OLESTR("CHsmServer::SetCopyFilesUserLimit"), OLESTR(""));
  3307. m_copyfilesUserLimit= limit;
  3308. WsbTraceOut(OLESTR("CHsmServer::SetCopyFilesUserLimit"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3309. return(hr);
  3310. }
  3311. HRESULT
  3312. CHsmServer::GetCopyFilesLimit(
  3313. OUT ULONG* pLimit
  3314. )
  3315. /*++
  3316. Implements:
  3317. CHsmServer::GetCopyFilesLimit().
  3318. --*/
  3319. {
  3320. HRESULT hr = S_OK;
  3321. WsbTraceIn(OLESTR("CHsmServer::GetCopyFilesLimit"), OLESTR(""));
  3322. try {
  3323. CComPtr<IHsmStoragePool> pStoragePool;
  3324. ULONG count;
  3325. GUID mediaSetId;
  3326. CWsbBstrPtr dummy;
  3327. DWORD dwNofDrives;
  3328. WsbAssert(0 != pLimit, E_POINTER);
  3329. // Get relevant media set - assume only one pool !!
  3330. WsbAffirmHr(m_pStoragePools->GetEntries(&count));
  3331. WsbAffirm(1 == count, E_FAIL);
  3332. WsbAffirmHr(m_pStoragePools->At(0, IID_IHsmStoragePool, (void **)&pStoragePool));
  3333. WsbAffirmHr(pStoragePool->GetMediaSet(&mediaSetId, &dummy));
  3334. // Get number of available drives in the system
  3335. WsbAffirmHr(m_pHsmMediaMgr->GetNofAvailableDrives(mediaSetId, &dwNofDrives));
  3336. // Deteremine actual limit
  3337. *pLimit = max(1, min(m_copyfilesUserLimit, dwNofDrives));
  3338. WsbTrace(OLESTR("CHsmServer::GetCopyFilesLimit: Limit is %lu\n"), *pLimit);
  3339. } WsbCatch(hr);
  3340. WsbTraceOut(OLESTR("CHsmServer::GetCopyFilesLimit"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3341. return(hr);
  3342. }
  3343. HRESULT
  3344. CHsmServer::AreJobsEnabled( void )
  3345. /*++
  3346. Implements:
  3347. IHsmServer::AreJobsDisabled().
  3348. --*/
  3349. {
  3350. HRESULT hr = S_OK;
  3351. WsbTraceIn(OLESTR("CHsmServer::AreJobsEnabled"), OLESTR(""));
  3352. EnterCriticalSection(&m_JobDisableLock);
  3353. hr = (m_JobsEnabled ? S_OK : S_FALSE);
  3354. LeaveCriticalSection(&m_JobDisableLock);
  3355. WsbTraceOut(OLESTR("CHsmServer::AreJobsEnabled"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3356. return(hr);
  3357. }
  3358. HRESULT
  3359. CHsmServer::EnableAllJobs( void )
  3360. /*++
  3361. Implements:
  3362. IHsmServer::EnableAllJobs().
  3363. --*/
  3364. {
  3365. HRESULT hr = S_OK;
  3366. WsbTraceIn(OLESTR("CHsmServer::EnableAllJobs"), OLESTR(""));
  3367. EnterCriticalSection(&m_JobDisableLock);
  3368. try {
  3369. m_JobsEnabled = TRUE;
  3370. WsbAffirmHr(RestartSuspendedJobs());
  3371. } WsbCatch(hr);
  3372. LeaveCriticalSection(&m_JobDisableLock);
  3373. WsbTraceOut(OLESTR("CHsmServer::EnableAllJobs"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3374. return(hr);
  3375. }
  3376. HRESULT
  3377. CHsmServer::DisableAllJobs( void )
  3378. /*++
  3379. Implements:
  3380. IHsmServer::DisableAllJobs().
  3381. Notes:
  3382. The medthod tries to disable all jobs.
  3383. If any job is active or starting, it fails with HSM_E_DISABLE_RUNNING_JOBS and calls
  3384. RestartSuspendedJobs to restart any job that alreay became suspended beacuse of this
  3385. unsuccessful disabling attempt.
  3386. --*/
  3387. {
  3388. HRESULT hr = S_OK;
  3389. WsbTraceIn(OLESTR("CHsmServer::DisableAllJobs"), OLESTR(""));
  3390. EnterCriticalSection(&m_JobDisableLock);
  3391. try {
  3392. ULONG nJobs;
  3393. m_JobsEnabled = FALSE;
  3394. // Loop over jobs
  3395. WsbAffirmHr(m_pJobs->GetEntries(&nJobs));
  3396. for (ULONG i = 0; i < nJobs; i++) {
  3397. CComPtr<IHsmJob> pJob;
  3398. HSM_JOB_STATE state;
  3399. WsbAffirmHr(m_pJobs->At(i, IID_IHsmJob, (void**) &pJob));
  3400. // Check if this job is suspended
  3401. WsbAffirmHr(pJob->GetState(&state));
  3402. if ((HSM_JOB_STATE_ACTIVE == state) || (HSM_JOB_STATE_STARTING == state)) {
  3403. // Cannot disable jobs
  3404. m_JobsEnabled = TRUE;
  3405. hr = HSM_E_DISABLE_RUNNING_JOBS;
  3406. RestartSuspendedJobs();
  3407. break;
  3408. }
  3409. }
  3410. } WsbCatch(hr);
  3411. LeaveCriticalSection(&m_JobDisableLock);
  3412. WsbTraceOut(OLESTR("CHsmServer::DisableAllJobs"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3413. return(hr);
  3414. }
  3415. HRESULT
  3416. CHsmServer::RestartSuspendedJobs(
  3417. void
  3418. )
  3419. /*++
  3420. Implements:
  3421. IHsmServer::RestartSuspendedJobs().
  3422. --*/
  3423. {
  3424. HRESULT hr = S_OK;
  3425. WsbTraceIn(OLESTR("CHsmServer::RestartSuspendedJobs"), OLESTR(""));
  3426. try {
  3427. ULONG nJobs;
  3428. // Loop over jobs
  3429. // Note: this algorithm is unfair because jobs at the end of the
  3430. // list could "starve" because jobs at the beginning are more likely
  3431. // to get started. The assumption is that there should be very few
  3432. // jobs waiting to run. If this assumption proves to be false, some
  3433. WsbAffirmHr(m_pJobs->GetEntries(&nJobs));
  3434. // sort of priority scheme will be needed.
  3435. for (ULONG i = 0; i < nJobs; i++) {
  3436. CComPtr<IHsmJob> pJob;
  3437. HSM_JOB_STATE state;
  3438. WsbAffirmHr(m_pJobs->At(i, IID_IHsmJob, (void**) &pJob));
  3439. // Check if this job is suspended
  3440. WsbAffirmHr(pJob->GetState(&state));
  3441. if (HSM_JOB_STATE_SUSPENDED == state) {
  3442. // This may fail, but we don't care
  3443. pJob->Restart();
  3444. }
  3445. }
  3446. } WsbCatch(hr);
  3447. WsbTraceOut(OLESTR("CHsmServer::RestartSuspendedJobs"), OLESTR("hr = <%ls>"),
  3448. WsbHrAsString(hr));
  3449. return(hr);
  3450. }
  3451. HRESULT
  3452. CHsmServer::LockMountingMedias( void )
  3453. /*++
  3454. Implements:
  3455. IHsmServer::LockMountingMedias().
  3456. --*/
  3457. {
  3458. HRESULT hr = S_OK;
  3459. EnterCriticalSection(&m_MountingMediasLock);
  3460. return(hr);
  3461. }
  3462. HRESULT
  3463. CHsmServer::UnlockMountingMedias( void )
  3464. /*++
  3465. Implements:
  3466. IHsmServer::UnlockMountingMedias().
  3467. --*/
  3468. {
  3469. HRESULT hr = S_OK;
  3470. LeaveCriticalSection(&m_MountingMediasLock);
  3471. return(hr);
  3472. }
  3473. HRESULT
  3474. CHsmServer::ResetSegmentValidMark( void )
  3475. /*++
  3476. Implements:
  3477. IHsmServer::ResetSegmentValidMark().
  3478. --*/
  3479. {
  3480. HRESULT hr = S_OK;
  3481. BOOL bOpenDb = FALSE;
  3482. CComPtr<IWsbDbSession> pDbSession;
  3483. WsbTraceIn(OLESTR("CHsmServer::ResetSegmentValidMark"), OLESTR(""));
  3484. try {
  3485. CComPtr<ISegRec> pSegRec;
  3486. USHORT uSegFlags;
  3487. // open Engine's Segment database
  3488. WsbAffirmHr(m_pSegmentDatabase->Open(&pDbSession));
  3489. bOpenDb = TRUE;
  3490. // Traverse segment records
  3491. WsbAffirmHr(m_pSegmentDatabase->GetEntity(pDbSession, HSM_SEG_REC_TYPE,
  3492. IID_ISegRec, (void**)&pSegRec));
  3493. for (hr = pSegRec->First(); S_OK == hr; hr = pSegRec->Next()) {
  3494. WsbAffirmHr(pSegRec->GetSegmentFlags(&uSegFlags));
  3495. if (uSegFlags & SEG_REC_MARKED_AS_VALID) {
  3496. // Need to reset this bit
  3497. uSegFlags &= ~SEG_REC_MARKED_AS_VALID;
  3498. WsbAffirmHr(pSegRec->SetSegmentFlags(uSegFlags));
  3499. WsbAffirmHr(pSegRec->Write());
  3500. }
  3501. }
  3502. // If we fell out of the loop because we ran out of segments, reset the HRESULT
  3503. if (hr == WSB_E_NOTFOUND) {
  3504. hr = S_OK;
  3505. } else {
  3506. WsbAffirmHr(hr);
  3507. }
  3508. } WsbCatch(hr);
  3509. if (bOpenDb) {
  3510. hr = m_pSegmentDatabase->Close(pDbSession);
  3511. }
  3512. WsbTraceOut(OLESTR("CHsmServer::ResetSegmentValidMark"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3513. return(hr);
  3514. }
  3515. HRESULT
  3516. CHsmServer::ResetMediaValidBytes( void )
  3517. /*++
  3518. Implements:
  3519. IHsmServer::ResetMediaValidBytes().
  3520. --*/
  3521. {
  3522. HRESULT hr = S_OK;
  3523. BOOL bOpenDb = FALSE;
  3524. CComPtr<IWsbDbSession> pDbSession;
  3525. WsbTraceIn(OLESTR("CHsmServer::ResetMediaValidBytes"), OLESTR(""));
  3526. try {
  3527. CComPtr<IMediaInfo> pMediaInfo;
  3528. // open Engine's Segment database
  3529. WsbAffirmHr(m_pSegmentDatabase->Open(&pDbSession));
  3530. bOpenDb = TRUE;
  3531. // Traverse segment records
  3532. WsbAffirmHr(m_pSegmentDatabase->GetEntity(pDbSession, HSM_MEDIA_INFO_REC_TYPE,
  3533. IID_IMediaInfo, (void**)&pMediaInfo));
  3534. for (hr = pMediaInfo->First(); S_OK == hr; hr = pMediaInfo->Next()) {
  3535. WsbAffirmHr(pMediaInfo->SetLogicalValidBytes(0));
  3536. WsbAffirmHr(pMediaInfo->Write());
  3537. }
  3538. // If we fell out of the loop because we ran out of segments, reset the HRESULT
  3539. if (hr == WSB_E_NOTFOUND) {
  3540. hr = S_OK;
  3541. } else {
  3542. WsbAffirmHr(hr);
  3543. }
  3544. } WsbCatch(hr);
  3545. if (bOpenDb) {
  3546. hr = m_pSegmentDatabase->Close(pDbSession);
  3547. }
  3548. WsbTraceOut(OLESTR("CHsmServer::ResetMediaValidBytes"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3549. return(hr);
  3550. }
  3551. HRESULT
  3552. CHsmServer::GetSegmentPosition(
  3553. IN REFGUID bagId,
  3554. IN LONGLONG fileStart,
  3555. IN LONGLONG fileSize,
  3556. OUT GUID* pPosMedia,
  3557. OUT LONGLONG* pPosOffset)
  3558. /*++
  3559. Implements:
  3560. IHsmServer::GetSegmentPosition().
  3561. --*/
  3562. {
  3563. HRESULT hr = S_OK;
  3564. BOOL bOpenDb = FALSE;
  3565. CComPtr<IWsbDbSession> pDbSession;
  3566. CComPtr<ISegDb> pSegDb;
  3567. WsbTraceIn(OLESTR("CHsmServer::GetSegmentPosition"), OLESTR(""));
  3568. try {
  3569. CComPtr<ISegRec> pSegRec;
  3570. // open Engine's Segment database
  3571. WsbAffirmHr(m_pSegmentDatabase->Open(&pDbSession));
  3572. bOpenDb = TRUE;
  3573. // Find segemnt
  3574. WsbAffirmHr(m_pSegmentDatabase->QueryInterface(IID_ISegDb, (void**) &pSegDb));
  3575. WsbAffirmHr(pSegDb->SegFind(pDbSession, bagId, fileStart, fileSize, &pSegRec));
  3576. // Extract output
  3577. WsbAffirmHr(pSegRec->GetPrimPos(pPosMedia));
  3578. WsbAffirmHr(pSegRec->GetSecPos(pPosOffset));
  3579. } WsbCatch(hr);
  3580. if (bOpenDb) {
  3581. hr = m_pSegmentDatabase->Close(pDbSession);
  3582. }
  3583. WsbTraceOut(OLESTR("CHsmServer::GetSegmentPosition"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3584. return(hr);
  3585. }
  3586. void
  3587. CHsmServer::StopAutosaveThread(
  3588. void
  3589. )
  3590. /*++
  3591. Routine Description:
  3592. Stop the Autosave thread:
  3593. First try gracefully, using the termination event
  3594. If doesn't work, just terminate the thread
  3595. Arguments:
  3596. None.
  3597. Return Value:
  3598. S_OK - Success.
  3599. --*/
  3600. {
  3601. HRESULT hr = S_OK;
  3602. WsbTraceIn(OLESTR("CHsmServer::StopAutosaveThread"), OLESTR(""));
  3603. try {
  3604. // Terminate the autosave thread
  3605. if (m_autosaveThread) {
  3606. // Signal thread to terminate
  3607. SetEvent(m_terminateEvent);
  3608. // Wait for the thread, if it doesn't terminate gracefully - kill it
  3609. switch (WaitForSingleObject(m_autosaveThread, 20000)) {
  3610. case WAIT_FAILED: {
  3611. WsbTrace(OLESTR("CHsmServer::StopAutosaveThread: WaitForSingleObject returned error %lu\n"), GetLastError());
  3612. }
  3613. // fall through...
  3614. case WAIT_TIMEOUT: {
  3615. WsbTrace(OLESTR("CHsmServer::StopAutosaveThread: force terminating of autosave thread.\n"));
  3616. DWORD dwExitCode;
  3617. if (GetExitCodeThread( m_autosaveThread, &dwExitCode)) {
  3618. if (dwExitCode == STILL_ACTIVE) { // thread still active
  3619. if (!TerminateThread (m_autosaveThread, 0)) {
  3620. WsbTrace(OLESTR("CHsmServer::StopAutosaveThread: TerminateThread returned error %lu\n"), GetLastError());
  3621. }
  3622. }
  3623. } else {
  3624. WsbTrace(OLESTR("CHsmServer::StopAutosaveThread: GetExitCodeThread returned error %lu\n"), GetLastError());
  3625. }
  3626. break;
  3627. }
  3628. default:
  3629. // Thread terminated gracefully
  3630. WsbTrace(OLESTR("CHsmServer::StopAutosaveThread: Autosave thread terminated gracefully\n"));
  3631. break;
  3632. }
  3633. // Best effort done for terminating auto-backup thread
  3634. CloseHandle(m_autosaveThread);
  3635. m_autosaveThread = 0;
  3636. }
  3637. } WsbCatch(hr);
  3638. WsbTraceOut(OLESTR("CHsmServer::StopAutosaveThread"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3639. }
  3640. HRESULT
  3641. CHsmServer::InternalSavePersistData(
  3642. void
  3643. )
  3644. /*++
  3645. Implements:
  3646. CHsmServer::InternalSavePersistData().
  3647. --*/
  3648. {
  3649. HRESULT hr = S_OK;
  3650. WsbTraceIn(OLESTR("CHsmServer::InternalSavePersistData"), OLESTR(""));
  3651. try {
  3652. DWORD status, errWait;
  3653. CComPtr<IPersistFile> pPersistFile;
  3654. // Synchronize saving of persistent data with snapshot signaling event
  3655. status = WaitForSingleObject(m_savingEvent, EVENT_WAIT_TIMEOUT);
  3656. // Save anyway, then report if the Wait function returned an unexpected error
  3657. errWait = GetLastError();
  3658. // Note: Don't throw exception here because even if saving fails, we still need
  3659. // to set the saving event.
  3660. hr = (((IUnknown*) (IHsmServer*) this)->QueryInterface(IID_IPersistFile,
  3661. (void**) &pPersistFile));
  3662. if (SUCCEEDED(hr)) {
  3663. hr = WsbSafeSave(pPersistFile);
  3664. }
  3665. // Check Wait status... Note that hr remains OK because the saving itself completed fine
  3666. switch (status) {
  3667. case WAIT_OBJECT_0:
  3668. // The expected case
  3669. SetEvent(m_savingEvent);
  3670. break;
  3671. case WAIT_TIMEOUT:
  3672. // Don't log anything for now: This might happen if snapshot process takes
  3673. // too long for some reason, but logging seems to just confuse the user -
  3674. // he really can not (and should not) do anything...
  3675. WsbTraceAlways(OLESTR("CHsmServer::InternalSavePersistData: Wait for Single Object timed out after %lu ms\n"), EVENT_WAIT_TIMEOUT);
  3676. break;
  3677. case WAIT_FAILED:
  3678. WsbTraceAlways(OLESTR("CHsmServer::InternalSavePersistData: Wait for Single Object returned error %lu\n"), errWait);
  3679. break;
  3680. default:
  3681. WsbTraceAlways(OLESTR("CHsmServer::InternalSavePersistData: Wait for Single Object returned unexpected status %lu\n"), status);
  3682. break;
  3683. }
  3684. } WsbCatch(hr);
  3685. WsbTraceOut(OLESTR("CHsmServer::InternalSavePersistData"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3686. return(hr);
  3687. }
  3688. HRESULT
  3689. CHsmServer::CancelMountingMedias( void )
  3690. /*++
  3691. Implements:
  3692. CHsmServer::CancelMountingMedias().
  3693. --*/
  3694. {
  3695. HRESULT hr = S_OK;
  3696. CComPtr<IWsbEnum> pEnum;
  3697. CComPtr<IMountingMedia> pMountingMedia;
  3698. WsbTraceIn(OLESTR("CHsmServer::CancelMountingMedias"), OLESTR(""));
  3699. try {
  3700. WsbAffirmHr(m_pMountingMedias->Enum(&pEnum));
  3701. // Loop through all mounting media and release waiting mounting clients
  3702. for (hr = pEnum->First(IID_IMountingMedia, (void**) &pMountingMedia);
  3703. SUCCEEDED(hr);
  3704. hr = pEnum->Next(IID_IMountingMedia, (void**) &pMountingMedia)) {
  3705. pMountingMedia->MountDone();
  3706. pMountingMedia = 0;
  3707. }
  3708. if (hr == WSB_E_NOTFOUND) {
  3709. hr = S_OK;
  3710. }
  3711. } WsbCatch(hr);
  3712. WsbTraceOut(OLESTR("CHsmServer::CancelMountingMedias"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3713. return(hr);
  3714. }
  3715. //
  3716. // Methods of the class which uses to upgrade a Win2K rms to current rms
  3717. //
  3718. HRESULT
  3719. CHsmUpgradeRmsDb::FinalConstruct(
  3720. void
  3721. )
  3722. /*++
  3723. Implements:
  3724. CComObjectRoot::FinalConstruct
  3725. --*/
  3726. {
  3727. HRESULT hr = S_OK;
  3728. WsbTraceIn(OLESTR("CHsmUpgradeRmsDb::FinalConstruct"), OLESTR("") );
  3729. try {
  3730. WsbAffirmHr(CWsbPersistable::FinalConstruct());
  3731. m_pServer = NULL;
  3732. } WsbCatch(hr);
  3733. WsbTraceOut(OLESTR("CHsmUpgradeRmsDb::FinalConstruct"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  3734. return(hr);
  3735. }
  3736. void
  3737. CHsmUpgradeRmsDb::FinalRelease(
  3738. void
  3739. )
  3740. /*++
  3741. Implements:
  3742. CComObjectRoot::FinalRelease
  3743. --*/
  3744. {
  3745. HRESULT hr = S_OK;
  3746. WsbTraceIn(OLESTR("CHsmUpgradeRmsDb::FinalRelease"), OLESTR(""));
  3747. CWsbPersistable::FinalRelease();
  3748. WsbTraceOut(OLESTR("CHsmUpgradeRmsDb::FinalRelease"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  3749. }
  3750. HRESULT
  3751. CHsmUpgradeRmsDb::GetClassID(
  3752. OUT CLSID* pClsid)
  3753. /*++
  3754. Implements:
  3755. IPersist::GetClassId
  3756. --*/
  3757. {
  3758. HRESULT hr = S_OK;
  3759. WsbTraceIn(OLESTR("CHsmUpgradeRmsDb::GetClassID"), OLESTR(""));
  3760. try {
  3761. WsbAssert(0 != pClsid, E_POINTER);
  3762. // Return Rms class id since this is what the old col file represents
  3763. *pClsid = CLSID_CRmsServer;
  3764. } WsbCatch(hr);
  3765. WsbTraceOut(OLESTR("CHsmUpgradeRmsDb::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid));
  3766. return hr;
  3767. }
  3768. HRESULT
  3769. CHsmUpgradeRmsDb::Save(
  3770. IN IStream* /*pStream*/,
  3771. IN BOOL /*clearDirty*/
  3772. )
  3773. /*++
  3774. Implements:
  3775. IPersistStream::Save().
  3776. --*/
  3777. {
  3778. HRESULT hr = E_NOTIMPL;
  3779. WsbTraceIn(OLESTR("CHsmUpgradeRmsDb::Save"), OLESTR(""));
  3780. // Not implemented - this class should be used only for load
  3781. WsbTraceOut(OLESTR("CHsmUpgradeRmsDb::Save"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3782. return(hr);
  3783. }
  3784. HRESULT
  3785. CHsmUpgradeRmsDb::Load(
  3786. IN IStream* pStream
  3787. )
  3788. /*++
  3789. Implements:
  3790. IPersistStream::Load().
  3791. --*/
  3792. {
  3793. HRESULT hr = S_OK;
  3794. WsbTraceIn(OLESTR("CHsmUpgradeRmsDb::Load"), OLESTR(""));
  3795. try {
  3796. ULONG buildVersion;
  3797. ULONG databaseVersion;
  3798. ULONG expectedVersion = RMS_WIN2K_DB_VERSION;
  3799. WsbAssert(0 != pStream, E_POINTER);
  3800. // Make sure this is the right version of the Rms database to load
  3801. WsbAffirmHr(WsbLoadFromStream(pStream, &databaseVersion));
  3802. if (databaseVersion != expectedVersion) {
  3803. WsbLogEvent( RMS_MESSAGE_DATABASE_VERSION_MISMATCH, 0, NULL, WsbQuickString(WsbPtrToUlongAsString(&expectedVersion)),
  3804. WsbQuickString(WsbPtrToUlongAsString(&databaseVersion)), NULL );
  3805. WsbThrow(RMS_E_DATABASE_VERSION_MISMATCH);
  3806. }
  3807. // Read in the build version but don't do anything with it.
  3808. WsbAffirmHr(WsbLoadFromStream(pStream, &buildVersion));
  3809. // Let Rms manager to this its load
  3810. CComPtr<IPersistStream> pIStream;
  3811. WsbAffirmHr(m_pServer->QueryInterface(IID_IPersistStream, (void **)&pIStream));
  3812. WsbAffirmHr(pIStream->Load(pStream));
  3813. } WsbCatch(hr);
  3814. WsbTraceOut(OLESTR("CHsmUpgradeRmsDb::Load"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3815. return(hr);
  3816. }
  3817. HRESULT CHsmUpgradeRmsDb::Init(
  3818. IN IRmsServer *pHsmMediaMgr
  3819. )
  3820. /*++
  3821. Implements:
  3822. IHsmUpgradeRmsDb::Init().
  3823. --*/
  3824. {
  3825. HRESULT hr = S_OK;
  3826. WsbTraceIn(OLESTR("CHsmUpgradeRmsDb::Init"),OLESTR(""));
  3827. try {
  3828. WsbAssert(0 != pHsmMediaMgr, E_POINTER);
  3829. m_pServer = pHsmMediaMgr;
  3830. } WsbCatch(hr);
  3831. WsbTraceOut(OLESTR("CHsmUpgradeRmsDb::Init"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3832. return hr;
  3833. }