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.

2511 lines
72 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. fsasrvr.cpp
  5. Abstract:
  6. This class contains represents a file system for NTFS.
  7. Author:
  8. Chuck Bardeen [cbardeen] 1-Dec-1996
  9. Revision History:
  10. Chris Timmes [ctimmes] 31-Dec-1997
  11. - basically rewrote the ScanForResources() method to fix RAID bug 117412
  12. (volumes which were once manageable but are now unmanageable still show as
  13. manageable in the UI).
  14. --*/
  15. #include "stdafx.h"
  16. #include "job.h"
  17. #include "fsa.h"
  18. #include "fsaprv.h"
  19. #include "fsasrvr.h"
  20. #include "HsmConn.h"
  21. #include "wsbdb.h"
  22. #include "wsbtrak.h"
  23. #include "wsbvol.h"
  24. #include "task.h"
  25. #include "rsbuild.h"
  26. #include "rsevents.h"
  27. #include "ntverp.h"
  28. #include <winioctl.h>
  29. #include <setupapi.h>
  30. #include <objbase.h>
  31. #include <stdio.h>
  32. #include <initguid.h>
  33. #include <mountmgr.h>
  34. static short g_InstanceCount = 0;
  35. // Non-member function initially called for autosave thread
  36. static DWORD FsaStartAutosave(
  37. void* pVoid
  38. )
  39. {
  40. return(((CFsaServer*) pVoid)->Autosave());
  41. }
  42. HRESULT
  43. CFsaServer::Autosave(
  44. void
  45. )
  46. /*++
  47. Routine Description:
  48. Implements an autosave loop.
  49. Arguments:
  50. None.
  51. Return Value:
  52. Doesn't matter.
  53. --*/
  54. {
  55. HRESULT hr = S_OK;
  56. ULONG l_autosaveInterval = m_autosaveInterval;
  57. BOOL exitLoop = FALSE;
  58. WsbTraceIn(OLESTR("CFsaServer::Autosave"), OLESTR(""));
  59. try {
  60. while (m_autosaveInterval && (! exitLoop)) {
  61. // Wait for termination event, if timeout occurs, check if we can perform Autosave
  62. switch (WaitForSingleObject(m_terminateEvent, l_autosaveInterval)) {
  63. case WAIT_OBJECT_0:
  64. // Need to terminate
  65. WsbTrace(OLESTR("CFsaServer::Autosave: signaled to terminate\n"));
  66. exitLoop = TRUE;
  67. break;
  68. case WAIT_TIMEOUT:
  69. // Check if backup need to be performed
  70. WsbTrace(OLESTR("CFsaServer::Autosave: Autosave awakened\n"));
  71. // Don't do this if we're suspended
  72. if (!m_Suspended) {
  73. // Save data
  74. // NOTE: Because this is a separate thread, there is the possibility
  75. // of a conflict if the main thread is changing some data at the same
  76. // time we're trying to save it.
  77. // If a save is already happening, just skip this one and
  78. // go back to sleep
  79. hr = SaveAll();
  80. // If the save fails, increase the sleep time to avoid filling
  81. // the event log
  82. if (!SUCCEEDED(hr)) {
  83. if ((MAX_AUTOSAVE_INTERVAL / 2) < l_autosaveInterval) {
  84. l_autosaveInterval = MAX_AUTOSAVE_INTERVAL;
  85. } else {
  86. l_autosaveInterval *= 2;
  87. }
  88. } else {
  89. l_autosaveInterval = m_autosaveInterval;
  90. }
  91. }
  92. break; // end of timeout case
  93. case WAIT_FAILED:
  94. default:
  95. WsbTrace(OLESTR("CFsaServer::Autosave: WaitForSingleObject returned error %lu\n"), GetLastError());
  96. exitLoop = TRUE;
  97. break;
  98. } // end of switch
  99. } // end of while
  100. } WsbCatch(hr);
  101. WsbTraceOut(OLESTR("CFsaServer::Autosave"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  102. return(hr);
  103. }
  104. HRESULT
  105. CFsaServer::CreateInstance(
  106. REFCLSID rclsid,
  107. REFIID riid,
  108. void **ppv
  109. )
  110. {
  111. HRESULT hr = S_OK;
  112. hr = CoCreateInstance(rclsid, NULL, CLSCTX_SERVER, riid, ppv);
  113. return hr;
  114. }
  115. HRESULT
  116. CFsaServer::DoRecovery(
  117. void
  118. )
  119. /*++
  120. Routine Description:
  121. Do recovery.
  122. Arguments:
  123. None.
  124. Return Value:
  125. S_OK - Success.
  126. --*/
  127. {
  128. HRESULT hr = S_OK;
  129. WsbTraceIn(OLESTR("CFsaServer::DoRecovery"), OLESTR(""));
  130. try {
  131. CComPtr<IWsbEnum> pEnum;
  132. CComPtr<IFsaResourcePriv> pResourcePriv;
  133. CComPtr<IFsaResource> pResource;
  134. // Loop over resources and tell them to do their own recovery
  135. WsbAffirmPointer(m_pResources);
  136. WsbAffirmHr(m_pResources->Enum(&pEnum));
  137. hr = pEnum->First(IID_IFsaResourcePriv, (void**)&pResourcePriv);
  138. while (S_OK == hr) {
  139. WsbAffirmHr(pResourcePriv->QueryInterface(IID_IFsaResource, (void**) &pResource));
  140. if ((pResource->IsActive() == S_OK) && (pResource->IsAvailable() == S_OK)) {
  141. hr = pResourcePriv->DoRecovery();
  142. // Log event if (S_OK != hr) ???
  143. }
  144. // Release this resource and get the next one
  145. pResource = 0;
  146. pResourcePriv = 0;
  147. hr = pEnum->Next(IID_IFsaResourcePriv, (void**)&pResourcePriv);
  148. }
  149. if (WSB_E_NOTFOUND == hr) {
  150. hr = S_OK;
  151. }
  152. } WsbCatch(hr);
  153. WsbTraceOut(OLESTR("CFsaServer::DoRecovery"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  154. return(hr);
  155. }
  156. HRESULT
  157. CFsaServer::EnumResources(
  158. OUT IWsbEnum** ppEnum
  159. )
  160. /*++
  161. Implements:
  162. IFsaServer::EnumResources().
  163. --*/
  164. {
  165. HRESULT hr = S_OK;
  166. try {
  167. WsbAssert(0 != ppEnum, E_POINTER);
  168. //
  169. // We can't trust that the resource information
  170. // that we have is current so redo the scan. This
  171. // is expensive and should be changed once we
  172. // know how NT can tell us when things have
  173. // changed
  174. //
  175. try {
  176. WsbAffirmHr(ScanForResources());
  177. } WsbCatch( hr );
  178. WsbAffirmHr(m_pResources->Enum(ppEnum));
  179. } WsbCatch(hr);
  180. return(hr);
  181. }
  182. HRESULT
  183. CFsaServer::FinalConstruct(
  184. void
  185. )
  186. /*++
  187. Implements:
  188. CComObjectRoot::FinalConstruct().
  189. --*/
  190. {
  191. HRESULT hr = S_OK;
  192. WsbTraceIn(OLESTR("CFsaServer::FinalConstruct"), OLESTR(""));
  193. hr = CWsbPersistable::FinalConstruct();
  194. // Keep it simple, most of the work is done in Init();
  195. m_terminateEvent = NULL;
  196. m_savingEvent = NULL;
  197. m_id = GUID_NULL;
  198. m_Suspended = FALSE;
  199. m_isUnmanageDbSysInitialized = FALSE;
  200. if (hr == S_OK) {
  201. g_InstanceCount++;
  202. }
  203. WsbTrace(OLESTR("CFsaServer::FinalConstruct: Instance count = %d\n"), g_InstanceCount);
  204. WsbTraceOut(OLESTR("CFsaServer::FinalConstruct"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  205. return(hr);
  206. }
  207. void
  208. CFsaServer::FinalRelease(
  209. void
  210. )
  211. /*++
  212. Implements:
  213. CComObjectRoot::FinalRelease().
  214. --*/
  215. {
  216. HRESULT hr = S_OK;
  217. CComPtr<IPersistFile> pPersistFile;
  218. WsbTraceIn(OLESTR("CFsaServer::FinalRelease"), OLESTR(""));
  219. try {
  220. HSM_SYSTEM_STATE SysState;
  221. SysState.State = HSM_STATE_SHUTDOWN;
  222. ChangeSysState(&SysState);
  223. } WsbCatch(hr)
  224. // Let the parent class do his thing.
  225. CWsbPersistable::FinalRelease();
  226. // Free String members
  227. // Note: Member objects held in smart-pointers are freed when the
  228. // smart-pointer destructor is being called (as part of this object destruction)
  229. m_dbPath.Free();
  230. m_name.Free();
  231. // Free autosave terminate event
  232. if (m_terminateEvent != NULL) {
  233. CloseHandle(m_terminateEvent);
  234. m_terminateEvent = NULL;
  235. }
  236. // Clean up database system
  237. m_pDbSys->Terminate();
  238. if (m_isUnmanageDbSysInitialized) {
  239. m_pUnmanageDbSys->Terminate();
  240. m_isUnmanageDbSysInitialized = FALSE;
  241. }
  242. if (m_savingEvent != NULL) {
  243. CloseHandle(m_savingEvent);
  244. m_savingEvent = NULL;
  245. }
  246. if (hr == S_OK) {
  247. g_InstanceCount--;
  248. }
  249. WsbTrace(OLESTR("CFsaServer::FinalRelease: Instance count = %d\n"), g_InstanceCount);
  250. WsbTraceOut(OLESTR("CFsaServer::FinalRelease"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  251. }
  252. HRESULT
  253. CFsaServer::FindResourceByAlternatePath(
  254. IN OLECHAR* path,
  255. OUT IFsaResource** ppResource
  256. )
  257. /*++
  258. Implements:
  259. IFsaServer::FindResourceByAlternatePath().
  260. --*/
  261. {
  262. HRESULT hr = S_OK;
  263. CComPtr<IFsaResourcePriv> pResourcePriv;
  264. CComPtr<IFsaResource> pResource;
  265. WsbTraceIn(OLESTR("CFsaServer::FindResourceByAlternatePath"), OLESTR("path = <%ls>"), path);
  266. try {
  267. WsbAssert(0 != path, E_POINTER);
  268. WsbAssert(0 != ppResource, E_POINTER);
  269. WsbAffirmPointer(m_pResources);
  270. // Create an FsaResource that will scan for us.
  271. WsbAffirmHr(CoCreateInstance(CLSID_CFsaResourceNTFS, NULL, CLSCTX_SERVER, IID_IFsaResourcePriv, (void**) &pResourcePriv));
  272. WsbAffirmHr(pResourcePriv->SetAlternatePath(path));
  273. WsbAffirmHr(pResourcePriv->QueryInterface(IID_IFsaResource, (void**) &pResource));
  274. WsbAffirmHr(pResource->CompareBy(FSA_RESOURCE_COMPARE_ALTERNATEPATH));
  275. WsbAffirmHr(m_pResources->Find(pResource, IID_IFsaResource, (void**) ppResource));
  276. } WsbCatch(hr);
  277. WsbTraceOut(OLESTR("CFsaServer::FindResourceByAlternatePath"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  278. return(hr);
  279. }
  280. HRESULT
  281. CFsaServer::FindResourceById(
  282. IN GUID id,
  283. OUT IFsaResource** ppResource
  284. )
  285. /*++
  286. Implements:
  287. IFsaServer::FindResourceById().
  288. --*/
  289. {
  290. HRESULT hr = S_OK;
  291. CComPtr<IFsaResourcePriv> pResourcePriv;
  292. CComPtr<IFsaResource> pResource;
  293. WsbTraceIn(OLESTR("CFsaServer::FindResourceById"), OLESTR("id = <%ls>"), WsbGuidAsString(id));
  294. try {
  295. WsbAssert(0 != ppResource, E_POINTER);
  296. WsbAffirmPointer(m_pResources);
  297. // Create an FsaResource that will scan for us.
  298. WsbAffirmHr(CoCreateInstance(CLSID_CFsaResourceNTFS, NULL, CLSCTX_SERVER, IID_IFsaResourcePriv, (void**) &pResourcePriv));
  299. WsbAffirmHr(pResourcePriv->SetIdentifier(id));
  300. WsbAffirmHr(pResourcePriv->QueryInterface(IID_IFsaResource, (void**) &pResource));
  301. WsbAffirmHr(pResource->CompareBy(FSA_RESOURCE_COMPARE_ID));
  302. WsbAffirmHr(m_pResources->Find(pResource, IID_IFsaResource, (void**) ppResource));
  303. } WsbCatch(hr);
  304. WsbTraceOut(OLESTR("CFsaServer::FindResourceById"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  305. return(hr);
  306. }
  307. HRESULT
  308. CFsaServer::FindResourceByName(
  309. IN OLECHAR* name,
  310. OUT IFsaResource** ppResource
  311. )
  312. /*++
  313. Implements:
  314. IFsaServer::FindResourceByName().
  315. --*/
  316. {
  317. HRESULT hr = S_OK;
  318. CComPtr<IFsaResourcePriv> pResourcePriv;
  319. CComPtr<IFsaResource> pResource;
  320. WsbTraceIn(OLESTR("CFsaServer::FindResourceByName"), OLESTR("name = <%ls>"), name);
  321. try {
  322. WsbAssert(0 != ppResource, E_POINTER);
  323. WsbAffirmPointer(m_pResources);
  324. // Create an FsaResource that will scan for us.
  325. WsbAffirmHr(CoCreateInstance(CLSID_CFsaResourceNTFS, NULL, CLSCTX_SERVER, IID_IFsaResourcePriv, (void**) &pResourcePriv));
  326. WsbAffirmHr(pResourcePriv->SetName(name));
  327. WsbAffirmHr(pResourcePriv->QueryInterface(IID_IFsaResource, (void**) &pResource));
  328. WsbAffirmHr(pResource->CompareBy(FSA_RESOURCE_COMPARE_NAME));
  329. WsbAffirmHr(m_pResources->Find(pResource, IID_IFsaResource, (void**) ppResource));
  330. } WsbCatch(hr);
  331. WsbTraceOut(OLESTR("CFsaServer::FindResourceByName"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  332. return(hr);
  333. }
  334. HRESULT
  335. CFsaServer::FindResourceByPath(
  336. IN OLECHAR* path,
  337. OUT IFsaResource** ppResource
  338. )
  339. /*++
  340. Implements:
  341. IFsaServer::FindResourceByPath().
  342. --*/
  343. {
  344. HRESULT hr = S_OK;
  345. CComPtr<IFsaResourcePriv> pResourcePriv;
  346. CComPtr<IFsaResource> pResource;
  347. WsbTraceIn(OLESTR("CFsaServer::FindResourceByPath"), OLESTR("path = <%ls>"), path);
  348. try {
  349. WsbAssert(0 != path, E_POINTER);
  350. WsbAssert(0 != ppResource, E_POINTER);
  351. WsbAffirmPointer(m_pResources);
  352. // Create an FsaResource that will scan for us.
  353. WsbAffirmHr(CoCreateInstance(CLSID_CFsaResourceNTFS, NULL, CLSCTX_SERVER, IID_IFsaResourcePriv, (void**) &pResourcePriv));
  354. //WsbAffirmHr(pResourcePriv->SetPath(path));
  355. WsbAffirmHr(pResourcePriv->SetUserFriendlyName(path));
  356. WsbAffirmHr(pResourcePriv->QueryInterface(IID_IFsaResource, (void**) &pResource));
  357. //WsbAffirmHr(pResource->CompareBy(FSA_RESOURCE_COMPARE_PATH));
  358. WsbAffirmHr(pResource->CompareBy(FSA_RESOURCE_COMPARE_USER_NAME));
  359. WsbAffirmHr(m_pResources->Find(pResource, IID_IFsaResource, (void**) ppResource));
  360. } WsbCatch(hr);
  361. WsbTraceOut(OLESTR("CFsaServer::FindResourceByPath"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  362. return(hr);
  363. }
  364. HRESULT
  365. CFsaServer::FindResourceBySerial(
  366. IN ULONG serial,
  367. OUT IFsaResource** ppResource
  368. )
  369. /*++
  370. Implements:
  371. IFsaServer::FindResourceBySerial().
  372. --*/
  373. {
  374. HRESULT hr = S_OK;
  375. CComPtr<IFsaResourcePriv> pResourcePriv;
  376. CComPtr<IFsaResource> pResource;
  377. WsbTraceIn(OLESTR("CFsaServer::FindResourceBySerial"), OLESTR("serial = <%lu>"), serial);
  378. try {
  379. WsbAssert(0 != ppResource, E_POINTER);
  380. WsbAffirmPointer(m_pResources);
  381. // Create an FsaResource that will scan for us.
  382. WsbAffirmHr(CoCreateInstance(CLSID_CFsaResourceNTFS, NULL, CLSCTX_SERVER, IID_IFsaResourcePriv, (void**) &pResourcePriv));
  383. WsbAffirmHr(pResourcePriv->SetSerial(serial));
  384. WsbAffirmHr(pResourcePriv->QueryInterface(IID_IFsaResource, (void**) &pResource));
  385. WsbAffirmHr(pResource->CompareBy(FSA_RESOURCE_COMPARE_SERIAL));
  386. WsbAffirmHr(m_pResources->Find(pResource, IID_IFsaResource, (void**) ppResource));
  387. } WsbCatch(hr);
  388. WsbTraceOut(OLESTR("CFsaServer::FindResourceBySerial"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  389. return(hr);
  390. }
  391. HRESULT
  392. CFsaServer::FindResourceByStickyName(
  393. IN OLECHAR* name,
  394. OUT IFsaResource** ppResource
  395. )
  396. /*++
  397. Implements:
  398. IFsaServer::FindResourceByStickyName().
  399. --*/
  400. {
  401. HRESULT hr = S_OK;
  402. CComPtr<IFsaResourcePriv> pResourcePriv;
  403. CComPtr<IFsaResource> pResource;
  404. WsbTraceIn(OLESTR("CFsaServer::FindResourceByStickyName"), OLESTR("name = <%ls>"), name);
  405. try {
  406. WsbAssert(0 != ppResource, E_POINTER);
  407. WsbAffirmPointer(m_pResources);
  408. // Create an FsaResource that will scan for us.
  409. WsbAffirmHr(CoCreateInstance(CLSID_CFsaResourceNTFS, NULL, CLSCTX_SERVER, IID_IFsaResourcePriv, (void**) &pResourcePriv));
  410. WsbAffirmHr(pResourcePriv->SetStickyName(name));
  411. WsbAffirmHr(pResourcePriv->QueryInterface(IID_IFsaResource, (void**) &pResource));
  412. WsbAffirmHr(pResource->CompareBy(FSA_RESOURCE_COMPARE_STICKY_NAME));
  413. WsbAffirmHr(m_pResources->Find(pResource, IID_IFsaResource, (void**) ppResource));
  414. } WsbCatch(hr);
  415. WsbTraceOut(OLESTR("CFsaServer::FindResourceByStickyName"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  416. return(hr);
  417. }
  418. HRESULT
  419. CFsaServer::GetAutosave(
  420. OUT ULONG* pMilliseconds
  421. )
  422. /*++
  423. Implements:
  424. IFsaServer::GetAutosave().
  425. --*/
  426. {
  427. HRESULT hr = S_OK;
  428. WsbTraceIn(OLESTR("CFsaServer::GetAutosave"), OLESTR(""));
  429. try {
  430. WsbAssert(0 != pMilliseconds, E_POINTER);
  431. *pMilliseconds = m_autosaveInterval;
  432. } WsbCatch(hr);
  433. WsbTraceOut(OLESTR("CFsaServer::GetAutosave"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  434. return(hr);
  435. }
  436. HRESULT
  437. CFsaServer::GetBuildVersion(
  438. ULONG *pBuildVersion
  439. )
  440. /*++
  441. Implements:
  442. IWsbServer::GetBuildVersion().
  443. --*/
  444. {
  445. HRESULT hr = S_OK;
  446. WsbTraceIn(OLESTR("CFsaServer::GetBuildVersion"), OLESTR(""));
  447. try {
  448. WsbAssertPointer(pBuildVersion);
  449. *pBuildVersion = m_buildVersion;
  450. } WsbCatch(hr);
  451. WsbTraceOut(OLESTR("CFsaServer::GetBuildVersion"), OLESTR("hr = <%ls>, Version = <%ls)"),
  452. WsbHrAsString(hr), RsBuildVersionAsString(m_buildVersion));
  453. return ( hr );
  454. }
  455. HRESULT
  456. CFsaServer::GetClassID(
  457. OUT CLSID* pClsid
  458. )
  459. /*++
  460. Implements:
  461. IPersist::GetClassID().
  462. --*/
  463. {
  464. HRESULT hr = S_OK;
  465. WsbTraceIn(OLESTR("CFsaServer::GetClassID"), OLESTR(""));
  466. try {
  467. WsbAssert(0 != pClsid, E_POINTER);
  468. *pClsid = CLSID_CFsaServerNTFS;
  469. } WsbCatch(hr);
  470. WsbTraceOut(OLESTR("CFsaServer::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid));
  471. return(hr);
  472. }
  473. HRESULT
  474. CFsaServer::GetDatabaseVersion(
  475. ULONG *pDatabaseVersion
  476. )
  477. /*++
  478. Implements:
  479. IWsbServer::GetDatabaseVersion().
  480. --*/
  481. {
  482. HRESULT hr = S_OK;
  483. WsbTraceIn(OLESTR("CFsaServer::GetDatabaseVersion"), OLESTR(""));
  484. *pDatabaseVersion = m_databaseVersion;
  485. WsbTraceOut(OLESTR("CFsaServer::GetDatabaseVersion"), OLESTR("hr = <%ls>, Version = <%ls)"),
  486. WsbHrAsString(hr), WsbPtrToUlongAsString(pDatabaseVersion));
  487. return ( hr );
  488. }
  489. HRESULT
  490. CFsaServer::GetDbPath(
  491. OUT OLECHAR** pPath,
  492. IN ULONG bufferSize
  493. )
  494. /*++
  495. Implements:
  496. IFsaServer::GetDbPath().
  497. --*/
  498. {
  499. HRESULT hr = S_OK;
  500. WsbTraceIn(OLESTR("CFsaServer::GetDbPath"), OLESTR(""));
  501. try {
  502. WsbAssert(0 != pPath, E_POINTER);
  503. // Right now it is hard coded. This will probably change to something from the registry.
  504. WsbAffirmHr(m_dbPath.CopyTo(pPath, bufferSize));
  505. } WsbCatch(hr);
  506. WsbTraceOut(OLESTR("CFsaServer::GetDbPath"), OLESTR("hr = <%ls>, path = <%ls)"),
  507. WsbHrAsString(hr), WsbPtrToStringAsString(pPath));
  508. return(hr);
  509. }
  510. HRESULT
  511. CFsaServer::GetDbPathAndName(
  512. OUT OLECHAR** pPath,
  513. IN ULONG bufferSize
  514. )
  515. /*++
  516. Implements:
  517. IFsaServer::GetDbPathAndName().
  518. --*/
  519. {
  520. HRESULT hr = S_OK;
  521. CWsbStringPtr tmpString;
  522. try {
  523. WsbAssert(0 != pPath, E_POINTER);
  524. tmpString = m_dbPath;
  525. tmpString.Append(OLESTR("\\RsFsa.col"));
  526. WsbAffirmHr(tmpString.CopyTo(pPath, bufferSize));
  527. } WsbCatch(hr);
  528. return(hr);
  529. }
  530. HRESULT
  531. CFsaServer::GetIDbPath(
  532. OUT OLECHAR** pPath,
  533. IN ULONG bufferSize
  534. )
  535. /*++
  536. Implements:
  537. IFsaServer::GetIDbPath().
  538. --*/
  539. {
  540. HRESULT hr = S_OK;
  541. CWsbStringPtr tmpString;
  542. try {
  543. WsbAssert(0 != pPath, E_POINTER);
  544. WsbAffirmHr(GetDbPath(&tmpString, 0));
  545. tmpString.Append(OLESTR("\\"));
  546. tmpString.Append(FSA_DB_DIRECTORY);
  547. WsbAffirmHr(tmpString.CopyTo(pPath, bufferSize));
  548. } WsbCatch(hr);
  549. return(hr);
  550. }
  551. HRESULT
  552. CFsaServer::GetUnmanageIDbPath(
  553. OUT OLECHAR** pPath,
  554. IN ULONG bufferSize
  555. )
  556. /*++
  557. Implements:
  558. IFsaServer::GetIDbPath().
  559. --*/
  560. {
  561. HRESULT hr = S_OK;
  562. CWsbStringPtr tmpString;
  563. try {
  564. WsbAssert(0 != pPath, E_POINTER);
  565. WsbAffirmHr(GetDbPath(&tmpString, 0));
  566. tmpString.Append(OLESTR("\\"));
  567. tmpString.Append(FSA_DB_DIRECTORY);
  568. tmpString.Append(OLESTR("\\"));
  569. tmpString.Append(UNMANAGE_DB_DIRECTORY);
  570. WsbAffirmHr(tmpString.CopyTo(pPath, bufferSize));
  571. } WsbCatch(hr);
  572. return(hr);
  573. }
  574. HRESULT
  575. CFsaServer::GetIDbSys(
  576. OUT IWsbDbSys** ppDbSys
  577. )
  578. /*++
  579. Implements:
  580. IFsaServer::GetIDbSys().
  581. --*/
  582. {
  583. HRESULT hr = S_OK;
  584. try {
  585. WsbAssert(0 != ppDbSys, E_POINTER);
  586. *ppDbSys = m_pDbSys;
  587. m_pDbSys->AddRef();
  588. } WsbCatch(hr);
  589. return(hr);
  590. }
  591. HRESULT
  592. CFsaServer::GetUnmanageIDbSys(
  593. OUT IWsbDbSys** ppDbSys
  594. )
  595. /*++
  596. Implements:
  597. IFsaServer::GetUnmanageIDbSys().
  598. --*/
  599. {
  600. HRESULT hr = S_OK;
  601. WsbTraceIn(OLESTR("CFsaServer::GetUnmanageIDbSys"), OLESTR(""));
  602. try {
  603. CWsbStringPtr tmpString;
  604. WsbAssert(0 != ppDbSys, E_POINTER);
  605. // Unlike the premigarted db-sys-instance, we initialize the unamange db-sys-instance
  606. // only when it is required for the first time
  607. if (! m_isUnmanageDbSysInitialized) {
  608. WsbAffirmHr(CoCreateInstance(CLSID_CWsbDbSys, NULL, CLSCTX_SERVER, IID_IWsbDbSys, (void**) &m_pUnmanageDbSys));
  609. WsbAffirmHr(GetUnmanageIDbPath(&tmpString, 0));
  610. WsbAffirmHr(m_pUnmanageDbSys->Init(tmpString, IDB_SYS_INIT_FLAG_NO_LOGGING |
  611. IDB_SYS_INIT_FLAG_SPECIAL_ERROR_MSG | IDB_SYS_INIT_FLAG_NO_BACKUP));
  612. m_isUnmanageDbSysInitialized = TRUE;
  613. }
  614. *ppDbSys = m_pUnmanageDbSys;
  615. m_pUnmanageDbSys->AddRef();
  616. } WsbCatch(hr);
  617. WsbTraceOut(OLESTR("CFsaServer::GetUnmanageIDbSys"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  618. return(hr);
  619. }
  620. HRESULT
  621. CFsaServer::GetId(
  622. OUT GUID* pId
  623. )
  624. /*++
  625. Implements:
  626. IWsbServer::GetId().
  627. --*/
  628. {
  629. return(GetIdentifier(pId));
  630. }
  631. HRESULT
  632. CFsaServer::GetIdentifier(
  633. OUT GUID* pId
  634. )
  635. /*++
  636. Implements:
  637. IFsaServer::GetIdentifier().
  638. --*/
  639. {
  640. HRESULT hr = S_OK;
  641. try {
  642. WsbAssert(0 != pId, E_POINTER);
  643. *pId = m_id;
  644. } WsbCatch(hr);
  645. return(hr);
  646. }
  647. HRESULT
  648. CFsaServer::GetFilter(
  649. OUT IFsaFilter** ppFilter
  650. )
  651. /*++
  652. Implements:
  653. IFsaServer::GetFilter().
  654. --*/
  655. {
  656. HRESULT hr = S_OK;
  657. try {
  658. WsbAssert(0 != ppFilter, E_POINTER);
  659. *ppFilter = m_pFilter;
  660. m_pFilter->AddRef();
  661. } WsbCatch(hr);
  662. return(hr);
  663. }
  664. HRESULT
  665. CFsaServer::GetLogicalName(
  666. OUT OLECHAR** pName,
  667. IN ULONG bufferSize
  668. )
  669. /*++
  670. Implements:
  671. IFsaServer::GetLogicalName().
  672. --*/
  673. {
  674. HRESULT hr = S_OK;
  675. CWsbStringPtr tmpString;
  676. try {
  677. WsbAssert(0 != pName, E_POINTER);
  678. WsbAffirmHr(tmpString.TakeFrom(*pName, bufferSize));
  679. try {
  680. // This is an arbitrary choice for the naming convention. Nothing has been
  681. // decided upon.
  682. tmpString = m_name;
  683. WsbAffirmHr(tmpString.Append(OLESTR("\\NTFS")));
  684. } WsbCatch(hr);
  685. WsbAffirmHr(tmpString.GiveTo(pName));
  686. } WsbCatch(hr);
  687. return(hr);
  688. }
  689. HRESULT
  690. CFsaServer::GetName(
  691. OUT OLECHAR** pName,
  692. IN ULONG bufferSize
  693. )
  694. /*++
  695. Implements:
  696. IFsaServer::GetName().
  697. --*/
  698. {
  699. HRESULT hr = S_OK;
  700. try {
  701. WsbAssert(0 != pName, E_POINTER);
  702. WsbAffirmHr(m_name.CopyTo(pName, bufferSize));
  703. } WsbCatch(hr);
  704. return(hr);
  705. }
  706. HRESULT CFsaServer::GetRegistryName (
  707. OLECHAR **pName,
  708. ULONG bufferSize
  709. )
  710. /*++
  711. Implements:
  712. IWsbServer::GetRegistryName().
  713. --*/
  714. {
  715. HRESULT hr = S_OK;
  716. try {
  717. CWsbStringPtr tmpString;
  718. WsbAssert(0 != pName, E_POINTER);
  719. tmpString = FSA_REGISTRY_NAME;
  720. WsbAffirmHr(tmpString.CopyTo(pName, bufferSize));
  721. } WsbCatch( hr );
  722. return (hr);
  723. }
  724. HRESULT
  725. CFsaServer::GetSizeMax(
  726. OUT ULARGE_INTEGER* pSize
  727. )
  728. /*++
  729. Implements:
  730. IPersistStream::GetSizeMax().
  731. --*/
  732. {
  733. HRESULT hr = S_OK;
  734. CComPtr<IPersistStream> pPersistStream;
  735. ULARGE_INTEGER entrySize;
  736. WsbTraceIn(OLESTR("CFsaServer::GetSizeMax"), OLESTR(""));
  737. try {
  738. WsbAssert(0 != pSize, E_POINTER);
  739. // Determine the size for a rule with no criteria.
  740. pSize->QuadPart = WsbPersistSize((wcslen(m_name) + 1) * sizeof(OLECHAR)) + WsbPersistSizeOf(GUID);
  741. // Now allocate space for the resource collection.
  742. WsbAffirmPointer(m_pResources);
  743. WsbAffirmHr(m_pResources->QueryInterface(IID_IPersistStream, (void**) &pPersistStream));
  744. WsbAffirmHr(pPersistStream->GetSizeMax(&entrySize));
  745. pSize->QuadPart += entrySize.QuadPart;
  746. pPersistStream = 0;
  747. // Now allocate space for the filter.
  748. WsbAffirmHr(m_pFilter->QueryInterface(IID_IPersistStream, (void**) &pPersistStream));
  749. WsbAffirmHr(pPersistStream->GetSizeMax(&entrySize));
  750. pSize->QuadPart += entrySize.QuadPart;
  751. pPersistStream = 0;
  752. } WsbCatch(hr);
  753. WsbTraceOut(OLESTR("CFsaServer::GetSizeMax"), OLESTR("hr = <%ls>, Size = <%ls>"), WsbHrAsString(hr), WsbPtrToUliAsString(pSize));
  754. return(hr);
  755. }
  756. HRESULT
  757. CFsaServer::Init(
  758. void
  759. )
  760. /*++
  761. Implements:
  762. CFsaServer::Init().
  763. --*/
  764. {
  765. HRESULT hr = S_OK;
  766. CComPtr<IPersistFile> pPersistFile;
  767. CComPtr<IWsbServer> pWsbServer;
  768. CComPtr<IFsaFilterPriv> pFilterPriv;
  769. CWsbStringPtr tmpString;
  770. HANDLE pHandle;
  771. LUID backupValue;
  772. HANDLE tokenHandle;
  773. TOKEN_PRIVILEGES newState;
  774. DWORD lErr;
  775. WsbTraceIn(OLESTR("CFsaServer::Init"), OLESTR(""));
  776. try {
  777. // Store of the name of the server and path to meta data
  778. WsbAffirmHr(WsbGetComputerName(m_name));
  779. WsbAffirmHr(WsbGetMetaDataPath(m_dbPath));
  780. // Set the build and database parameters
  781. m_databaseVersion = FSA_CURRENT_DB_VERSION;
  782. m_buildVersion = RS_BUILD_VERSION;
  783. // Set the autosave parameters.
  784. m_autosaveInterval = DEFAULT_AUTOSAVE_INTERVAL;
  785. m_autosaveThread = 0;
  786. // Enable the backup operator privilege. This is required to insure that we
  787. // have full access to all resources on the system.
  788. pHandle = GetCurrentProcess();
  789. WsbAffirmStatus(OpenProcessToken(pHandle, MAXIMUM_ALLOWED, &tokenHandle));
  790. // adjust backup token privileges
  791. WsbAffirmStatus(LookupPrivilegeValueW(NULL, L"SeBackupPrivilege", &backupValue));
  792. newState.PrivilegeCount = 1;
  793. newState.Privileges[0].Luid = backupValue;
  794. newState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  795. WsbAffirmStatus(AdjustTokenPrivileges(tokenHandle, FALSE, &newState, (DWORD)0, NULL, NULL));
  796. // Note that AdjustTokenPrivileges may return success even if it did not assign all privileges.
  797. // We check last error here to insure everything was set.
  798. if ((lErr = GetLastError()) != ERROR_SUCCESS) {
  799. // Not backup user or some other error
  800. //
  801. // TODO: Should we fail here or just log something?
  802. WsbLogEvent( FSA_MESSAGE_SERVICE_UNABLE_TO_SET_BACKUP_PRIVILEGE, 0, NULL,
  803. WsbHrAsString(HRESULT_FROM_WIN32(lErr)), NULL );
  804. }
  805. WsbAffirmStatus(LookupPrivilegeValueW(NULL, L"SeRestorePrivilege", &backupValue));
  806. newState.PrivilegeCount = 1;
  807. newState.Privileges[0].Luid = backupValue;
  808. newState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  809. WsbAffirmStatus(AdjustTokenPrivileges(tokenHandle, FALSE, &newState, (DWORD)0, NULL, NULL));
  810. // Note that AdjustTokenPrivileges may return success even if it did not assign all privileges.
  811. // We check last error here to insure everything was set.
  812. if ((lErr = GetLastError()) != ERROR_SUCCESS) {
  813. // Not backup user or some other error
  814. //
  815. // TODO: Should we fail here or just log something?
  816. WsbLogEvent( FSA_MESSAGE_SERVICE_UNABLE_TO_SET_RESTORE_PRIVILEGE, 0, NULL,
  817. WsbHrAsString(HRESULT_FROM_WIN32(lErr)), NULL );
  818. }
  819. CloseHandle(tokenHandle);
  820. // Check to see if trtacking of last access dates is enabled. If not,
  821. // we don't want to start the service. However, Microsoft wants us to
  822. // start it anyway, so we will log a warning.
  823. if (IsUpdatingAccessDates() != S_OK) {
  824. WsbLogEvent(FSA_MESSAGE_NOT_UPDATING_ACCESS_DATES, 0, NULL, NULL);
  825. }
  826. // Create the event that synchronize saving of persistent data with snapshots
  827. WsbAffirmHandle(m_savingEvent = CreateEvent(NULL, FALSE, TRUE, HSM_FSA_STATE_EVENT));
  828. // Create the IDB system for this process
  829. WsbAffirmHr(CoCreateInstance(CLSID_CWsbDbSys, NULL, CLSCTX_SERVER, IID_IWsbDbSys, (void**) &m_pDbSys));
  830. // Initialize the IDB system
  831. WsbAffirmHr(GetIDbPath(&tmpString, 0));
  832. WsbAffirmHr(m_pDbSys->Init(tmpString, IDB_SYS_INIT_FLAG_LIMITED_LOGGING |
  833. IDB_SYS_INIT_FLAG_SPECIAL_ERROR_MSG | IDB_SYS_INIT_FLAG_NO_BACKUP));
  834. // Create the resource collection (with no items).
  835. WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, NULL, CLSCTX_SERVER, IID_IWsbCollection, (void**) &m_pResources));
  836. // Create the Filter.
  837. WsbAffirmHr(CoCreateInstance(CLSID_CFsaFilterNTFS, NULL, CLSCTX_SERVER, IID_IFsaFilter, (void**) &m_pFilter));
  838. WsbAffirmHr(m_pFilter->QueryInterface(IID_IFsaFilterPriv, (void**) &pFilterPriv));
  839. WsbAffirmHr(pFilterPriv->Init((IFsaServer*) this));
  840. // Try to load the server from stored information. If this fails, then store out the current state.
  841. WsbAffirmHr(((IUnknown*) (IFsaServer*) this)->QueryInterface(IID_IWsbServer, (void**) &pWsbServer));
  842. WsbAffirmHr(WsbServiceSafeInitialize(pWsbServer, TRUE, FALSE, NULL));
  843. // Register the FSA Service.
  844. WsbAffirmHr(GetLogicalName(&tmpString, 0));
  845. WsbAffirmHr(HsmPublish(HSMCONN_TYPE_FSA, tmpString, m_id, m_name, CLSID_CFsaServerNTFS));
  846. // Update our information about the available resources, and save it out.
  847. WsbAffirmHr(ScanForResources());
  848. // Save updated information
  849. hr = SaveAll();
  850. // S_FALSE just means that FSA is already saving...
  851. if ((S_OK != hr) && (S_FALSE != hr)) {
  852. WsbAffirmHr(hr);
  853. }
  854. // Check if recovery is needed
  855. WsbAffirmHr(DoRecovery());
  856. // If the filter is enabled, then start it.
  857. if (m_pFilter->IsEnabled() == S_OK) {
  858. WsbAffirmHr(m_pFilter->Start());
  859. }
  860. // Create termination event for auto-backup thread
  861. WsbAffirmHandle((m_terminateEvent = CreateEvent(NULL, FALSE, FALSE, NULL)));
  862. // If the autosave interval is non-zero, start the autosave thread
  863. if (m_autosaveInterval) {
  864. ULONG interval = m_autosaveInterval;
  865. WsbAffirm(0 == m_autosaveThread, E_FAIL);
  866. m_autosaveInterval = 0;
  867. // Trick SetAutosave into starting the thread
  868. WsbAffirmHr(SetAutosave(interval));
  869. }
  870. } WsbCatch(hr);
  871. WsbTraceOut(OLESTR("CFsaServer::Init"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  872. return(hr);
  873. }
  874. HRESULT
  875. CFsaServer::IsUpdatingAccessDates(
  876. void
  877. )
  878. /*++
  879. Implements:
  880. IFsaServer::IsUpdatingAccessDates().
  881. --*/
  882. {
  883. HRESULT hr = S_OK;
  884. DWORD value = 0;
  885. // See if the appropriate registry entry has been created and has the
  886. // specified value of 1. This disables access time updating.
  887. if ((WsbGetRegistryValueDWORD(NULL, OLESTR("SYSTEM\\CurrentControlSet\\Control\\FileSystem"), OLESTR("NtfsDisableLastAccessUpdate"), &value) == S_OK) &&
  888. (0 != value)) {
  889. hr = S_FALSE;
  890. }
  891. return(hr);
  892. }
  893. HRESULT
  894. CFsaServer::Load(
  895. IN IStream* pStream
  896. )
  897. /*++
  898. Implements:
  899. IPersistStream::Load().
  900. --*/
  901. {
  902. HRESULT hr = S_OK;
  903. CComPtr<IPersistStream> pPersistStream;
  904. WsbTraceIn(OLESTR("CFsaServer::Load"), OLESTR(""));
  905. try {
  906. WsbAssert(0 != pStream, E_POINTER);
  907. // Do the easy stuff, but make sure that this order matches the order
  908. // in the save method.
  909. //
  910. // Make sure this is the right version of the database to load
  911. //
  912. ULONG tmpDatabaseVersion;
  913. WsbAffirmHr(WsbLoadFromStream(pStream, &tmpDatabaseVersion));
  914. if (tmpDatabaseVersion != m_databaseVersion) {
  915. //
  916. // The database version this server is expecting does not
  917. // match that of the saved database - so error out.
  918. WsbLogEvent( FSA_MESSAGE_DATABASE_VERSION_MISMATCH, 0, NULL, WsbQuickString(WsbPtrToUlongAsString(&m_databaseVersion)),
  919. WsbQuickString(WsbPtrToUlongAsString(&tmpDatabaseVersion)), NULL );
  920. WsbThrow(FSA_E_DATABASE_VERSION_MISMATCH);
  921. }
  922. //
  923. // Now read in the build version but don't do anything with it. It is in the
  924. // databases for dump programs to display
  925. //
  926. ULONG tmpBuildVersion;
  927. WsbAffirmHr(WsbLoadFromStream(pStream, &tmpBuildVersion));
  928. WsbAffirmHr(WsbLoadFromStream(pStream, &m_id));
  929. WsbAffirmHr(WsbLoadFromStream(pStream, &m_name, 0));
  930. WsbAffirmHr(WsbLoadFromStream(pStream, &m_autosaveInterval));
  931. // Load the resource collection.
  932. WsbAffirmPointer(m_pResources);
  933. WsbAffirmHr(m_pResources->QueryInterface(IID_IPersistStream, (void**) &pPersistStream));
  934. WsbAffirmHr(pPersistStream->Load(pStream));
  935. pPersistStream = 0;
  936. // Load the filter.
  937. WsbAffirmHr(m_pFilter->QueryInterface(IID_IPersistStream, (void**) &pPersistStream));
  938. WsbAffirmHr(pPersistStream->Load(pStream));
  939. pPersistStream = 0;
  940. } WsbCatch(hr);
  941. WsbTraceOut(OLESTR("CFsaServer::Load"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  942. return(hr);
  943. }
  944. HRESULT
  945. CFsaServer::Save(
  946. IN IStream* pStream,
  947. IN BOOL clearDirty
  948. )
  949. /*++
  950. Implements:
  951. IPersistStream::Save().
  952. --*/
  953. {
  954. HRESULT hr = S_OK;
  955. CComPtr<IPersistStream> pPersistStream;
  956. WsbTraceIn(OLESTR("CFsaServer::Save"), OLESTR("clearDirty = <%ls>"), WsbBoolAsString(clearDirty));
  957. try {
  958. WsbAssert(0 != pStream, E_POINTER);
  959. // Do the easy stuff, but make sure that this order matches the order
  960. // in the load method.
  961. WsbAffirmHr(WsbSaveToStream(pStream, m_databaseVersion));
  962. WsbAffirmHr(WsbSaveToStream(pStream, m_buildVersion));
  963. WsbAffirmHr(WsbSaveToStream(pStream, m_id));
  964. WsbAffirmHr(WsbSaveToStream(pStream, m_name));
  965. WsbAffirmHr(WsbSaveToStream(pStream, m_autosaveInterval));
  966. // Save off the resource collections.
  967. WsbAffirmPointer(m_pResources);
  968. WsbAffirmHr(m_pResources->QueryInterface(IID_IPersistStream, (void**) &pPersistStream));
  969. WsbAffirmHr(pPersistStream->Save(pStream, clearDirty));
  970. pPersistStream = 0;
  971. // Save off the filter.
  972. WsbAffirmHr(m_pFilter->QueryInterface(IID_IPersistStream, (void**) &pPersistStream));
  973. WsbAffirmHr(pPersistStream->Save(pStream, clearDirty));
  974. pPersistStream = 0;
  975. // If we got it saved and we were asked to clear the dirty bit, then
  976. // do so now.
  977. if (clearDirty) {
  978. m_isDirty = FALSE;
  979. }
  980. } WsbCatch(hr);
  981. WsbTraceOut(OLESTR("CFsaServer::Save"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  982. return(hr);
  983. }
  984. HRESULT
  985. CFsaServer::SaveAll(
  986. void
  987. )
  988. /*++
  989. Implements:
  990. IwsbServer::SaveAll
  991. Return Value:
  992. S_OK - Success
  993. S_FALSE - Already saving
  994. Other - Error
  995. --*/
  996. {
  997. HRESULT hr = S_OK;
  998. static BOOL saving = FALSE;
  999. WsbTraceIn(OLESTR("CFsaServer::SaveAll"), OLESTR(""));
  1000. try {
  1001. DWORD status, errWait;
  1002. CComPtr<IPersistFile> pPersistFile;
  1003. WsbAffirm(!saving, S_FALSE);
  1004. // Synchronize saving of persistent data with snapshot signaling event
  1005. saving = TRUE;
  1006. status = WaitForSingleObject(m_savingEvent, EVENT_WAIT_TIMEOUT);
  1007. // Save anyway, then report if the Wait function returned an unexpected error
  1008. errWait = GetLastError();
  1009. // Note: Don't throw exception here because even if saving fails, we still need
  1010. // to set the saving event and reset the saving flag.
  1011. hr = (((IUnknown*) (IFsaServer*) this)->QueryInterface(IID_IPersistFile, (void**) &pPersistFile));
  1012. if (SUCCEEDED(hr)) {
  1013. hr = WsbSafeSave(pPersistFile);
  1014. }
  1015. // Check Wait status... Note that hr remains OK because the saving itself completed fine
  1016. switch (status) {
  1017. case WAIT_OBJECT_0:
  1018. // The expected case
  1019. if (! SetEvent(m_savingEvent)) {
  1020. // Don't abort, just trace error
  1021. WsbTraceAlways(OLESTR("CFsaServer::SaveAll: SetEvent returned unexpected error %lu\n"), GetLastError());
  1022. }
  1023. break;
  1024. case WAIT_TIMEOUT:
  1025. // TEMPORARY: Should we log somethig here? This might happen if snapshot process
  1026. // takes too long for some reason, but logging seems to just confuse the user
  1027. // and he really can not (and should not) do anything...
  1028. WsbTraceAlways(OLESTR("CFsaServer::SaveAll: Wait for Single Object timed out after %lu ms\n"), EVENT_WAIT_TIMEOUT);
  1029. break;
  1030. case WAIT_FAILED:
  1031. WsbTraceAlways(OLESTR("CFsaServer::SaveAll: Wait for Single Object returned error %lu\n"), errWait);
  1032. break;
  1033. default:
  1034. WsbTraceAlways(OLESTR("CFsaServer::SaveAll: Wait for Single Object returned unexpected status %lu\n"), status);
  1035. break;
  1036. }
  1037. saving = FALSE;
  1038. } WsbCatch(hr);
  1039. WsbTraceOut(OLESTR("CFsaServer::SaveAll"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1040. return(hr);
  1041. }
  1042. HRESULT
  1043. CFsaServer::ScanForResources(
  1044. void
  1045. )
  1046. /*++
  1047. Implements:
  1048. IFsaServer::ScanForResources().
  1049. Routine Description:
  1050. This routine implements the COM method for creating (on the first call) or
  1051. updating (on all subsequent calls) the persisted ('master') collection of
  1052. resources (i.e., drives/volumes) which are MANAGEABLE by this HSM system.
  1053. The method contains 3 phases (sections). The first phase creates a 'working'
  1054. resource collection, which it then populates with all manageable resources it
  1055. finds after scanning all resources on this computer. (Only NTFS-formatted
  1056. volumes which support sparse files and reparse points are considered to be
  1057. manageable by Sakkara.) The second phase then correlates, or 'synchronizes',
  1058. the contents of the 'working' collection with those of the 'master' collection.
  1059. This synchronization consists of adding to the 'master' collection any resources
  1060. contained in the 'working' collection which are not in the 'master' collection,
  1061. and updating any resources already in the master collection from the resources
  1062. in the working collection. The third phase 'synchronizes' (compares) the contents
  1063. of the master collection to those in the working collection. Any resources in
  1064. the master collection which are not in the working collection are marked as 'not
  1065. available' so those resources do not appear in any list of manageable
  1066. resources presented to the user.
  1067. NOTE that the method does not end by explicitly releasing the working resource
  1068. collection. This is because the interface pointer to the working collection is
  1069. contained within a smart pointer, which automatically calls Release() on itself
  1070. when it goes out of scope. The working collection derives from the
  1071. CWsbIndexedCollection class, which contains a Critical Section. This section is
  1072. destroyed on a Release() call, so subsequent calls to Release() would fail
  1073. (normally with an Access Violation in NTDLL.dll) due to the non-existence of the
  1074. Critical Section. For this reason the working collection is allowed to auto-
  1075. garbage collect itself when it goes out of scope at method end (which also
  1076. releases all the resources contained in the working collection).
  1077. Arguments:
  1078. none.
  1079. Return Value:
  1080. S_OK - The call succeeded (the persisted collection of manageable resources on
  1081. this computer was either created or updated).
  1082. E_FAIL - The call to get the logical names of all drives (resources) on this
  1083. computer failed.
  1084. E_UNEXPECTED - Thrown if the total number of either working collection or master
  1085. collection resources were not processed during the synchronization phases.
  1086. Any other value - The call failed because one of the Remote Storage API calls
  1087. contained internally in this method failed. The error value returned is
  1088. specific to the API call which failed.
  1089. --*/
  1090. {
  1091. HRESULT hr = S_OK;
  1092. HRESULT searchHr = E_FAIL;
  1093. CComPtr<IWsbCollection> pWorkingResourceCollection;
  1094. CComPtr<IWsbEnum> pEnum;
  1095. CComPtr<IFsaResource> pScannedResource;
  1096. CComPtr<IFsaResourcePriv> pScannedResourcePriv;
  1097. CComPtr<IFsaResource> pWorkingResource;
  1098. CComPtr<IFsaResource> pMasterResource;
  1099. CComPtr<IFsaResourcePriv> pMasterResourcePriv;
  1100. GUID id = GUID_NULL;
  1101. DWORD i = 0;
  1102. DWORD j = 0;
  1103. ULONG nbrResources = 0;
  1104. ULONG nbrResourcesSynced = 0;
  1105. ULONG nbrResourcesUpdated = 0;
  1106. ULONG nbrResourcesAdded = 0;
  1107. CWsbStringPtr tmpString;
  1108. // The below variables are used in support of the code which scans all resources known
  1109. // by this computer in building the working collection of manageable resources (the
  1110. // code contained in Phase 1 below). The code is written to discover ALL resources,
  1111. // including those mounted without drive letters.
  1112. BOOL b;
  1113. PWSTR dosName; // Pointer to a null-terminated Unicode
  1114. // character string.
  1115. HANDLE hVol;
  1116. WCHAR volName[2*MAX_PATH];
  1117. WCHAR driveName[10];
  1118. WCHAR driveNameWOBack[10];
  1119. WCHAR driveLetter;
  1120. WCHAR otherName[MAX_PATH];
  1121. WsbTraceIn(OLESTR("CFsaServer::ScanForResources"), OLESTR(""));
  1122. try {
  1123. WsbAffirmPointer(m_pResources);
  1124. //
  1125. // First phase: Scan all resources, load manageable ones in a 'working' collection.
  1126. //
  1127. // Create the 'working' resource collection (with no items).
  1128. // This is where the results of this scan will be stored.
  1129. WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, NULL,
  1130. CLSCTX_SERVER, IID_IWsbCollection,
  1131. (void**) &pWorkingResourceCollection));
  1132. // Begin code added to use new API's which discover all volumes, including those
  1133. // mounted without drive letters (new feature to NT5) - added by Mike Lotz
  1134. driveName[1] = ':';
  1135. driveName[2] = '\\';
  1136. driveName[3] = 0;
  1137. // drive name without back slash
  1138. driveNameWOBack[1] = ':';
  1139. driveNameWOBack[2] = 0;
  1140. // Find the first volume on this computer. Call returns the long, ugly PNP name.
  1141. hVol = FindFirstVolume( volName, MAX_PATH );
  1142. if ( INVALID_HANDLE_VALUE != hVol ) {
  1143. do {
  1144. // Release the current interface pointers that will be reused in this loop.
  1145. // This drops the ref count to 0, releasing memory, object (if it was not
  1146. // added to the collection), and the interface pointer itself, but not the
  1147. // smart pointer instance.
  1148. //
  1149. // Do first so we gaurantee cleanup before reuse
  1150. //
  1151. pScannedResource = 0;
  1152. pScannedResourcePriv = 0;
  1153. // The long, ugly PNP name.
  1154. tmpString = volName;
  1155. // Initialize
  1156. dosName = NULL;
  1157. WsbTrace(OLESTR("CFsaServer::ScanForResources - Searching for %ws\n"),
  1158. tmpString);
  1159. // Loop through this computer's volumes/resources until we find the one
  1160. // that 'FindFirstVolume' or 'FindNextVolume' returned to us. (Note they
  1161. // are not returned in drive letter order, but in PNP name order.) We do
  1162. // this since we need the drive letter for the resource (if there is one),
  1163. // and currently neither of the above calls returns it.
  1164. for (driveLetter = L'C'; driveLetter <= L'Z'; driveLetter++) {
  1165. driveName[0] = driveLetter;
  1166. driveNameWOBack[0] = driveLetter;
  1167. b = GetVolumeNameForVolumeMountPoint(driveName, otherName,
  1168. MAX_PATH);
  1169. // If unable to get a volume name for the mount point (if 'driveLetter'
  1170. // volume doesn't exist) jump back to the 'top' of the for loop.
  1171. if (!b) {
  1172. continue;
  1173. }
  1174. WsbTrace(OLESTR("CFsaServer::ScanForResources - for drive letter %ws "
  1175. L"volume name is %ws\n"),
  1176. driveName, otherName);
  1177. // if 'tmpString' (the long, ugly PNP volume name returned by the
  1178. // 'Find[First/Next]Volume' call) and 'otherName' (also the PNP
  1179. // volume name, but is returned by the 'GetVolumeNameFor...
  1180. // VolumeMountPoint call) ARE equal (lstrcmpi returns 0 if the 2
  1181. // strings it compares are equal), set 'dosName' and break out of
  1182. // the for loop, continuing thru the do-while.
  1183. if (!lstrcmpi(tmpString, otherName)) {
  1184. dosName = driveNameWOBack;
  1185. break;
  1186. }
  1187. } // end for loop
  1188. if (NULL != dosName) {
  1189. WsbTrace(OLESTR("CFsaServer::ScanForResources - DOS name is %ws "
  1190. L"Volume name to use is %ws\n"),
  1191. dosName, (WCHAR *)tmpString);
  1192. } else {
  1193. WsbTrace(OLESTR("CFsaServer::ScanForResources - No DOS name, "
  1194. L"Volume name to use is %ws\n"),
  1195. (WCHAR *)tmpString);
  1196. // Find if the volume is mounted in a mount point other than drive letter
  1197. HRESULT hrMount = WsbGetFirstMountPoint(tmpString, otherName, MAX_PATH);
  1198. if (S_OK == hrMount) {
  1199. if (wcslen(otherName) > 1) {
  1200. // Remove trailing backslash
  1201. dosName = otherName;
  1202. dosName[wcslen(otherName)-1] = 0;
  1203. WsbTrace(OLESTR("CFsaServer::ScanForResources - Mount path is %ws\n"),
  1204. dosName);
  1205. }
  1206. } else {
  1207. WsbTrace(OLESTR("CFsaServer::ScanForResources - no Mount path found, hr = <%ls>\n"),
  1208. WsbHrAsString(hrMount));
  1209. }
  1210. }
  1211. // end of code added to support volumes without drive letters.
  1212. WsbTrace(OLESTR("CFsaServer::ScanForResources - Checking resource %ls "
  1213. L"for manageability\n"),
  1214. (WCHAR *) tmpString);
  1215. // Create Resource instance to be used to test volume manageability. Get
  1216. // 'private' (non-exposed) interface since test method (Init()) is there.
  1217. WsbAffirmHr(CoCreateInstance(CLSID_CFsaResourceNTFS, NULL,
  1218. CLSCTX_SERVER, IID_IFsaResourcePriv,
  1219. (void**) &pScannedResourcePriv));
  1220. try {
  1221. // Test volume for manageability. If so, get and store volume info,
  1222. // assign a Guid to the volume (if not already done), and create and/or
  1223. // locate the Premigrated DB.
  1224. WsbAffirmHr(pScannedResourcePriv->Init((IFsaServer*) this, tmpString,
  1225. dosName));
  1226. // We have a manageable volume (resource). Get 'public' interface for
  1227. // the resource since this is what is stored in the collection.
  1228. WsbAffirmHr(pScannedResourcePriv->QueryInterface(IID_IFsaResource,
  1229. (void**) &pScannedResource));
  1230. // Add the manageable resource to the 'working' collection.
  1231. WsbAffirmHr( pWorkingResourceCollection->Add( pScannedResource ) );
  1232. WsbAffirmHr(pScannedResource->GetIdentifier( &id ) );
  1233. WsbTrace
  1234. (OLESTR("CFsaServer::ScanForResources - Added <%ls> to working list "
  1235. L"(id = %ls)\n"),
  1236. (WCHAR *) tmpString, WsbGuidAsString(id));
  1237. // Test if Init() call above failed. If so, skip this volume, go on to next.
  1238. } WsbCatchAndDo(hr, if ((FSA_E_UNMANAGABLE == hr) ||
  1239. (FSA_E_NOMEDIALOADED == hr)) {hr = S_OK;}
  1240. else {
  1241. if (NULL != dosName) {
  1242. WsbLogEvent(FSA_MESSAGE_BAD_VOLUME, 0, NULL,
  1243. (WCHAR *) dosName, WsbHrAsString(hr), 0);
  1244. } else {
  1245. WsbLogEvent(FSA_MESSAGE_BAD_VOLUME, 0, NULL,
  1246. (WCHAR *) tmpString, WsbHrAsString(hr), 0);
  1247. }
  1248. //
  1249. // Do not fail just because one volume got an error
  1250. hr = S_OK;
  1251. });
  1252. // end do-while; process next resource on this computer
  1253. } while ( FindNextVolume( hVol, volName, MAX_PATH ) );
  1254. // close the handle
  1255. FindVolumeClose( hVol );
  1256. } // if INVALID_HANDLE_VALUE != hVol
  1257. // If first phase didn't complete Ok abort this method (with Trace & Logging).
  1258. WsbAssertHrOk( hr );
  1259. //
  1260. // Second phase: Correlate/synchronize resources in 'working' collection with
  1261. // those in the 'master' (persisted) collection.
  1262. //
  1263. // Get number of resources stored in the working collection.
  1264. WsbAffirmHr( pWorkingResourceCollection->GetEntries( &nbrResources ) );
  1265. // Get iterator to working collection.
  1266. WsbAffirmHr( pWorkingResourceCollection->Enum( &pEnum ) );
  1267. // For each resource in the 'working' collection, search the 'master' collection
  1268. // to see if the resource is listed. If so, update the master resource's state
  1269. // from the working resource. If not, add it.
  1270. for ( hr = pEnum->First( IID_IFsaResource, (void**) &pWorkingResource );
  1271. SUCCEEDED( hr );
  1272. hr = pEnum->Next( IID_IFsaResource, (void**) &pWorkingResource ) ) {
  1273. // Release reused interface pointers for next loop iteration.
  1274. // Do first to gaurantee clean pointer before use
  1275. pMasterResource = 0;
  1276. pMasterResourcePriv = 0;
  1277. // Search for this resource in master collection. (There is no need to
  1278. // set the 'working' resource's 'compare by' field since it is constructed
  1279. // with the 'compare by id' value and we haven't changed it.)
  1280. searchHr = m_pResources->Find( pWorkingResource, IID_IFsaResource,
  1281. (void**) &pMasterResource );
  1282. try {
  1283. if ( SUCCEEDED( searchHr ) ) {
  1284. // A matching resource entry has been found in the master
  1285. // collection, so update it.
  1286. // Get the 'private' interface to the master resource & update it
  1287. // from the working resource.
  1288. WsbAffirmHr(pMasterResource->QueryInterface( IID_IFsaResourcePriv,
  1289. (void**) &pMasterResourcePriv ) );
  1290. WsbAffirmHr(pMasterResourcePriv->UpdateFrom( (IFsaServer*) this,
  1291. pWorkingResource ) );
  1292. /*/ *** TEMP TRACE - remove from normal code path for efficiency.
  1293. CWsbStringPtr workingRsc;
  1294. CWsbStringPtr masterRsc;
  1295. GUID workingRscId = GUID_NULL;
  1296. // First get the path (root of volume) & id of the 'working' resource.
  1297. WsbAffirmHr(pWorkingResource->GetPath( &workingRsc, 0 ) );
  1298. WsbAffirmHr(pWorkingResource->GetIdentifier( &workingRscId ) );
  1299. // then that of the 'master' resource.
  1300. WsbAffirmHr(pMasterResource->GetPath( &masterRsc, 0 ) );
  1301. WsbTrace(OLESTR("CFsaServer::ScanForResources - "
  1302. L"Master resource <%ls> updated from working resource <%ls>"
  1303. L" (id = <%ls>).\n"),
  1304. (OLECHAR*)masterRsc, (OLECHAR*)workingRsc,
  1305. WsbGuidAsString( workingRscId ) );
  1306. // *** End TEMP TRACE */
  1307. nbrResourcesUpdated += 1;
  1308. }
  1309. else if ( WSB_E_NOTFOUND == searchHr ) {
  1310. // No matching entry found in the master collection, add it, indicate
  1311. // synchronization success.
  1312. WsbAffirmHr( m_pResources->Add( pWorkingResource ) );
  1313. /*/ *** TEMP TRACE - remove from normal code path for efficiency.
  1314. CWsbStringPtr workingRsc;
  1315. GUID workingRscId = GUID_NULL;
  1316. // Get the path (root of volume) and id of the 'working' resource.
  1317. WsbAffirmHr(pWorkingResource->GetPath( &workingRsc, 0 ) );
  1318. WsbAffirmHr(pWorkingResource->GetIdentifier( &workingRscId ) );
  1319. WsbTrace(OLESTR("CFsaServer::ScanForResources - "
  1320. L"Working resource <%ls> added to master collection "
  1321. L"(id = <%ls>.\n"),
  1322. workingRsc, WsbGuidAsString( workingRscId ) );
  1323. // *** End TEMP TRACE */
  1324. nbrResourcesAdded += 1;
  1325. searchHr = S_OK;
  1326. }
  1327. // Trap any unexpected search failure: Trace, Log, Throw; skip to next rsc.
  1328. WsbAssertHrOk( searchHr );
  1329. // This volume has been synchronized in the master collection, register
  1330. // or update the FSA Resource in Directory Services as necessary.
  1331. WsbAffirmHr(pWorkingResource->GetLogicalName(&tmpString, 0));
  1332. WsbAffirmHr(HsmPublish(HSMCONN_TYPE_RESOURCE, tmpString, id, 0, m_id));
  1333. } WsbCatch( hr );
  1334. // Done with this Resource. Increment count of resources synchronized and
  1335. // release interface pointer for next iteration.
  1336. nbrResourcesSynced += 1;
  1337. pWorkingResource = 0;
  1338. } // end 'for'
  1339. // Ensure all resources in working collection were processed. If not,
  1340. // Trace, Log and Throw and abort the method.
  1341. WsbAssert( nbrResources == nbrResourcesSynced, E_UNEXPECTED );
  1342. // Ensure we are at the end of the working collection. If not, abort.
  1343. WsbAssert( WSB_E_NOTFOUND == hr, hr );
  1344. hr = S_OK;
  1345. WsbTrace(OLESTR("CFsaServer::ScanForResources - "
  1346. L"2nd phase (1st search): Total working resources %lu. "
  1347. L"Resources updated %lu, resources added %lu.\n"),
  1348. nbrResources, nbrResourcesUpdated, nbrResourcesAdded);
  1349. //
  1350. // Third phase: Correlate/synchronize resources in 'master' collection with
  1351. // those in the 'working' collection.
  1352. //
  1353. // Reset counters for next for loop
  1354. nbrResourcesSynced = 0;
  1355. nbrResourcesUpdated = 0;
  1356. // Get number of volumes stored in the 'master' Resource collection.
  1357. WsbAffirmHr( m_pResources->GetEntries( &nbrResources ) );
  1358. // Release the collection enumerator since we are about to reuse it.
  1359. pEnum = 0;
  1360. // Get an iterator to the 'master' collection
  1361. WsbAffirmHr( m_pResources->Enum( &pEnum ) );
  1362. /*/ *** TEMP TRACE - remove from normal code path for efficiency.
  1363. CWsbStringPtr masterResource;
  1364. GUID masterResourceId = GUID_NULL;
  1365. // *** End TEMP TRACE */
  1366. // For each volume in the 'master' collection, search the 'working' collection
  1367. // to see if the resource is listed. If so, skip to the next resource. If not
  1368. // (this indicates this resource is no longer manageable), mark it as not available
  1369. // in the 'master' collection's resource, which prevents the resource from
  1370. // being displayed whenever the list of manageable resources is presented.
  1371. pMasterResource = 0;
  1372. for ( hr = pEnum->First( IID_IFsaResource, (void**) &pMasterResource );
  1373. SUCCEEDED( hr );
  1374. pMasterResource = 0, hr = pEnum->Next( IID_IFsaResource, (void**) &pMasterResource ) ) {
  1375. pMasterResourcePriv = 0;
  1376. pWorkingResource = 0;
  1377. // Set the search key, then search for this resource in working collection.
  1378. // (Even though resource objects are constructed with their 'compare by' field
  1379. // set to 'compare by id', reset it here in case it has changed.)
  1380. WsbAffirmHr( pMasterResource->CompareBy( FSA_RESOURCE_COMPARE_ID ) );
  1381. searchHr = pWorkingResourceCollection->Find( pMasterResource, IID_IFsaResource,
  1382. (void**) &pWorkingResource );
  1383. try {
  1384. if ( WSB_E_NOTFOUND == searchHr ) {
  1385. // No matching entry found in the 'working' collection, so this
  1386. // resource is no longer manageable. Mark it as not-available.
  1387. /*/ *** TEMP TRACE - remove from normal code path for efficiency.
  1388. CWsbStringPtr masterRsc;
  1389. GUID masterRscId = GUID_NULL;
  1390. // Get the path (root of volume) and GUID of the 'master' resource
  1391. // before it is nulled.
  1392. WsbAffirmHr(pMasterResource->GetPath( &masterRsc, 0 ) );
  1393. WsbAffirmHr(pMasterResource->GetIdentifier( &masterRscId ) );
  1394. // *** End TEMP TRACE */
  1395. //
  1396. // Make it not available and null out the path, sticky name, and user friendly name so
  1397. // it is not confused with another resource with the same name.
  1398. //
  1399. WsbAffirmHr(pMasterResource->QueryInterface( IID_IFsaResourcePriv,
  1400. (void**) &pMasterResourcePriv ) );
  1401. WsbAffirmHr(pMasterResource->SetIsAvailable(FALSE));
  1402. WsbAffirmHr(pMasterResourcePriv->SetPath(OLESTR("")));
  1403. WsbAffirmHr(pMasterResourcePriv->SetStickyName(OLESTR("")));
  1404. WsbAffirmHr(pMasterResourcePriv->SetUserFriendlyName(OLESTR("")));
  1405. // Indicate synchronization success (for Assert below)
  1406. searchHr = S_OK;
  1407. /*/ *** TEMP TRACE - remove from normal code path for efficiency.
  1408. WsbTrace(OLESTR("CFsaServer::ScanForResources - "
  1409. L"Master resource <%ls> (path = <%ls>) was marked unavailable.\n"),
  1410. WsbGuidAsString( masterRscId ), masterRsc );
  1411. // *** End TEMP TRACE */
  1412. nbrResourcesUpdated += 1;
  1413. }
  1414. // Trap any unexpected search failure: Trace, Log, Throw; skip to next rsc.
  1415. WsbAssertHrOk( searchHr );
  1416. } WsbCatch( hr );
  1417. // Done with this Resource. Increment count of resources synchronized and
  1418. // release interface pointer for next iteration.
  1419. nbrResourcesSynced += 1;
  1420. /*/ *** TEMP TRACE - remove from normal code path for efficiency.
  1421. // Get the path of the 'master' resource.
  1422. WsbAffirmHr(pMasterResource->GetPath( &masterResource, 0 ) );
  1423. WsbAffirmHr(pMasterResource->GetIdentifier( &masterResourceId ) );
  1424. WsbTrace(OLESTR("CFsaServer::ScanForResources - "
  1425. L"Processed Master resource <%ls> (path = <%ls>), "
  1426. L"moving on to next Master...\n"),
  1427. WsbGuidAsString( masterResourceId ), masterResource );
  1428. // *** End TEMP TRACE */
  1429. pMasterResource = 0;
  1430. } // end 'for'
  1431. // Ensure all resources in master collection were processed. If not,
  1432. // Trace, Log and Throw and abort the method.
  1433. WsbAssert( nbrResources == nbrResourcesSynced, E_UNEXPECTED );
  1434. // Ensure we are at the end of the master collection. If not, abort.
  1435. WsbAssert( WSB_E_NOTFOUND == hr, hr );
  1436. hr = S_OK;
  1437. WsbTrace(OLESTR("CFsaServer::ScanForResources - "
  1438. L"3rd phase (2nd search): Total master resources %lu. "
  1439. L"Resources marked as not available: %lu.\n"),
  1440. nbrResources, nbrResourcesUpdated );
  1441. } WsbCatch( hr );
  1442. // Scan done. Again, DO NOT explicitly release the 'working' collection due to
  1443. // the reasons listed in the final paragraph under "Routine Description" above.
  1444. // Both the working resource collection, and all the resources it contains, will
  1445. // be released implicitly at method end.
  1446. WsbTraceOut(OLESTR("CFsaServer::ScanForResources"), OLESTR("hr = <%ls>"),
  1447. WsbHrAsString(hr));
  1448. return( hr );
  1449. }
  1450. HRESULT
  1451. CFsaServer::SetAutosave(
  1452. IN ULONG milliseconds
  1453. )
  1454. /*++
  1455. Implements:
  1456. IFsaServer::SetAutosave().
  1457. --*/
  1458. {
  1459. HRESULT hr = S_OK;
  1460. WsbTraceIn(OLESTR("CFsaServer::SetAutosave"), OLESTR("milliseconds = <%ls>"), WsbPtrToUlongAsString( &milliseconds ) );
  1461. try {
  1462. // Don't do anything if interval isn't changing
  1463. if (milliseconds != m_autosaveInterval) {
  1464. // Close the current thread
  1465. if (m_autosaveThread) {
  1466. StopAutosaveThread();
  1467. }
  1468. m_autosaveInterval = milliseconds;
  1469. // Start/restart the autosave thread
  1470. if (m_autosaveInterval) {
  1471. DWORD threadId;
  1472. WsbAffirm((m_autosaveThread = CreateThread(0, 0, FsaStartAutosave, (void*) this, 0, &threadId)) != 0, HRESULT_FROM_WIN32(GetLastError()));
  1473. }
  1474. }
  1475. } WsbCatch(hr);
  1476. WsbTraceOut(OLESTR("CFsaServer::SetAutosave"), OLESTR("hr = <%ls> m_runInterval = <%ls>"), WsbHrAsString(hr), WsbPtrToUlongAsString( &m_autosaveInterval ) );
  1477. return(hr);
  1478. }
  1479. HRESULT CFsaServer::SetId(
  1480. GUID id
  1481. )
  1482. /*++
  1483. Implements:
  1484. IWsbServer::SetId().
  1485. --*/
  1486. {
  1487. HRESULT hr = S_OK;
  1488. WsbTraceIn(OLESTR("CFsaServer::SetId"), OLESTR("id = <%ls>"), WsbGuidAsString( id ) );
  1489. m_id = id;
  1490. WsbTraceOut(OLESTR("CFsaServer::SetId"), OLESTR("hr = <%ls>"), WsbHrAsString( hr ) );
  1491. return( hr );
  1492. }
  1493. HRESULT
  1494. CFsaServer::SetIsUpdatingAccessDates(
  1495. BOOL isUpdating
  1496. )
  1497. /*++
  1498. Implements:
  1499. IFsaServer::IsUpdatingAccessDates().
  1500. --*/
  1501. {
  1502. HRESULT hr = S_OK;
  1503. try {
  1504. // Removing the key allows for updating access times, and setting it
  1505. // to 1 causes updating to be stopped.
  1506. if (isUpdating) {
  1507. WsbAffirmHr(WsbRemoveRegistryValue(NULL, OLESTR("SYSTEM\\CurrentControlSet\\Control\\FileSystem"), OLESTR("NtfsDisableLastAccessUpdate")));
  1508. } else {
  1509. WsbAffirmHr(WsbSetRegistryValueDWORD(NULL, OLESTR("SYSTEM\\CurrentControlSet\\Control\\FileSystem"), OLESTR("NtfsDisableLastAccessUpdate"), 1));
  1510. }
  1511. } WsbCatch(hr);
  1512. return(hr);
  1513. }
  1514. HRESULT
  1515. CFsaServer::ChangeSysState(
  1516. IN OUT HSM_SYSTEM_STATE* pSysState
  1517. )
  1518. /*++
  1519. Implements:
  1520. IHsmSystemState::ChangeSysState().
  1521. --*/
  1522. {
  1523. HRESULT hr = S_OK;
  1524. WsbTraceIn(OLESTR("CFsaServer::ChangeSysState"), OLESTR(""));
  1525. try {
  1526. if (pSysState->State & HSM_STATE_SUSPEND) {
  1527. if (!m_Suspended) {
  1528. m_Suspended = TRUE;
  1529. // Save data
  1530. SaveAll();
  1531. }
  1532. } else if (pSysState->State & HSM_STATE_RESUME) {
  1533. m_Suspended = FALSE;
  1534. } else if (pSysState->State & HSM_STATE_SHUTDOWN) {
  1535. // Close the autosave thread
  1536. StopAutosaveThread();
  1537. if (m_pFilter != NULL) {
  1538. //
  1539. // Kill the filter thread and cancel the IOCTLS pending in the kernel filter
  1540. //
  1541. m_pFilter->StopIoctlThread();
  1542. }
  1543. }
  1544. // Notify resources
  1545. if (m_pResources) {
  1546. //
  1547. // Scan through the resources and notify
  1548. //
  1549. CComPtr<IWsbEnum> pEnum;
  1550. CComPtr<IFsaResourcePriv> pResourcePriv;
  1551. WsbAffirmHr(m_pResources->Enum(&pEnum));
  1552. hr = pEnum->First(IID_IFsaResourcePriv, (void**)&pResourcePriv);
  1553. while (S_OK == hr) {
  1554. hr = pResourcePriv->ChangeSysState(pSysState);
  1555. pResourcePriv = 0;
  1556. hr = pEnum->Next(IID_IFsaResourcePriv, (void**)&pResourcePriv);
  1557. }
  1558. if (WSB_E_NOTFOUND == hr) {
  1559. hr = S_OK;
  1560. }
  1561. }
  1562. if (pSysState->State & HSM_STATE_SHUTDOWN) {
  1563. // Dump object table info
  1564. WSB_OBJECT_TRACE_TYPES;
  1565. WSB_OBJECT_TRACE_POINTERS(WSB_OTP_STATISTICS | WSB_OTP_ALL);
  1566. }
  1567. } WsbCatch(hr);
  1568. WsbTraceOut(OLESTR("CFsaServer::ChangeSysState"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1569. return(hr);
  1570. }
  1571. HRESULT
  1572. CFsaServer::Unload(
  1573. void
  1574. )
  1575. /*++
  1576. Implements:
  1577. IwsbServer::Unload
  1578. Return Value:
  1579. S_OK - Success
  1580. Other - Error
  1581. --*/
  1582. {
  1583. HRESULT hr = S_OK;
  1584. WsbTraceIn(OLESTR("CFsaServer::Unload"), OLESTR(""));
  1585. try {
  1586. // We only need to release what may have gotten set/created by
  1587. // a failed Load attempt.
  1588. if (m_pResources) {
  1589. WsbAffirmHr(m_pResources->RemoveAllAndRelease());
  1590. }
  1591. m_name.Free();
  1592. } WsbCatch(hr);
  1593. WsbTraceOut(OLESTR("CFsaServer::Unload"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1594. return(hr);
  1595. }
  1596. HRESULT
  1597. CFsaServer::DestroyObject(
  1598. void
  1599. )
  1600. /*++
  1601. Implements:
  1602. IWsbServer::DestroyObject
  1603. Return Value:
  1604. S_OK - Success
  1605. --*/
  1606. {
  1607. HRESULT hr = S_OK;
  1608. WsbTraceIn(OLESTR("CFsaServer::DestroyObject"), OLESTR(""));
  1609. CComObject<CFsaServer> *pFsaDelete = (CComObject<CFsaServer> *)this;
  1610. delete pFsaDelete;
  1611. WsbTraceOut(OLESTR("CFsaServer::DestroyObject"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1612. return(hr);
  1613. }
  1614. HRESULT
  1615. CFsaServer::GetNtProductVersion (
  1616. OLECHAR **pNtProductVersion,
  1617. ULONG bufferSize
  1618. )
  1619. /*++
  1620. Implements:
  1621. IWsbServer::GetNtProductVersion().
  1622. --*/
  1623. {
  1624. HRESULT hr = S_OK;
  1625. try {
  1626. CWsbStringPtr tmpString;
  1627. WsbAssert(0 != pNtProductVersion, E_POINTER);
  1628. tmpString = VER_PRODUCTVERSION_STRING;
  1629. WsbAffirmHr(tmpString.CopyTo(pNtProductVersion, bufferSize));
  1630. } WsbCatch( hr );
  1631. return (hr);
  1632. }
  1633. HRESULT
  1634. CFsaServer::GetNtProductBuild(
  1635. ULONG *pNtProductBuild
  1636. )
  1637. /*++
  1638. Implements:
  1639. IWsbServer::GetNtProductBuild().
  1640. --*/
  1641. {
  1642. HRESULT hr = S_OK;
  1643. WsbTraceIn(OLESTR("CFsaServer::GetNtProductBuild"), OLESTR(""));
  1644. *pNtProductBuild = VER_PRODUCTBUILD;
  1645. WsbTraceOut(OLESTR("CFsaServer::GetNtProductBuild"), OLESTR("hr = <%ls>, Version = <%ls)"),
  1646. WsbHrAsString(hr), WsbLongAsString(VER_PRODUCTBUILD));
  1647. return ( hr );
  1648. }
  1649. HRESULT
  1650. CFsaServer::CheckAccess(
  1651. WSB_ACCESS_TYPE AccessType
  1652. )
  1653. /*++
  1654. Implements:
  1655. IWsbServer::CheckAccess().
  1656. --*/
  1657. {
  1658. WsbTraceIn(OLESTR("CFsaServer::CheckAccess"), OLESTR(""));
  1659. HRESULT hr = S_OK;
  1660. try {
  1661. //
  1662. // Do the impersonation
  1663. //
  1664. WsbAffirmHr( CoImpersonateClient() );
  1665. hr = WsbCheckAccess( AccessType );
  1666. CoRevertToSelf();
  1667. } WsbCatchAndDo( hr,
  1668. //
  1669. // Handle case where there is no COM context to check against
  1670. // in which case we are the service so any security is allowed.
  1671. //
  1672. if( ( hr == RPC_E_NO_CONTEXT ) || ( hr != RPC_E_CALL_COMPLETE ) ) {
  1673. hr = S_OK;
  1674. }
  1675. );
  1676. WsbTraceOut(OLESTR("CFsaServer::CheckAccess"), OLESTR("hr = <%ls>"), WsbHrAsString( hr ) );
  1677. return( hr );
  1678. }
  1679. HRESULT
  1680. CFsaServer::GetTrace(
  1681. OUT IWsbTrace ** ppTrace
  1682. )
  1683. /*++
  1684. Implements:
  1685. IWsbServer::GetTrace().
  1686. --*/
  1687. {
  1688. WsbTraceIn(OLESTR("CFsaServer::GetTrace"), OLESTR("ppTrace = <0x%p>"), ppTrace);
  1689. HRESULT hr = S_OK;
  1690. try {
  1691. WsbAffirmPointer(ppTrace);
  1692. *ppTrace = 0;
  1693. WsbAffirmPointer(m_pTrace);
  1694. *ppTrace = m_pTrace;
  1695. (*ppTrace)->AddRef();
  1696. } WsbCatch(hr);
  1697. WsbTraceOut(OLESTR("CFsaServer::GetTrace"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1698. return(hr);
  1699. }
  1700. HRESULT
  1701. CFsaServer::SetTrace(
  1702. OUT IWsbTrace * pTrace
  1703. )
  1704. /*++
  1705. Implements:
  1706. IWsbServer::SetTrace().
  1707. --*/
  1708. {
  1709. WsbTraceIn(OLESTR("CFsaServer::SetTrace"), OLESTR("pTrace = <0x%p>"), pTrace);
  1710. HRESULT hr = S_OK;
  1711. try {
  1712. WsbAffirmPointer(pTrace);
  1713. m_pTrace = pTrace;
  1714. } WsbCatch(hr);
  1715. WsbTraceOut(OLESTR("CFsaServer::SetTrace"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1716. return(hr);
  1717. }
  1718. void
  1719. CFsaServer::StopAutosaveThread(
  1720. void
  1721. )
  1722. /*++
  1723. Routine Description:
  1724. Stop the Autosave thread:
  1725. First try gracefully, using the termination event
  1726. If doesn't work, just terminate the thread
  1727. Arguments:
  1728. None.
  1729. Return Value:
  1730. S_OK - Success.
  1731. --*/
  1732. {
  1733. HRESULT hr = S_OK;
  1734. WsbTraceIn(OLESTR("CFsaServer::StopAutosaveThread"), OLESTR(""));
  1735. try {
  1736. // Terminate the autosave thread
  1737. if (m_autosaveThread) {
  1738. // Signal thread to terminate
  1739. SetEvent(m_terminateEvent);
  1740. // Wait for the thread, if it doesn't terminate gracefully - kill it
  1741. switch (WaitForSingleObject(m_autosaveThread, 20000)) {
  1742. case WAIT_FAILED: {
  1743. WsbTrace(OLESTR("CFsaServer::StopAutosaveThread: WaitForSingleObject returned error %lu\n"), GetLastError());
  1744. }
  1745. // fall through...
  1746. case WAIT_TIMEOUT: {
  1747. WsbTrace(OLESTR("CFsaServer::StopAutosaveThread: force terminating of autosave thread.\n"));
  1748. DWORD dwExitCode;
  1749. if (GetExitCodeThread( m_autosaveThread, &dwExitCode)) {
  1750. if (dwExitCode == STILL_ACTIVE) { // thread still active
  1751. if (!TerminateThread (m_autosaveThread, 0)) {
  1752. WsbTrace(OLESTR("CFsaServer::StopAutosaveThread: TerminateThread returned error %lu\n"), GetLastError());
  1753. }
  1754. }
  1755. } else {
  1756. WsbTrace(OLESTR("CFsaServer::StopAutosaveThread: GetExitCodeThread returned error %lu\n"), GetLastError());
  1757. }
  1758. break;
  1759. }
  1760. default:
  1761. // Thread terminated gracefully
  1762. WsbTrace(OLESTR("CFsaServer::StopAutosaveThread: Autosave thread terminated gracefully\n"));
  1763. break;
  1764. }
  1765. // Best effort done for terminating auto-backup thread
  1766. CloseHandle(m_autosaveThread);
  1767. m_autosaveThread = 0;
  1768. }
  1769. } WsbCatch(hr);
  1770. WsbTraceOut(OLESTR("CFsaServer::StopAutosaveThread"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1771. }