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.

320 lines
10 KiB

  1. #include "precomp.hxx"
  2. #pragma hdrstop
  3. #include <shguidp.h> // CLSID_MyDocuments, CLSID_ShellFSFolder
  4. #include <shlobjp.h> // SHFlushSFCache()
  5. #include "util.h"
  6. #include "dll.h"
  7. #include "resource.h"
  8. #include "sddl.h"
  9. #include "strsafe.h"
  10. HRESULT GetFolderDisplayName(UINT csidl, LPTSTR pszPath, UINT cch)
  11. {
  12. *pszPath = 0;
  13. LPITEMIDLIST pidl;
  14. if (SUCCEEDED(SHGetFolderLocation(NULL, csidl | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, &pidl)))
  15. {
  16. SHGetNameAndFlags(pidl, SHGDN_NORMAL, pszPath, cch, NULL);
  17. ILFree(pidl);
  18. }
  19. return *pszPath ? S_OK : E_FAIL;
  20. }
  21. #define MYDOCS_CLSID TEXT("{450d8fba-ad25-11d0-98a8-0800361b1103}") // CLSID_MyDocuments
  22. // Create/Updates file in SendTo directory to have current display name
  23. void UpdateSendToFile()
  24. {
  25. TCHAR szSendToDir[MAX_PATH];
  26. if (S_OK == SHGetFolderPath(NULL, CSIDL_SENDTO, NULL, SHGFP_TYPE_CURRENT, szSendToDir))
  27. {
  28. // Create c:\winnt\profile\chrisg\sendto\<display name>.mydocs
  29. BOOL bDeleteOnly = FALSE;
  30. TCHAR szNewFile[MAX_PATH];
  31. TCHAR szName[MAX_PATH];
  32. if (SUCCEEDED(GetFolderDisplayName(CSIDL_PERSONAL, szName, ARRAYSIZE(szName))))
  33. {
  34. PathCleanupSpec(NULL, szName); // map any illegal chars to file sys chars
  35. PathRemoveBlanks(szName);
  36. PathCombine(szNewFile, szSendToDir, szName);
  37. StringCchCat(szNewFile, ARRAYSIZE(szNewFile), TEXT(".mydocs"));
  38. }
  39. else
  40. {
  41. // we can't create a new file, because we don't have a name
  42. bDeleteOnly = TRUE;
  43. }
  44. TCHAR szFile[MAX_PATH];
  45. WIN32_FIND_DATA fd;
  46. // delete c:\winnt\profile\chrisg\sendto\*.mydocs
  47. PathCombine(szFile, szSendToDir, TEXT("*.mydocs"));
  48. HANDLE hFind = FindFirstFile(szFile, &fd);
  49. if (hFind != INVALID_HANDLE_VALUE)
  50. {
  51. do
  52. {
  53. PathCombine(szFile, szSendToDir, fd.cFileName);
  54. if (0 == lstrcmp(szFile, szNewFile))
  55. {
  56. // The file that we needed to create already exists,
  57. // just leave it in place instead of deleting it and
  58. // then creating it again below (this fixes
  59. // app compat problems - see NT bug 246932)
  60. bDeleteOnly = TRUE;
  61. // file now has the exact display name, MUI adjusts the return from GetFolderDisplayName and
  62. // since we run this every time we dont have to worry about localizing the sendto target.
  63. }
  64. else
  65. {
  66. DeleteFile(szFile);
  67. }
  68. } while (FindNextFile(hFind, &fd));
  69. FindClose(hFind);
  70. }
  71. if (!bDeleteOnly)
  72. {
  73. hFind = CreateFile(szNewFile, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
  74. if (hFind != INVALID_HANDLE_VALUE)
  75. {
  76. CloseHandle(hFind);
  77. // file now has the exact display name, MUI adjusts the return from GetFolderDisplayName and
  78. // since we run this every time we dont have to worry about localizing the sendto target.
  79. }
  80. else
  81. {
  82. // might be illegal chars in the file name, fall back to the default MyDocs name here
  83. }
  84. }
  85. }
  86. }
  87. // test pszChild against pszParent to see if
  88. // pszChild is equal (PATH_IS_EQUAL) or
  89. // a DIRECT child (PATH_IS_CHILD)
  90. DWORD ComparePaths(LPCTSTR pszChild, LPCTSTR pszParent)
  91. {
  92. DWORD dwRet = PATH_IS_DIFFERENT;
  93. TCHAR szParent[MAX_PATH];
  94. StringCchCopy(szParent, ARRAYSIZE(szParent), pszParent);
  95. if (PathIsRoot(szParent) && (-1 != PathGetDriveNumber(szParent)))
  96. {
  97. szParent[2] = 0; // trip D:\ -> D: to make code below work
  98. }
  99. INT cchParent = lstrlen(szParent);
  100. INT cchChild = lstrlen(pszChild);
  101. if (cchParent <= cchChild)
  102. {
  103. TCHAR szChild[MAX_PATH];
  104. StringCchCopy(szChild, ARRAYSIZE(szChild), pszChild);
  105. LPTSTR pszChildSlice = szChild + cchParent;
  106. if (TEXT('\\') == *pszChildSlice)
  107. {
  108. *pszChildSlice = 0;
  109. }
  110. if (lstrcmpi(szChild, szParent) == 0)
  111. {
  112. if (cchParent < cchChild)
  113. {
  114. LPTSTR pTmp = pszChildSlice + 1;
  115. while (*pTmp && *pTmp != TEXT('\\'))
  116. {
  117. pTmp++; // find second level path segments
  118. }
  119. if (!(*pTmp))
  120. {
  121. dwRet = PATH_IS_CHILD; // direct child
  122. }
  123. }
  124. else
  125. {
  126. dwRet = PATH_IS_EQUAL;
  127. }
  128. }
  129. }
  130. return dwRet;
  131. }
  132. // Checks the path to see if it is marked as system or read only and
  133. // then check desktop.ini for CLSID or CLSID2 entry...
  134. BOOL IsPathAlreadyShellFolder(LPCTSTR pszPath, DWORD dwAttrib)
  135. {
  136. BOOL bIsShellFolder = FALSE;
  137. if (PathIsSystemFolder(pszPath, dwAttrib))
  138. {
  139. TCHAR szDesktopIni[MAX_PATH];
  140. PathCombine(szDesktopIni, pszPath, TEXT("desktop.ini"));
  141. // Check for CLSID entry...
  142. TCHAR szBuffer[MAX_PATH];
  143. GetPrivateProfileString(TEXT(".ShellClassInfo"), TEXT("CLSID"), TEXT("foo"), szBuffer, ARRAYSIZE(szBuffer), szDesktopIni);
  144. if ((lstrcmpi(szBuffer, TEXT("foo")) !=0) &&
  145. (lstrcmpi(szBuffer, MYDOCS_CLSID) !=0))
  146. {
  147. bIsShellFolder = TRUE;
  148. }
  149. // Check for CLSID2 entry...
  150. GetPrivateProfileString(TEXT(".ShellClassInfo"), TEXT("CLSID2"), TEXT("foo"), szBuffer, ARRAYSIZE(szBuffer), szDesktopIni);
  151. if ((lstrcmpi(szBuffer, TEXT("foo")) != 0) &&
  152. (lstrcmpi(szBuffer, MYDOCS_CLSID) != 0))
  153. {
  154. bIsShellFolder = TRUE;
  155. }
  156. }
  157. return bIsShellFolder;
  158. }
  159. const struct
  160. {
  161. DWORD dwDir;
  162. DWORD dwFlags;
  163. DWORD dwRet;
  164. }
  165. _adirs[] =
  166. {
  167. { CSIDL_DESKTOP, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_DESKTOP },
  168. { CSIDL_PERSONAL, PATH_IS_EQUAL , PATH_IS_MYDOCS },
  169. { CSIDL_SENDTO, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_SENDTO },
  170. { CSIDL_RECENT, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_RECENT },
  171. { CSIDL_HISTORY, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_HISTORY },
  172. { CSIDL_COOKIES, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_COOKIES },
  173. { CSIDL_PRINTHOOD, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_PRINTHOOD },
  174. { CSIDL_NETHOOD, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_NETHOOD },
  175. { CSIDL_STARTMENU, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_STARTMENU },
  176. { CSIDL_TEMPLATES, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_TEMPLATES },
  177. { CSIDL_FAVORITES, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_FAVORITES },
  178. { CSIDL_FONTS, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_FONTS },
  179. { CSIDL_APPDATA, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_APPDATA },
  180. { CSIDL_INTERNET_CACHE, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_TEMP_INET },
  181. { CSIDL_COMMON_STARTMENU, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_STARTMENU },
  182. { CSIDL_COMMON_DESKTOPDIRECTORY, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_DESKTOP },
  183. { CSIDL_WINDOWS, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_WINDOWS },
  184. { CSIDL_SYSTEM, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_SYSTEM },
  185. { CSIDL_PROFILE, PATH_IS_EQUAL , PATH_IS_PROFILE },
  186. };
  187. BOOL PathEndsInDot(LPCTSTR pszPath)
  188. {
  189. // CreateDirectory("c:\foo.") or CreateDirectory("c:\foo.....")
  190. // will succeed but create a directory named "c:\foo", which isn't
  191. // what the user asked for. So we use this function to guard
  192. // against those cases.
  193. //
  194. // Note that this simple test also picks off "c:\foo\." -- ok for
  195. // our purposes.
  196. UINT cLen = lstrlen(pszPath);
  197. return (cLen >= 1) && (pszPath[cLen - 1] == TEXT('.'));
  198. }
  199. //
  200. // Checks the path to see if it is okay as a MyDocs path
  201. //
  202. DWORD IsPathGoodMyDocsPath(HWND hwnd, LPCTSTR pszPath)
  203. {
  204. if (NULL == pszPath)
  205. {
  206. return PATH_IS_ERROR;
  207. }
  208. TCHAR szRootPath[MAX_PATH];
  209. StringCchCopy(szRootPath, ARRAYSIZE(szRootPath), pszPath);
  210. if (!PathStripToRoot(szRootPath))
  211. {
  212. return PATH_IS_ERROR;
  213. }
  214. if (PathEndsInDot(pszPath))
  215. {
  216. return PATH_IS_ERROR;
  217. }
  218. DWORD dwRes, dwAttr = GetFileAttributes(pszPath);
  219. if (dwAttr == 0xFFFFFFFF)
  220. {
  221. if (0xFFFFFFFF == GetFileAttributes(szRootPath))
  222. {
  223. // If the root path doesn't exist, then we're not going
  224. // to be able to create a path:
  225. return PATH_IS_ERROR;
  226. }
  227. else
  228. {
  229. return PATH_IS_NONEXISTENT;
  230. }
  231. }
  232. if (!(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
  233. {
  234. return PATH_IS_NONDIR;
  235. }
  236. for (int i = 0; i < ARRAYSIZE(_adirs); i++)
  237. {
  238. TCHAR szPathToCheck[MAX_PATH];
  239. //
  240. // Check for various special shell folders
  241. //
  242. if (S_OK == SHGetFolderPath(hwnd, _adirs[i].dwDir | CSIDL_FLAG_DONT_VERIFY, NULL, SHGFP_TYPE_CURRENT, szPathToCheck))
  243. {
  244. dwRes = ComparePaths(pszPath, szPathToCheck);
  245. if (dwRes & _adirs[i].dwFlags)
  246. {
  247. //
  248. // The inevitable exceptions
  249. //
  250. switch (_adirs[i].dwDir)
  251. {
  252. case CSIDL_DESKTOP:
  253. if (PATH_IS_CHILD == dwRes)
  254. {
  255. continue; // allowing subfolder of CSIDL_DESKTOP
  256. }
  257. break;
  258. default:
  259. break;
  260. } // switch
  261. return _adirs[i].dwRet;
  262. }
  263. }
  264. }
  265. //
  266. // Make sure path isn't set as a system or some other kind of
  267. // folder that already has a CLSID or CLSID2 entry...
  268. //
  269. if (IsPathAlreadyShellFolder(pszPath, dwAttr))
  270. {
  271. return PATH_IS_SHELLFOLDER;
  272. }
  273. return PATH_IS_GOOD;
  274. }