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

803 lines
23 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 2001
  6. //
  7. // File: admin.cpp
  8. //
  9. // Authors;
  10. // Jeff Saathoff (jeffreys)
  11. //
  12. // Notes;
  13. // Support for Administratively pinned folders
  14. //--------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "strings.h"
  18. #include "registry.h"
  19. DWORD WINAPI _PinAdminFoldersThread(LPVOID);
  20. //*************************************************************
  21. //
  22. // ApplyAdminFolderPolicy
  23. //
  24. // Purpose: Pin the admin folder list
  25. //
  26. // Parameters: none
  27. //
  28. // Return: none
  29. //
  30. // Notes:
  31. //
  32. //*************************************************************
  33. void
  34. ApplyAdminFolderPolicy(void)
  35. {
  36. BOOL bNoNet = FALSE;
  37. CSCIsServerOffline(NULL, &bNoNet);
  38. if (!bNoNet)
  39. {
  40. SHCreateThread(_PinAdminFoldersThread, NULL, CTF_COINIT | CTF_FREELIBANDEXIT, NULL);
  41. }
  42. }
  43. //
  44. // Does a particular path exist in the DPA of path strings?
  45. //
  46. BOOL
  47. ExistsAPF(
  48. HDPA hdpa,
  49. LPCTSTR pszPath
  50. )
  51. {
  52. const int cItems = DPA_GetPtrCount(hdpa);
  53. for (int i = 0; i < cItems; i++)
  54. {
  55. LPCTSTR pszItem = (LPCTSTR)DPA_GetPtr(hdpa, i);
  56. if (pszItem && (0 == lstrcmpi(pszItem, pszPath)))
  57. return TRUE;
  58. }
  59. return FALSE;
  60. }
  61. BOOL
  62. ReadAPFFromRegistry(HDPA hdpaFiles)
  63. {
  64. const HKEY rghkeyRoots[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
  65. for (int i = 0; i < ARRAYSIZE(rghkeyRoots); i++)
  66. {
  67. HKEY hKey;
  68. // Read in the Administratively pinned folder list.
  69. if (ERROR_SUCCESS == RegOpenKeyEx(rghkeyRoots[i], c_szRegKeyAPF, 0, KEY_QUERY_VALUE, &hKey))
  70. {
  71. TCHAR szName[MAX_PATH];
  72. DWORD dwIndex = 0, dwSize = ARRAYSIZE(szName);
  73. while (ERROR_SUCCESS == _RegEnumValueExp(hKey, dwIndex, szName, &dwSize, NULL, NULL, NULL, NULL))
  74. {
  75. if (!ExistsAPF(hdpaFiles, szName))
  76. {
  77. LPTSTR pszDup;
  78. if (LocalAllocString(&pszDup, szName))
  79. {
  80. if (-1 == DPA_AppendPtr(hdpaFiles, pszDup))
  81. {
  82. LocalFreeString(&pszDup);
  83. }
  84. }
  85. }
  86. dwSize = ARRAYSIZE(szName);
  87. dwIndex++;
  88. }
  89. RegCloseKey(hKey);
  90. }
  91. }
  92. return TRUE;
  93. }
  94. BOOL
  95. BuildFRList(HDPA hdpaFiles)
  96. {
  97. HKEY hKey;
  98. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"), 0, KEY_QUERY_VALUE, &hKey))
  99. {
  100. TCHAR szName[MAX_PATH];
  101. DWORD cchName = ARRAYSIZE(szName);
  102. TCHAR szValue[MAX_PATH];
  103. DWORD cbValue = sizeof(szValue);
  104. DWORD dwIndex = 0;
  105. while (ERROR_SUCCESS == RegEnumValue(hKey,
  106. dwIndex,
  107. szName,
  108. &cchName,
  109. NULL,
  110. NULL,
  111. (LPBYTE)szValue,
  112. &cbValue))
  113. {
  114. LPTSTR pszUNC = NULL;
  115. GetRemotePath(szValue, &pszUNC);
  116. if (pszUNC)
  117. {
  118. if (-1 == DPA_AppendPtr(hdpaFiles, pszUNC))
  119. {
  120. LocalFreeString(&pszUNC);
  121. }
  122. }
  123. cchName = ARRAYSIZE(szName);
  124. cbValue = sizeof(szValue);
  125. dwIndex++;
  126. }
  127. RegCloseKey(hKey);
  128. }
  129. return TRUE;
  130. }
  131. BOOL
  132. ReconcileAPF(HDPA hdpaPin, HDPA hdpaUnpin)
  133. {
  134. HKEY hKey;
  135. int cItems;
  136. int i;
  137. //
  138. // First, try to convert everything to UNC
  139. //
  140. cItems = DPA_GetPtrCount(hdpaPin);
  141. for (i = 0; i < cItems; i++)
  142. {
  143. LPTSTR pszItem = (LPTSTR)DPA_GetPtr(hdpaPin, i);
  144. if (!PathIsUNC(pszItem))
  145. {
  146. LPTSTR pszUNC = NULL;
  147. GetRemotePath(pszItem, &pszUNC);
  148. if (pszUNC)
  149. {
  150. DPA_SetPtr(hdpaPin, i, pszUNC);
  151. LocalFree(pszItem);
  152. }
  153. }
  154. }
  155. // Read in the previous Administratively pinned folder list for this user.
  156. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegKeyAPFResult, 0, KEY_QUERY_VALUE, &hKey))
  157. {
  158. TCHAR szName[MAX_PATH];
  159. DWORD dwIndex = 0, dwSize = ARRAYSIZE(szName);
  160. while (ERROR_SUCCESS == _RegEnumValueExp(hKey, dwIndex, szName, &dwSize, NULL, NULL, NULL, NULL))
  161. {
  162. if (!ExistsAPF(hdpaPin, szName))
  163. {
  164. LPTSTR pszDup = NULL;
  165. // This one is not in the new list, save it in the Unpin list
  166. if (LocalAllocString(&pszDup, szName))
  167. {
  168. if (-1 == DPA_AppendPtr(hdpaUnpin, pszDup))
  169. {
  170. LocalFreeString(&pszDup);
  171. }
  172. }
  173. }
  174. dwSize = ARRAYSIZE(szName);
  175. dwIndex++;
  176. }
  177. RegCloseKey(hKey);
  178. }
  179. // Save out the new admin pin list for this user
  180. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER,
  181. c_szRegKeyAPFResult,
  182. 0,
  183. NULL,
  184. REG_OPTION_NON_VOLATILE,
  185. KEY_SET_VALUE,
  186. NULL,
  187. &hKey,
  188. NULL))
  189. {
  190. // Add reg entries from the Pin list
  191. cItems = DPA_GetPtrCount(hdpaPin);
  192. for (i = 0; i < cItems; i++)
  193. {
  194. DWORD dwValue = 0;
  195. RegSetValueEx(hKey, (LPCTSTR)DPA_GetPtr(hdpaPin, i), 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
  196. }
  197. // Remove reg entries from the Unpin list
  198. cItems = DPA_GetPtrCount(hdpaUnpin);
  199. for (i = 0; i < cItems; i++)
  200. {
  201. RegDeleteValue(hKey, (LPCTSTR)DPA_GetPtr(hdpaUnpin, i));
  202. }
  203. RegCloseKey(hKey);
  204. }
  205. return TRUE;
  206. }
  207. DWORD WINAPI
  208. _AdminFillCallback(LPCTSTR /*pszName*/,
  209. DWORD /*dwStatus*/,
  210. DWORD /*dwHintFlags*/,
  211. DWORD /*dwPinCount*/,
  212. LPWIN32_FIND_DATA /*pFind32*/,
  213. DWORD /*dwReason*/,
  214. DWORD /*dwParam1*/,
  215. DWORD /*dwParam2*/,
  216. DWORD_PTR /*dwContext*/)
  217. {
  218. if (WAIT_OBJECT_0 == WaitForSingleObject(g_heventTerminate, 0))
  219. return CSCPROC_RETURN_ABORT;
  220. return CSCPROC_RETURN_CONTINUE;
  221. }
  222. void
  223. _DoAdminPin(LPCTSTR pszItem, LPWIN32_FIND_DATA pFind32)
  224. {
  225. DWORD dwHintFlags = 0;
  226. TraceEnter(TRACE_ADMINPIN, "_DoAdminPin");
  227. if (!pszItem || !*pszItem)
  228. TraceLeaveVoid();
  229. TraceAssert(PathIsUNC(pszItem));
  230. // This may fail, for example if the file is not in the cache
  231. CSCQueryFileStatus(pszItem, NULL, NULL, &dwHintFlags);
  232. // Is the admin flag already turned on?
  233. if (!(dwHintFlags & FLAG_CSC_HINT_PIN_ADMIN))
  234. {
  235. //
  236. // Pin the item
  237. //
  238. if (CSCPinFile(pszItem,
  239. dwHintFlags | FLAG_CSC_HINT_PIN_ADMIN,
  240. NULL,
  241. NULL,
  242. &dwHintFlags))
  243. {
  244. ShellChangeNotify(pszItem, pFind32, FALSE);
  245. }
  246. }
  247. //
  248. // Make sure files are filled.
  249. //
  250. // Yes, this takes longer, and isn't necessary if you stay logged
  251. // on, since the CSC agent fills everything in the background.
  252. //
  253. // However, JDP's are using this with laptop pools, and for
  254. // people who logon just to get the latest stuff, then immediately
  255. // disconnect their laptop and hit the road. They need to have
  256. // everything filled right away.
  257. //
  258. if (!pFind32 || !(pFind32->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  259. {
  260. CSCFillSparseFiles(pszItem, FALSE, _AdminFillCallback, 0);
  261. }
  262. Trace((TEXT("AdminPin %s"), pszItem));
  263. TraceLeaveVoid();
  264. }
  265. void
  266. _PinLinkTarget(LPCTSTR pszLink)
  267. {
  268. LPTSTR pszTarget = NULL;
  269. TraceEnter(TRACE_ADMINPIN, "_PinLinkTarget");
  270. TraceAssert(pszLink);
  271. // We only want to pin a link target if it's a file (not a directory).
  272. // GetLinkTarget does this check and only returns files.
  273. GetLinkTarget(pszLink, &pszTarget, NULL);
  274. if (pszTarget)
  275. {
  276. WIN32_FIND_DATA fd = {0};
  277. LPCTSTR pszT = PathFindFileName(pszTarget);
  278. fd.dwFileAttributes = 0;
  279. lstrcpyn(fd.cFileName, pszT ? pszT : pszTarget, ARRAYSIZE(fd.cFileName));
  280. // Pin the target
  281. _DoAdminPin(pszTarget, &fd);
  282. LocalFree(pszTarget);
  283. }
  284. TraceLeaveVoid();
  285. }
  286. // export this from shell32.dll
  287. BOOL PathIsShortcut(LPCTSTR pszItem, DWORD dwAttributes)
  288. {
  289. BOOL bIsShortcut = FALSE;
  290. SHFILEINFO sfi;
  291. sfi.dwAttributes = SFGAO_LINK;
  292. if (SHGetFileInfo(pszItem, dwAttributes, &sfi, sizeof(sfi), SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED | SHGFI_USEFILEATTRIBUTES))
  293. {
  294. bIsShortcut = (sfi.dwAttributes & SFGAO_LINK);
  295. }
  296. return bIsShortcut;
  297. }
  298. DWORD WINAPI
  299. _PinAdminFolderCallback(LPCTSTR pszItem,
  300. ENUM_REASON eReason,
  301. LPWIN32_FIND_DATA pFind32,
  302. LPARAM /*lpContext*/)
  303. {
  304. TraceEnter(TRACE_ADMINPIN, "_PinAdminFolderCallback");
  305. TraceAssert(pszItem);
  306. if (WAIT_OBJECT_0 == WaitForSingleObject(g_heventTerminate, 0))
  307. TraceLeaveValue(CSCPROC_RETURN_ABORT);
  308. if (!pszItem || !*pszItem)
  309. TraceLeaveValue(CSCPROC_RETURN_SKIP);
  310. if (eReason == ENUM_REASON_FILE || eReason == ENUM_REASON_FOLDER_BEGIN)
  311. {
  312. // If it's a link, pin the target
  313. if (PathIsShortcut(pszItem, pFind32 ? pFind32->dwFileAttributes : 0))
  314. _PinLinkTarget(pszItem);
  315. // Pin the item
  316. if (PathIsUNC(pszItem))
  317. _DoAdminPin(pszItem, pFind32);
  318. }
  319. TraceLeaveValue(CSCPROC_RETURN_CONTINUE);
  320. }
  321. void
  322. _UnpinLinkTarget(LPCTSTR pszLink)
  323. {
  324. LPTSTR pszTarget = NULL;
  325. TraceEnter(TRACE_ADMINPIN, "_UnpinLinkTarget");
  326. TraceAssert(pszLink);
  327. // We only want to unpin a link target if it's a file (not a directory).
  328. // GetLinkTarget does this check and only returns files.
  329. GetLinkTarget(pszLink, &pszTarget, NULL);
  330. if (pszTarget)
  331. {
  332. DWORD dwStatus = 0;
  333. DWORD dwPinCount = 0;
  334. DWORD dwHintFlags = 0;
  335. if (CSCQueryFileStatus(pszTarget, &dwStatus, &dwPinCount, &dwHintFlags)
  336. && (dwHintFlags & FLAG_CSC_HINT_PIN_ADMIN))
  337. {
  338. // Unpin the target
  339. CSCUnpinFile(pszTarget,
  340. FLAG_CSC_HINT_PIN_ADMIN,
  341. &dwStatus,
  342. &dwPinCount,
  343. &dwHintFlags);
  344. if (0 == dwPinCount && 0 == dwHintFlags
  345. && !(dwStatus & FLAG_CSCUI_COPY_STATUS_LOCALLY_DIRTY))
  346. {
  347. WIN32_FIND_DATA fd = {0};
  348. LPCTSTR pszT = PathFindFileName(pszTarget);
  349. fd.dwFileAttributes = 0;
  350. lstrcpyn(fd.cFileName, pszT ? pszT : pszTarget, ARRAYSIZE(fd.cFileName));
  351. CscDelete(pszTarget);
  352. ShellChangeNotify(pszTarget, &fd, FALSE);
  353. }
  354. }
  355. LocalFree(pszTarget);
  356. }
  357. TraceLeaveVoid();
  358. }
  359. DWORD WINAPI
  360. _UnpinAdminFolderCallback(LPCTSTR pszItem,
  361. ENUM_REASON eReason,
  362. DWORD dwStatus,
  363. DWORD dwHintFlags,
  364. DWORD dwPinCount,
  365. LPWIN32_FIND_DATA pFind32,
  366. LPARAM /*dwContext*/)
  367. {
  368. BOOL bDeleteItem = FALSE;
  369. TraceEnter(TRACE_ADMINPIN, "_UnpinAdminFolderCallback");
  370. if (WAIT_OBJECT_0 == WaitForSingleObject(g_heventTerminate, 0))
  371. TraceLeaveValue(CSCPROC_RETURN_ABORT);
  372. if (!pszItem || !*pszItem)
  373. TraceLeaveValue(CSCPROC_RETURN_SKIP);
  374. TraceAssert(PathIsUNC(pszItem));
  375. if (eReason == ENUM_REASON_FILE)
  376. {
  377. if (PathIsShortcut(pszItem, pFind32 ? pFind32->dwFileAttributes : 0))
  378. {
  379. _UnpinLinkTarget(pszItem);
  380. }
  381. }
  382. if ((eReason == ENUM_REASON_FILE || eReason == ENUM_REASON_FOLDER_BEGIN)
  383. && (dwHintFlags & FLAG_CSC_HINT_PIN_ADMIN))
  384. {
  385. // Unpin the item
  386. CSCUnpinFile(pszItem,
  387. FLAG_CSC_HINT_PIN_ADMIN,
  388. &dwStatus,
  389. &dwPinCount,
  390. &dwHintFlags);
  391. //
  392. // If it's a file, delete it below on this pass
  393. //
  394. bDeleteItem = (ENUM_REASON_FILE == eReason);
  395. Trace((TEXT("AdminUnpin %s"), pszItem));
  396. }
  397. else if (ENUM_REASON_FOLDER_END == eReason)
  398. {
  399. //
  400. // Delete any unused folders in the post-order part of the traversal.
  401. //
  402. // Note that dwPinCount and dwHintFlags are always 0 in the
  403. // post-order part of the traversal, so fetch them here.
  404. //
  405. bDeleteItem = CSCQueryFileStatus(pszItem, &dwStatus, &dwPinCount, &dwHintFlags);
  406. }
  407. //
  408. // Delete items that are no longer pinned and have no offline changes
  409. //
  410. if (bDeleteItem
  411. && 0 == dwPinCount && 0 == dwHintFlags
  412. && !(dwStatus & FLAG_CSCUI_COPY_STATUS_LOCALLY_DIRTY))
  413. {
  414. CscDelete(pszItem);
  415. ShellChangeNotify(pszItem, pFind32, FALSE);
  416. }
  417. TraceLeaveValue(CSCPROC_RETURN_CONTINUE);
  418. }
  419. //
  420. // Determines if a path is a "special" file pinned by the folder
  421. // redirection code.
  422. //
  423. BOOL
  424. _IsSpecialRedirectedFile(
  425. LPCTSTR pszPath,
  426. HDPA hdpaFRList
  427. )
  428. {
  429. TraceAssert(NULL != pszPath);
  430. TraceAssert(!IsBadStringPtr(pszPath, MAX_PATH));
  431. if (hdpaFRList)
  432. {
  433. const int cchPath = lstrlen(pszPath);
  434. int i;
  435. for (i = 0; i < DPA_GetPtrCount(hdpaFRList); i++)
  436. {
  437. LPCTSTR pszThis = (LPCTSTR)DPA_GetPtr(hdpaFRList, i);
  438. int cchThis = lstrlen(pszThis);
  439. if (cchPath >= cchThis)
  440. {
  441. //
  442. // Path being examined is the same length or longer than
  443. // current path from the table. Possible match.
  444. //
  445. if (0 == StrCmpNI(pszPath, pszThis, cchThis))
  446. {
  447. //
  448. // Path being examined is either the same as,
  449. // or a child of, the current path from the table.
  450. //
  451. if (TEXT('\0') == *(pszPath + cchThis))
  452. {
  453. //
  454. // Path is same as this path from the table.
  455. //
  456. return TRUE;
  457. }
  458. else if (0 == lstrcmpi(pszPath + cchThis + 1, L"desktop.ini"))
  459. {
  460. //
  461. // Path is for a desktop.ini file that exists in the
  462. // root of one of our special folders.
  463. //
  464. return TRUE;
  465. }
  466. }
  467. }
  468. }
  469. }
  470. return FALSE;
  471. }
  472. DWORD WINAPI
  473. _ResetPinCountsCallback(LPCTSTR pszItem,
  474. ENUM_REASON eReason,
  475. DWORD dwStatus,
  476. DWORD dwHintFlags,
  477. DWORD dwPinCount,
  478. LPWIN32_FIND_DATA /*pFind32*/,
  479. LPARAM dwContext)
  480. {
  481. TraceEnter(TRACE_ADMINPIN, "_ResetPinCountsCallback");
  482. if (WAIT_OBJECT_0 == WaitForSingleObject(g_heventTerminate, 0))
  483. TraceLeaveValue(CSCPROC_RETURN_ABORT);
  484. if (!pszItem || !*pszItem)
  485. TraceLeaveValue(CSCPROC_RETURN_SKIP);
  486. TraceAssert(PathIsUNC(pszItem));
  487. if (eReason == ENUM_REASON_FILE || eReason == ENUM_REASON_FOLDER_BEGIN)
  488. {
  489. DWORD dwCurrentPinCount = dwPinCount;
  490. DWORD dwDesiredPinCount = _IsSpecialRedirectedFile(pszItem, (HDPA)dwContext) ? 1 : 0;
  491. while (dwCurrentPinCount-- > dwDesiredPinCount)
  492. {
  493. CSCUnpinFile(pszItem,
  494. FLAG_CSC_HINT_COMMAND_ALTER_PIN_COUNT,
  495. &dwStatus,
  496. &dwPinCount,
  497. &dwHintFlags);
  498. }
  499. }
  500. TraceLeaveValue(CSCPROC_RETURN_CONTINUE);
  501. }
  502. int CALLBACK _LocalFreeCallback(LPVOID p, LPVOID)
  503. {
  504. // OK to pass NULL to LocalFree
  505. LocalFree(p);
  506. return 1;
  507. }
  508. DWORD WINAPI
  509. _PinAdminFoldersThread(LPVOID)
  510. {
  511. TraceEnter(TRACE_ADMINPIN, "_PinAdminFoldersThread");
  512. TraceAssert(IsCSCEnabled());
  513. HANDLE rghSyncObj[] = { g_heventTerminate,
  514. g_hmutexAdminPin };
  515. UINT wmAdminPin = RegisterWindowMessage(c_szAPFMessage);
  516. //
  517. // Wait until we either own the "admin pin" mutex OR the
  518. // "terminate" event is set.
  519. //
  520. TraceMsg("Waiting for 'admin-pin' mutex or 'terminate' event...");
  521. DWORD dwWait = WaitForMultipleObjects(ARRAYSIZE(rghSyncObj),
  522. rghSyncObj,
  523. FALSE,
  524. INFINITE);
  525. if (1 == (dwWait - WAIT_OBJECT_0))
  526. {
  527. HKEY hkCSC = NULL;
  528. FILETIME ft = {0};
  529. RegCreateKeyEx(HKEY_CURRENT_USER,
  530. c_szCSCKey,
  531. 0,
  532. NULL,
  533. REG_OPTION_NON_VOLATILE,
  534. KEY_QUERY_VALUE | KEY_SET_VALUE,
  535. NULL,
  536. &hkCSC,
  537. NULL);
  538. if (hkCSC)
  539. {
  540. GetSystemTimeAsFileTime(&ft);
  541. RegSetValueEx(hkCSC, c_szAPFStart, 0, REG_BINARY, (LPBYTE)&ft, sizeof(ft));
  542. RegDeleteValue(hkCSC, c_szAPFEnd);
  543. }
  544. if (wmAdminPin)
  545. SendNotifyMessage(HWND_BROADCAST, wmAdminPin, 0, 0);
  546. TraceMsg("Thread now owns 'admin-pin' mutex.");
  547. //
  548. // We own the "admin pin" mutex. OK to perform admin pin.
  549. //
  550. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
  551. //
  552. // Get the Admin Folders list from the registry
  553. //
  554. HDPA hdpaFiles = DPA_Create(10);
  555. HDPA hdpaUnpin = DPA_Create(4);
  556. if (NULL != hdpaFiles && NULL != hdpaUnpin)
  557. {
  558. DWORD dwResult = CSCPROC_RETURN_CONTINUE;
  559. int cFiles;
  560. int i;
  561. //
  562. // NTRAID#NTBUG9-376185-2001/04/24-jeffreys
  563. // NTRAID#NTBUG9-379736-2001/04/24-jeffreys
  564. //
  565. // Unless directed by policy, pin all redirected special folders.
  566. //
  567. if (!CConfig::GetSingleton().NoAdminPinSpecialFolders())
  568. {
  569. BuildFRList(hdpaFiles);
  570. }
  571. ReadAPFFromRegistry(hdpaFiles);
  572. ReconcileAPF(hdpaFiles, hdpaUnpin);
  573. //
  574. // Iterate through the unpin list and unpin the items
  575. //
  576. //
  577. cFiles = DPA_GetPtrCount(hdpaUnpin);
  578. for (i = 0; i < cFiles; i++)
  579. {
  580. LPTSTR pszItem = (LPTSTR)DPA_GetPtr(hdpaUnpin, i);
  581. DWORD dwStatus = 0;
  582. DWORD dwPinCount = 0;
  583. DWORD dwHintFlags = 0;
  584. // If this fails, then it's not cached and there's nothing to do
  585. if (CSCPROC_RETURN_CONTINUE == dwResult &&
  586. CSCQueryFileStatus(pszItem, &dwStatus, &dwPinCount, &dwHintFlags))
  587. {
  588. // Unpin this item
  589. dwResult = _UnpinAdminFolderCallback(pszItem, ENUM_REASON_FILE, dwStatus, dwHintFlags, dwPinCount, NULL, 0);
  590. if (CSCPROC_RETURN_CONTINUE == dwResult
  591. && PathIsUNC(pszItem))
  592. {
  593. // Unpin everything under this folder (if it's a folder)
  594. dwResult = _CSCEnumDatabase(pszItem, TRUE, _UnpinAdminFolderCallback, 0);
  595. // Delete this item if it's no longer used (won't cause any
  596. // harm if it's not a folder).
  597. _UnpinAdminFolderCallback(pszItem, ENUM_REASON_FOLDER_END, 0, 0, 0, NULL, 0);
  598. }
  599. }
  600. if (CSCPROC_RETURN_ABORT == dwResult)
  601. {
  602. // We failed to clean this one up completely, so remember it for next time
  603. SHSetValue(HKEY_CURRENT_USER, c_szRegKeyAPFResult, pszItem, REG_DWORD, &dwResult, sizeof(dwResult));
  604. }
  605. }
  606. //
  607. // Iterate through the list and pin the items
  608. //
  609. cFiles = DPA_GetPtrCount(hdpaFiles);
  610. for (i = 0; i < cFiles && CSCPROC_RETURN_CONTINUE == dwResult; i++)
  611. {
  612. LPTSTR pszItem = (LPTSTR)DPA_GetPtr(hdpaFiles, i);
  613. // Pin this item
  614. dwResult = _PinAdminFolderCallback(pszItem, ENUM_REASON_FILE, NULL, 0);
  615. // Pin everything under this folder (if it's a folder)
  616. if (CSCPROC_RETURN_CONTINUE == dwResult
  617. && PathIsUNC(pszItem))
  618. {
  619. dwResult = _Win32EnumFolder(pszItem, TRUE, _PinAdminFolderCallback, 0);
  620. }
  621. }
  622. }
  623. if (NULL != hdpaFiles)
  624. {
  625. DPA_DestroyCallback(hdpaFiles, _LocalFreeCallback, 0);
  626. }
  627. if (NULL != hdpaUnpin)
  628. {
  629. DPA_DestroyCallback(hdpaUnpin, _LocalFreeCallback, 0);
  630. }
  631. //
  632. // Reduce pin counts on everything since we don't use them anymore.
  633. // This is a one time (per user) cleanup.
  634. //
  635. DWORD dwCleanupDone = 0;
  636. DWORD dwSize = sizeof(dwCleanupDone);
  637. if (hkCSC)
  638. {
  639. RegQueryValueEx(hkCSC, c_szPinCountsReset, 0, NULL, (LPBYTE)&dwCleanupDone, &dwSize);
  640. }
  641. if (0 == dwCleanupDone)
  642. {
  643. HDPA hdpaFRList = DPA_Create(4);
  644. if (hdpaFRList)
  645. {
  646. BuildFRList(hdpaFRList);
  647. }
  648. TraceMsg("Doing pin count cleanup.");
  649. if (CSCPROC_RETURN_ABORT != _CSCEnumDatabase(NULL, TRUE, _ResetPinCountsCallback, (LPARAM)hdpaFRList)
  650. && hkCSC)
  651. {
  652. dwCleanupDone = 1;
  653. RegSetValueEx(hkCSC, c_szPinCountsReset, 0, REG_DWORD, (LPBYTE)&dwCleanupDone, sizeof(dwCleanupDone));
  654. }
  655. if (hdpaFRList)
  656. {
  657. DPA_DestroyCallback(hdpaFRList, _LocalFreeCallback, 0);
  658. }
  659. }
  660. if (hkCSC)
  661. {
  662. GetSystemTimeAsFileTime(&ft);
  663. RegSetValueEx(hkCSC, c_szAPFEnd, 0, REG_BINARY, (LPBYTE)&ft, sizeof(ft));
  664. RegCloseKey(hkCSC);
  665. }
  666. if (wmAdminPin)
  667. SendNotifyMessage(HWND_BROADCAST, wmAdminPin, 1, 0);
  668. TraceMsg("Thread releasing 'admin-pin' mutex.");
  669. ReleaseMutex(g_hmutexAdminPin);
  670. }
  671. TraceMsg("_PinAdminFoldersThread exiting");
  672. TraceLeaveValue(0);
  673. }