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.

3314 lines
77 KiB

  1. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. //
  3. // D A V C D A T A . C P P
  4. //
  5. // HTTP 1.1/DAV 1.0 request handling via ISAPI
  6. //
  7. // DAVCDATA is the dav process executable for storing handles that should
  8. // not be recycled when worker process recycle. It also contains the timing
  9. // code for timing out locks, and it establishes the shared memory for
  10. // the DAV worker processes.
  11. //
  12. // This process must run under the same identity as the worker processes.
  13. //
  14. // Copyright 2000 Microsoft Corporation, All Rights Reserved
  15. //
  16. /////////////////////////////////////////////////////////////////////////////
  17. #include "_davcdata.h"
  18. #include <caldbg.h>
  19. #include <crc.h>
  20. #include <davsc.h>
  21. #include <fhcache.h>
  22. #include <ex\autoptr.h>
  23. #include <ex\baselist.h>
  24. #include <ex\buffer.h>
  25. #include <ex\calcom.h>
  26. #include <ex\gencache.h>
  27. #include <ex\reg.h>
  28. #include <ex\synchro.h>
  29. #include <ex\sz.h>
  30. // Code borrowed from htpext mem.cpp so we have use of the global heap
  31. //
  32. #define g_szMemDll L"staxmem.dll"
  33. struct CHeap
  34. {
  35. static BOOL FInit();
  36. static void Deinit();
  37. static LPVOID Alloc( SIZE_T cb );
  38. static LPVOID Realloc( LPVOID lpv, SIZE_T cb );
  39. static VOID Free( LPVOID pv );
  40. };
  41. #include <memx.h>
  42. // Mapping the exdav non-throwing allocators to something local
  43. //
  44. LPVOID __fastcall ExAlloc( UINT cb ) { return g_heap.Alloc( cb ); }
  45. LPVOID __fastcall ExRealloc( LPVOID pv, UINT cb ) { return g_heap.Realloc( pv, cb ); }
  46. VOID __fastcall ExFree( LPVOID pv ) { g_heap.Free( pv ); }
  47. // GUIDs
  48. //
  49. const GUID CLSID_FileHandleCache = { 0xa93b88df, 0xef9d, 0x420c, { 0xb4, 0x69, 0xce, 0x07, 0x4e, 0xbe, 0x94, 0xbc}};
  50. const GUID IID_IFileHandleCache = { 0x3017e0e1, 0x94d6, 0x4896, { 0xbc, 0x57, 0xb2, 0xdf, 0x75, 0x92, 0xd1, 0x75 }};
  51. DEC_CONST WCHAR gc_wsz_RegServer[] = L"/RegServer";
  52. DEC_CONST INT gc_cch_RegServer = CchConstString(gc_wsz_RegServer);
  53. DEC_CONST WCHAR gc_wsz_UnregServer[] = L"/UnregServer";
  54. DEC_CONST INT gc_cch_UnregServer = CchConstString(gc_wsz_UnregServer);
  55. DEC_CONST WCHAR gc_wsz_Embedding[] = L"-Embedding";
  56. DEC_CONST INT gc_cch_Embedding = CchConstString(gc_wsz_Embedding);
  57. DEC_CONST WCHAR gc_wsz_CLSIDWW[] = L"CLSID\\";
  58. DEC_CONST INT gc_cch_CLSIDWW = CchConstString(gc_wsz_CLSIDWW);
  59. DEC_CONST WCHAR gc_wsz_AppIDWW[] = L"AppID\\";
  60. DEC_CONST INT gc_cch_AppIDWW = CchConstString(gc_wsz_AppIDWW);
  61. DEC_CONST WCHAR gc_wsz_AppID[] = L"AppID";
  62. DEC_CONST WCHAR gc_wsz_WebDAVFileHandleCache[] = L"Web DAV File Handle Cache";
  63. DEC_CONST INT gc_cch_WebDAVFileHandleCache = CchConstString(gc_wsz_WebDAVFileHandleCache);
  64. DEC_CONST WCHAR gc_wszLaunchPermission[] = L"LaunchPermission";
  65. DEC_CONST INT gc_cchLaunchPermission = CchConstString(gc_wszLaunchPermission);
  66. DEC_CONST WCHAR gc_wszIIS_WPG[] = L"IIS_WPG";
  67. DEC_CONST INT gc_cchIIS_WPG = CchConstString(gc_wszIIS_WPG);
  68. DEC_CONST WCHAR gc_wsz_WWLocalServer32[]= L"\\LocalServer32";
  69. DEC_CONST INT gc_cch_WWLocalServer32 = CchConstString(gc_wsz_WWLocalServer32);
  70. DEC_CONST WCHAR gc_wsz_IFileHandleCache[] = L"IFileHandleCache";
  71. DEC_CONST INT gc_cch_IFileHandleCache = CchConstString(gc_wsz_IFileHandleCache);
  72. #ifdef DBG
  73. BOOL g_fDavTrace = FALSE;
  74. DEC_CONST CHAR gc_szDbgIni[] = "DAVCData.INI";
  75. DEC_CONST INT gc_cchDbgIni = CchConstString(gc_szDbgIni);
  76. #endif
  77. // Timer constants and globals.
  78. //
  79. const DWORD WAIT_PERIOD = 60000; // 1 min = 60 sec = 60,000 milliseconds
  80. // Helper functions
  81. //
  82. BOOL FCanUnloadServer();
  83. static DWORD s_dwMainTID = 0;
  84. // ===============================================================
  85. // Supporting class definitions
  86. // ===============================================================
  87. class CHandleArray
  88. {
  89. protected:
  90. HANDLE m_rgHandles[MAXIMUM_WAIT_OBJECTS];
  91. UINT m_uiHandles;
  92. public:
  93. CHandleArray() :
  94. m_uiHandles(0)
  95. {
  96. }
  97. HANDLE * PhGetHandles()
  98. {
  99. return m_rgHandles;
  100. }
  101. UINT UiGetHandleCount()
  102. {
  103. return m_uiHandles;
  104. }
  105. BOOL FIsFull()
  106. {
  107. return (MAXIMUM_WAIT_OBJECTS == m_uiHandles);
  108. }
  109. VOID AddHandle(HANDLE h)
  110. {
  111. Assert(FALSE == FIsFull());
  112. m_rgHandles[m_uiHandles++] = h;
  113. }
  114. VOID RemoveHandle(UINT uiIndex, BOOL fCloseHandle)
  115. {
  116. Assert(m_uiHandles > uiIndex);
  117. if (fCloseHandle)
  118. {
  119. CloseHandle(m_rgHandles[uiIndex]);
  120. }
  121. memcpy(m_rgHandles + uiIndex, m_rgHandles + uiIndex + 1, (m_uiHandles - uiIndex - 1) * sizeof(HANDLE));
  122. m_uiHandles--;
  123. }
  124. };
  125. class CHandleArrayForHandlePool : public CListElement<CHandleArrayForHandlePool>,
  126. public CHandleArray
  127. {
  128. public:
  129. // Indexes to the handles in the array
  130. //
  131. enum
  132. {
  133. ih_external_update,
  134. ih_delete_timer,
  135. c_events,
  136. ih_wp = c_events
  137. };
  138. CHandleArrayForHandlePool(HANDLE hEvtNewWP,
  139. HANDLE hEvtDelTimer)
  140. {
  141. Assert(c_events < MAXIMUM_WAIT_OBJECTS);
  142. AddHandle(hEvtNewWP);
  143. AddHandle(hEvtDelTimer);
  144. }
  145. BOOL FIsEmpty()
  146. {
  147. Assert(c_events <= m_uiHandles);
  148. return (c_events == m_uiHandles);
  149. }
  150. };
  151. class CHandlePool : public Singleton<CHandlePool>
  152. {
  153. HANDLE m_hEvtUpdatesAllowed;
  154. HANDLE m_hEvtStartListening;
  155. HANDLE m_hEvtExternalUpdate;
  156. HANDLE m_hEvtDelTimer;
  157. LONG m_lUpdatesInProgress;
  158. LONG m_lShutDown;
  159. CCriticalSection m_cs;
  160. CListHead<CHandleArrayForHandlePool> m_listHandleArrayForHandlePool;
  161. // Wait period in miliseconds for looking at single handle bucket
  162. //
  163. enum { WAIT_POLL_PERIOD = 5000 };
  164. //
  165. // Friend declarations required by Singleton template
  166. //
  167. friend class Singleton<CHandlePool>;
  168. // CREATORS
  169. //
  170. CHandlePool() :
  171. m_hEvtUpdatesAllowed(NULL),
  172. m_hEvtStartListening(NULL),
  173. m_hEvtExternalUpdate(NULL),
  174. m_hEvtDelTimer(NULL),
  175. m_lUpdatesInProgress(0),
  176. m_lShutDown(0)
  177. {
  178. }
  179. ~CHandlePool()
  180. {
  181. UnInitialize();
  182. }
  183. // NOT IMPLEMENTED
  184. //
  185. CHandlePool& operator=( const CHandlePool& );
  186. CHandlePool( const CHandlePool& );
  187. public:
  188. // CREATORS
  189. //
  190. // Instance creating/destroying routines provided
  191. // by the Singleton template.
  192. //
  193. using Singleton<CHandlePool>::CreateInstance;
  194. using Singleton<CHandlePool>::DestroyInstance;
  195. using Singleton<CHandlePool>::Instance;
  196. HRESULT HrInitialize()
  197. {
  198. HRESULT hr = S_OK;
  199. HANDLE hWaitingThread = NULL;
  200. auto_handle<HANDLE> a_hEvtUpdatesAllowed;
  201. auto_handle<HANDLE> a_hEvtStartListening;
  202. auto_handle<HANDLE> a_hEvtExternalUpdate;
  203. auto_handle<HANDLE> a_hEvtDelTimer;
  204. auto_ptr<CHandleArrayForHandlePool> a_pHandleArrayForHandlePool;
  205. // Create the event that is used to indicate if the updates are allowed.
  206. // While this event is set the updates can be performed and noone is
  207. // listening on the handles in the pool handle arrays.
  208. //
  209. a_hEvtUpdatesAllowed = CreateEvent (NULL, // lpEventAttributes
  210. TRUE, // bManualReset
  211. FALSE, // bInitialState
  212. NULL); // lpName
  213. if (NULL == a_hEvtUpdatesAllowed.get())
  214. {
  215. hr = HRESULT_FROM_WIN32(GetLastError());
  216. DebugTrace ("CreateEvent failed 0x%08lX\n", hr);
  217. goto ret;
  218. }
  219. // Create event that triggers the thread to again start listening on
  220. // process handes.
  221. //
  222. a_hEvtStartListening = CreateEvent (NULL, // lpEventAttributes
  223. FALSE, // bManualReset
  224. FALSE, // bInitialState
  225. NULL); // lpName
  226. if (NULL == a_hEvtStartListening.get())
  227. {
  228. hr = HRESULT_FROM_WIN32(GetLastError());
  229. DebugTrace ("CreateEvent failed 0x%08lX\n", hr);
  230. goto ret;
  231. }
  232. // Create the event that is used to notify the arrival of new event
  233. //
  234. a_hEvtExternalUpdate = CreateEvent (NULL, // lpEventAttributes
  235. FALSE, // bManualReset
  236. FALSE, // bInitialState
  237. NULL); // lpName
  238. if (NULL == a_hEvtExternalUpdate.get())
  239. {
  240. hr = HRESULT_FROM_WIN32(GetLastError());
  241. DebugTrace ("CreateEvent failed 0x%08lX\n", hr);
  242. goto ret;
  243. }
  244. // Create the event that listens for timer deletion
  245. //
  246. a_hEvtDelTimer = CreateEvent (NULL, // lpEventAttributes
  247. FALSE, // bManualReset
  248. FALSE, // bInitialState
  249. NULL); // lpName
  250. if (NULL == a_hEvtDelTimer.get())
  251. {
  252. hr = HRESULT_FROM_WIN32(GetLastError());
  253. DebugTrace ("CreateEvent failed 0x%08lX\n", hr);
  254. goto ret;
  255. }
  256. a_pHandleArrayForHandlePool = new CHandleArrayForHandlePool(a_hEvtExternalUpdate.get(), a_hEvtDelTimer.get());
  257. if (NULL == a_pHandleArrayForHandlePool.get())
  258. {
  259. hr = E_OUTOFMEMORY;
  260. DebugTrace ("Allocation failed 0x%08lX\n", hr);
  261. goto ret;
  262. }
  263. m_listHandleArrayForHandlePool.Append(a_pHandleArrayForHandlePool.relinquish());
  264. m_hEvtUpdatesAllowed = a_hEvtUpdatesAllowed.relinquish();
  265. m_hEvtStartListening = a_hEvtStartListening.relinquish();
  266. m_hEvtExternalUpdate = a_hEvtExternalUpdate.relinquish();
  267. m_hEvtDelTimer = a_hEvtDelTimer.relinquish();
  268. ret:
  269. if (FAILED(hr))
  270. {
  271. UnInitialize();
  272. }
  273. return hr;
  274. }
  275. VOID UnInitialize()
  276. {
  277. CHandleArrayForHandlePool * pHandleArrayForHandlePool;
  278. pHandleArrayForHandlePool = m_listHandleArrayForHandlePool.GetListHead();
  279. while (pHandleArrayForHandlePool)
  280. {
  281. HANDLE * pHandles = pHandleArrayForHandlePool->PhGetHandles();
  282. UINT uiHandles = pHandleArrayForHandlePool->UiGetHandleCount();
  283. for (UINT ui = CHandleArrayForHandlePool::ih_wp; ui < uiHandles; ui++)
  284. {
  285. CloseHandle(pHandles[ui]);
  286. }
  287. m_listHandleArrayForHandlePool.Remove(pHandleArrayForHandlePool);
  288. delete pHandleArrayForHandlePool;
  289. pHandleArrayForHandlePool = m_listHandleArrayForHandlePool.GetListHead();
  290. }
  291. if (m_hEvtUpdatesAllowed)
  292. {
  293. CloseHandle(m_hEvtUpdatesAllowed);
  294. }
  295. if (m_hEvtStartListening)
  296. {
  297. CloseHandle(m_hEvtStartListening);
  298. }
  299. if (m_hEvtExternalUpdate)
  300. {
  301. CloseHandle(m_hEvtExternalUpdate);
  302. }
  303. if (m_hEvtDelTimer)
  304. {
  305. CloseHandle(m_hEvtDelTimer);
  306. }
  307. }
  308. VOID AllowUpdatesToExecute()
  309. {
  310. // Allow updates and start waiting for them to end
  311. //
  312. SetEvent(m_hEvtUpdatesAllowed);
  313. WaitForSingleObject(m_hEvtStartListening,
  314. INFINITE);
  315. }
  316. VOID AllowShutdownToExecute()
  317. {
  318. InterlockedExchange(&m_lShutDown, 1);
  319. SetEvent(m_hEvtUpdatesAllowed);
  320. }
  321. VOID DisallowUpdates()
  322. {
  323. // We disallow updates only if we are not in shutdown. I.e.
  324. // we are in the listening loop
  325. //
  326. if (0 == InterlockedCompareExchange(&m_lShutDown,
  327. 1,
  328. 1))
  329. {
  330. ResetEvent(m_hEvtUpdatesAllowed);
  331. }
  332. }
  333. HRESULT HrAddHandle(HANDLE h)
  334. {
  335. HRESULT hr = S_OK;
  336. BOOL fHandleAdded = FALSE;
  337. // Inform the thread that is waiting on process handles
  338. // that the update has arrived. We do this only if there
  339. // were no other updates in progress.
  340. //
  341. if (1 == InterlockedIncrement(&m_lUpdatesInProgress))
  342. {
  343. DisallowUpdates();
  344. SetEvent(m_hEvtExternalUpdate);
  345. }
  346. // Wait until the listening thread is ready for updates, I.e. it
  347. // stopped listening on process handles or doing other work.
  348. //
  349. WaitForSingleObject(m_hEvtUpdatesAllowed,
  350. INFINITE);
  351. {
  352. CSynchronizedBlock sb(m_cs);
  353. CHandleArrayForHandlePool * pHandleArrayForHandlePoolNext;
  354. pHandleArrayForHandlePoolNext = m_listHandleArrayForHandlePool.GetListHead();
  355. do
  356. {
  357. Assert(NULL != pHandleArrayForHandlePoolNext);
  358. if (pHandleArrayForHandlePoolNext->FIsFull())
  359. {
  360. pHandleArrayForHandlePoolNext = pHandleArrayForHandlePoolNext->GetNextListElement();
  361. }
  362. else
  363. {
  364. pHandleArrayForHandlePoolNext->AddHandle(h);
  365. fHandleAdded = TRUE;
  366. break;
  367. }
  368. }
  369. while (NULL != pHandleArrayForHandlePoolNext);
  370. if (FALSE == fHandleAdded)
  371. {
  372. auto_ptr<CHandleArrayForHandlePool> a_pHandleArrayForHandlePool;
  373. Assert(NULL != m_hEvtExternalUpdate);
  374. Assert(NULL != m_hEvtDelTimer);
  375. a_pHandleArrayForHandlePool = new CHandleArrayForHandlePool(m_hEvtExternalUpdate, m_hEvtDelTimer);
  376. if (NULL == a_pHandleArrayForHandlePool.get())
  377. {
  378. hr = E_OUTOFMEMORY;
  379. DebugTrace ("Allocation failed 0x%08lX\n", hr);
  380. goto ret;
  381. }
  382. a_pHandleArrayForHandlePool->AddHandle(h);
  383. m_listHandleArrayForHandlePool.Append(a_pHandleArrayForHandlePool.relinquish());
  384. }
  385. }
  386. // If this is last update to leave allow the thread listening
  387. // on process handles to proceed
  388. //
  389. if (0 == InterlockedDecrement(&m_lUpdatesInProgress))
  390. {
  391. DisallowUpdates();
  392. SetEvent(m_hEvtStartListening);
  393. }
  394. ret:
  395. return hr;
  396. }
  397. VOID RemoveHandleInternal(CHandleArrayForHandlePool * pHandleArrayForHandlePool, UINT uiIndex)
  398. {
  399. pHandleArrayForHandlePool->RemoveHandle(uiIndex, TRUE);
  400. if (pHandleArrayForHandlePool->FIsEmpty())
  401. {
  402. // Do not remove the last buffer in the list as we
  403. // still want to wait for the events of external update
  404. //
  405. if (1 < m_listHandleArrayForHandlePool.ListSize())
  406. {
  407. m_listHandleArrayForHandlePool.Remove(pHandleArrayForHandlePool);
  408. delete pHandleArrayForHandlePool;
  409. }
  410. }
  411. }
  412. VOID SignalTimerDelete()
  413. {
  414. SetEvent(m_hEvtDelTimer);
  415. }
  416. static DWORD __stdcall DwWaitOnWPs (PVOID pvThreadData);
  417. };
  418. class CLockData
  419. {
  420. // Constant values
  421. //
  422. enum { DEFAULT_LOCK_TIMEOUT = 60 * 3 };
  423. // Lock ID
  424. //
  425. LARGE_INTEGER m_liLockID;
  426. // Lock description data
  427. //
  428. DWORD m_dwAccess;
  429. DWORD m_dwLockType;
  430. DWORD m_dwLockScope;
  431. DWORD m_dwSecondsTimeout;
  432. // Resource and comment strings
  433. //
  434. auto_ptr<WCHAR> m_pwszResourceString;
  435. auto_ptr<WCHAR> m_pwszOwnerComment;
  436. // Owner of the lock
  437. //
  438. DWORD m_dwSidLength;
  439. auto_ptr<BYTE> m_pbSid;
  440. // File handle that this process is holding to keep the
  441. // file open. It must be duplicated before using
  442. //
  443. auto_handle<HANDLE> m_hFileHandle;
  444. // Lock cache timeout data
  445. //
  446. FILETIME m_ftLastAccess;
  447. // Cached values to speed up timeout calculation
  448. //
  449. FILETIME m_ftRememberNow;
  450. BOOL m_fHasTimedOut;
  451. // Lock token string
  452. //
  453. UINT m_cchToken;
  454. WCHAR m_rgwchToken[MAX_LOCKTOKEN_LENGTH];
  455. public:
  456. // CREATORS
  457. //
  458. CLockData() :
  459. m_dwAccess(0),
  460. m_dwLockType(0),
  461. m_dwLockScope(0),
  462. m_dwSecondsTimeout(DEFAULT_LOCK_TIMEOUT),
  463. m_dwSidLength(0),
  464. m_fHasTimedOut(FALSE),
  465. m_cchToken(0)
  466. {
  467. m_liLockID.QuadPart = 0;
  468. m_ftLastAccess.dwLowDateTime = 0;
  469. m_ftLastAccess.dwHighDateTime = 0;
  470. m_ftRememberNow.dwLowDateTime = 0;
  471. m_ftRememberNow.dwHighDateTime = 0;
  472. }
  473. ~CLockData()
  474. {
  475. }
  476. HRESULT HrInitialize(LPCWSTR pwszGuid,
  477. LARGE_INTEGER liLockID,
  478. DWORD dwAccess,
  479. DWORD dwLockType,
  480. DWORD dwLockScope,
  481. DWORD dwSecondsTimeout,
  482. LPCWSTR pwszResourceString,
  483. LPCWSTR pwszOwnerComment,
  484. DWORD dwSid,
  485. BYTE * pbSid)
  486. {
  487. HRESULT hr = S_OK;
  488. // Opaquelocktoken format is partially defined by our IETF spec.
  489. // First opaquelocktoken:<our guid>, then our specific lock id.
  490. //
  491. m_cchToken = _snwprintf(m_rgwchToken,
  492. CElems(m_rgwchToken),
  493. L"<opaquelocktoken:%ls:%I64d>",
  494. pwszGuid,
  495. liLockID);
  496. if (((-1) == static_cast<INT>(m_cchToken)) || (CElems(m_rgwchToken) == m_cchToken))
  497. {
  498. // This should not happen as we give sufficient buffer. But let us
  499. // handle this to the best of our ability for preventive reasons.
  500. //
  501. Assert(0);
  502. m_cchToken = CElems(m_rgwchToken) - 1;
  503. m_rgwchToken[m_cchToken] = L'\0';
  504. }
  505. m_liLockID = liLockID;
  506. m_dwAccess = dwAccess;
  507. m_dwLockType = dwLockType;
  508. m_dwLockScope = dwLockScope;
  509. if (dwSecondsTimeout)
  510. {
  511. m_dwSecondsTimeout = dwSecondsTimeout;
  512. }
  513. if (pwszResourceString)
  514. {
  515. UINT cchResourceString = static_cast<UINT>(wcslen(pwszResourceString));
  516. m_pwszResourceString = static_cast<LPWSTR>(ExAlloc(CbSizeWsz(cchResourceString)));
  517. if (NULL == m_pwszResourceString.get())
  518. {
  519. hr = E_OUTOFMEMORY;
  520. goto ret;
  521. }
  522. memcpy(m_pwszResourceString.get(), pwszResourceString, sizeof(WCHAR) * cchResourceString);
  523. m_pwszResourceString[cchResourceString] = L'\0';
  524. }
  525. if (pwszOwnerComment)
  526. {
  527. UINT cchOwnerComment = static_cast<UINT>(wcslen(pwszOwnerComment));
  528. m_pwszOwnerComment = static_cast<LPWSTR>(ExAlloc(CbSizeWsz(cchOwnerComment)));
  529. if (NULL == m_pwszOwnerComment.get())
  530. {
  531. hr = E_OUTOFMEMORY;
  532. goto ret;
  533. }
  534. memcpy(m_pwszOwnerComment.get(), pwszOwnerComment, sizeof(WCHAR) * cchOwnerComment);
  535. m_pwszOwnerComment[cchOwnerComment] = L'\0';
  536. }
  537. m_pbSid = static_cast<BYTE *>(ExAlloc(dwSid));
  538. if (NULL == m_pbSid.get())
  539. {
  540. hr = E_OUTOFMEMORY;
  541. goto ret;
  542. }
  543. if (!CopySid(dwSid, m_pbSid.get(), pbSid))
  544. {
  545. hr = HRESULT_FROM_WIN32(GetLastError());
  546. goto ret;
  547. }
  548. m_dwSidLength = dwSid;
  549. // Lastly set in the last file time that this was accessed.
  550. //
  551. GetSystemTimeAsFileTime(&m_ftLastAccess);
  552. ret:
  553. return hr;
  554. }
  555. HRESULT HrLockFile(HANDLE hFile, DWORD dwProcessId)
  556. {
  557. HRESULT hr = S_OK;
  558. auto_handle<HANDLE> a_hProcess = NULL;
  559. auto_handle<HANDLE> a_hDupFileHandle = NULL;
  560. a_hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId);
  561. if (NULL == a_hProcess.get())
  562. {
  563. hr = HRESULT_FROM_WIN32(GetLastError());
  564. DebugTrace("Opening original process failed 0x%08lX\n", hr);
  565. goto ret;
  566. }
  567. if (!DuplicateHandle(a_hProcess.get(),
  568. hFile,
  569. GetCurrentProcess(),
  570. a_hDupFileHandle.load(),
  571. 0,
  572. FALSE,
  573. DUPLICATE_SAME_ACCESS))
  574. {
  575. hr = HRESULT_FROM_WIN32(GetLastError());
  576. DebugTrace("Failed to duplicate handle 0x%08lX\n", hr);
  577. goto ret;
  578. }
  579. m_hFileHandle = a_hDupFileHandle.relinquish();
  580. ret:
  581. return hr;
  582. }
  583. // Lock ID
  584. //
  585. LARGE_INTEGER LiLockID()
  586. {
  587. return m_liLockID;
  588. }
  589. // Lock token string
  590. //
  591. UINT CchLockTokenString(LPCWSTR * ppwszLockToken) const
  592. {
  593. if (ppwszLockToken)
  594. {
  595. *ppwszLockToken = m_rgwchToken;
  596. }
  597. return m_cchToken;
  598. }
  599. // Resource string
  600. //
  601. LPCWSTR PwszResourceString() const
  602. {
  603. return m_pwszResourceString.get();
  604. }
  605. // Owner comment
  606. //
  607. LPCWSTR PwszOwnerComment() const
  608. {
  609. return m_pwszOwnerComment.get();
  610. }
  611. // Touch the lock
  612. //
  613. VOID SetLastAccess(FILETIME ftNow)
  614. {
  615. m_ftLastAccess = ftNow;
  616. }
  617. // Set timeout
  618. //
  619. VOID SetSecondsTimeout(DWORD dwSecondsTimeout)
  620. {
  621. m_dwSecondsTimeout = dwSecondsTimeout;
  622. }
  623. // Check the owner
  624. //
  625. BOOL FIsSameOwner(PSID pSid) const
  626. {
  627. BOOL fIsSameOwner = TRUE;
  628. Assert(pSid);
  629. Assert(IsValidSid(m_pbSid.get()));
  630. Assert(IsValidSid(pSid));
  631. if (!EqualSid(m_pbSid.get(), pSid))
  632. {
  633. fIsSameOwner = FALSE;
  634. }
  635. return fIsSameOwner;
  636. }
  637. // Check the resource
  638. //
  639. BOOL FIsSameResource(LPCWSTR pwszResource) const
  640. {
  641. BOOL fIsSameResource = TRUE;
  642. Assert(pwszResource);
  643. if (_wcsicmp(m_pwszResourceString.get(), pwszResource))
  644. {
  645. fIsSameResource = FALSE;
  646. }
  647. return fIsSameResource;
  648. }
  649. // Check the type
  650. //
  651. BOOL FIsSameType(DWORD dwLockType) const
  652. {
  653. return (0 != (dwLockType & m_dwLockType));
  654. }
  655. // Fill the data of the lock into the structure for marshalling
  656. //
  657. VOID FillSNewLockData(SNewLockData * pnld) const
  658. {
  659. Assert(pnld);
  660. pnld->m_dwAccess = m_dwAccess;
  661. pnld->m_dwLockType = m_dwLockType;
  662. pnld->m_dwLockScope = m_dwLockScope;
  663. pnld->m_dwSecondsTimeout = m_dwSecondsTimeout;
  664. pnld->m_pwszResourceString = m_pwszResourceString.get();
  665. pnld->m_pwszOwnerComment = m_pwszOwnerComment.get();
  666. }
  667. // Fill the handle data of the lock for marshalling
  668. //
  669. VOID FillSLockHandleData(SLockHandleData * plhd) const
  670. {
  671. Assert(plhd);
  672. plhd->h = reinterpret_cast<DWORD_PTR>(m_hFileHandle.get());
  673. plhd->dwProcessID = /*CLockCache::Instance().DwGetThisProcessID();*/ GetCurrentProcessId();
  674. }
  675. BOOL FIsExpired(FILETIME ftNow)
  676. {
  677. // This function will be called twice during each ExpiredLocks
  678. // check. The first time it is called we should do the checks
  679. // and set the m_fHasTimedOut call. The second time we want to
  680. // avoid it because we all ready know the answer. By keeping
  681. // track of the ftNow times we are called with we can determine
  682. // if we have all ready done the calculation or not.
  683. // We also know that no matter what once a lock times out, it should
  684. // remain timed out for it's lifetime.
  685. //
  686. if ((!m_fHasTimedOut) && (0 != CompareFileTime(&ftNow, &m_ftRememberNow)))
  687. {
  688. // Find out if based on the time passed in has the lock expired
  689. //
  690. INT64 i64TimePassed;
  691. DWORD dwSecondsPassed;
  692. // Do the math to figure out when this lock expires/expired.
  693. //
  694. // First calculate how many seconds have passed since this lock
  695. // was last accessed.
  696. // Subtract the filetimes to get the time passed in 100-nanosecond
  697. // increments. (That's how filetimes count.)
  698. // NOTE: Operation bellow is very dangerous on 64 bit platforms,
  699. // as the filetimes need to be alligned on 8 byte boundary. So even
  700. // change in order of current member variables or adding new ones
  701. // can get us in the trouble
  702. //
  703. i64TimePassed = ((*(INT64*)&ftNow) - (*(INT64*)&m_ftLastAccess));
  704. // Convert our time passed into seconds (10,000,000 100-nanosec incs in a second).
  705. //
  706. dwSecondsPassed = static_cast<DWORD>(i64TimePassed/10000000);
  707. // Compare the timeout from the lock object to the count of seconds.
  708. // If this lock object has expired, remove it.
  709. //
  710. m_fHasTimedOut = m_dwSecondsTimeout < dwSecondsPassed;
  711. m_ftRememberNow = ftNow;
  712. }
  713. return m_fHasTimedOut;
  714. }
  715. };
  716. typedef CLockData* PLockData;
  717. class CLockCache : public Singleton<CLockCache>
  718. {
  719. //
  720. // Friend declarations required by Singleton template
  721. //
  722. friend class Singleton<CLockCache>;
  723. // Guid string for our lock IDs
  724. //
  725. WCHAR m_rgwchGuid[gc_cchMaxGuid];
  726. // Current process ID
  727. //
  728. DWORD m_dwThisProcessId;
  729. // Next lock ID counter
  730. //
  731. LARGE_INTEGER m_liLastLockID;
  732. class LIKey
  733. {
  734. public:
  735. LARGE_INTEGER m_li;
  736. LIKey(LARGE_INTEGER li) :
  737. m_li(li)
  738. {
  739. }
  740. // operators for use with the hash cache
  741. //
  742. int hash( const int rhs ) const
  743. {
  744. return (m_li.LowPart % rhs);
  745. }
  746. bool isequal( const LIKey& rhs ) const
  747. {
  748. return (m_li.QuadPart == rhs.m_li.QuadPart);
  749. }
  750. };
  751. typedef CCache<LIKey, PLockData> CLockCacheById;
  752. typedef CCache<CRCWsziLI, PLockData> CLockCacheByName;
  753. CMRWLock m_mrwCache;
  754. CLockCacheById m_lockCacheById;
  755. CLockCacheByName m_lockCacheByName;
  756. HANDLE m_hTimer;
  757. class COpClear : public CLockCacheById::IOp
  758. {
  759. // NOT IMPLEMENTED
  760. //
  761. COpClear& operator=( const COpClear& );
  762. public:
  763. // CREATORS
  764. //
  765. COpClear()
  766. {
  767. }
  768. BOOL operator() (const LIKey&,
  769. const PLockData& pLockData)
  770. {
  771. delete pLockData;
  772. return TRUE;
  773. }
  774. };
  775. class COpExpire : public CLockCacheById::IOp
  776. {
  777. FILETIME m_ftNow;
  778. CLockCacheById& m_lockCacheById;
  779. CLockCacheByName& m_lockCacheByName;
  780. // NOT IMPLEMENTED
  781. //
  782. COpExpire& operator=( const COpExpire& );
  783. public:
  784. // CREATORS
  785. //
  786. COpExpire(FILETIME ftNow,
  787. CLockCacheById& lockCacheById,
  788. CLockCacheByName& lockCacheByName) : m_ftNow(ftNow),
  789. m_lockCacheById(lockCacheById),
  790. m_lockCacheByName(lockCacheByName)
  791. {
  792. }
  793. BOOL operator() (const LIKey&,
  794. const PLockData& pLockData)
  795. {
  796. if (pLockData->FIsExpired(m_ftNow))
  797. {
  798. m_lockCacheById.Remove(LIKey(pLockData->LiLockID()));
  799. m_lockCacheByName.Remove(CRCWsziLI(pLockData->PwszResourceString(),
  800. pLockData->LiLockID(),
  801. TRUE));
  802. delete pLockData;
  803. }
  804. return TRUE;
  805. }
  806. };
  807. class COpGatherLockData : public CLockCacheByName::IOp
  808. {
  809. // The path to match
  810. //
  811. LPCWSTR m_pwszPath;
  812. // Lock type to match
  813. //
  814. DWORD m_dwLockType;
  815. // Error code in which operation has ended
  816. //
  817. HRESULT m_hr;
  818. // Results gathered by the operation
  819. //
  820. DWORD m_dwLocksFound;
  821. ChainedBuffer<SNewLockData> m_chBufNewLockData;
  822. ChainedBuffer<LPWSTR> m_chBufPLockTokens;
  823. // NOT IMPLEMENTED
  824. //
  825. COpGatherLockData& operator=( const COpGatherLockData& );
  826. public:
  827. // CREATORS
  828. //
  829. COpGatherLockData( LPCWSTR pwszPath,
  830. DWORD dwLockType ) :
  831. m_pwszPath(pwszPath),
  832. m_dwLockType(dwLockType),
  833. m_hr(S_OK),
  834. m_dwLocksFound(0)
  835. {
  836. }
  837. // MANIPULATORS
  838. //
  839. VOID Invoke( CLockCacheByName& cache )
  840. {
  841. // Do the ForEachMatch()
  842. //
  843. LARGE_INTEGER li;
  844. li.QuadPart = 0;
  845. cache.ForEachMatch( CRCWsziLI(m_pwszPath, li, FALSE), *this );
  846. }
  847. BOOL operator() (const CRCWsziLI&,
  848. const PLockData& pLockData)
  849. {
  850. BOOL fSuccess = TRUE;
  851. if (pLockData->FIsSameType(m_dwLockType))
  852. {
  853. SNewLockData * pNewLockData;
  854. LPWSTR * ppLockToken;
  855. pNewLockData = m_chBufNewLockData.Alloc(sizeof(SNewLockData));
  856. if (NULL == pNewLockData)
  857. {
  858. m_hr = E_OUTOFMEMORY;
  859. fSuccess = FALSE;
  860. goto ret;
  861. }
  862. pLockData->FillSNewLockData(pNewLockData);
  863. ppLockToken = m_chBufPLockTokens.Alloc(sizeof(LPWSTR));
  864. if (NULL == ppLockToken)
  865. {
  866. m_hr = E_OUTOFMEMORY;
  867. fSuccess = FALSE;
  868. goto ret;
  869. }
  870. pLockData->CchLockTokenString(const_cast<LPCWSTR *>(ppLockToken));
  871. m_dwLocksFound++;
  872. }
  873. ret:
  874. return fSuccess;
  875. }
  876. HRESULT HrLocksFound(DWORD * pdwLocksFound)
  877. {
  878. HRESULT hr = m_hr;
  879. Assert(pdwLocksFound);
  880. if (FAILED(hr))
  881. {
  882. goto ret;
  883. }
  884. *pdwLocksFound = m_dwLocksFound;
  885. ret:
  886. return hr;
  887. }
  888. HRESULT HrGetData(SNewLockData * pNewLockData,
  889. LPWSTR * ppwszLockToken)
  890. {
  891. HRESULT hr = m_hr;
  892. auto_co_task_mem<WCHAR> a_pwszResourceString;
  893. auto_co_task_mem<WCHAR> a_pwszOwnerComment;
  894. auto_co_task_mem<WCHAR> a_pwszLockToken;
  895. UINT cch;
  896. DWORD dw1 = 0;
  897. DWORD dw2 = 0;
  898. Assert(pNewLockData);
  899. Assert(ppwszLockToken);
  900. if (FAILED(hr))
  901. {
  902. goto ret;
  903. }
  904. m_chBufNewLockData.Dump(pNewLockData, sizeof(SNewLockData) * m_dwLocksFound);
  905. m_chBufPLockTokens.Dump(ppwszLockToken, sizeof(LPWSTR) * m_dwLocksFound);
  906. for (dw1 = 0; dw1 < m_dwLocksFound; dw1++)
  907. {
  908. cch = static_cast<UINT>(wcslen(pNewLockData[dw1].m_pwszResourceString));
  909. a_pwszResourceString = static_cast<LPWSTR>(CoTaskMemAlloc(CbSizeWsz(cch)));
  910. if (NULL == a_pwszResourceString.get())
  911. {
  912. hr = E_OUTOFMEMORY;
  913. goto ret;
  914. }
  915. memcpy(a_pwszResourceString.get(), pNewLockData[dw1].m_pwszResourceString, sizeof(WCHAR) * (cch + 1));
  916. cch = static_cast<UINT>(wcslen(pNewLockData[dw1].m_pwszOwnerComment));
  917. a_pwszOwnerComment = static_cast<LPWSTR>(CoTaskMemAlloc(CbSizeWsz(cch)));
  918. if (NULL == a_pwszOwnerComment.get())
  919. {
  920. hr = E_OUTOFMEMORY;
  921. goto ret;
  922. }
  923. memcpy(a_pwszOwnerComment.get(), pNewLockData[dw1].m_pwszOwnerComment, sizeof(WCHAR) * (cch + 1));
  924. cch = static_cast<UINT>(wcslen(ppwszLockToken[dw1]));
  925. a_pwszLockToken= static_cast<LPWSTR>(CoTaskMemAlloc(CbSizeWsz(cch)));
  926. if (NULL == a_pwszLockToken.get())
  927. {
  928. hr = E_OUTOFMEMORY;
  929. goto ret;
  930. }
  931. memcpy(a_pwszLockToken.get(), ppwszLockToken[dw1], sizeof(WCHAR) * (cch + 1));
  932. pNewLockData[dw1].m_pwszResourceString = a_pwszResourceString.relinquish();
  933. pNewLockData[dw1].m_pwszOwnerComment = a_pwszOwnerComment.relinquish();
  934. ppwszLockToken[dw1] = a_pwszLockToken.relinquish();
  935. }
  936. ret:
  937. if (FAILED(hr))
  938. {
  939. // Cleanup whatever we have allocated so far
  940. //
  941. for (dw2 = 0; dw2 < dw1; dw2++)
  942. {
  943. CoTaskMemFree(pNewLockData[dw1].m_pwszResourceString);
  944. CoTaskMemFree(pNewLockData[dw1].m_pwszOwnerComment);
  945. CoTaskMemFree(ppwszLockToken[dw1]);
  946. }
  947. }
  948. return hr;
  949. }
  950. };
  951. // CREATORS
  952. //
  953. CLockCache() :
  954. m_dwThisProcessId(0),
  955. m_hTimer(NULL)
  956. {
  957. m_liLastLockID.QuadPart = 0x0000003200000032;
  958. }
  959. ~CLockCache()
  960. {
  961. COpClear opClear;
  962. m_lockCacheById.ForEach(opClear);
  963. }
  964. // NOT IMPLEMENTED
  965. //
  966. CLockCache& operator=( const CLockCache& );
  967. CLockCache( const CLockCache& );
  968. LARGE_INTEGER LiGetNewLockID()
  969. {
  970. LARGE_INTEGER liLockID;
  971. //$BUGBUG. There is a problem if while high part is incrementing
  972. // other thread comes in and tries to get the next ID. As lower part
  973. // would be already incremented it still may get old high part. This
  974. // is very rare condition, but we should have some synchronization
  975. // here.
  976. //
  977. liLockID.LowPart = InterlockedIncrement(reinterpret_cast<LONG *>(&m_liLastLockID.LowPart));
  978. if (0 == liLockID.LowPart)
  979. {
  980. liLockID.HighPart = InterlockedIncrement(&m_liLastLockID.HighPart);
  981. }
  982. else
  983. {
  984. liLockID.HighPart = m_liLastLockID.HighPart;
  985. }
  986. return liLockID;
  987. }
  988. VOID ExpireLocks()
  989. {
  990. FILETIME ftNow;
  991. // Get the current time
  992. //
  993. GetSystemTimeAsFileTime(&ftNow);
  994. // Protect ourselves for the operation
  995. //
  996. CSynchronizedWriteBlock swb(m_mrwCache);
  997. // Initialize the operation
  998. //
  999. COpExpire opExpire(ftNow,
  1000. m_lockCacheById,
  1001. m_lockCacheByName);
  1002. // Iterate through the cache trying to expire items
  1003. //
  1004. m_lockCacheById.ForEach(opExpire);
  1005. // Attempt to kill the timer if there are no locks
  1006. //
  1007. if (0 == m_lockCacheById.CItems())
  1008. {
  1009. CHandlePool::Instance().SignalTimerDelete();
  1010. }
  1011. }
  1012. static VOID CALLBACK CheckLocks(PVOID pvIgnored, BOOLEAN fIgnored)
  1013. {
  1014. Instance().ExpireLocks();
  1015. }
  1016. HRESULT HrLaunchLockTimer()
  1017. {
  1018. HRESULT hr = S_OK;
  1019. HANDLE hTimer = NULL;
  1020. // We do not protect ourselves for the operation as
  1021. // the only caller already protects us...
  1022. if (NULL == m_hTimer)
  1023. {
  1024. if (!CreateTimerQueueTimer(&hTimer, // timer that we created
  1025. NULL, // use default timer queue
  1026. CheckLocks, // function that will check the locks in the cache
  1027. // and release any expired locks.
  1028. NULL, // parameter to the callback function
  1029. WAIT_PERIOD, // how long to wait before calling the callback function
  1030. // the first time.
  1031. WAIT_PERIOD, // how long to wait between calls to the callback function
  1032. WT_EXECUTEINIOTHREAD)) // where to execute the function call...
  1033. {
  1034. hr = HRESULT_FROM_WIN32(GetLastError());
  1035. goto ret;
  1036. }
  1037. m_hTimer = hTimer;
  1038. }
  1039. ret:
  1040. return hr;
  1041. }
  1042. VOID DeleteLockTimer(HANDLE hTimer)
  1043. {
  1044. if (NULL != hTimer)
  1045. {
  1046. // Try to delete the timer, but if it fails just leave it there
  1047. //
  1048. if (!DeleteTimerQueueTimer(NULL, //default timer queue
  1049. hTimer, // timer
  1050. INVALID_HANDLE_VALUE)) // blocking call
  1051. {
  1052. DebugTrace ("Failed to delete timer 0x%08lX\n", HRESULT_FROM_WIN32(GetLastError()));
  1053. }
  1054. }
  1055. }
  1056. public:
  1057. // CREATORS
  1058. //
  1059. // Instance creating/destroying routines provided
  1060. // by the Singleton template.
  1061. //
  1062. using Singleton<CLockCache>::CreateInstance;
  1063. using Singleton<CLockCache>::DestroyInstance;
  1064. using Singleton<CLockCache>::Instance;
  1065. HRESULT HrInitialize()
  1066. {
  1067. HRESULT hr = S_OK;
  1068. DWORD dwResult;
  1069. UUID guid = {0};
  1070. if (!m_lockCacheById.FInit())
  1071. {
  1072. hr = E_OUTOFMEMORY;
  1073. goto ret;
  1074. }
  1075. if (!m_lockCacheByName.FInit())
  1076. {
  1077. hr = E_OUTOFMEMORY;
  1078. goto ret;
  1079. }
  1080. if (!m_mrwCache.FInitialize())
  1081. {
  1082. hr = E_OUTOFMEMORY;
  1083. goto ret;
  1084. }
  1085. dwResult = UuidCreate(&guid);
  1086. if (RPC_S_OK != dwResult)
  1087. {
  1088. hr = HRESULT_FROM_WIN32(dwResult);
  1089. goto ret;
  1090. }
  1091. wsprintfW(m_rgwchGuid, gc_wszGuidFormat,
  1092. guid.Data1, guid.Data2, guid.Data3,
  1093. guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
  1094. guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
  1095. m_dwThisProcessId = GetCurrentProcessId();
  1096. ret:
  1097. return hr;
  1098. }
  1099. DWORD DwGetThisProcessID()
  1100. {
  1101. return m_dwThisProcessId;
  1102. }
  1103. VOID DeleteLockTimerIfNotUsed()
  1104. {
  1105. HANDLE hTimer = NULL;
  1106. {
  1107. // Protect ourselves for the operation
  1108. //
  1109. CSynchronizedWriteBlock swb(m_mrwCache);
  1110. if (NULL != m_hTimer)
  1111. {
  1112. // Kill the timer if there are no locks
  1113. //
  1114. if (0 == m_lockCacheById.CItems())
  1115. {
  1116. hTimer = m_hTimer;
  1117. m_hTimer = NULL;
  1118. }
  1119. }
  1120. }
  1121. DeleteLockTimer(hTimer);
  1122. }
  1123. VOID DeleteLockTimerFinal()
  1124. {
  1125. // We do not null out the member variable as this
  1126. // will serve as a flag for potential COM threads still
  1127. // coming in and trying to create new timers. They
  1128. // will not do that if the handle is not NULL.
  1129. //
  1130. DeleteLockTimer(m_hTimer);
  1131. }
  1132. HRESULT HrGetGUIDString( UINT cchBufferLen,
  1133. WCHAR * pwszGUIDString,
  1134. UINT * pcchGUIDString)
  1135. {
  1136. HRESULT hr = S_OK;
  1137. if (gc_cchMaxGuid > cchBufferLen)
  1138. {
  1139. *pcchGUIDString = gc_cchMaxGuid;
  1140. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1141. goto ret;
  1142. }
  1143. memcpy(pwszGUIDString, m_rgwchGuid, sizeof(WCHAR) * gc_cchMaxGuid);
  1144. *pcchGUIDString = gc_cchMaxGuid;
  1145. ret:
  1146. return hr;
  1147. }
  1148. HRESULT HrGetNewLockData(HANDLE hFile,
  1149. DWORD dwProcessId,
  1150. DWORD dwSid,
  1151. BYTE * pbSid,
  1152. SNewLockData * pnld,
  1153. UINT cchBufferLen,
  1154. WCHAR * pwszLockToken,
  1155. UINT * pcchLockToken)
  1156. {
  1157. HRESULT hr = S_OK;
  1158. LARGE_INTEGER liLockID;
  1159. LPCWSTR pwszLockTokenT;
  1160. UINT cchLockTokenT;
  1161. auto_ptr<CLockData> a_pLockData;
  1162. a_pLockData = new CLockData();
  1163. if (NULL == a_pLockData.get())
  1164. {
  1165. hr = E_OUTOFMEMORY;
  1166. goto ret;
  1167. }
  1168. liLockID = LiGetNewLockID();
  1169. hr = a_pLockData->HrInitialize(m_rgwchGuid,
  1170. liLockID,
  1171. pnld->m_dwAccess,
  1172. pnld->m_dwLockType,
  1173. pnld->m_dwLockScope,
  1174. pnld->m_dwSecondsTimeout,
  1175. pnld->m_pwszResourceString,
  1176. pnld->m_pwszOwnerComment,
  1177. dwSid,
  1178. pbSid);
  1179. if (FAILED(hr))
  1180. {
  1181. goto ret;
  1182. }
  1183. // Check if we will have enough space to return lock token header
  1184. //
  1185. cchLockTokenT = a_pLockData->CchLockTokenString(&pwszLockTokenT);
  1186. if (cchBufferLen < cchLockTokenT + 1)
  1187. {
  1188. *pcchLockToken = cchLockTokenT + 1;
  1189. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1190. goto ret;
  1191. }
  1192. hr = a_pLockData->HrLockFile(hFile, dwProcessId);
  1193. if (FAILED(hr))
  1194. {
  1195. goto ret;
  1196. }
  1197. // Add the lock data to the cache
  1198. //
  1199. {
  1200. LIKey liKey(liLockID);
  1201. CRCWsziLI crcWsziLIKey(a_pLockData->PwszResourceString(),
  1202. a_pLockData->LiLockID(),
  1203. TRUE);
  1204. CSynchronizedWriteBlock swb(m_mrwCache);
  1205. if (!m_lockCacheById.FAdd(liKey,
  1206. a_pLockData.get()))
  1207. {
  1208. hr = E_OUTOFMEMORY;
  1209. goto ret;
  1210. }
  1211. if (!m_lockCacheByName.FAdd(crcWsziLIKey,
  1212. a_pLockData.get()))
  1213. {
  1214. // Remove the previous entry
  1215. //
  1216. m_lockCacheById.Remove(liKey);
  1217. hr = E_OUTOFMEMORY;
  1218. goto ret;
  1219. }
  1220. hr = HrLaunchLockTimer();
  1221. if (FAILED(hr))
  1222. {
  1223. // Remove the previous entries
  1224. //
  1225. m_lockCacheById.Remove(liKey);
  1226. m_lockCacheByName.Remove(crcWsziLIKey);
  1227. goto ret;
  1228. }
  1229. memcpy(pwszLockToken, pwszLockTokenT, sizeof(WCHAR) * cchLockTokenT);
  1230. pwszLockToken[cchLockTokenT] = L'\0';
  1231. *pcchLockToken = cchLockTokenT + 1;
  1232. a_pLockData.relinquish();
  1233. }
  1234. ret:
  1235. return hr;
  1236. }
  1237. HRESULT HrGetLockData(LARGE_INTEGER liLockID,
  1238. DWORD dwSid,
  1239. BYTE * pbSid,
  1240. LPCWSTR pwszPath,
  1241. DWORD dwTimeout,
  1242. SNewLockData * pnld,
  1243. SLockHandleData * plhd,
  1244. UINT cchBufferLen,
  1245. WCHAR * pwszLockToken,
  1246. UINT *pcchLockToken)
  1247. {
  1248. HRESULT hr = S_OK;
  1249. auto_co_task_mem<WCHAR> a_pwszResourceString;
  1250. auto_co_task_mem<WCHAR> a_pwszOwnerComment;
  1251. LIKey liKey(liLockID);
  1252. CSynchronizedWriteBlock swb(m_mrwCache);
  1253. CLockData * pLockData;
  1254. if (m_lockCacheById.FFetch(liKey,
  1255. &pLockData))
  1256. {
  1257. FILETIME ftNow;
  1258. GetSystemTimeAsFileTime(&ftNow);
  1259. if (pLockData->FIsExpired(ftNow))
  1260. {
  1261. m_lockCacheById.Remove(liKey);
  1262. m_lockCacheByName.Remove(CRCWsziLI(pLockData->PwszResourceString(),
  1263. pLockData->LiLockID(),
  1264. TRUE));
  1265. delete pLockData;
  1266. hr = E_DAV_LOCK_NOT_FOUND;
  1267. goto ret;
  1268. }
  1269. else
  1270. {
  1271. pLockData->SetLastAccess(ftNow);
  1272. if (!pLockData->FIsSameOwner(pbSid))
  1273. {
  1274. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  1275. goto ret;
  1276. }
  1277. if (!pLockData->FIsSameResource(pwszPath))
  1278. {
  1279. hr = E_DAV_CONFLICTING_PATHS;
  1280. goto ret;
  1281. }
  1282. if (pnld)
  1283. {
  1284. LPCWSTR pwszLockTokenT;
  1285. UINT cchLockTokenT = pLockData->CchLockTokenString(&pwszLockTokenT) + 1;
  1286. UINT cchOwnerOrResource;
  1287. if (cchBufferLen < cchLockTokenT)
  1288. {
  1289. *pcchLockToken = cchLockTokenT;
  1290. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1291. goto ret;
  1292. }
  1293. memcpy(pwszLockToken, pwszLockTokenT, sizeof(WCHAR) * cchLockTokenT);
  1294. *pcchLockToken = cchLockTokenT;
  1295. cchOwnerOrResource = static_cast<UINT>(wcslen(pLockData->PwszResourceString()));
  1296. a_pwszResourceString = static_cast<LPWSTR>(CoTaskMemAlloc(CbSizeWsz(cchOwnerOrResource)));
  1297. if (NULL == a_pwszResourceString.get())
  1298. {
  1299. hr = E_OUTOFMEMORY;
  1300. goto ret;
  1301. }
  1302. memcpy(a_pwszResourceString.get(), pLockData->PwszResourceString(), sizeof(WCHAR) * (cchOwnerOrResource + 1));
  1303. cchOwnerOrResource = static_cast<UINT>(wcslen(pLockData->PwszOwnerComment()));
  1304. a_pwszOwnerComment = static_cast<LPWSTR>(CoTaskMemAlloc(CbSizeWsz(cchOwnerOrResource)));
  1305. if (NULL == a_pwszOwnerComment.get())
  1306. {
  1307. hr = E_OUTOFMEMORY;
  1308. goto ret;
  1309. }
  1310. memcpy(a_pwszOwnerComment.get(), pLockData->PwszOwnerComment(), sizeof(WCHAR) * (cchOwnerOrResource + 1));
  1311. pLockData->FillSNewLockData(pnld);
  1312. pnld->m_pwszResourceString = a_pwszResourceString.relinquish();
  1313. pnld->m_pwszOwnerComment = a_pwszOwnerComment.relinquish();
  1314. }
  1315. if (plhd)
  1316. {
  1317. pLockData->FillSLockHandleData(plhd);
  1318. }
  1319. // If there was a timeout passed in for a refresh then set it
  1320. //
  1321. if (dwTimeout)
  1322. {
  1323. pLockData->SetSecondsTimeout(dwTimeout);
  1324. }
  1325. }
  1326. }
  1327. else
  1328. {
  1329. hr = E_DAV_LOCK_NOT_FOUND;
  1330. goto ret;
  1331. }
  1332. ret:
  1333. return hr;
  1334. }
  1335. HRESULT HrDeleteLock(LARGE_INTEGER liLockID)
  1336. {
  1337. CSynchronizedWriteBlock swb(m_mrwCache);
  1338. CLockData * pLockData;
  1339. if (m_lockCacheById.FFetch(LIKey(liLockID),
  1340. &pLockData))
  1341. {
  1342. m_lockCacheById.Remove(LIKey(liLockID));
  1343. m_lockCacheByName.Remove(CRCWsziLI(pLockData->PwszResourceString(),
  1344. pLockData->LiLockID(),
  1345. TRUE));
  1346. delete pLockData;
  1347. }
  1348. return S_OK;
  1349. }
  1350. HRESULT HrGetAllLockDataForName(LPCWSTR pwszPath,
  1351. DWORD dwLockType,
  1352. DWORD * pdwLocksFound,
  1353. SNewLockData ** ppNewLockDatas,
  1354. LPWSTR ** ppwszLockTokens)
  1355. {
  1356. HRESULT hr = S_OK;
  1357. auto_co_task_mem<SNewLockData> a_pNewLockData;
  1358. auto_co_task_mem<LPWSTR> a_ppwszLockToken;
  1359. DWORD dwLocksFound;
  1360. {
  1361. CSynchronizedReadBlock srb(m_mrwCache);
  1362. COpGatherLockData op(pwszPath, dwLockType);
  1363. op.Invoke(m_lockCacheByName);
  1364. hr = op.HrLocksFound(&dwLocksFound);
  1365. if (FAILED(hr))
  1366. {
  1367. goto ret;
  1368. }
  1369. a_pNewLockData = static_cast<SNewLockData *>(CoTaskMemAlloc(sizeof(SNewLockData) * dwLocksFound));
  1370. if (NULL == a_pNewLockData.get())
  1371. {
  1372. hr = E_OUTOFMEMORY;
  1373. goto ret;
  1374. }
  1375. a_ppwszLockToken = static_cast<LPWSTR *>(CoTaskMemAlloc(sizeof(LPCWSTR) * dwLocksFound));
  1376. if (NULL == a_ppwszLockToken.get())
  1377. {
  1378. hr = E_OUTOFMEMORY;
  1379. goto ret;
  1380. }
  1381. hr = op.HrGetData(a_pNewLockData.get(), a_ppwszLockToken.get());
  1382. if (FAILED(hr))
  1383. {
  1384. goto ret;
  1385. }
  1386. }
  1387. *pdwLocksFound = dwLocksFound;
  1388. *ppNewLockDatas = a_pNewLockData.relinquish();
  1389. *ppwszLockTokens = a_ppwszLockToken.relinquish();
  1390. ret:
  1391. return hr;
  1392. }
  1393. };
  1394. // DAV File Handle Cache
  1395. //
  1396. class CFileHandleCache : public IFileHandleCache
  1397. {
  1398. static BOOL s_fHasBeenStarted;
  1399. static LONG s_cActiveComponents;
  1400. LONG m_cRef;
  1401. public:
  1402. static BOOL FNoActiveComponents();
  1403. // Constructor
  1404. //
  1405. CFileHandleCache();
  1406. virtual ~CFileHandleCache();
  1407. // IUnknown
  1408. //
  1409. virtual HRESULT __stdcall QueryInterface(REFIID iid,
  1410. void ** ppvObject);
  1411. virtual ULONG __stdcall AddRef();
  1412. virtual ULONG __stdcall Release();
  1413. // IFileHandleCache
  1414. //
  1415. virtual HRESULT __stdcall HrRegisterWorkerProcess(DWORD dwProcessId);
  1416. virtual HRESULT _stdcall HrGetGUIDString( UINT cchBufferLen,
  1417. WCHAR * pwszGUIDString,
  1418. UINT * pcchGUIDString);
  1419. virtual HRESULT __stdcall HrGetNewLockData(DWORD_PTR hFile,
  1420. DWORD dwProcessId,
  1421. DWORD dwSid,
  1422. BYTE * pbSid,
  1423. SNewLockData * pnld,
  1424. UINT cchBufferLen,
  1425. WCHAR * pwszLockToken,
  1426. UINT * pcchLockToken);
  1427. virtual HRESULT __stdcall HrGetLockData(LARGE_INTEGER liLockID,
  1428. DWORD dwSid,
  1429. BYTE * pbSid,
  1430. LPCWSTR pwszPath,
  1431. DWORD dwTimeout,
  1432. SNewLockData *pnld,
  1433. SLockHandleData * plhd,
  1434. UINT cchBufferLen,
  1435. WCHAR * pwszLockToken,
  1436. UINT * pcchLockToken);
  1437. virtual HRESULT __stdcall HrCheckLockID(LARGE_INTEGER liLockID,
  1438. DWORD dwSid,
  1439. BYTE * pbSid,
  1440. LPCWSTR pwszPath);
  1441. virtual HRESULT __stdcall HrDeleteLock(LARGE_INTEGER liLockID);
  1442. virtual HRESULT __stdcall HrGetAllLockDataForName(LPCWSTR pwszPath,
  1443. DWORD dwLockType,
  1444. DWORD * pdwLocksFound,
  1445. SNewLockData ** ppNewLockDatas,
  1446. LPWSTR ** ppwszLockTokens);
  1447. };
  1448. BOOL CFileHandleCache::s_fHasBeenStarted = FALSE;
  1449. LONG CFileHandleCache::s_cActiveComponents = 0;
  1450. CFileHandleCache::FNoActiveComponents()
  1451. {
  1452. if (0 == InterlockedCompareExchange(&s_cActiveComponents,
  1453. 0,
  1454. 0))
  1455. {
  1456. return s_fHasBeenStarted;
  1457. }
  1458. else
  1459. {
  1460. return FALSE;
  1461. }
  1462. }
  1463. CFileHandleCache::CFileHandleCache() : m_cRef(1)
  1464. {
  1465. InterlockedIncrement(&s_cActiveComponents);
  1466. s_fHasBeenStarted = TRUE;
  1467. }
  1468. CFileHandleCache::~CFileHandleCache()
  1469. {
  1470. InterlockedDecrement(&s_cActiveComponents);
  1471. }
  1472. HRESULT
  1473. CFileHandleCache::QueryInterface(REFIID iid,
  1474. void ** ppvObject)
  1475. {
  1476. HRESULT hr = S_OK;
  1477. if ((IID_IUnknown == iid) || (IID_IFileHandleCache == iid))
  1478. {
  1479. AddRef();
  1480. *ppvObject = static_cast<IFileHandleCache *>(this);
  1481. }
  1482. else
  1483. {
  1484. *ppvObject = NULL;
  1485. hr = E_NOINTERFACE;
  1486. }
  1487. return hr;
  1488. }
  1489. ULONG
  1490. CFileHandleCache::AddRef()
  1491. {
  1492. return InterlockedIncrement(&m_cRef);
  1493. }
  1494. ULONG
  1495. CFileHandleCache::Release()
  1496. {
  1497. if (0 == InterlockedDecrement(&m_cRef))
  1498. {
  1499. delete this;
  1500. return 0;
  1501. }
  1502. return m_cRef;
  1503. }
  1504. HRESULT
  1505. CFileHandleCache::HrRegisterWorkerProcess(DWORD dwProcessId)
  1506. {
  1507. HRESULT hr = S_OK;
  1508. auto_handle<HANDLE> a_hWP;
  1509. // Open the worker process handle so that we can synchronize on it
  1510. //
  1511. a_hWP = OpenProcess(SYNCHRONIZE,
  1512. FALSE,
  1513. dwProcessId);
  1514. if (NULL == a_hWP.get())
  1515. {
  1516. hr = HRESULT_FROM_WIN32(GetLastError());
  1517. DebugTrace ("Failed to open worker process handle 0x%08lX\n", hr);
  1518. goto ret;
  1519. }
  1520. // Add the handle to the handle pool, so that we could listen on it
  1521. //
  1522. hr = CHandlePool::Instance().HrAddHandle(a_hWP.get());
  1523. if (FAILED(hr))
  1524. {
  1525. DebugTrace ("Failed to add worker process handle 0x%08lX\n", hr);
  1526. goto ret;
  1527. }
  1528. a_hWP.relinquish();
  1529. ret:
  1530. return hr;
  1531. }
  1532. HRESULT
  1533. CFileHandleCache::HrGetGUIDString( UINT cchBufferLen,
  1534. WCHAR * pwszGUIDString,
  1535. UINT * pcchGUIDString)
  1536. {
  1537. return CLockCache::Instance().HrGetGUIDString(cchBufferLen,
  1538. pwszGUIDString,
  1539. pcchGUIDString);
  1540. }
  1541. HRESULT
  1542. CFileHandleCache::HrGetNewLockData(DWORD_PTR hFile,
  1543. DWORD dwProcessId,
  1544. DWORD dwSid,
  1545. BYTE * pbSid,
  1546. SNewLockData * pnld,
  1547. UINT cchBufferLen,
  1548. WCHAR * pwszLockToken,
  1549. UINT * pcchLockToken)
  1550. {
  1551. return CLockCache::Instance().HrGetNewLockData(reinterpret_cast<HANDLE>(hFile),
  1552. dwProcessId,
  1553. dwSid,
  1554. pbSid,
  1555. pnld,
  1556. cchBufferLen,
  1557. pwszLockToken,
  1558. pcchLockToken);
  1559. }
  1560. HRESULT
  1561. CFileHandleCache::HrGetLockData(LARGE_INTEGER liLockID,
  1562. DWORD dwSid,
  1563. BYTE * pbSid,
  1564. LPCWSTR pwszPath,
  1565. DWORD dwTimeout,
  1566. SNewLockData *pnld,
  1567. SLockHandleData * plhd,
  1568. UINT cchBufferLen,
  1569. WCHAR * pwszLockToken,
  1570. UINT * pcchLockToken)
  1571. {
  1572. return CLockCache::Instance().HrGetLockData(liLockID,
  1573. dwSid,
  1574. pbSid,
  1575. pwszPath,
  1576. dwTimeout,
  1577. pnld,
  1578. plhd,
  1579. cchBufferLen,
  1580. pwszLockToken,
  1581. pcchLockToken);
  1582. }
  1583. HRESULT
  1584. CFileHandleCache::HrCheckLockID(LARGE_INTEGER liLockID,
  1585. DWORD dwSid,
  1586. BYTE * pbSid,
  1587. LPCWSTR pwszPath)
  1588. {
  1589. return CLockCache::Instance().HrGetLockData(liLockID,
  1590. dwSid,
  1591. pbSid,
  1592. pwszPath,
  1593. 0,
  1594. NULL,
  1595. NULL,
  1596. 0,
  1597. NULL,
  1598. NULL);
  1599. }
  1600. HRESULT
  1601. CFileHandleCache::HrDeleteLock(LARGE_INTEGER liLockID)
  1602. {
  1603. return CLockCache::Instance().HrDeleteLock(liLockID);
  1604. }
  1605. HRESULT
  1606. CFileHandleCache::HrGetAllLockDataForName(LPCWSTR pwszPath,
  1607. DWORD dwLockType,
  1608. DWORD * pdwLocksFound,
  1609. SNewLockData ** ppNewLockDatas,
  1610. LPWSTR ** ppwszLockTokens)
  1611. {
  1612. return CLockCache::Instance().HrGetAllLockDataForName(pwszPath,
  1613. dwLockType,
  1614. pdwLocksFound,
  1615. ppNewLockDatas,
  1616. ppwszLockTokens);
  1617. }
  1618. // DAV File Handle Cache class factory
  1619. //
  1620. class CFileHandleCacheClassFactory : public IClassFactory
  1621. {
  1622. // Count of locks
  1623. //
  1624. static LONG s_cServerLocks;
  1625. static IUnknown * s_pIClassFactory;
  1626. static DWORD s_dwRegister;
  1627. LONG m_cRef;
  1628. public:
  1629. static HRESULT HrStartFactory();
  1630. static HRESULT HrStopFactory();
  1631. static BOOL FServerNotLocked();
  1632. // Constructor
  1633. //
  1634. CFileHandleCacheClassFactory();
  1635. // IUnknown
  1636. //
  1637. virtual HRESULT __stdcall QueryInterface(REFIID iid,
  1638. void** ppvObject) ;
  1639. virtual ULONG __stdcall AddRef() ;
  1640. virtual ULONG __stdcall Release() ;
  1641. // IClassFactory
  1642. //
  1643. virtual HRESULT __stdcall CreateInstance(IUnknown* pUnkOuter,
  1644. REFIID iid,
  1645. void ** ppvObject);
  1646. virtual HRESULT __stdcall LockServer(BOOL fLock);
  1647. };
  1648. LONG CFileHandleCacheClassFactory::s_cServerLocks = 0;
  1649. IUnknown * CFileHandleCacheClassFactory::s_pIClassFactory = NULL;
  1650. DWORD CFileHandleCacheClassFactory::s_dwRegister = 0;
  1651. HRESULT
  1652. CFileHandleCacheClassFactory::HrStartFactory()
  1653. {
  1654. HRESULT hr = S_OK;
  1655. auto_ref_ptr<IUnknown> a_pIClassFactory;
  1656. DWORD dwRegister;
  1657. a_pIClassFactory.take_ownership(new CFileHandleCacheClassFactory());
  1658. if (NULL == a_pIClassFactory.get())
  1659. {
  1660. hr = E_OUTOFMEMORY;
  1661. goto ret;
  1662. }
  1663. hr = CoRegisterClassObject(CLSID_FileHandleCache,
  1664. a_pIClassFactory.get(),
  1665. CLSCTX_LOCAL_SERVER,
  1666. REGCLS_MULTIPLEUSE,
  1667. &dwRegister);
  1668. if (FAILED(hr))
  1669. {
  1670. goto ret;
  1671. }
  1672. s_pIClassFactory = a_pIClassFactory.relinquish();
  1673. s_dwRegister = dwRegister;
  1674. ret:
  1675. return hr;
  1676. }
  1677. HRESULT
  1678. CFileHandleCacheClassFactory::HrStopFactory()
  1679. {
  1680. HRESULT hr = S_OK;
  1681. IUnknown * pIClassFactory;
  1682. DWORD dwRegister;
  1683. Assert(s_pIClassFactory);
  1684. Assert(s_dwRegister);
  1685. pIClassFactory = s_pIClassFactory;
  1686. dwRegister = s_dwRegister;
  1687. hr = CoRevokeClassObject(dwRegister);
  1688. if (FAILED(hr))
  1689. {
  1690. goto ret;
  1691. }
  1692. pIClassFactory->Release();
  1693. s_pIClassFactory = NULL;
  1694. s_dwRegister = 0;
  1695. ret:
  1696. return hr;
  1697. }
  1698. BOOL CFileHandleCacheClassFactory::FServerNotLocked()
  1699. {
  1700. return (0 == InterlockedCompareExchange(&s_cServerLocks,
  1701. 0,
  1702. 0));
  1703. }
  1704. CFileHandleCacheClassFactory::CFileHandleCacheClassFactory() : m_cRef(1)
  1705. {
  1706. }
  1707. HRESULT
  1708. CFileHandleCacheClassFactory::QueryInterface(REFIID iid,
  1709. void** ppvObject)
  1710. {
  1711. HRESULT hr = S_OK;
  1712. if ((IID_IUnknown == iid) || (IID_IClassFactory == iid))
  1713. {
  1714. AddRef();
  1715. *ppvObject = static_cast<IClassFactory *>(this);
  1716. }
  1717. else
  1718. {
  1719. *ppvObject = NULL;
  1720. hr = E_NOINTERFACE;
  1721. }
  1722. return hr;
  1723. }
  1724. ULONG
  1725. CFileHandleCacheClassFactory::AddRef()
  1726. {
  1727. return InterlockedIncrement(&m_cRef);
  1728. }
  1729. ULONG
  1730. CFileHandleCacheClassFactory::Release()
  1731. {
  1732. ULONG cRef = InterlockedDecrement(&m_cRef);
  1733. if (0 == cRef)
  1734. {
  1735. delete this;
  1736. return 0;
  1737. }
  1738. return cRef;
  1739. }
  1740. HRESULT
  1741. CFileHandleCacheClassFactory::CreateInstance(IUnknown* pUnkOuter,
  1742. REFIID iid,
  1743. void ** ppvObject)
  1744. {
  1745. HRESULT hr = S_OK;
  1746. auto_ref_ptr<IUnknown> a_pIFileHandleCache;
  1747. if (NULL != pUnkOuter)
  1748. {
  1749. // Don't allow aggregation. No need for it.
  1750. //
  1751. hr = CLASS_E_NOAGGREGATION;
  1752. goto ret;
  1753. }
  1754. a_pIFileHandleCache.take_ownership(new CFileHandleCache());
  1755. if (NULL == a_pIFileHandleCache.get())
  1756. {
  1757. hr = E_OUTOFMEMORY;
  1758. goto ret;
  1759. }
  1760. hr = a_pIFileHandleCache->QueryInterface(iid, ppvObject);
  1761. if (FAILED(hr))
  1762. {
  1763. goto ret;
  1764. }
  1765. ret:
  1766. return hr;
  1767. }
  1768. HRESULT
  1769. CFileHandleCacheClassFactory::LockServer(BOOL fLock)
  1770. {
  1771. if (fLock)
  1772. {
  1773. InterlockedIncrement(&s_cServerLocks);
  1774. }
  1775. else
  1776. {
  1777. InterlockedDecrement(&s_cServerLocks);
  1778. }
  1779. return S_OK;
  1780. }
  1781. BOOL FCanUnloadServer()
  1782. {
  1783. return (CFileHandleCache::FNoActiveComponents() && CFileHandleCacheClassFactory::FServerNotLocked());
  1784. }
  1785. // CHandlePool class
  1786. //
  1787. DWORD
  1788. CHandlePool::DwWaitOnWPs (PVOID pvThreadData)
  1789. {
  1790. DWORD dwRet;
  1791. CHandleArrayForHandlePool * pHandleArrayForHandlePool;
  1792. pHandleArrayForHandlePool = Instance().m_listHandleArrayForHandlePool.GetListHead();
  1793. Assert(NULL != pHandleArrayForHandlePool);
  1794. while (!FCanUnloadServer())
  1795. {
  1796. dwRet = WaitForMultipleObjects (pHandleArrayForHandlePool->UiGetHandleCount(), // nCount
  1797. pHandleArrayForHandlePool->PhGetHandles(), // lpHandles,
  1798. FALSE, // fWaitAll,
  1799. WAIT_POLL_PERIOD); // wait for specified period
  1800. switch (dwRet)
  1801. {
  1802. case WAIT_TIMEOUT:
  1803. pHandleArrayForHandlePool = pHandleArrayForHandlePool->GetNextListElementInCircle();
  1804. break;
  1805. case WAIT_OBJECT_0 + CHandleArrayForHandlePool::ih_external_update:
  1806. // Allow the updates to execute and then get the list head
  1807. // as the array you had may be already gone.
  1808. //
  1809. Instance().AllowUpdatesToExecute();
  1810. pHandleArrayForHandlePool = Instance().m_listHandleArrayForHandlePool.GetListHead();
  1811. break;
  1812. case WAIT_OBJECT_0 + CHandleArrayForHandlePool::ih_delete_timer:
  1813. CLockCache::Instance().DeleteLockTimerIfNotUsed();
  1814. break;
  1815. default:
  1816. Assert(CHandleArrayForHandlePool::ih_wp <= pHandleArrayForHandlePool->UiGetHandleCount());
  1817. if ((WAIT_OBJECT_0 + CHandleArrayForHandlePool::ih_wp <= dwRet) &&
  1818. (WAIT_OBJECT_0 + pHandleArrayForHandlePool->UiGetHandleCount() - 1 >= dwRet))
  1819. {
  1820. // Remove the handle and then get the list head
  1821. // as the array you had may be already gone.
  1822. //
  1823. Instance().RemoveHandleInternal(pHandleArrayForHandlePool, dwRet - WAIT_OBJECT_0);
  1824. pHandleArrayForHandlePool = Instance().m_listHandleArrayForHandlePool.GetListHead();
  1825. }
  1826. break;
  1827. }
  1828. };
  1829. // This call will loose all updates to be executed so incoming COM calls would
  1830. // not block waiting on permission to execute the update
  1831. //
  1832. Instance().AllowShutdownToExecute();
  1833. // This call will block untill all expiry callbacks have completed
  1834. //
  1835. CLockCache::Instance().DeleteLockTimerFinal();
  1836. // Post the quit message. We do this in a loop to catch
  1837. // the case if this code has been reached faster than
  1838. // the message queue was created on the original thread
  1839. //
  1840. while (0 == PostThreadMessage(s_dwMainTID,
  1841. WM_QUIT,
  1842. 0,
  1843. 0))
  1844. {
  1845. Sleep(WAIT_POLL_PERIOD);
  1846. }
  1847. return S_OK;
  1848. }
  1849. // ===============================================================
  1850. // File lock cache server registration routines
  1851. // ===============================================================
  1852. HRESULT HrRegisterServer(LPCWSTR pwszModulePath, // EXE module path
  1853. UINT cchModulePath, // Module path length
  1854. LPCWSTR pwszModuleName, // EXE module name
  1855. UINT cchModuleName, // Module name length
  1856. const CLSID& clsid) // Class ID
  1857. {
  1858. HRESULT hr = S_OK;
  1859. DWORD dwResult;
  1860. SECURITY_DESCRIPTOR sdAbsolute;
  1861. CStackBuffer<BYTE> pSidOwnerAndGroup;
  1862. CStackBuffer<BYTE> pSidIIS_WPG;
  1863. CStackBuffer<BYTE> pSidLocalService;
  1864. CStackBuffer<BYTE> pSidNetworkService;
  1865. CStackBuffer<WCHAR> pwszDomainName;
  1866. DWORD cbSidOwnerAndGroup = 0;
  1867. DWORD cbSidIIS_WPG = 0;
  1868. DWORD cbSidLocalService = 0;
  1869. DWORD cbSidNetworkService = 0;
  1870. DWORD cchDomainName = 0;
  1871. SID_NAME_USE snu;
  1872. CStackBuffer<BYTE> pACL;
  1873. DWORD cbACL = 0;
  1874. CStackBuffer<BYTE> pSelfRelativeSD;
  1875. DWORD cbSelfRelativeSD = 0;
  1876. CStackBuffer<WCHAR, (MAX_PATH + 1) * sizeof(WCHAR)> pwszKey;
  1877. CRegKey regKeyCLSID;
  1878. CRegKey regKeyCLSIDLocalServer;
  1879. CRegKey regKeyAppIdCLSID;
  1880. CRegKey regKeyAppIdModule;
  1881. auto_co_task_mem<WCHAR> pwszCLSID;
  1882. UINT cchCLSID;
  1883. // First of all try to build up security descriptor for launch permissions
  1884. //
  1885. // Initialize security descriptor
  1886. //
  1887. if (FALSE == InitializeSecurityDescriptor(&sdAbsolute,
  1888. SECURITY_DESCRIPTOR_REVISION))
  1889. {
  1890. hr = HRESULT_FROM_WIN32(GetLastError());
  1891. goto ret;
  1892. }
  1893. // Get the SID for the Administrators group
  1894. //
  1895. // Get the size of memory needed for the sid.
  1896. //
  1897. if (FALSE == CreateWellKnownSid(WinBuiltinAdministratorsSid,
  1898. NULL,
  1899. NULL,
  1900. &cbSidOwnerAndGroup))
  1901. {
  1902. hr = HRESULT_FROM_WIN32(GetLastError());
  1903. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  1904. {
  1905. goto ret;
  1906. }
  1907. else
  1908. {
  1909. hr = S_OK;
  1910. }
  1911. }
  1912. Assert (0 < cbSidOwnerAndGroup);
  1913. if (!pSidOwnerAndGroup.resize(cbSidOwnerAndGroup))
  1914. {
  1915. hr = E_OUTOFMEMORY;
  1916. goto ret;
  1917. }
  1918. // Ok now we can get the SID
  1919. //
  1920. if (FALSE == CreateWellKnownSid(WinBuiltinAdministratorsSid,
  1921. NULL,
  1922. pSidOwnerAndGroup.get(),
  1923. &cbSidOwnerAndGroup))
  1924. {
  1925. hr = HRESULT_FROM_WIN32(GetLastError());
  1926. goto ret;
  1927. }
  1928. // Set security descriptor owner and group
  1929. //
  1930. if (FALSE == SetSecurityDescriptorOwner(&sdAbsolute,
  1931. pSidOwnerAndGroup.get(),
  1932. FALSE))
  1933. {
  1934. hr = HRESULT_FROM_WIN32(GetLastError());
  1935. goto ret;
  1936. }
  1937. if (FALSE == SetSecurityDescriptorGroup(&sdAbsolute,
  1938. pSidOwnerAndGroup.get(),
  1939. FALSE))
  1940. {
  1941. hr = HRESULT_FROM_WIN32(GetLastError());
  1942. goto ret;
  1943. }
  1944. // Lookup IIS worker process group SID
  1945. //
  1946. if (FALSE == LookupAccountNameW(NULL,
  1947. gc_wszIIS_WPG,
  1948. NULL,
  1949. &cbSidIIS_WPG,
  1950. NULL,
  1951. &cchDomainName,
  1952. &snu))
  1953. {
  1954. hr = HRESULT_FROM_WIN32(GetLastError());
  1955. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  1956. {
  1957. goto ret;
  1958. }
  1959. else
  1960. {
  1961. hr = S_OK;
  1962. }
  1963. }
  1964. Assert (0 < cbSidIIS_WPG);
  1965. if (!pSidIIS_WPG.resize(cbSidIIS_WPG))
  1966. {
  1967. hr = E_OUTOFMEMORY;
  1968. goto ret;
  1969. }
  1970. if (!pwszDomainName.resize(cchDomainName * sizeof(WCHAR)))
  1971. {
  1972. hr = E_OUTOFMEMORY;
  1973. goto ret;
  1974. }
  1975. if (FALSE == LookupAccountNameW(NULL,
  1976. gc_wszIIS_WPG,
  1977. pSidIIS_WPG.get(),
  1978. &cbSidIIS_WPG,
  1979. pwszDomainName.get(),
  1980. &cchDomainName,
  1981. &snu))
  1982. {
  1983. hr = HRESULT_FROM_WIN32(GetLastError());
  1984. goto ret;
  1985. }
  1986. if (SidTypeAlias != snu)
  1987. {
  1988. hr = E_FAIL;
  1989. goto ret;
  1990. }
  1991. // Get the SID for the local service account
  1992. //
  1993. // Get the size of memory needed for the sid.
  1994. //
  1995. if (FALSE == CreateWellKnownSid(WinLocalServiceSid,
  1996. NULL,
  1997. NULL,
  1998. &cbSidLocalService))
  1999. {
  2000. hr = HRESULT_FROM_WIN32(GetLastError());
  2001. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  2002. {
  2003. goto ret;
  2004. }
  2005. else
  2006. {
  2007. hr = S_OK;
  2008. }
  2009. }
  2010. Assert (0 < cbSidLocalService);
  2011. if (!pSidLocalService.resize(cbSidLocalService))
  2012. {
  2013. hr = E_OUTOFMEMORY;
  2014. goto ret;
  2015. }
  2016. // Ok now we can get the SID
  2017. //
  2018. if (FALSE == CreateWellKnownSid(WinLocalServiceSid,
  2019. NULL,
  2020. pSidLocalService.get(),
  2021. &cbSidLocalService))
  2022. {
  2023. hr = HRESULT_FROM_WIN32(GetLastError());
  2024. goto ret;
  2025. }
  2026. // Get the SID for the network service account
  2027. //
  2028. // Get the size of memory needed for the sid.
  2029. //
  2030. if (FALSE == CreateWellKnownSid(WinNetworkServiceSid,
  2031. NULL,
  2032. NULL,
  2033. &cbSidNetworkService))
  2034. {
  2035. hr = HRESULT_FROM_WIN32(GetLastError());
  2036. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  2037. {
  2038. goto ret;
  2039. }
  2040. else
  2041. {
  2042. hr = S_OK;
  2043. }
  2044. }
  2045. Assert (0 < cbSidNetworkService);
  2046. if (!pSidNetworkService.resize(cbSidNetworkService))
  2047. {
  2048. hr = E_OUTOFMEMORY;
  2049. goto ret;
  2050. }
  2051. // Ok now we can get the SID
  2052. //
  2053. if (FALSE == CreateWellKnownSid(WinNetworkServiceSid,
  2054. NULL,
  2055. pSidNetworkService.get(),
  2056. &cbSidNetworkService))
  2057. {
  2058. hr = HRESULT_FROM_WIN32(GetLastError());
  2059. goto ret;
  2060. }
  2061. // Set up the launch permissions ACL
  2062. // We will be adding 4 aces
  2063. // 1. IIS_WPG
  2064. // 2. Administrators
  2065. // 3. Local Service
  2066. // 4. Network Service
  2067. //
  2068. cbACL = sizeof(ACL) +
  2069. (4 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof (DWORD))) +
  2070. GetLengthSid(pSidIIS_WPG.get()) +
  2071. GetLengthSid(pSidOwnerAndGroup.get()) +
  2072. GetLengthSid(pSidLocalService.get()) +
  2073. GetLengthSid(pSidNetworkService.get());
  2074. if (!pACL.resize(cbACL))
  2075. {
  2076. hr = E_OUTOFMEMORY;
  2077. goto ret;
  2078. }
  2079. if (FALSE == InitializeAcl(reinterpret_cast<PACL>(pACL.get()),
  2080. cbACL,
  2081. ACL_REVISION))
  2082. {
  2083. hr = HRESULT_FROM_WIN32(GetLastError());
  2084. goto ret;
  2085. }
  2086. if (FALSE == AddAccessAllowedAce(reinterpret_cast<PACL>(pACL.get()),
  2087. ACL_REVISION,
  2088. COM_RIGHTS_EXECUTE,
  2089. pSidIIS_WPG.get()))
  2090. {
  2091. hr = HRESULT_FROM_WIN32(GetLastError());
  2092. goto ret;
  2093. }
  2094. if (FALSE == AddAccessAllowedAce(reinterpret_cast<PACL>(pACL.get()),
  2095. ACL_REVISION,
  2096. COM_RIGHTS_EXECUTE,
  2097. pSidOwnerAndGroup.get()))
  2098. {
  2099. hr = HRESULT_FROM_WIN32(GetLastError());
  2100. goto ret;
  2101. }
  2102. if (FALSE == AddAccessAllowedAce(reinterpret_cast<PACL>(pACL.get()),
  2103. ACL_REVISION,
  2104. COM_RIGHTS_EXECUTE,
  2105. pSidLocalService.get()))
  2106. {
  2107. hr = HRESULT_FROM_WIN32(GetLastError());
  2108. goto ret;
  2109. }
  2110. if (FALSE == AddAccessAllowedAce(reinterpret_cast<PACL>(pACL.get()),
  2111. ACL_REVISION,
  2112. COM_RIGHTS_EXECUTE,
  2113. pSidNetworkService.get()))
  2114. {
  2115. hr = HRESULT_FROM_WIN32(GetLastError());
  2116. goto ret;
  2117. }
  2118. if (FALSE == SetSecurityDescriptorDacl(&sdAbsolute,
  2119. TRUE,
  2120. reinterpret_cast<PACL>(pACL.get()),
  2121. FALSE))
  2122. {
  2123. hr = HRESULT_FROM_WIN32(GetLastError());
  2124. goto ret;
  2125. }
  2126. // Make self relative security descriptor out of absolute for storing in the registry
  2127. //
  2128. if (FALSE == MakeSelfRelativeSD(&sdAbsolute,
  2129. NULL,
  2130. &cbSelfRelativeSD))
  2131. {
  2132. hr = HRESULT_FROM_WIN32(GetLastError());
  2133. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  2134. {
  2135. goto ret;
  2136. }
  2137. else
  2138. {
  2139. hr = S_OK;
  2140. }
  2141. }
  2142. if (!pSelfRelativeSD.resize(cbSelfRelativeSD))
  2143. {
  2144. hr = E_OUTOFMEMORY;
  2145. goto ret;
  2146. }
  2147. if (FALSE == MakeSelfRelativeSD(&sdAbsolute,
  2148. pSelfRelativeSD.get(),
  2149. &cbSelfRelativeSD))
  2150. {
  2151. hr = HRESULT_FROM_WIN32(GetLastError());
  2152. goto ret;
  2153. }
  2154. // Procceed with setting up registry keys
  2155. //
  2156. hr = StringFromCLSID(CLSID_FileHandleCache, &pwszCLSID);
  2157. if (FAILED(hr))
  2158. {
  2159. goto ret;
  2160. }
  2161. cchCLSID = static_cast<UINT>(wcslen(pwszCLSID.get()));
  2162. if (!pwszKey.resize((gc_cch_CLSIDWW + cchCLSID + 1) * sizeof(WCHAR)))
  2163. {
  2164. hr = E_OUTOFMEMORY;
  2165. goto ret;
  2166. }
  2167. memcpy(pwszKey.get(), gc_wsz_CLSIDWW, gc_cch_CLSIDWW * sizeof(WCHAR));
  2168. memcpy(pwszKey.get() + gc_cch_CLSIDWW, pwszCLSID.get(), cchCLSID * sizeof(WCHAR));
  2169. pwszKey[gc_cch_CLSIDWW + cchCLSID] = L'\0';
  2170. dwResult = regKeyCLSID.DwCreate(HKEY_CLASSES_ROOT, pwszKey.get());
  2171. if (ERROR_SUCCESS != dwResult)
  2172. {
  2173. hr = HRESULT_FROM_WIN32(dwResult);
  2174. goto ret;
  2175. }
  2176. dwResult = regKeyCLSID.DwSetValue(NULL,
  2177. REG_SZ,
  2178. gc_wsz_WebDAVFileHandleCache,
  2179. (gc_cch_WebDAVFileHandleCache + 1) * sizeof(WCHAR));
  2180. if (ERROR_SUCCESS != dwResult)
  2181. {
  2182. hr = HRESULT_FROM_WIN32(dwResult);
  2183. goto ret;
  2184. }
  2185. dwResult = regKeyCLSID.DwSetValue(gc_wsz_AppID,
  2186. REG_SZ,
  2187. pwszCLSID.get(),
  2188. (cchCLSID + 1) * sizeof(WCHAR));
  2189. if (ERROR_SUCCESS != dwResult)
  2190. {
  2191. hr = HRESULT_FROM_WIN32(dwResult);
  2192. goto ret;
  2193. }
  2194. if (!pwszKey.resize((gc_cch_CLSIDWW + cchCLSID + gc_cch_WWLocalServer32 + 1) * sizeof(WCHAR)))
  2195. {
  2196. hr = E_OUTOFMEMORY;
  2197. goto ret;
  2198. }
  2199. memcpy(pwszKey.get(), gc_wsz_CLSIDWW, gc_cch_CLSIDWW * sizeof(WCHAR));
  2200. memcpy(pwszKey.get() + gc_cch_CLSIDWW, pwszCLSID.get(), cchCLSID * sizeof(WCHAR));
  2201. memcpy(pwszKey.get() + gc_cch_CLSIDWW + cchCLSID, gc_wsz_WWLocalServer32, gc_cch_WWLocalServer32 * sizeof(WCHAR));
  2202. pwszKey[gc_cch_CLSIDWW + cchCLSID + gc_cch_WWLocalServer32] = L'\0';
  2203. dwResult = regKeyCLSIDLocalServer.DwCreate(HKEY_CLASSES_ROOT, pwszKey.get());
  2204. if (ERROR_SUCCESS != dwResult)
  2205. {
  2206. hr = HRESULT_FROM_WIN32(dwResult);
  2207. goto ret;
  2208. }
  2209. dwResult = regKeyCLSIDLocalServer.DwSetValue(NULL,
  2210. REG_SZ,
  2211. pwszModulePath,
  2212. (cchModulePath + 1) * sizeof(WCHAR));
  2213. if (ERROR_SUCCESS != dwResult)
  2214. {
  2215. hr = HRESULT_FROM_WIN32(dwResult);
  2216. goto ret;
  2217. }
  2218. if (!pwszKey.resize((gc_cch_AppIDWW + cchCLSID + 1) * sizeof(WCHAR)))
  2219. {
  2220. hr = E_OUTOFMEMORY;
  2221. goto ret;
  2222. }
  2223. memcpy(pwszKey.get(), gc_wsz_AppIDWW, gc_cch_AppIDWW * sizeof(WCHAR));
  2224. memcpy(pwszKey.get() + gc_cch_AppIDWW, pwszCLSID.get(), cchCLSID * sizeof(WCHAR));
  2225. pwszKey[gc_cch_AppIDWW + cchCLSID] = L'\0';
  2226. dwResult = regKeyAppIdCLSID.DwCreate(HKEY_CLASSES_ROOT, pwszKey.get());
  2227. if (ERROR_SUCCESS != dwResult)
  2228. {
  2229. hr = HRESULT_FROM_WIN32(dwResult);
  2230. goto ret;
  2231. }
  2232. dwResult = regKeyAppIdCLSID.DwSetValue(NULL,
  2233. REG_SZ,
  2234. gc_wsz_WebDAVFileHandleCache,
  2235. (gc_cch_WebDAVFileHandleCache + 1) * sizeof(WCHAR));
  2236. if (ERROR_SUCCESS != dwResult)
  2237. {
  2238. hr = HRESULT_FROM_WIN32(dwResult);
  2239. goto ret;
  2240. }
  2241. dwResult = regKeyAppIdCLSID.DwSetValue(gc_wszLaunchPermission,
  2242. REG_BINARY,
  2243. pSelfRelativeSD.get(),
  2244. cbSelfRelativeSD);
  2245. if (ERROR_SUCCESS != dwResult)
  2246. {
  2247. hr = HRESULT_FROM_WIN32(dwResult);
  2248. goto ret;
  2249. }
  2250. if (!pwszKey.resize((gc_cch_AppIDWW + cchModuleName + 1) * sizeof(WCHAR)))
  2251. {
  2252. hr = E_OUTOFMEMORY;
  2253. goto ret;
  2254. }
  2255. memcpy(pwszKey.get(), gc_wsz_AppIDWW, gc_cch_AppIDWW * sizeof(WCHAR));
  2256. memcpy(pwszKey.get() + gc_cch_AppIDWW, pwszModuleName, cchModuleName * sizeof(WCHAR));
  2257. pwszKey[gc_cch_AppIDWW + cchModuleName] = L'\0';
  2258. dwResult = regKeyAppIdModule.DwCreate(HKEY_CLASSES_ROOT, pwszKey.get());
  2259. if (ERROR_SUCCESS != dwResult)
  2260. {
  2261. hr = HRESULT_FROM_WIN32(dwResult);
  2262. goto ret;
  2263. }
  2264. dwResult = regKeyAppIdModule.DwSetValue(gc_wsz_AppID,
  2265. REG_SZ,
  2266. pwszCLSID.get(),
  2267. (cchCLSID + 1) * sizeof(WCHAR));
  2268. if (ERROR_SUCCESS != dwResult)
  2269. {
  2270. hr = HRESULT_FROM_WIN32(dwResult);
  2271. goto ret;
  2272. }
  2273. ret:
  2274. return hr;
  2275. }
  2276. HRESULT HrUnregisterServer(LPCWSTR pwszModuleName, // EXE module name
  2277. UINT cchModuleName, // Module name length
  2278. const CLSID& clsid) // Class ID)
  2279. {
  2280. HRESULT hr = S_OK;
  2281. DWORD dwResult;
  2282. CStackBuffer<WCHAR, (MAX_PATH + 1) * sizeof(WCHAR)> pwszKey;
  2283. auto_co_task_mem<WCHAR> pwszCLSID;
  2284. UINT cchCLSID;
  2285. hr = StringFromCLSID(CLSID_FileHandleCache, &pwszCLSID);
  2286. if (FAILED(hr))
  2287. {
  2288. goto ret;
  2289. }
  2290. cchCLSID = static_cast<UINT>(wcslen(pwszCLSID.get()));
  2291. if (!pwszKey.resize((gc_cch_CLSIDWW + cchCLSID + gc_cch_WWLocalServer32 + 1) * sizeof(WCHAR)))
  2292. {
  2293. hr = E_OUTOFMEMORY;
  2294. goto ret;
  2295. }
  2296. memcpy(pwszKey.get(), gc_wsz_CLSIDWW, gc_cch_CLSIDWW * sizeof(WCHAR));
  2297. memcpy(pwszKey.get() + gc_cch_CLSIDWW, pwszCLSID.get(), cchCLSID * sizeof(WCHAR));
  2298. memcpy(pwszKey.get() + gc_cch_CLSIDWW + cchCLSID, gc_wsz_WWLocalServer32, gc_cch_WWLocalServer32 * sizeof(WCHAR));
  2299. pwszKey[gc_cch_CLSIDWW + cchCLSID + gc_cch_WWLocalServer32] = L'\0';
  2300. dwResult = RegDeleteKeyW(HKEY_CLASSES_ROOT,
  2301. pwszKey.get());
  2302. if (ERROR_SUCCESS != dwResult && ERROR_FILE_NOT_FOUND != dwResult)
  2303. {
  2304. hr = HRESULT_FROM_WIN32(dwResult);
  2305. goto ret;
  2306. }
  2307. pwszKey[gc_cch_CLSIDWW + cchCLSID] = L'\0';
  2308. dwResult = RegDeleteKeyW(HKEY_CLASSES_ROOT,
  2309. pwszKey.get());
  2310. if (ERROR_SUCCESS != dwResult && ERROR_FILE_NOT_FOUND != dwResult)
  2311. {
  2312. hr = HRESULT_FROM_WIN32(dwResult);
  2313. goto ret;
  2314. }
  2315. if (!pwszKey.resize((gc_cch_AppIDWW + cchCLSID + 1) * sizeof(WCHAR)))
  2316. {
  2317. hr = E_OUTOFMEMORY;
  2318. goto ret;
  2319. }
  2320. memcpy(pwszKey.get(), gc_wsz_AppIDWW, gc_cch_AppIDWW * sizeof(WCHAR));
  2321. memcpy(pwszKey.get() + gc_cch_AppIDWW, pwszCLSID.get(), cchCLSID * sizeof(WCHAR));
  2322. pwszKey[gc_cch_AppIDWW + cchCLSID] = L'\0';
  2323. dwResult = RegDeleteKeyW(HKEY_CLASSES_ROOT,
  2324. pwszKey.get());
  2325. if (ERROR_SUCCESS != dwResult && ERROR_FILE_NOT_FOUND != dwResult)
  2326. {
  2327. hr = HRESULT_FROM_WIN32(dwResult);
  2328. goto ret;
  2329. }
  2330. if (!pwszKey.resize((gc_cch_AppIDWW + cchModuleName + 1) * sizeof(WCHAR)))
  2331. {
  2332. hr = E_OUTOFMEMORY;
  2333. goto ret;
  2334. }
  2335. memcpy(pwszKey.get(), gc_wsz_AppIDWW, gc_cch_AppIDWW * sizeof(WCHAR));
  2336. memcpy(pwszKey.get() + gc_cch_AppIDWW, pwszModuleName, cchModuleName * sizeof(WCHAR));
  2337. pwszKey[gc_cch_AppIDWW + cchModuleName] = L'\0';
  2338. dwResult = RegDeleteKeyW(HKEY_CLASSES_ROOT,
  2339. pwszKey.get());
  2340. if (ERROR_SUCCESS != dwResult && ERROR_FILE_NOT_FOUND != dwResult)
  2341. {
  2342. hr = HRESULT_FROM_WIN32(dwResult);
  2343. goto ret;
  2344. }
  2345. ret:
  2346. return hr;
  2347. }
  2348. HRESULT HrInitCOMSecurity ()
  2349. {
  2350. HRESULT hr = S_OK;
  2351. SECURITY_DESCRIPTOR sdAbsolute;
  2352. CStackBuffer<BYTE> pSidOwnerAndGroup;
  2353. CStackBuffer<BYTE> pSidIIS_WPG;
  2354. CStackBuffer<BYTE> pSidLocalService;
  2355. CStackBuffer<BYTE> pSidNetworkService;
  2356. CStackBuffer<WCHAR> pwszDomainName;
  2357. DWORD cbSidOwnerAndGroup = 0;
  2358. DWORD cbSidIIS_WPG = 0;
  2359. DWORD cbSidLocalService = 0;
  2360. DWORD cbSidNetworkService = 0;
  2361. DWORD cchDomainName = 0;
  2362. SID_NAME_USE snu;
  2363. CStackBuffer<BYTE> pACL;
  2364. DWORD cbACL = 0;
  2365. // First of all try to build up security descriptor for access permissions
  2366. //
  2367. // Initialize security descriptor
  2368. //
  2369. if (FALSE == InitializeSecurityDescriptor(&sdAbsolute,
  2370. SECURITY_DESCRIPTOR_REVISION))
  2371. {
  2372. hr = HRESULT_FROM_WIN32(GetLastError());
  2373. goto ret;
  2374. }
  2375. // Lookup owner and primary group SID
  2376. //
  2377. // Get the size of memory needed for the sid.
  2378. //
  2379. if (FALSE == CreateWellKnownSid(WinBuiltinAdministratorsSid,
  2380. NULL,
  2381. NULL,
  2382. &cbSidOwnerAndGroup))
  2383. {
  2384. hr = HRESULT_FROM_WIN32(GetLastError());
  2385. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  2386. {
  2387. goto ret;
  2388. }
  2389. else
  2390. {
  2391. hr = S_OK;
  2392. }
  2393. }
  2394. Assert (0 < cbSidOwnerAndGroup);
  2395. if (!pSidOwnerAndGroup.resize(cbSidOwnerAndGroup))
  2396. {
  2397. hr = E_OUTOFMEMORY;
  2398. goto ret;
  2399. }
  2400. // Ok now we can get the SID
  2401. //
  2402. if (FALSE == CreateWellKnownSid(WinBuiltinAdministratorsSid,
  2403. NULL,
  2404. pSidOwnerAndGroup.get(),
  2405. &cbSidOwnerAndGroup))
  2406. {
  2407. hr = HRESULT_FROM_WIN32(GetLastError());
  2408. goto ret;
  2409. }
  2410. // Set security descriptor owner and group
  2411. //
  2412. if (FALSE == SetSecurityDescriptorOwner(&sdAbsolute,
  2413. pSidOwnerAndGroup.get(),
  2414. FALSE))
  2415. {
  2416. hr = HRESULT_FROM_WIN32(GetLastError());
  2417. goto ret;
  2418. }
  2419. if (FALSE == SetSecurityDescriptorGroup(&sdAbsolute,
  2420. pSidOwnerAndGroup.get(),
  2421. FALSE))
  2422. {
  2423. hr = HRESULT_FROM_WIN32(GetLastError());
  2424. goto ret;
  2425. }
  2426. // Lookup IIS worker process group SID
  2427. //
  2428. if (FALSE == LookupAccountNameW(NULL,
  2429. gc_wszIIS_WPG,
  2430. NULL,
  2431. &cbSidIIS_WPG,
  2432. NULL,
  2433. &cchDomainName,
  2434. &snu))
  2435. {
  2436. hr = HRESULT_FROM_WIN32(GetLastError());
  2437. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  2438. {
  2439. goto ret;
  2440. }
  2441. else
  2442. {
  2443. hr = S_OK;
  2444. }
  2445. }
  2446. Assert (0 < cbSidIIS_WPG);
  2447. if (!pSidIIS_WPG.resize(cbSidIIS_WPG))
  2448. {
  2449. hr = E_OUTOFMEMORY;
  2450. goto ret;
  2451. }
  2452. if (!pwszDomainName.resize(cchDomainName * sizeof(WCHAR)))
  2453. {
  2454. hr = E_OUTOFMEMORY;
  2455. goto ret;
  2456. }
  2457. if (FALSE == LookupAccountNameW(NULL,
  2458. gc_wszIIS_WPG,
  2459. pSidIIS_WPG.get(),
  2460. &cbSidIIS_WPG,
  2461. pwszDomainName.get(),
  2462. &cchDomainName,
  2463. &snu))
  2464. {
  2465. hr = HRESULT_FROM_WIN32(GetLastError());
  2466. goto ret;
  2467. }
  2468. if (SidTypeAlias != snu)
  2469. {
  2470. hr = E_FAIL;
  2471. goto ret;
  2472. }
  2473. // Get the SID for the local service account
  2474. //
  2475. // Get the size of memory needed for the sid.
  2476. //
  2477. if (FALSE == CreateWellKnownSid(WinLocalServiceSid,
  2478. NULL,
  2479. NULL,
  2480. &cbSidLocalService))
  2481. {
  2482. hr = HRESULT_FROM_WIN32(GetLastError());
  2483. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  2484. {
  2485. goto ret;
  2486. }
  2487. else
  2488. {
  2489. hr = S_OK;
  2490. }
  2491. }
  2492. Assert (0 < cbSidLocalService);
  2493. if (!pSidLocalService.resize(cbSidLocalService))
  2494. {
  2495. hr = E_OUTOFMEMORY;
  2496. goto ret;
  2497. }
  2498. // Ok now we can get the SID
  2499. //
  2500. if (FALSE == CreateWellKnownSid(WinLocalServiceSid,
  2501. NULL,
  2502. pSidLocalService.get(),
  2503. &cbSidLocalService))
  2504. {
  2505. hr = HRESULT_FROM_WIN32(GetLastError());
  2506. goto ret;
  2507. }
  2508. // Get the SID for the network service account
  2509. //
  2510. // Get the size of memory needed for the sid.
  2511. //
  2512. if (FALSE == CreateWellKnownSid(WinNetworkServiceSid,
  2513. NULL,
  2514. NULL,
  2515. &cbSidNetworkService))
  2516. {
  2517. hr = HRESULT_FROM_WIN32(GetLastError());
  2518. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  2519. {
  2520. goto ret;
  2521. }
  2522. else
  2523. {
  2524. hr = S_OK;
  2525. }
  2526. }
  2527. Assert (0 < cbSidNetworkService);
  2528. if (!pSidNetworkService.resize(cbSidNetworkService))
  2529. {
  2530. hr = E_OUTOFMEMORY;
  2531. goto ret;
  2532. }
  2533. // Ok now we can get the SID
  2534. //
  2535. if (FALSE == CreateWellKnownSid(WinNetworkServiceSid,
  2536. NULL,
  2537. pSidNetworkService.get(),
  2538. &cbSidNetworkService))
  2539. {
  2540. hr = HRESULT_FROM_WIN32(GetLastError());
  2541. goto ret;
  2542. }
  2543. // Set up the launch permissions ACL
  2544. // We will be adding 4 aces
  2545. // 1. IIS_WPG
  2546. // 2. Administrators
  2547. // 3. Local Service
  2548. // 4. Network Service
  2549. //
  2550. cbACL = sizeof(ACL) +
  2551. (4 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof (DWORD))) +
  2552. GetLengthSid(pSidIIS_WPG.get()) +
  2553. GetLengthSid(pSidOwnerAndGroup.get()) +
  2554. GetLengthSid(pSidLocalService.get()) +
  2555. GetLengthSid(pSidNetworkService.get());
  2556. if (!pACL.resize(cbACL))
  2557. {
  2558. hr = E_OUTOFMEMORY;
  2559. goto ret;
  2560. }
  2561. if (FALSE == InitializeAcl(reinterpret_cast<PACL>(pACL.get()),
  2562. cbACL,
  2563. ACL_REVISION))
  2564. {
  2565. hr = HRESULT_FROM_WIN32(GetLastError());
  2566. goto ret;
  2567. }
  2568. if (FALSE == AddAccessAllowedAce(reinterpret_cast<PACL>(pACL.get()),
  2569. ACL_REVISION,
  2570. COM_RIGHTS_EXECUTE,
  2571. pSidIIS_WPG.get()))
  2572. {
  2573. hr = HRESULT_FROM_WIN32(GetLastError());
  2574. goto ret;
  2575. }
  2576. if (FALSE == AddAccessAllowedAce(reinterpret_cast<PACL>(pACL.get()),
  2577. ACL_REVISION,
  2578. COM_RIGHTS_EXECUTE,
  2579. pSidOwnerAndGroup.get()))
  2580. {
  2581. hr = HRESULT_FROM_WIN32(GetLastError());
  2582. goto ret;
  2583. }
  2584. if (FALSE == AddAccessAllowedAce(reinterpret_cast<PACL>(pACL.get()),
  2585. ACL_REVISION,
  2586. COM_RIGHTS_EXECUTE,
  2587. pSidLocalService.get()))
  2588. {
  2589. hr = HRESULT_FROM_WIN32(GetLastError());
  2590. goto ret;
  2591. }
  2592. if (FALSE == AddAccessAllowedAce(reinterpret_cast<PACL>(pACL.get()),
  2593. ACL_REVISION,
  2594. COM_RIGHTS_EXECUTE,
  2595. pSidNetworkService.get()))
  2596. {
  2597. hr = HRESULT_FROM_WIN32(GetLastError());
  2598. goto ret;
  2599. }
  2600. if (FALSE == SetSecurityDescriptorDacl(&sdAbsolute,
  2601. TRUE,
  2602. reinterpret_cast<PACL>(pACL.get()),
  2603. FALSE))
  2604. {
  2605. hr = HRESULT_FROM_WIN32(GetLastError());
  2606. goto ret;
  2607. }
  2608. hr = CoInitializeSecurity(&sdAbsolute,
  2609. -1,
  2610. NULL,
  2611. NULL,
  2612. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  2613. RPC_C_IMP_LEVEL_IDENTIFY,
  2614. NULL,
  2615. EOAC_DYNAMIC_CLOAKING | EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL,
  2616. NULL);
  2617. if (FAILED(hr))
  2618. {
  2619. goto ret;
  2620. }
  2621. ret:
  2622. return hr;
  2623. }
  2624. HRESULT HrExecuteServer()
  2625. {
  2626. HRESULT hr = S_OK;
  2627. HANDLE hThread;
  2628. MSG msg;
  2629. // Save of the current thread ID so that the thread we will create
  2630. // would know who post pessages to
  2631. //
  2632. s_dwMainTID = GetCurrentThreadId();
  2633. // Now create thread that waits on events and WP handles
  2634. //
  2635. hThread = CreateThread (NULL, // lpThreadAttributes
  2636. 0, // dwStackSize, ignored
  2637. CHandlePool::DwWaitOnWPs, // lpStartAddress
  2638. NULL, // lpParam
  2639. 0, // Start immediately
  2640. NULL); // lpThreadId
  2641. if (NULL == hThread)
  2642. {
  2643. hr = HRESULT_FROM_WIN32(GetLastError());
  2644. DebugTrace ("CreateThread failed 0x%08lX\n", hr);
  2645. goto ret;
  2646. }
  2647. // We need to close the handle to avoid having the thread object remains in the system forever.
  2648. //
  2649. CloseHandle(hThread);
  2650. // Wait for shutdown message that will be posted by the thread we created above
  2651. //
  2652. while (::GetMessage(&msg, 0, 0, 0))
  2653. {
  2654. ::DispatchMessage(&msg) ;
  2655. }
  2656. ret:
  2657. return msg.wParam;
  2658. }
  2659. // ===============================================================
  2660. // Main Routine
  2661. // ===============================================================
  2662. int WINAPI WinMain(HINSTANCE hInstance,
  2663. HINSTANCE hPrevInstance,
  2664. LPSTR lpCmdLine,
  2665. int nCmdShow)
  2666. {
  2667. HRESULT hr = S_OK;
  2668. BOOL fStartDAVFileCacheServer = FALSE;
  2669. BOOL fHeapInitialized = FALSE;
  2670. BOOL fCOMInitialized = FALSE;
  2671. BOOL fClassFactoryStarted = FALSE;
  2672. // Setup the heap for the process
  2673. //
  2674. if (!g_heap.FInit())
  2675. {
  2676. hr = E_OUTOFMEMORY;
  2677. DebugTrace ("Heap initialization failed 0x%08lX\n", hr);
  2678. goto ret;
  2679. }
  2680. fHeapInitialized = TRUE;
  2681. {
  2682. CStackBuffer<WCHAR, (MAX_PATH + 1) * sizeof(WCHAR)> pwszModulePath;
  2683. UINT cchModulePath = MAX_PATH + 1;
  2684. LPWSTR pwszModuleName;
  2685. UINT cchModuleName;
  2686. LPWSTR * argv;
  2687. INT argc = 0;
  2688. cchModulePath = GetModuleFileNameW(NULL,
  2689. pwszModulePath.get(),
  2690. cchModulePath);
  2691. if (0 == cchModulePath)
  2692. {
  2693. hr = HRESULT_FROM_WIN32(GetLastError());
  2694. DebugTrace ("Getting module path failed 0x%08lX\n", hr);
  2695. goto ret;
  2696. }
  2697. pwszModuleName = wcsrchr(pwszModulePath.get(), L'\\');
  2698. if (NULL == pwszModuleName)
  2699. {
  2700. pwszModuleName = wcsrchr(pwszModulePath.get(), L':');
  2701. }
  2702. if (pwszModuleName)
  2703. {
  2704. while (L'\\' == pwszModuleName[0] ||
  2705. L':' == pwszModuleName[0])
  2706. {
  2707. pwszModuleName++;
  2708. }
  2709. }
  2710. else
  2711. {
  2712. pwszModuleName = pwszModulePath.get();
  2713. }
  2714. cchModuleName = static_cast<UINT>(wcslen(pwszModuleName));
  2715. argv = CommandLineToArgvW(GetCommandLineW(),
  2716. &argc);
  2717. if (NULL == argv)
  2718. {
  2719. hr = HRESULT_FROM_WIN32(GetLastError());
  2720. DebugTrace ("Getting argument list failed 0x%08lX\n", hr);
  2721. goto ret;
  2722. }
  2723. // Do not fail up to the GlobalFree call
  2724. // If command line has parameters...
  2725. //
  2726. if (2 == argc)
  2727. {
  2728. if (!_wcsicmp(argv[1], gc_wsz_RegServer))
  2729. {
  2730. hr = HrRegisterServer(pwszModulePath.get(),
  2731. cchModulePath,
  2732. pwszModuleName,
  2733. cchModuleName,
  2734. CLSID_FileHandleCache);
  2735. }
  2736. else if (!_wcsicmp(argv[1], gc_wsz_UnregServer))
  2737. {
  2738. hr = HrUnregisterServer(pwszModuleName,
  2739. cchModuleName,
  2740. CLSID_FileHandleCache);
  2741. }
  2742. else if (!_wcsicmp(argv[1], gc_wsz_Embedding))
  2743. {
  2744. fStartDAVFileCacheServer = TRUE;
  2745. }
  2746. }
  2747. if (NULL != GlobalFree(argv))
  2748. {
  2749. hr = HRESULT_FROM_WIN32(GetLastError());
  2750. DebugTrace ("Freeing argument list failed 0x%08lX\n", hr);
  2751. goto ret;
  2752. }
  2753. if (!fStartDAVFileCacheServer)
  2754. {
  2755. goto ret;
  2756. }
  2757. }
  2758. // Setup lock cache
  2759. //
  2760. hr = CLockCache::CreateInstance().HrInitialize();
  2761. if (FAILED(hr))
  2762. {
  2763. DebugTrace ("Lock cache initialization failed 0x%08lX\n", hr);
  2764. goto ret;
  2765. }
  2766. // Setup handle pool for worker process handles
  2767. //
  2768. hr = CHandlePool::CreateInstance().HrInitialize();
  2769. if (FAILED(hr))
  2770. {
  2771. DebugTrace ("Handle pool initialization failed 0x%08lX\n", hr);
  2772. goto ret;
  2773. }
  2774. hr = CoInitializeEx(NULL,
  2775. COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY);
  2776. if (FAILED(hr))
  2777. {
  2778. DebugTrace ("COM initialization failed 0x%08lX\n", hr);
  2779. goto ret;
  2780. }
  2781. fCOMInitialized = TRUE;
  2782. hr = HrInitCOMSecurity ();
  2783. if (FAILED(hr))
  2784. {
  2785. DebugTrace ("COM security initialization failed 0x%08lX\n", hr);
  2786. goto ret;
  2787. }
  2788. hr = CFileHandleCacheClassFactory::HrStartFactory();
  2789. if (FAILED(hr))
  2790. {
  2791. DebugTrace ("File handle cache class factory startup failed 0x%08lX\n", hr);
  2792. goto ret;
  2793. }
  2794. fClassFactoryStarted = TRUE;
  2795. hr = HrExecuteServer();
  2796. if (FAILED(hr))
  2797. {
  2798. DebugTrace ("Run failed 0x%08lX\n", hr);
  2799. goto ret;
  2800. }
  2801. ret:
  2802. if (fClassFactoryStarted)
  2803. {
  2804. (VOID) CFileHandleCacheClassFactory::HrStopFactory();
  2805. }
  2806. if (fCOMInitialized)
  2807. {
  2808. CoUninitialize();
  2809. }
  2810. // Singleton takes care of tracking if it was initialized or not itself,
  2811. // so we simply always call DestroyInstance()
  2812. //
  2813. CHandlePool::DestroyInstance();
  2814. CLockCache::DestroyInstance();
  2815. if (fHeapInitialized)
  2816. {
  2817. g_heap.Deinit();
  2818. }
  2819. return hr;
  2820. }