Leaked source code of windows server 2003
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.

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