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.

401 lines
12 KiB

  1. // History:
  2. // 5-30-94 KurtE Created.
  3. #include "shellprv.h"
  4. #pragma hdrstop
  5. //#define PARANOID_VALIDATE_UPDATE
  6. // Define our global states here. Note: we will do it per process
  7. typedef struct _RLPI // Registry List Process Info
  8. {
  9. HDPA hdpaRLList; // The dpa of items
  10. BOOL fCSInitialized; // Have we initialized the CS in this process
  11. BOOL fListValid; // Is the list up to date and valid
  12. CRITICAL_SECTION csRLList; // The critical section for the process
  13. } RLPI;
  14. RLPI g_rlpi = {NULL, FALSE, FALSE};
  15. // Simple DPA compare function make sure we don't have elsewhere...
  16. int CALLBACK _CompareStrings(LPVOID sz1, LPVOID sz2, LPARAM lparam)
  17. {
  18. return lstrcmpi((LPTSTR)sz1, (LPTSTR)sz2);
  19. }
  20. void RLEnterCritical()
  21. {
  22. if (!g_rlpi.fCSInitialized)
  23. {
  24. // Do this under the global critical section.
  25. ENTERCRITICAL;
  26. if (!g_rlpi.fCSInitialized)
  27. {
  28. g_rlpi.fCSInitialized = TRUE;
  29. InitializeCriticalSection(&g_rlpi.csRLList);
  30. }
  31. LEAVECRITICAL;
  32. }
  33. EnterCriticalSection(&g_rlpi.csRLList);
  34. }
  35. void RLLeaveCritical()
  36. {
  37. LeaveCriticalSection(&g_rlpi.csRLList);
  38. }
  39. // Enumerate through the registry looking for paths that
  40. // we may wish to track. The current ones that we look for
  41. STDAPI_(BOOL) RLEnumRegistry(HDPA hdpa, PRLCALLBACK pfnrlcb, LPCTSTR pszSource, LPCTSTR pszDest)
  42. {
  43. HKEY hkeyRoot;
  44. // First look in the App Paths section
  45. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_APPPATHS, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hkeyRoot))
  46. {
  47. int iRootName;
  48. TCHAR szRootName[80];
  49. for (iRootName = 0;
  50. RegEnumKey(hkeyRoot, iRootName, szRootName, ARRAYSIZE(szRootName)) == ERROR_SUCCESS;
  51. iRootName++)
  52. {
  53. // Now see if the app has a qualifid path here.
  54. HKEY hkeySecond;
  55. TCHAR szPath[MAX_PATH];
  56. long cbValue = sizeof(szPath);
  57. if (SHRegGetValue(hkeyRoot, szRootName, NULL, SRRF_RT_REG_SZ, NULL, szPath, &cbValue) == ERROR_SUCCESS)
  58. {
  59. PathUnquoteSpaces(szPath);
  60. pfnrlcb(hdpa, hkeyRoot, szRootName, NULL, szPath, pszSource, pszDest);
  61. }
  62. // Now try to enum this key for Path Value.
  63. if (ERROR_SUCCESS == RegOpenKeyEx(hkeyRoot, szRootName, 0, KEY_QUERY_VALUE, &hkeySecond))
  64. {
  65. cbValue = sizeof(szPath);
  66. if (SHQueryValueEx(hkeySecond, TEXT("PATH"), NULL, NULL, szPath, &cbValue) == ERROR_SUCCESS)
  67. {
  68. // this is a ";" separated list
  69. LPTSTR psz = StrChr(szPath, TEXT(';'));
  70. if (psz)
  71. *psz = 0;
  72. PathUnquoteSpaces(szPath);
  73. pfnrlcb(hdpa, hkeySecond, NULL, TEXT("PATH"), szPath, pszSource, pszDest);
  74. }
  75. RegCloseKey(hkeySecond);
  76. }
  77. }
  78. RegCloseKey(hkeyRoot);
  79. }
  80. return TRUE;
  81. }
  82. // This is the call back called to build the list of paths.
  83. BOOL CALLBACK _RLBuildListCallBack(HDPA hdpa, HKEY hkey, LPCTSTR pszKey,
  84. LPCTSTR pszValueName, LPTSTR pszValue, LPCTSTR pszSource, LPCTSTR pszDest)
  85. {
  86. int iIndex;
  87. // Also don't add any relative paths.
  88. if (PathIsRelative(pszValue) || (lstrlen(pszValue) < 3))
  89. return TRUE;
  90. // Don't try UNC names as this can get expensive...
  91. if (PathIsUNC(pszValue))
  92. return TRUE;
  93. // If it is already in our list, we can simply return now..
  94. if (DPA_Search(hdpa, pszValue, 0, _CompareStrings, 0, DPAS_SORTED) != -1)
  95. return TRUE;
  96. // If it is in our old list then
  97. if (g_rlpi.hdpaRLList && ((iIndex = DPA_Search(g_rlpi.hdpaRLList, pszValue, 0,
  98. _CompareStrings, 0, DPAS_SORTED)) != -1))
  99. {
  100. // Found the item in the old list.
  101. TraceMsg(TF_REG, "_RLBuildListCallBack: Add from old list %s", pszValue);
  102. DPA_InsertPtr(hdpa,
  103. DPA_Search(hdpa, pszValue, 0,
  104. _CompareStrings, 0,
  105. DPAS_SORTED|DPAS_INSERTBEFORE),
  106. (LPTSTR)DPA_FastGetPtr(g_rlpi.hdpaRLList, iIndex));
  107. // now remove it from the old list
  108. DPA_DeletePtr(g_rlpi.hdpaRLList, iIndex);
  109. }
  110. else
  111. {
  112. // Not in either list.
  113. // Now see if we can convert the short name to a long name
  114. TCHAR szLongName[MAX_PATH];
  115. int cchName;
  116. int cchLongName;
  117. LPTSTR psz;
  118. if (!GetLongPathName(pszValue, szLongName, ARRAYSIZE(szLongName)))
  119. szLongName[0] = 0;
  120. if (lstrcmpi(szLongName, pszValue) == 0)
  121. szLongName[0] = 0; // Don't need both strings.
  122. cchName = lstrlen(pszValue);
  123. cchLongName =lstrlen(szLongName);
  124. psz = (LPTSTR)LocalAlloc(LPTR,
  125. (cchName + 1 + cchLongName + 1) * sizeof(TCHAR));
  126. if (psz)
  127. {
  128. HRESULT hr;
  129. BOOL fOk;
  130. TraceMsg(TF_REG, "_RLBuildListCallBack: Add %s", pszValue);
  131. hr = StringCchCopy(psz, cchName + 1, pszValue);
  132. if (FAILED(hr))
  133. {
  134. fOk = FALSE;
  135. }
  136. hr = StringCchCopy(psz + cchName + 1, cchLongName + 1, szLongName);
  137. if (FAILED(hr))
  138. {
  139. fOk = FALSE;
  140. }
  141. if (fOk)
  142. {
  143. return DPA_InsertPtr(hdpa,
  144. DPA_Search(hdpa, pszValue, 0,
  145. _CompareStrings, 0,
  146. DPAS_SORTED|DPAS_INSERTBEFORE),
  147. psz);
  148. }
  149. }
  150. }
  151. return TRUE;
  152. }
  153. // This function will build the list of items that we
  154. // will look through to see if the user may have changed the path of
  155. // of one of the programs that is registered in the registry.
  156. //
  157. BOOL WINAPI RLBuildListOfPaths()
  158. {
  159. BOOL fRet = FALSE;
  160. HDPA hdpa;
  161. DEBUG_CODE( DWORD dwStart = GetCurrentTime(); )
  162. RLEnterCritical();
  163. hdpa = DPA_Create(0);
  164. if (!hdpa)
  165. goto Error;
  166. // And initialize the list
  167. fRet = RLEnumRegistry(hdpa, _RLBuildListCallBack, NULL, NULL);
  168. // If we had on old list destroy it now.
  169. if (g_rlpi.hdpaRLList)
  170. {
  171. // Walk through all of the items in the list and
  172. // delete all of the strings.
  173. int i;
  174. for (i = DPA_GetPtrCount(g_rlpi.hdpaRLList)-1; i >= 0; i--)
  175. LocalFree((HLOCAL)DPA_FastGetPtr(g_rlpi.hdpaRLList, i));
  176. DPA_Destroy(g_rlpi.hdpaRLList);
  177. }
  178. g_rlpi.hdpaRLList = hdpa;
  179. g_rlpi.fListValid = TRUE; // Say that we are valid...
  180. DEBUG_CODE( TraceMsg(TF_REG, "RLBuildListOfPaths time: %ld", GetCurrentTime()-dwStart); )
  181. Error:
  182. RLLeaveCritical();
  183. return fRet;
  184. }
  185. // this function does any cleanup necessary for when a process
  186. // is no longer going to use the Registry list.
  187. void WINAPI RLTerminate()
  188. {
  189. int i;
  190. if (!g_rlpi.hdpaRLList)
  191. return;
  192. RLEnterCritical();
  193. // Re-check under critical section in case somebody else destroyed
  194. // it while we were waiting
  195. if (g_rlpi.hdpaRLList)
  196. {
  197. // Walk through all of the items in the list and
  198. // delete all of the strings.
  199. for (i = DPA_GetPtrCount(g_rlpi.hdpaRLList)-1; i >= 0; i--)
  200. LocalFree((HLOCAL)DPA_FastGetPtr(g_rlpi.hdpaRLList, i));
  201. DPA_Destroy(g_rlpi.hdpaRLList);
  202. g_rlpi.hdpaRLList = NULL;
  203. }
  204. RLLeaveCritical();
  205. }
  206. // This function returns TRUE if the path that is passed
  207. // in is contained in one or more of the paths that we extracted from
  208. // the registry.
  209. int WINAPI RLIsPathInList(LPCTSTR pszPath)
  210. {
  211. int i = -1;
  212. RLEnterCritical();
  213. if (!g_rlpi.hdpaRLList || !g_rlpi.fListValid)
  214. RLBuildListOfPaths();
  215. if (g_rlpi.hdpaRLList)
  216. {
  217. int cchPath = lstrlen(pszPath);
  218. for (i = DPA_GetPtrCount(g_rlpi.hdpaRLList) - 1; i >= 0; i--)
  219. {
  220. LPTSTR psz = DPA_FastGetPtr(g_rlpi.hdpaRLList, i);
  221. if (PathCommonPrefix(pszPath, psz, NULL) == cchPath)
  222. break;
  223. // See if a long file name to check.
  224. psz += lstrlen(psz) + 1;
  225. if (*psz && (PathCommonPrefix(pszPath, psz, NULL) == cchPath))
  226. break;
  227. }
  228. }
  229. RLLeaveCritical();
  230. return i; // -1 if none, >= 0 index
  231. }
  232. // This is the call back called to build the list of of paths.
  233. //
  234. BOOL CALLBACK _RLRenameCallBack(HDPA hdpa, HKEY hkey, LPCTSTR pszKey,
  235. LPCTSTR pszValueName, LPTSTR pszValue, LPCTSTR pszSource, LPCTSTR pszDest)
  236. {
  237. int cbMatch = PathCommonPrefix(pszValue, pszSource, NULL);
  238. if (cbMatch == lstrlen(pszSource))
  239. {
  240. TCHAR szPath[MAX_PATH+64]; // Add some slop just in case...
  241. // Found a match, lets try to rebuild the new line
  242. StringCchCopy(szPath, ARRAYSIZE(szPath), pszDest);
  243. StringCchCat(szPath, ARRAYSIZE(szPath), pszValue + cbMatch);
  244. if (pszValueName)
  245. RegSetValueEx(hkey, pszValueName, 0, REG_SZ, (BYTE *)szPath, (lstrlen(szPath) + 1) * sizeof(TCHAR));
  246. else
  247. RegSetValue(hkey, pszKey, REG_SZ, szPath, lstrlen(szPath));
  248. }
  249. // Make sure that we have not allready added
  250. // this path to our list.
  251. if (DPA_Search(hdpa, pszValue, 0, _CompareStrings, 0, DPAS_SORTED) == -1)
  252. {
  253. // One to Add!
  254. LPTSTR psz = StrDup(pszValue);
  255. if (psz)
  256. {
  257. return DPA_InsertPtr(hdpa,
  258. DPA_Search(hdpa, pszValue, 0,
  259. _CompareStrings, 0,
  260. DPAS_SORTED | DPAS_INSERTBEFORE), psz);
  261. }
  262. }
  263. return TRUE;
  264. }
  265. // This function handles the cases when we are notified of
  266. // a change to the file system and then we need to see if there are
  267. // any changes that we need to make to the regisry to handle the changes.
  268. int WINAPI RLFSChanged(LONG lEvent, LPITEMIDLIST pidl, LPITEMIDLIST pidlExtra)
  269. {
  270. TCHAR szSrc[MAX_PATH];
  271. TCHAR szDest[MAX_PATH+8]; // For slop like Quotes...
  272. int iIndex;
  273. LPTSTR psz;
  274. int iRet = -1;
  275. int i;
  276. // First see if the operation is something we are interested in.
  277. if ((lEvent & (SHCNE_RENAMEITEM | SHCNE_RENAMEFOLDER)) == 0)
  278. return -1; // Nope
  279. if (!SHGetPathFromIDList(pidl, szSrc))
  280. {
  281. // must be a rename of a non-filesys object (such as a printer!)
  282. return -1;
  283. }
  284. SHGetPathFromIDList(pidlExtra, szDest);
  285. // If either are roots we really can not rename them...
  286. if (PathIsRoot(szSrc) || PathIsRoot(szDest))
  287. return -1;
  288. // ignore if coming from bitbucket or going to ...
  289. // check bitbucket first. that's a cheap call
  290. if ((lEvent & SHCNE_RENAMEITEM) &&
  291. (IsFileInBitBucket(szSrc) || IsFileInBitBucket(szDest)))
  292. return -1;
  293. RLEnterCritical();
  294. // Now see if the source file is in our list of paths
  295. iIndex = RLIsPathInList(szSrc);
  296. if (iIndex != -1)
  297. {
  298. // Now make sure we are working with the short name
  299. // Note we may only be a subpiece of this item.
  300. // Count how many fields there are in the szSrc Now;
  301. for (i = 0, psz = szSrc; psz; i++)
  302. {
  303. psz = StrChr(psz + 1, TEXT('\\'));
  304. }
  305. StringCchCopy(szSrc, ARRAYSIZE(szSrc), (LPTSTR)DPA_FastGetPtr(g_rlpi.hdpaRLList, iIndex));
  306. // Now truncate off stuff that is not from us Go one more then we countd
  307. // above and if we have a non null value cut it off there.
  308. for (psz = szSrc; i > 0; i--)
  309. {
  310. psz = StrChr(psz+1, TEXT('\\'));
  311. }
  312. if (psz)
  313. *psz = 0;
  314. // verify that this is a fully qulified path and that it exists
  315. // before we go and muck with the registry.
  316. if (!PathIsRelative(szDest) && PathFileExistsAndAttributes(szDest, NULL) && (lstrlen(szDest) >= 3))
  317. {
  318. // Yes, so now lets reenum and try to update the paths...
  319. PathGetShortPath(szDest); // Convert to a short name...
  320. RLEnumRegistry(g_rlpi.hdpaRLList, _RLRenameCallBack, szSrc, szDest);
  321. // We changed something so mark it to be rebuilt
  322. g_rlpi.fListValid = FALSE; // Force it to rebuild.
  323. iRet = 1;
  324. }
  325. }
  326. RLLeaveCritical();
  327. return iRet;
  328. }