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.

802 lines
24 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. DWORD WINAPI _PinAdminFoldersThread(LPVOID);
  19. //*************************************************************
  20. //
  21. // ApplyAdminFolderPolicy
  22. //
  23. // Purpose: Pin the admin folder list
  24. //
  25. // Parameters: none
  26. //
  27. // Return: none
  28. //
  29. // Notes:
  30. //
  31. //*************************************************************
  32. void
  33. ApplyAdminFolderPolicy(void)
  34. {
  35. BOOL bNoNet = FALSE;
  36. CSCIsServerOffline(NULL, &bNoNet);
  37. if (!bNoNet)
  38. {
  39. SHCreateThread(_PinAdminFoldersThread, NULL, CTF_COINIT | CTF_FREELIBANDEXIT, NULL);
  40. }
  41. }
  42. //
  43. // Does a particular path exist in the DPA of path strings?
  44. //
  45. BOOL
  46. ExistsAPF(
  47. HDPA hdpa,
  48. LPCTSTR pszPath
  49. )
  50. {
  51. const int cItems = DPA_GetPtrCount(hdpa);
  52. for (int i = 0; i < cItems; i++)
  53. {
  54. LPCTSTR pszItem = (LPCTSTR)DPA_GetPtr(hdpa, i);
  55. if (pszItem && (0 == lstrcmpi(pszItem, pszPath)))
  56. return TRUE;
  57. }
  58. return FALSE;
  59. }
  60. BOOL
  61. ReadAPFFromRegistry(HDPA hdpaFiles)
  62. {
  63. const HKEY rghkeyRoots[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
  64. for (int i = 0; i < ARRAYSIZE(rghkeyRoots); i++)
  65. {
  66. HKEY hKey;
  67. // Read in the Administratively pinned folder list.
  68. if (ERROR_SUCCESS == RegOpenKeyEx(rghkeyRoots[i], c_szRegKeyAPF, 0, KEY_QUERY_VALUE, &hKey))
  69. {
  70. TCHAR szName[MAX_PATH];
  71. DWORD dwIndex = 0, dwSize = ARRAYSIZE(szName);
  72. while (ERROR_SUCCESS == _RegEnumValueExp(hKey, dwIndex, szName, &dwSize, NULL, NULL, NULL, NULL))
  73. {
  74. if (!ExistsAPF(hdpaFiles, szName))
  75. {
  76. LPTSTR pszDup;
  77. if (LocalAllocString(&pszDup, szName))
  78. {
  79. if (-1 == DPA_AppendPtr(hdpaFiles, pszDup))
  80. {
  81. LocalFreeString(&pszDup);
  82. }
  83. }
  84. }
  85. dwSize = ARRAYSIZE(szName);
  86. dwIndex++;
  87. }
  88. RegCloseKey(hKey);
  89. }
  90. }
  91. return TRUE;
  92. }
  93. BOOL
  94. BuildFRList(HDPA hdpaFiles)
  95. {
  96. HKEY hKey;
  97. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"), 0, KEY_QUERY_VALUE, &hKey))
  98. {
  99. TCHAR szName[MAX_PATH];
  100. DWORD cchName = ARRAYSIZE(szName);
  101. TCHAR szValue[MAX_PATH];
  102. DWORD cbValue = sizeof(szValue);
  103. DWORD dwIndex = 0;
  104. while (ERROR_SUCCESS == RegEnumValue(hKey,
  105. dwIndex,
  106. szName,
  107. &cchName,
  108. NULL,
  109. NULL,
  110. (LPBYTE)szValue,
  111. &cbValue))
  112. {
  113. LPTSTR pszUNC = NULL;
  114. GetRemotePath(szValue, &pszUNC);
  115. if (pszUNC)
  116. {
  117. if (-1 == DPA_AppendPtr(hdpaFiles, pszUNC))
  118. {
  119. LocalFreeString(&pszUNC);
  120. }
  121. }
  122. cchName = ARRAYSIZE(szName);
  123. cbValue = sizeof(szValue);
  124. dwIndex++;
  125. }
  126. RegCloseKey(hKey);
  127. }
  128. return TRUE;
  129. }
  130. BOOL
  131. ReconcileAPF(HDPA hdpaPin, HDPA hdpaUnpin)
  132. {
  133. HKEY hKey;
  134. int cItems;
  135. int i;
  136. //
  137. // First, try to convert everything to UNC
  138. //
  139. cItems = DPA_GetPtrCount(hdpaPin);
  140. for (i = 0; i < cItems; i++)
  141. {
  142. LPTSTR pszItem = (LPTSTR)DPA_GetPtr(hdpaPin, i);
  143. if (!PathIsUNC(pszItem))
  144. {
  145. LPTSTR pszUNC = NULL;
  146. GetRemotePath(pszItem, &pszUNC);
  147. if (pszUNC)
  148. {
  149. DPA_SetPtr(hdpaPin, i, pszUNC);
  150. LocalFree(pszItem);
  151. }
  152. }
  153. }
  154. // Read in the previous Administratively pinned folder list for this user.
  155. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegKeyAPFResult, 0, KEY_QUERY_VALUE, &hKey))
  156. {
  157. TCHAR szName[MAX_PATH];
  158. DWORD dwIndex = 0, dwSize = ARRAYSIZE(szName);
  159. while (ERROR_SUCCESS == _RegEnumValueExp(hKey, dwIndex, szName, &dwSize, NULL, NULL, NULL, NULL))
  160. {
  161. if (!ExistsAPF(hdpaPin, szName))
  162. {
  163. LPTSTR pszDup = NULL;
  164. // This one is not in the new list, save it in the Unpin list
  165. if (LocalAllocString(&pszDup, szName))
  166. {
  167. if (-1 == DPA_AppendPtr(hdpaUnpin, pszDup))
  168. {
  169. LocalFreeString(&pszDup);
  170. }
  171. }
  172. }
  173. dwSize = ARRAYSIZE(szName);
  174. dwIndex++;
  175. }
  176. RegCloseKey(hKey);
  177. }
  178. // Save out the new admin pin list for this user
  179. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER,
  180. c_szRegKeyAPFResult,
  181. 0,
  182. NULL,
  183. REG_OPTION_NON_VOLATILE,
  184. KEY_SET_VALUE,
  185. NULL,
  186. &hKey,
  187. NULL))
  188. {
  189. // Add reg entries from the Pin list
  190. cItems = DPA_GetPtrCount(hdpaPin);
  191. for (i = 0; i < cItems; i++)
  192. {
  193. DWORD dwValue = 0;
  194. RegSetValueEx(hKey, (LPCTSTR)DPA_GetPtr(hdpaPin, i), 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
  195. }
  196. // Remove reg entries from the Unpin list
  197. cItems = DPA_GetPtrCount(hdpaUnpin);
  198. for (i = 0; i < cItems; i++)
  199. {
  200. RegDeleteValue(hKey, (LPCTSTR)DPA_GetPtr(hdpaUnpin, i));
  201. }
  202. RegCloseKey(hKey);
  203. }
  204. return TRUE;
  205. }
  206. DWORD WINAPI
  207. _AdminFillCallback(LPCTSTR /*pszName*/,
  208. DWORD /*dwStatus*/,
  209. DWORD /*dwHintFlags*/,
  210. DWORD /*dwPinCount*/,
  211. LPWIN32_FIND_DATA /*pFind32*/,
  212. DWORD /*dwReason*/,
  213. DWORD /*dwParam1*/,
  214. DWORD /*dwParam2*/,
  215. DWORD_PTR /*dwContext*/)
  216. {
  217. if (WAIT_OBJECT_0 == WaitForSingleObject(g_heventTerminate, 0))
  218. return CSCPROC_RETURN_ABORT;
  219. return CSCPROC_RETURN_CONTINUE;
  220. }
  221. void
  222. _DoAdminPin(LPCTSTR pszItem, LPWIN32_FIND_DATA pFind32)
  223. {
  224. DWORD dwHintFlags = 0;
  225. TraceEnter(TRACE_ADMINPIN, "_DoAdminPin");
  226. if (!pszItem || !*pszItem)
  227. TraceLeaveVoid();
  228. TraceAssert(PathIsUNC(pszItem));
  229. // This may fail, for example if the file is not in the cache
  230. CSCQueryFileStatus(pszItem, NULL, NULL, &dwHintFlags);
  231. // Is the admin flag already turned on?
  232. if (!(dwHintFlags & FLAG_CSC_HINT_PIN_ADMIN))
  233. {
  234. //
  235. // Pin the item
  236. //
  237. if (CSCPinFile(pszItem,
  238. dwHintFlags | FLAG_CSC_HINT_PIN_ADMIN,
  239. NULL,
  240. NULL,
  241. &dwHintFlags))
  242. {
  243. ShellChangeNotify(pszItem, pFind32, FALSE);
  244. }
  245. }
  246. //
  247. // Make sure files are filled.
  248. //
  249. // Yes, this takes longer, and isn't necessary if you stay logged
  250. // on, since the CSC agent fills everything in the background.
  251. //
  252. // However, JDP's are using this with laptop pools, and for
  253. // people who logon just to get the latest stuff, then immediately
  254. // disconnect their laptop and hit the road. They need to have
  255. // everything filled right away.
  256. //
  257. if (!pFind32 || !(pFind32->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  258. {
  259. CSCFillSparseFiles(pszItem, FALSE, _AdminFillCallback, 0);
  260. }
  261. Trace((TEXT("AdminPin %s"), pszItem));
  262. TraceLeaveVoid();
  263. }
  264. void
  265. _PinLinkTarget(LPCTSTR pszLink)
  266. {
  267. LPTSTR pszTarget = NULL;
  268. TraceEnter(TRACE_ADMINPIN, "_PinLinkTarget");
  269. TraceAssert(pszLink);
  270. // We only want to pin a link target if it's a file (not a directory).
  271. // GetLinkTarget does this check and only returns files.
  272. GetLinkTarget(pszLink, &pszTarget, NULL);
  273. if (pszTarget)
  274. {
  275. WIN32_FIND_DATA fd = {0};
  276. fd.dwFileAttributes = 0;
  277. StringCchCopy(fd.cFileName, ARRAYSIZE(fd.cFileName), PathFindFileName(pszTarget));
  278. // Pin the target
  279. _DoAdminPin(pszTarget, &fd);
  280. LocalFree(pszTarget);
  281. }
  282. TraceLeaveVoid();
  283. }
  284. // export this from shell32.dll
  285. BOOL PathIsShortcut(LPCTSTR pszItem, DWORD dwAttributes)
  286. {
  287. BOOL bIsShortcut = FALSE;
  288. SHFILEINFO sfi;
  289. sfi.dwAttributes = SFGAO_LINK;
  290. if (SHGetFileInfo(pszItem, dwAttributes, &sfi, sizeof(sfi), SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED | SHGFI_USEFILEATTRIBUTES))
  291. {
  292. bIsShortcut = (sfi.dwAttributes & SFGAO_LINK);
  293. }
  294. return bIsShortcut;
  295. }
  296. DWORD WINAPI
  297. _PinAdminFolderCallback(LPCTSTR pszItem,
  298. ENUM_REASON eReason,
  299. LPWIN32_FIND_DATA pFind32,
  300. LPARAM /*lpContext*/)
  301. {
  302. TraceEnter(TRACE_ADMINPIN, "_PinAdminFolderCallback");
  303. TraceAssert(pszItem);
  304. if (WAIT_OBJECT_0 == WaitForSingleObject(g_heventTerminate, 0))
  305. TraceLeaveValue(CSCPROC_RETURN_ABORT);
  306. if (!pszItem || !*pszItem)
  307. TraceLeaveValue(CSCPROC_RETURN_SKIP);
  308. if (eReason == ENUM_REASON_FILE || eReason == ENUM_REASON_FOLDER_BEGIN)
  309. {
  310. // If it's a link, pin the target
  311. if (PathIsShortcut(pszItem, pFind32 ? pFind32->dwFileAttributes : 0))
  312. _PinLinkTarget(pszItem);
  313. // Pin the item
  314. if (PathIsUNC(pszItem))
  315. _DoAdminPin(pszItem, pFind32);
  316. }
  317. TraceLeaveValue(CSCPROC_RETURN_CONTINUE);
  318. }
  319. void
  320. _UnpinLinkTarget(LPCTSTR pszLink)
  321. {
  322. LPTSTR pszTarget = NULL;
  323. TraceEnter(TRACE_ADMINPIN, "_UnpinLinkTarget");
  324. TraceAssert(pszLink);
  325. // We only want to unpin a link target if it's a file (not a directory).
  326. // GetLinkTarget does this check and only returns files.
  327. GetLinkTarget(pszLink, &pszTarget, NULL);
  328. if (pszTarget)
  329. {
  330. DWORD dwStatus = 0;
  331. DWORD dwPinCount = 0;
  332. DWORD dwHintFlags = 0;
  333. if (CSCQueryFileStatus(pszTarget, &dwStatus, &dwPinCount, &dwHintFlags)
  334. && (dwHintFlags & FLAG_CSC_HINT_PIN_ADMIN))
  335. {
  336. // Unpin the target
  337. CSCUnpinFile(pszTarget,
  338. FLAG_CSC_HINT_PIN_ADMIN,
  339. &dwStatus,
  340. &dwPinCount,
  341. &dwHintFlags);
  342. if (0 == dwPinCount && 0 == dwHintFlags
  343. && !(dwStatus & FLAG_CSCUI_COPY_STATUS_LOCALLY_DIRTY))
  344. {
  345. WIN32_FIND_DATA fd = {0};
  346. fd.dwFileAttributes = 0;
  347. StringCchCopy(fd.cFileName, ARRAYSIZE(fd.cFileName), PathFindFileName(pszTarget));
  348. CscDelete(pszTarget);
  349. ShellChangeNotify(pszTarget, &fd, FALSE);
  350. }
  351. }
  352. LocalFree(pszTarget);
  353. }
  354. TraceLeaveVoid();
  355. }
  356. DWORD WINAPI
  357. _UnpinAdminFolderCallback(LPCTSTR pszItem,
  358. ENUM_REASON eReason,
  359. DWORD dwStatus,
  360. DWORD dwHintFlags,
  361. DWORD dwPinCount,
  362. LPWIN32_FIND_DATA pFind32,
  363. LPARAM /*dwContext*/)
  364. {
  365. BOOL bDeleteItem = FALSE;
  366. TraceEnter(TRACE_ADMINPIN, "_UnpinAdminFolderCallback");
  367. if (WAIT_OBJECT_0 == WaitForSingleObject(g_heventTerminate, 0))
  368. TraceLeaveValue(CSCPROC_RETURN_ABORT);
  369. if (!pszItem || !*pszItem)
  370. TraceLeaveValue(CSCPROC_RETURN_SKIP);
  371. TraceAssert(PathIsUNC(pszItem));
  372. if (eReason == ENUM_REASON_FILE)
  373. {
  374. if (PathIsShortcut(pszItem, pFind32 ? pFind32->dwFileAttributes : 0))
  375. {
  376. _UnpinLinkTarget(pszItem);
  377. }
  378. }
  379. if ((eReason == ENUM_REASON_FILE || eReason == ENUM_REASON_FOLDER_BEGIN)
  380. && (dwHintFlags & FLAG_CSC_HINT_PIN_ADMIN))
  381. {
  382. // Unpin the item
  383. CSCUnpinFile(pszItem,
  384. FLAG_CSC_HINT_PIN_ADMIN,
  385. &dwStatus,
  386. &dwPinCount,
  387. &dwHintFlags);
  388. //
  389. // If it's a file, delete it below on this pass
  390. //
  391. bDeleteItem = (ENUM_REASON_FILE == eReason);
  392. Trace((TEXT("AdminUnpin %s"), pszItem));
  393. }
  394. else if (ENUM_REASON_FOLDER_END == eReason)
  395. {
  396. //
  397. // Delete any unused folders in the post-order part of the traversal.
  398. //
  399. // Note that dwPinCount and dwHintFlags are always 0 in the
  400. // post-order part of the traversal, so fetch them here.
  401. //
  402. bDeleteItem = CSCQueryFileStatus(pszItem, &dwStatus, &dwPinCount, &dwHintFlags);
  403. }
  404. //
  405. // Delete items that are no longer pinned and have no offline changes
  406. //
  407. if (bDeleteItem
  408. && 0 == dwPinCount && 0 == dwHintFlags
  409. && !(dwStatus & FLAG_CSCUI_COPY_STATUS_LOCALLY_DIRTY))
  410. {
  411. CscDelete(pszItem);
  412. ShellChangeNotify(pszItem, pFind32, FALSE);
  413. }
  414. TraceLeaveValue(CSCPROC_RETURN_CONTINUE);
  415. }
  416. //
  417. // Determines if a path is a "special" file pinned by the folder
  418. // redirection code.
  419. //
  420. BOOL
  421. _IsSpecialRedirectedFile(
  422. LPCTSTR pszPath,
  423. HDPA hdpaFRList
  424. )
  425. {
  426. TraceAssert(NULL != pszPath);
  427. if (hdpaFRList)
  428. {
  429. const int cchPath = lstrlen(pszPath);
  430. int i;
  431. for (i = 0; i < DPA_GetPtrCount(hdpaFRList); i++)
  432. {
  433. LPCTSTR pszThis = (LPCTSTR)DPA_GetPtr(hdpaFRList, i);
  434. int cchThis = lstrlen(pszThis);
  435. if (cchPath >= cchThis)
  436. {
  437. //
  438. // Path being examined is the same length or longer than
  439. // current path from the table. Possible match.
  440. //
  441. if (0 == StrCmpNI(pszPath, pszThis, cchThis))
  442. {
  443. //
  444. // Path being examined is either the same as,
  445. // or a child of, the current path from the table.
  446. //
  447. if (TEXT('\0') == *(pszPath + cchThis))
  448. {
  449. //
  450. // Path is same as this path from the table.
  451. //
  452. return TRUE;
  453. }
  454. else if (0 == lstrcmpi(pszPath + cchThis + 1, L"desktop.ini"))
  455. {
  456. //
  457. // Path is for a desktop.ini file that exists in the
  458. // root of one of our special folders.
  459. //
  460. return TRUE;
  461. }
  462. }
  463. }
  464. }
  465. }
  466. return FALSE;
  467. }
  468. DWORD WINAPI
  469. _ResetPinCountsCallback(LPCTSTR pszItem,
  470. ENUM_REASON eReason,
  471. DWORD dwStatus,
  472. DWORD dwHintFlags,
  473. DWORD dwPinCount,
  474. LPWIN32_FIND_DATA /*pFind32*/,
  475. LPARAM dwContext)
  476. {
  477. TraceEnter(TRACE_ADMINPIN, "_ResetPinCountsCallback");
  478. if (WAIT_OBJECT_0 == WaitForSingleObject(g_heventTerminate, 0))
  479. TraceLeaveValue(CSCPROC_RETURN_ABORT);
  480. if (!pszItem || !*pszItem)
  481. TraceLeaveValue(CSCPROC_RETURN_SKIP);
  482. TraceAssert(PathIsUNC(pszItem));
  483. if (eReason == ENUM_REASON_FILE || eReason == ENUM_REASON_FOLDER_BEGIN)
  484. {
  485. DWORD dwCurrentPinCount = dwPinCount;
  486. DWORD dwDesiredPinCount = _IsSpecialRedirectedFile(pszItem, (HDPA)dwContext) ? 1 : 0;
  487. while (dwCurrentPinCount-- > dwDesiredPinCount)
  488. {
  489. CSCUnpinFile(pszItem,
  490. FLAG_CSC_HINT_COMMAND_ALTER_PIN_COUNT,
  491. &dwStatus,
  492. &dwPinCount,
  493. &dwHintFlags);
  494. }
  495. }
  496. TraceLeaveValue(CSCPROC_RETURN_CONTINUE);
  497. }
  498. int CALLBACK _LocalFreeCallback(LPVOID p, LPVOID)
  499. {
  500. // OK to pass NULL to LocalFree
  501. LocalFree(p);
  502. return 1;
  503. }
  504. DWORD WINAPI
  505. _PinAdminFoldersThread(LPVOID)
  506. {
  507. TraceEnter(TRACE_ADMINPIN, "_PinAdminFoldersThread");
  508. TraceAssert(IsCSCEnabled());
  509. HANDLE rghSyncObj[] = { g_heventTerminate,
  510. g_hmutexAdminPin };
  511. UINT wmAdminPin = RegisterWindowMessage(c_szAPFMessage);
  512. //
  513. // Wait until we either own the "admin pin" mutex OR the
  514. // "terminate" event is set.
  515. //
  516. // If the wait fails for some reason, e.g. we failed to
  517. // allocate one of these handles, we will abort immediately.
  518. // Is that OK?
  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. }