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.

1275 lines
38 KiB

  1. #define _SHFOLDER_
  2. #define NO_SHLWAPI_PATH
  3. #include <windows.h>
  4. #include <shlwapi.h>
  5. #include <shlobj.h>
  6. #include <shfolder.h>
  7. #include <platform.h>
  8. #include <strsafe.h>
  9. #include "resource.h"
  10. #ifdef DBG
  11. #define ASSERT(x) if (!(x)) DebugBreak();
  12. #else
  13. #define ASSERT(x)
  14. #endif
  15. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  16. // We can't rely on shlwapi SHUnicodeToAnsi/SHAnsiToUnicode in this module
  17. #define SHAnsiToUnicode(psz, pwsz, cchwsz) MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, psz, -1, pwsz, cchwsz)
  18. #define SHUnicodeToAnsi _SHUnicodeToAnsi
  19. //
  20. // Global array of static system SIDs, corresponding to UI_SystemSid
  21. //
  22. struct
  23. {
  24. SID sid; // contains 1 subauthority
  25. DWORD dwSubAuth[1]; // we currently need at most 2 subauthorities
  26. }
  27. c_StaticSids[] =
  28. {
  29. {{SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, {SECURITY_CREATOR_OWNER_RID}}, {0} },
  30. {{SID_REVISION, 1, SECURITY_NT_AUTHORITY, {SECURITY_AUTHENTICATED_USER_RID}}, {0} },
  31. {{SID_REVISION, 1, SECURITY_NT_AUTHORITY, {SECURITY_LOCAL_SYSTEM_RID}}, {0} },
  32. {{SID_REVISION, 2, SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_ADMINS} },
  33. {{SID_REVISION, 2, SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_POWER_USERS} },
  34. };
  35. #define SSI_CREATOROWNER 0
  36. #define SSI_AUTHUSER 1
  37. #define SSI_SYSTEM 2
  38. #define SSI_ADMIN 3
  39. #define SSI_POWERUSER 4
  40. typedef struct tagACEPARAMLIST
  41. {
  42. DWORD dwSidIndex;
  43. DWORD AccessMask;
  44. DWORD dwAceFlags;
  45. }
  46. ACEPARAMLIST;
  47. #define ACE_INHERIT (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE)
  48. #define FILE_MODIFY (FILE_ALL_ACCESS & ~(WRITE_DAC | WRITE_OWNER))
  49. const ACEPARAMLIST c_paplUnsecure[] =
  50. {
  51. SSI_SYSTEM, FILE_ALL_ACCESS, 0,
  52. SSI_SYSTEM, GENERIC_ALL, ACE_INHERIT,
  53. SSI_AUTHUSER, FILE_MODIFY, 0,
  54. SSI_AUTHUSER, FILE_MODIFY, ACE_INHERIT,
  55. };
  56. //
  57. // CSIDL_COMMON_DOCUMENTS
  58. // Admins, System, Creator Owner: Full Control - Container Inherit, Object Inherit
  59. // Users, Power Users: Read - Container Inherit, Object Inherit
  60. // Users, Power Users: Write - Container Inherit
  61. //
  62. // Non admin users can create files and directories. They have full control over
  63. // the files they create. All other users can read those files by default, but
  64. // they cannot modify the files unless the original creator gives them explicit
  65. // permissions to do so.
  66. //
  67. const ACEPARAMLIST c_paplCommonDocs[] =
  68. {
  69. SSI_SYSTEM, FILE_ALL_ACCESS, 0,
  70. SSI_SYSTEM, GENERIC_ALL, ACE_INHERIT,
  71. SSI_ADMIN, FILE_ALL_ACCESS, 0,
  72. SSI_ADMIN, GENERIC_ALL, ACE_INHERIT,
  73. SSI_CREATOROWNER, GENERIC_ALL, ACE_INHERIT,
  74. SSI_AUTHUSER, FILE_GENERIC_READ, 0,
  75. SSI_AUTHUSER, GENERIC_READ, ACE_INHERIT,
  76. SSI_AUTHUSER, FILE_GENERIC_WRITE, 0,
  77. SSI_AUTHUSER, GENERIC_WRITE, (CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE),
  78. SSI_POWERUSER, FILE_GENERIC_READ, 0,
  79. SSI_POWERUSER, GENERIC_READ, ACE_INHERIT,
  80. SSI_POWERUSER, FILE_GENERIC_WRITE, 0,
  81. SSI_POWERUSER, GENERIC_WRITE, (CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE),
  82. };
  83. //
  84. // CSIDL_COMMON_APPDATA
  85. // Admins, System, Creator Owner: Full Control - Container Inherit, Object Inherit
  86. // Power Users: Modify - Container Inherit, Object Inherit
  87. // Users: Read - Container Inherit, Object Inherit
  88. //
  89. // Users can only read common appdata which is presumably created by admins or
  90. // power users during setup.
  91. //
  92. const ACEPARAMLIST c_paplCommonAppData[] =
  93. {
  94. SSI_SYSTEM, FILE_ALL_ACCESS, 0,
  95. SSI_SYSTEM, GENERIC_ALL, ACE_INHERIT,
  96. SSI_ADMIN, FILE_ALL_ACCESS, 0,
  97. SSI_ADMIN, GENERIC_ALL, ACE_INHERIT,
  98. SSI_CREATOROWNER, GENERIC_ALL, ACE_INHERIT,
  99. SSI_AUTHUSER, FILE_GENERIC_READ, 0,
  100. SSI_AUTHUSER, GENERIC_READ, ACE_INHERIT,
  101. SSI_POWERUSER, FILE_MODIFY, 0,
  102. SSI_POWERUSER, FILE_MODIFY, ACE_INHERIT,
  103. };
  104. long _SHUnicodeToAnsi(LPCWSTR pwsz, LPSTR psz, long cchCount)
  105. {
  106. psz[0] = 0;
  107. return WideCharToMultiByte(CP_ACP, 0, pwsz, -1, psz, cchCount, 0, 0);
  108. }
  109. BOOL _SetDirAccess(LPCWSTR pszFile, const ACEPARAMLIST* papl, ULONG cPapl);
  110. HINSTANCE g_hinst = NULL;
  111. typedef void (__stdcall * PFNSHFLUSHSFCACHE)();
  112. BOOL IsNewShlwapi(HMODULE hmod)
  113. {
  114. DLLGETVERSIONPROC pfnGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hmod, "DllGetVersion");
  115. if (pfnGetVersion)
  116. {
  117. DLLVERSIONINFO dllinfo;
  118. dllinfo.cbSize = sizeof(dllinfo);
  119. if (pfnGetVersion(&dllinfo) == NOERROR)
  120. {
  121. return (dllinfo.dwMajorVersion > 5) ||
  122. ((dllinfo.dwMajorVersion == 5) &&
  123. ((dllinfo.dwMinorVersion > 0) ||
  124. ((dllinfo.dwMinorVersion == 0) &&
  125. (dllinfo.dwBuildNumber > 2012))));
  126. }
  127. }
  128. return 0;
  129. }
  130. void FlushShellFolderCache()
  131. {
  132. // We could link directly now, but this is a smaller delta...
  133. HMODULE hmod = LoadLibraryA("shlwapi.dll");
  134. if (hmod)
  135. {
  136. // avoid IE5 beta1 shlwapi.dll that has an export here but
  137. // not what we expect
  138. if (IsNewShlwapi(hmod))
  139. {
  140. PFNSHFLUSHSFCACHE pfn = (PFNSHFLUSHSFCACHE)GetProcAddress(hmod, (CHAR *) MAKEINTRESOURCE(419));
  141. if (pfn)
  142. pfn();
  143. }
  144. FreeLibrary(hmod);
  145. }
  146. }
  147. HRESULT _SHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath)
  148. {
  149. HRESULT hr = E_NOTIMPL;
  150. HMODULE hmod = LoadLibraryA("shell32.dll");
  151. if (hmod)
  152. {
  153. PFNSHGETFOLDERPATHW pfn = (PFNSHGETFOLDERPATHW)GetProcAddress(hmod, "SHGetFolderPathW");
  154. if (pfn)
  155. hr = pfn(hwnd, csidl, hToken, dwFlags, pszPath);
  156. FreeLibrary(hmod);
  157. }
  158. return hr;
  159. }
  160. BOOL RunningOnNT()
  161. {
  162. static BOOL s_fRunningOnNT = 42;
  163. if (s_fRunningOnNT == 42)
  164. {
  165. OSVERSIONINFO osvi;
  166. osvi.dwOSVersionInfoSize = sizeof(osvi);
  167. GetVersionEx(&osvi);
  168. s_fRunningOnNT = (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId);
  169. }
  170. return s_fRunningOnNT;
  171. }
  172. // shell32.SHGetSpecialFolderPath (175)
  173. // undocumented API, but the only one that exists on all platforms
  174. //
  175. // this thunk deals with the A/W issues based on the platform as
  176. // the export was TCHAR
  177. //
  178. typedef BOOL(__stdcall * PFNSHGETSPECIALFOLDERPATH)(HWND hwnd, LPWSTR pszPath, int csidl, BOOL fCreate);
  179. BOOL _SHGetSpecialFolderPath(HWND hwnd, LPWSTR pszPath, int csidl, BOOL fCreate)
  180. {
  181. BOOL bRet = FALSE;
  182. HMODULE hmod = LoadLibraryA("shell32.dll");
  183. if (hmod)
  184. {
  185. PFNSHGETSPECIALFOLDERPATH pfn = (PFNSHGETSPECIALFOLDERPATH)GetProcAddress(hmod, (CHAR*) MAKEINTRESOURCE(175));
  186. if (pfn)
  187. {
  188. if (RunningOnNT()) // compute from Get
  189. {
  190. bRet = pfn(hwnd, pszPath, csidl, fCreate);
  191. }
  192. else
  193. {
  194. CHAR szPath[MAX_PATH];
  195. szPath[0] = 0;
  196. bRet = pfn(hwnd, (LPWSTR)szPath, csidl, fCreate);
  197. if (bRet)
  198. SHAnsiToUnicode(szPath, pszPath, MAX_PATH); // WideCharToMultiByte wrapper
  199. }
  200. }
  201. FreeLibrary(hmod);
  202. }
  203. return bRet;
  204. }
  205. BOOL GetProgramFiles(LPCWSTR pszValue, LPWSTR pszPath)
  206. {
  207. HKEY hkey;
  208. DWORD cbPath = MAX_PATH;
  209. *pszPath = 0;
  210. if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 0, KEY_QUERY_VALUE, &hkey))
  211. {
  212. if (RunningOnNT())
  213. {
  214. cbPath *= sizeof(WCHAR);
  215. RegQueryValueExW(hkey, pszValue, NULL, NULL, (LPBYTE) pszPath, &cbPath);
  216. }
  217. else
  218. {
  219. CHAR szPath[MAX_PATH], szValue[64];
  220. szPath[0] = 0;
  221. _SHUnicodeToAnsi(pszValue, szValue, ARRAYSIZE(szValue));
  222. RegQueryValueExA(hkey, szValue, NULL, NULL, szPath, &cbPath);
  223. SHAnsiToUnicode(szPath, pszPath, MAX_PATH);
  224. }
  225. RegCloseKey(hkey);
  226. }
  227. return (BOOL)*pszPath;
  228. }
  229. // get the equiv of %USERPROFILE% on both win95 and NT
  230. //
  231. // on Win95 without user profiles turned on this will fail
  232. // out:
  233. // phkey optional out param
  234. //
  235. // returns:
  236. // length of the profile path
  237. UINT GetProfilePath(LPWSTR pszPath, HKEY *phkey, UINT *pcchProfile)
  238. {
  239. if (phkey)
  240. *phkey = NULL;
  241. if (pcchProfile)
  242. *pcchProfile = 0;
  243. if (RunningOnNT())
  244. {
  245. ExpandEnvironmentStringsW(L"%USERPROFILE%", pszPath, MAX_PATH);
  246. if (pszPath[0] == L'%')
  247. pszPath[0] = 0;
  248. }
  249. else
  250. {
  251. HKEY hkeyProfRec;
  252. LONG err;
  253. CHAR szProfileDir[MAX_PATH];
  254. szProfileDir [0] = 0;
  255. err = RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\ProfileReconciliation", 0, NULL,
  256. REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE,
  257. NULL, &hkeyProfRec, NULL);
  258. if (err == ERROR_SUCCESS)
  259. {
  260. DWORD cbData = sizeof(szProfileDir);
  261. RegQueryValueExA(hkeyProfRec, "ProfileDirectory", 0, NULL, (LPBYTE)szProfileDir, &cbData);
  262. if (phkey)
  263. *phkey = hkeyProfRec;
  264. else
  265. RegCloseKey(hkeyProfRec);
  266. if (pcchProfile)
  267. *pcchProfile = lstrlenA(szProfileDir);
  268. SHAnsiToUnicode(szProfileDir, pszPath, MAX_PATH);
  269. }
  270. }
  271. return lstrlenW(pszPath);
  272. }
  273. void SHGetWindowsDirectory(LPWSTR pszPath)
  274. {
  275. if (RunningOnNT())
  276. GetWindowsDirectoryW(pszPath, MAX_PATH);
  277. else
  278. {
  279. CHAR szPath[MAX_PATH];
  280. if (GetWindowsDirectoryA(szPath, ARRAYSIZE(szPath)-1))
  281. SHAnsiToUnicode(szPath, pszPath, MAX_PATH);
  282. }
  283. }
  284. #define CH_WHACK FILENAME_SEPARATOR_W
  285. // add a backslash to a qualified path
  286. //
  287. // in:
  288. // pszPath path (A:, C:\foo, etc)
  289. //
  290. // out:
  291. // pszPath A:\, C:\foo\ ;
  292. //
  293. // returns:
  294. // pointer to the NULL that terminates the path
  295. STDAPI_(LPWSTR) PathAddBackslash(LPWSTR pszPath)
  296. {
  297. LPWSTR pszEnd;
  298. // try to keep us from tromping over MAX_PATH in size.
  299. // if we find these cases, return NULL. Note: We need to
  300. // check those places that call us to handle their GP fault
  301. // if they try to use the NULL!
  302. int ichPath = lstrlenW(pszPath);
  303. if (ichPath >= (MAX_PATH - 1))
  304. return NULL;
  305. pszEnd = pszPath + ichPath;
  306. // this is really an error, caller shouldn't pass
  307. // an empty string
  308. if (!*pszPath)
  309. return pszEnd;
  310. /* Get the end of the source directory
  311. */
  312. switch(* (pszEnd-1)) {
  313. case CH_WHACK:
  314. break;
  315. default:
  316. *pszEnd++ = CH_WHACK;
  317. *pszEnd = 0;
  318. }
  319. return pszEnd;
  320. }
  321. // Returns a pointer to the last component of a path string.
  322. //
  323. // in:
  324. // path name, either fully qualified or not
  325. //
  326. // returns:
  327. // pointer into the path where the path is. if none is found
  328. // returns a poiter to the start of the path
  329. //
  330. // c:\foo\bar -> bar
  331. // c:\foo -> foo
  332. // c:\foo\ -> c:\foo\ (REVIEW: is this case busted?)
  333. // c:\ -> c:\ (REVIEW: this case is strange)
  334. // c: -> c:
  335. // foo -> foo
  336. STDAPI_(LPWSTR) PathFindFileName(LPCWSTR pPath)
  337. {
  338. LPCWSTR pT;
  339. for (pT = pPath; *pPath; ++pPath)
  340. {
  341. if ((pPath[0] == L'\\' || pPath[0] == L':' || pPath[0] == L'/')
  342. && pPath[1] && pPath[1] != L'\\' && pPath[1] != L'/')
  343. pT = pPath + 1;
  344. }
  345. return (LPWSTR)pT; // const -> non const
  346. }
  347. STDAPI_(LPWSTR) PathFindSecondFileName(LPCWSTR pPath)
  348. {
  349. LPCWSTR pT, pRet = NULL;
  350. for (pT = pPath; *pPath; ++pPath)
  351. {
  352. if ((pPath[0] == L'\\' || pPath[0] == L':' || pPath[0] == L'/')
  353. && pPath[1] && pPath[1] != L'\\' && pPath[1] != L'/')
  354. {
  355. pRet = pT; // remember last
  356. pT = pPath + 1;
  357. }
  358. }
  359. return (LPWSTR)pRet; // const -> non const
  360. }
  361. // This function is modified in that if the string's length is 0, the null terminator is NOT copied to the buffer.
  362. int _LoadStringExW(
  363. UINT wID,
  364. LPWSTR lpBuffer, // Unicode buffer
  365. int cchBufferMax, // cch in Unicode buffer
  366. WORD wLangId)
  367. {
  368. HRSRC hResInfo;
  369. HANDLE hStringSeg;
  370. LPWSTR lpsz;
  371. int cch;
  372. cch = 0;
  373. // String Tables are broken up into 16 string segments. Find the segment
  374. // containing the string we are interested in.
  375. if (hResInfo = FindResourceExW(g_hinst, (LPCWSTR)RT_STRING,
  376. (LPWSTR)((LONG_PTR)(((USHORT)wID >> 4) + 1)), wLangId))
  377. {
  378. // Load that segment.
  379. hStringSeg = LoadResource(g_hinst, hResInfo);
  380. // Lock the resource.
  381. if (lpsz = (LPWSTR)LockResource(hStringSeg))
  382. {
  383. // Move past the other strings in this segment.
  384. // (16 strings in a segment -> & 0x0F)
  385. wID &= 0x0F;
  386. while (TRUE)
  387. {
  388. cch = *((WORD *)lpsz++); // PASCAL like string count
  389. // first UTCHAR is count if TCHARs
  390. if (wID-- == 0) break;
  391. lpsz += cch; // Step to start if next string
  392. }
  393. // Account for the NULL
  394. cchBufferMax--;
  395. // Don't copy more than the max allowed.
  396. if (cch > cchBufferMax)
  397. cch = cchBufferMax;
  398. // Copy the string into the buffer.
  399. CopyMemory(lpBuffer, lpsz, cch * sizeof(WCHAR));
  400. // Attach Null terminator.
  401. lpBuffer[cch] = 0;
  402. }
  403. }
  404. return cch;
  405. }
  406. BOOL CALLBACK EnumResLangProc(HINSTANCE hinst, LPCWSTR lpszType, LPCWSTR lpszName, LANGID wLangId, LPARAM lParam)
  407. {
  408. *(LANGID *)lParam = wLangId;
  409. return FALSE;
  410. }
  411. BOOL CALLBACK EnumResNameProc(HINSTANCE hinst, LPCWSTR lpszType, LPCWSTR lpszName, LPARAM lParam)
  412. {
  413. EnumResourceLanguagesW(hinst, lpszType, lpszName, EnumResLangProc, lParam);
  414. return FALSE;
  415. }
  416. LANGID GetShellLangId()
  417. {
  418. static LANGID wShellLangID=0xffff;
  419. if (0xffff == wShellLangID)
  420. {
  421. BOOL fSuccess;
  422. HINSTANCE hShell;
  423. hShell = LoadLibraryA("shell32.dll");
  424. if (hShell)
  425. {
  426. EnumResourceNamesW(hShell, (LPWSTR) RT_VERSION, EnumResNameProc, (LPARAM) &wShellLangID);
  427. FreeLibrary(hShell);
  428. }
  429. if (0xffff == wShellLangID)
  430. wShellLangID = GetSystemDefaultLangID();
  431. }
  432. return wShellLangID;
  433. }
  434. void PathAppend(LPWSTR pszPath, LPCWSTR pszAppend)
  435. {
  436. if (pszPath && pszAppend && PathAddBackslash(pszPath))
  437. {
  438. StringCchCatW(pszPath, MAX_PATH, pszAppend);
  439. }
  440. }
  441. void PathAppendResource(LPWSTR pszPath, UINT id)
  442. {
  443. WCHAR sz[MAX_PATH];
  444. sz[0] = 0;
  445. if (!_LoadStringExW(id, sz, ARRAYSIZE(sz), GetShellLangId()))
  446. {
  447. _LoadStringExW(id, sz, ARRAYSIZE(sz), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
  448. }
  449. if (*sz)
  450. {
  451. PathAppend(pszPath, sz);
  452. }
  453. }
  454. const CHAR c_szUSF[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
  455. const CHAR c_szSF[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
  456. LONG RegSetStrW(HKEY hkey, LPCWSTR pszValueName, LPCWSTR pszValue)
  457. {
  458. return RegSetValueExW(hkey, pszValueName, 0, REG_SZ, (LPBYTE)pszValue, (lstrlenW(pszValue) + 1) * sizeof(WCHAR));
  459. }
  460. LONG RegSetStrA(HKEY hkey, LPCSTR pszValueName, LPCSTR pszValue)
  461. {
  462. return RegSetValueExA(hkey, pszValueName, 0, REG_SZ, (LPBYTE)pszValue, (lstrlenA(pszValue) + 1) * sizeof(CHAR));
  463. }
  464. void MakeFolderRoam(HKEY hkeyProfRec, LPCSTR pszName, LPCWSTR pszPath, UINT cchProfile)
  465. {
  466. HKEY hSubKey;
  467. LONG err;
  468. CHAR szPath[MAX_PATH];
  469. ASSERT(!RunningOnNT());
  470. _SHUnicodeToAnsi(pszPath, szPath, ARRAYSIZE(szPath));
  471. err = RegCreateKeyExA(hkeyProfRec, pszName, 0, NULL, REG_OPTION_NON_VOLATILE,
  472. KEY_SET_VALUE, NULL, &hSubKey, NULL);
  473. if (err == ERROR_SUCCESS)
  474. {
  475. CHAR szDefaultPath[MAX_PATH];
  476. DWORD dwOne = 1;
  477. LPCSTR pszEnd = szPath + cchProfile + 1;
  478. szDefaultPath[0] = 0;
  479. StringCchCopy(szDefaultPath, ARRAYSIZE(szDefaultPath), "*windir");
  480. StringCchCat(szDefaultPath, ARRAYSIZE(szDefaultPath), szPath + cchProfile);
  481. RegSetStrA(hSubKey, "CentralFile", pszEnd);
  482. RegSetStrA(hSubKey, "LocalFile", pszEnd);
  483. RegSetStrA(hSubKey, "Name", "*.*");
  484. RegSetStrA(hSubKey, "DefaultDir", szDefaultPath);
  485. RegSetValueExA(hSubKey, "MustBeRelative", 0, REG_DWORD, (LPBYTE)&dwOne, sizeof(dwOne));
  486. RegSetValueExA(hSubKey, "Default", 0, REG_DWORD, (LPBYTE)&dwOne, sizeof(dwOne));
  487. RegSetStrA(hSubKey, "RegKey", c_szUSF);
  488. RegSetStrA(hSubKey, "RegValue", pszName);
  489. RegCloseKey(hSubKey);
  490. }
  491. }
  492. typedef struct _FOLDER_INFO
  493. {
  494. int id; // CSIDL value
  495. HKEY hkRoot; // per user, per machine
  496. UINT idsDirName; // esource ID for directory name
  497. LPCSTR pszRegValue; // Name of reg value and ProfileReconciliation subkey
  498. BOOL (*pfnGetPath)(const struct _FOLDER_INFO *, LPWSTR); // compute the path if not found
  499. const ACEPARAMLIST* papl;
  500. ULONG cApl;
  501. }
  502. FOLDER_INFO;
  503. typedef struct _NT_FOLDER_INFO
  504. {
  505. const FOLDER_INFO *pfi;
  506. WCHAR wszRegValue[60]; // this should be long enough to hold the longest member of FOLDER_INFO.pszRegValue
  507. }
  508. NT_FOLDER_INFO;
  509. BOOL DownLevelRoaming(const FOLDER_INFO *pfi, LPWSTR pszPath)
  510. {
  511. HKEY hkeyProfRec;
  512. UINT cchProfile;
  513. UINT cwchProfile = GetProfilePath(pszPath, &hkeyProfRec, &cchProfile);
  514. if (cwchProfile)
  515. {
  516. PathAppendResource(pszPath, pfi->idsDirName);
  517. if (hkeyProfRec)
  518. {
  519. MakeFolderRoam(hkeyProfRec, pfi->pszRegValue, pszPath, cchProfile);
  520. RegCloseKey(hkeyProfRec);
  521. }
  522. }
  523. else
  524. {
  525. SHGetWindowsDirectory(pszPath);
  526. if (pfi->id == CSIDL_PERSONAL)
  527. {
  528. if (pszPath[1] == TEXT(':') &&
  529. pszPath[2] == TEXT('\\'))
  530. {
  531. pszPath[3] = 0; // strip to "C:\"
  532. }
  533. }
  534. PathAppendResource(pszPath, pfi->idsDirName);
  535. }
  536. return (BOOL)*pszPath;
  537. }
  538. BOOL DownLevelNonRoaming(const FOLDER_INFO *pfi, LPWSTR pszPath)
  539. {
  540. UINT cchProfile = GetProfilePath(pszPath, NULL, 0);
  541. if (cchProfile)
  542. {
  543. PathAppendResource(pszPath, pfi->idsDirName);
  544. }
  545. else
  546. {
  547. SHGetWindowsDirectory(pszPath);
  548. PathAppendResource(pszPath, pfi->idsDirName);
  549. }
  550. return (BOOL)*pszPath;
  551. }
  552. BOOL DownLevelRelative(UINT csidl, UINT id, LPWSTR pszPath)
  553. {
  554. *pszPath = 0; // assume error
  555. // since this is inside MyDocs make sure MyDocs exists first (for the create call)
  556. if (SHGetFolderPathW(NULL, csidl | CSIDL_FLAG_CREATE, NULL, 0, pszPath) == S_OK)
  557. {
  558. PathAppendResource(pszPath, id);
  559. }
  560. return (BOOL)*pszPath;
  561. }
  562. // we explictly don't want the MyPics folder to roam. the reasonaing being
  563. // that the contents of this are typically too large to give a good roaming
  564. // experience. but of course NT4 (< SP4) still roams everyting in the profile
  565. // dir thus this will roam on those platforms.
  566. BOOL DownLevelMyPictures(const FOLDER_INFO *pfi, LPWSTR pszPath)
  567. {
  568. return DownLevelRelative(CSIDL_PERSONAL, IDS_CSIDL_MYPICTURES, pszPath);
  569. }
  570. BOOL DownLevelMyMusic(const FOLDER_INFO *pfi, LPWSTR pszPath)
  571. {
  572. return DownLevelRelative(CSIDL_PERSONAL, IDS_CSIDL_MYMUSIC, pszPath);
  573. }
  574. BOOL DownLevelAdminTools(const FOLDER_INFO *pfi, LPWSTR pszPath)
  575. {
  576. return DownLevelRelative(CSIDL_PROGRAMS, IDS_CSIDL_ADMINTOOLS, pszPath);
  577. }
  578. BOOL DownLevelCommonAdminTools(const FOLDER_INFO *pfi, LPWSTR pszPath)
  579. {
  580. return DownLevelRelative(CSIDL_COMMON_PROGRAMS, IDS_CSIDL_ADMINTOOLS, pszPath);
  581. }
  582. const WCHAR c_wszAllUsers[] = L"All Users"; // not localized
  583. BOOL GetAllUsersRoot(LPWSTR pszPath)
  584. {
  585. if (GetProfilePath(pszPath, NULL, 0))
  586. {
  587. // yes, non localized "All Users" per ericflo (NT4 behavior)
  588. LPWSTR pszFileName = PathFindFileName(pszPath);
  589. StringCchCopyW(pszFileName, MAX_PATH - (lstrlenW(pszPath) - lstrlenW(pszFileName)), c_wszAllUsers);
  590. }
  591. else
  592. {
  593. // Win95 case
  594. SHGetWindowsDirectory(pszPath);
  595. // yes, non localized "All Users" per ericflo (NT4 behavior)
  596. PathAppend(pszPath, c_wszAllUsers);
  597. }
  598. return *pszPath;
  599. }
  600. BOOL DownLevelCommon(const FOLDER_INFO *pfi, LPWSTR pszPath)
  601. {
  602. if (GetAllUsersRoot(pszPath))
  603. {
  604. PathAppendResource(pszPath, pfi->idsDirName);
  605. }
  606. return (BOOL)*pszPath;
  607. }
  608. BOOL DownLevelCommonPrograms(const FOLDER_INFO *pfi, LPWSTR pszPath)
  609. {
  610. WCHAR szPath[MAX_PATH];
  611. if (S_OK == SHGetFolderPathW(NULL, CSIDL_PROGRAMS, NULL, 0, szPath))
  612. {
  613. if (GetAllUsersRoot(pszPath))
  614. {
  615. PathAppend(pszPath, PathFindSecondFileName(szPath));
  616. }
  617. }
  618. return (BOOL)*pszPath;
  619. }
  620. #define HKLM HKEY_LOCAL_MACHINE
  621. #define HKCU HKEY_CURRENT_USER
  622. const FOLDER_INFO c_rgFolders[] =
  623. {
  624. { CSIDL_PERSONAL, HKCU, IDS_CSIDL_PERSONAL, "Personal",
  625. DownLevelRoaming, NULL, 0 },
  626. { CSIDL_MYPICTURES, HKCU, IDS_CSIDL_MYPICTURES, "My Pictures",
  627. DownLevelMyPictures, NULL, 0 },
  628. { CSIDL_MYMUSIC, HKCU, IDS_CSIDL_MYMUSIC, "My Music",
  629. DownLevelMyMusic, NULL, 0 },
  630. { CSIDL_APPDATA, HKCU, IDS_CSIDL_APPDATA, "AppData",
  631. DownLevelRoaming, NULL, 0 },
  632. { CSIDL_LOCAL_APPDATA, HKCU, IDS_CSIDL_LOCAL_APPDATA, "Local AppData",
  633. DownLevelNonRoaming, NULL, 0 },
  634. { CSIDL_INTERNET_CACHE, HKCU, IDS_CSIDL_CACHE, "Cache",
  635. DownLevelNonRoaming, NULL, 0 },
  636. { CSIDL_COOKIES, HKCU, IDS_CSIDL_COOKIES, "Cookies",
  637. DownLevelRoaming, NULL, 0 },
  638. { CSIDL_HISTORY, HKCU, IDS_CSIDL_HISTORY, "History",
  639. DownLevelRoaming, NULL, 0 },
  640. { CSIDL_ADMINTOOLS, HKCU, IDS_CSIDL_ADMINTOOLS, "Administrative Tools",
  641. DownLevelAdminTools, NULL, 0 },
  642. { CSIDL_COMMON_APPDATA, HKLM, IDS_CSIDL_APPDATA, "Common AppData",
  643. DownLevelCommon, c_paplCommonAppData, ARRAYSIZE(c_paplCommonAppData) },
  644. { CSIDL_COMMON_DOCUMENTS, HKLM, IDS_CSIDL_COMMON_DOCUMENTS, "Common Documents",
  645. DownLevelCommon, c_paplCommonDocs, ARRAYSIZE(c_paplCommonDocs) },
  646. { CSIDL_COMMON_PROGRAMS, HKLM, 0, "Common Programs",
  647. DownLevelCommonPrograms, c_paplUnsecure, ARRAYSIZE(c_paplUnsecure) },
  648. { CSIDL_COMMON_ADMINTOOLS, HKLM, IDS_CSIDL_ADMINTOOLS, "Common Administrative Tools",
  649. DownLevelCommonAdminTools, c_paplUnsecure, ARRAYSIZE(c_paplUnsecure) },
  650. { -1, HKCU, 0, NULL, NULL, NULL }
  651. };
  652. BOOL UnExpandEnvironmentString(LPCWSTR pszPath, LPCWSTR pszEnvVar, LPWSTR pszResult, UINT cchResult)
  653. {
  654. DWORD nToCmp;
  655. WCHAR szEnvVar[MAX_PATH];
  656. szEnvVar[0] = 0;
  657. ASSERT(RunningOnNT());
  658. ExpandEnvironmentStringsW(pszEnvVar, szEnvVar, ARRAYSIZE(szEnvVar)); // don't count the NULL
  659. nToCmp = lstrlenW(szEnvVar);
  660. if (CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, szEnvVar, nToCmp, pszPath, nToCmp) == 2)
  661. {
  662. if (lstrlenW(pszPath) - (int)nToCmp + lstrlenW(pszEnvVar) < (int)cchResult)
  663. {
  664. StringCchCopyW(pszResult, cchResult, pszEnvVar);
  665. StringCchCatW(pszResult, cchResult, pszPath + nToCmp);
  666. return TRUE;
  667. }
  668. }
  669. return FALSE;
  670. }
  671. const FOLDER_INFO *FindFolderInfo(int csidl)
  672. {
  673. const FOLDER_INFO *pfi;
  674. for (pfi = c_rgFolders; pfi->id != -1; pfi++)
  675. {
  676. if (pfi->id == csidl)
  677. return pfi;
  678. }
  679. return NULL;
  680. }
  681. BOOL _SHCreateDirectory(LPCWSTR pszPath)
  682. {
  683. if (RunningOnNT())
  684. return CreateDirectoryW(pszPath, NULL);
  685. else
  686. {
  687. // no check for Unicode -> Ansi needed here, because we validated
  688. // the path in _EnsureExistsOrCreate()
  689. CHAR szPath[MAX_PATH];
  690. _SHUnicodeToAnsi(pszPath, szPath, ARRAYSIZE(szPath));
  691. return CreateDirectoryA(szPath, NULL);
  692. }
  693. }
  694. BOOL _CreateDirectoryDeep(LPCWSTR pszPath)
  695. {
  696. BOOL fRet = _SHCreateDirectory(pszPath);
  697. if (!fRet && (lstrlenW(pszPath) < MAX_PATH))
  698. {
  699. WCHAR *pSlash, szTemp[MAX_PATH];
  700. // There are certain error codes that we should bail out here
  701. // before going through and walking up the tree...
  702. switch (GetLastError())
  703. {
  704. case ERROR_FILENAME_EXCED_RANGE:
  705. case ERROR_FILE_EXISTS:
  706. return FALSE;
  707. }
  708. StringCchCopyW(szTemp, ARRAYSIZE(szTemp), pszPath);
  709. fRet = (PathAddBackslash(szTemp) != NULL); // for the loop below
  710. if (fRet)
  711. {
  712. // assume we have 'X:\' to start this should even work
  713. // on UNC names because will will ignore the first error
  714. pSlash = szTemp + 3;
  715. // create each part of the dir in order
  716. while (*pSlash)
  717. {
  718. while (*pSlash && *pSlash != CH_WHACK)
  719. pSlash ++;
  720. if (*pSlash)
  721. {
  722. *pSlash = 0; // terminate path at seperator
  723. fRet = _SHCreateDirectory(szTemp);
  724. }
  725. *pSlash++ = CH_WHACK; // put the seperator back
  726. }
  727. }
  728. }
  729. return fRet;
  730. }
  731. // check for
  732. // X:\foo
  733. // \\foo
  734. BOOL PathIsFullyQualified(LPCWSTR pszPath)
  735. {
  736. return pszPath[0] && pszPath[1] &&
  737. (pszPath[1] == ':' || (pszPath[0] == '\\' && pszPath[1] == '\\'));
  738. }
  739. HRESULT GetPathFromRegOrDefault(const NT_FOLDER_INFO *npfi, LPWSTR pszPath)
  740. {
  741. HRESULT hr;
  742. HKEY hkeyUserShellFolders;
  743. LONG err;
  744. CHAR szPath[MAX_PATH];
  745. const FOLDER_INFO *pfi = npfi->pfi;
  746. szPath[0] = 0;
  747. err = RegCreateKeyExA(pfi->hkRoot, c_szUSF, 0, NULL, REG_OPTION_NON_VOLATILE,
  748. KEY_QUERY_VALUE, NULL, &hkeyUserShellFolders, NULL);
  749. if (err == ERROR_SUCCESS)
  750. {
  751. DWORD dwType, cbData = MAX_PATH * sizeof(*pszPath);
  752. if (RunningOnNT())
  753. {
  754. err = RegQueryValueExW(hkeyUserShellFolders, npfi->wszRegValue, NULL, &dwType, (LPBYTE)pszPath, &cbData);
  755. }
  756. else
  757. {
  758. err = RegQueryValueExA(hkeyUserShellFolders, pfi->pszRegValue, NULL, &dwType, (LPBYTE)szPath, &cbData);
  759. SHAnsiToUnicode(szPath, pszPath, MAX_PATH);
  760. }
  761. if (err == ERROR_SUCCESS && cbData)
  762. {
  763. if (dwType == REG_EXPAND_SZ)
  764. {
  765. if (RunningOnNT())
  766. {
  767. WCHAR szExpand[MAX_PATH];
  768. szExpand[0] = 0;
  769. if (ExpandEnvironmentStringsW(pszPath, szExpand, ARRAYSIZE(szExpand)))
  770. {
  771. StringCchCopyW(pszPath, MAX_PATH, szExpand);
  772. }
  773. }
  774. else
  775. {
  776. CHAR szExpand[MAX_PATH];
  777. szExpand[0] = 0;
  778. if (ExpandEnvironmentStringsA(szPath, szExpand, ARRAYSIZE(szExpand)))
  779. {
  780. SHAnsiToUnicode(szExpand, pszPath, MAX_PATH);
  781. }
  782. }
  783. }
  784. }
  785. else if (pfi->pfnGetPath && pfi->pfnGetPath(pfi, pszPath))
  786. {
  787. err = ERROR_SUCCESS;
  788. // store results back to "User Shell Folders" on NT, but not on Win95
  789. if (RunningOnNT())
  790. {
  791. WCHAR szDefaultPath[MAX_PATH];
  792. HKEY hkeyWriteUserShellFolders;
  793. LONG err2;
  794. szDefaultPath[0] = 0;
  795. if (!UnExpandEnvironmentString(pszPath, L"%USERPROFILE%", szDefaultPath, ARRAYSIZE(szDefaultPath)))
  796. {
  797. if (!UnExpandEnvironmentString(pszPath, L"%SYSTEMROOT%", szDefaultPath, ARRAYSIZE(szDefaultPath)))
  798. {
  799. StringCchCopyW(szDefaultPath, ARRAYSIZE(szDefaultPath), pszPath);
  800. }
  801. }
  802. err2 = RegCreateKeyExA(pfi->hkRoot, c_szUSF, 0, NULL, REG_OPTION_NON_VOLATILE,
  803. KEY_SET_VALUE, NULL, &hkeyWriteUserShellFolders, NULL);
  804. if (err2 == ERROR_SUCCESS)
  805. {
  806. RegSetValueExW(hkeyWriteUserShellFolders, npfi->wszRegValue, 0, REG_EXPAND_SZ, (LPBYTE)szDefaultPath, (lstrlenW(szDefaultPath) + 1) * sizeof(szDefaultPath[0]));
  807. RegCloseKey(hkeyWriteUserShellFolders);
  808. }
  809. }
  810. }
  811. else
  812. err = ERROR_PATH_NOT_FOUND;
  813. // validate the returned path here
  814. if (err == ERROR_SUCCESS)
  815. {
  816. // expand failed (or some app messed up and did not use REG_EXPAND_SZ)
  817. if (*pszPath == L'%')
  818. {
  819. err = ERROR_ENVVAR_NOT_FOUND;
  820. *pszPath = 0;
  821. }
  822. else if (!PathIsFullyQualified(pszPath))
  823. {
  824. err = ERROR_PATH_NOT_FOUND;
  825. *pszPath = 0;
  826. }
  827. }
  828. RegCloseKey(hkeyUserShellFolders);
  829. }
  830. return HRESULT_FROM_WIN32(err);
  831. }
  832. HRESULT _EnsureExistsOrCreate(LPWSTR pszPath, BOOL bCreate, const ACEPARAMLIST* papl, ULONG cApl)
  833. {
  834. HRESULT hr;
  835. DWORD dwFileAttributes;
  836. if (RunningOnNT())
  837. dwFileAttributes = GetFileAttributesW(pszPath);
  838. else
  839. {
  840. CHAR szPath[MAX_PATH];
  841. if (_SHUnicodeToAnsi(pszPath, szPath, ARRAYSIZE(szPath)))
  842. dwFileAttributes = GetFileAttributesA(szPath);
  843. else
  844. {
  845. pszPath[0] = 0;
  846. return HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION);
  847. }
  848. }
  849. if (dwFileAttributes == -1)
  850. {
  851. if (bCreate)
  852. {
  853. if (_CreateDirectoryDeep(pszPath))
  854. {
  855. hr = S_OK;
  856. if (papl && RunningOnNT())
  857. {
  858. _SetDirAccess(pszPath, papl, cApl);
  859. }
  860. }
  861. else
  862. {
  863. hr = HRESULT_FROM_WIN32(GetLastError());
  864. *pszPath = 0;
  865. }
  866. }
  867. else
  868. {
  869. hr = S_FALSE;
  870. *pszPath = 0;
  871. }
  872. }
  873. else
  874. hr = S_OK;
  875. return hr;
  876. }
  877. HRESULT _DownLevelGetFolderPath(int csidl, LPWSTR pszPath, BOOL bCreate)
  878. {
  879. const FOLDER_INFO *pfi;
  880. HRESULT hr = E_INVALIDARG;
  881. *pszPath = 0; // assume error
  882. pfi = FindFolderInfo(csidl);
  883. if (pfi)
  884. {
  885. NT_FOLDER_INFO nfi;
  886. nfi.pfi = pfi;
  887. SHAnsiToUnicode(pfi->pszRegValue, nfi.wszRegValue, ARRAYSIZE(nfi.wszRegValue));
  888. // get default value from "User Shell Folders"
  889. hr = GetPathFromRegOrDefault(&nfi, pszPath);
  890. if (SUCCEEDED(hr))
  891. {
  892. hr = _EnsureExistsOrCreate(pszPath, bCreate, pfi->papl, pfi->cApl);
  893. if (hr == S_OK)
  894. {
  895. HKEY hkeyShellFolders;
  896. LONG err;
  897. // store to "Shell Folders"
  898. err = RegCreateKeyExA(pfi->hkRoot, c_szSF, 0, NULL, REG_OPTION_NON_VOLATILE,
  899. KEY_SET_VALUE, NULL, &hkeyShellFolders, NULL);
  900. if (err == ERROR_SUCCESS)
  901. {
  902. if (RunningOnNT())
  903. {
  904. RegSetStrW(hkeyShellFolders, nfi.wszRegValue, pszPath);
  905. }
  906. else
  907. {
  908. CHAR szPath[MAX_PATH];
  909. _SHUnicodeToAnsi(pszPath, szPath, ARRAYSIZE(szPath));
  910. RegSetStrA(hkeyShellFolders, pfi->pszRegValue, szPath);
  911. }
  912. RegCloseKey(hkeyShellFolders);
  913. }
  914. FlushShellFolderCache();
  915. }
  916. }
  917. }
  918. else
  919. {
  920. if (csidl == CSIDL_WINDOWS)
  921. {
  922. SHGetWindowsDirectory(pszPath);
  923. hr = S_OK;
  924. }
  925. else if (csidl == CSIDL_SYSTEM)
  926. {
  927. if (RunningOnNT())
  928. {
  929. GetSystemDirectoryW(pszPath, MAX_PATH);
  930. }
  931. else
  932. {
  933. CHAR szPath[MAX_PATH];
  934. szPath[0] = 0;
  935. GetSystemDirectoryA(szPath, ARRAYSIZE(szPath));
  936. SHAnsiToUnicode(szPath, pszPath, MAX_PATH);
  937. }
  938. hr = S_OK;
  939. }
  940. else if (csidl == CSIDL_PROGRAM_FILES)
  941. {
  942. hr = GetProgramFiles(L"ProgramFilesDir", pszPath) ? S_OK : S_FALSE;
  943. }
  944. else if (csidl == CSIDL_PROGRAM_FILES_COMMON)
  945. {
  946. hr = GetProgramFiles(L"CommonFilesDir", pszPath) ? S_OK : S_FALSE;
  947. }
  948. }
  949. return hr;
  950. }
  951. // We pass csidl to _SHGetSpecialFolderPath only for NT 4 English folders
  952. // NT bug # 60970
  953. // NT bug # 222510
  954. // NT bug # 221492
  955. STDAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath)
  956. {
  957. HRESULT hr = E_INVALIDARG;
  958. if (pszPath)
  959. {
  960. pszPath[0] = 0;
  961. hr = _SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath);
  962. if (hr == E_NOTIMPL || hr == E_INVALIDARG)
  963. {
  964. BOOL bCreate = csidl & CSIDL_FLAG_CREATE;
  965. csidl &= ~CSIDL_FLAG_MASK; // strip the flags
  966. if (hToken || dwFlags)
  967. return E_INVALIDARG;
  968. if ((csidl < CSIDL_LOCAL_APPDATA) && _SHGetSpecialFolderPath(hwnd, pszPath, csidl, bCreate))
  969. {
  970. hr = S_OK;
  971. }
  972. else
  973. {
  974. hr = _DownLevelGetFolderPath(csidl, pszPath, bCreate);
  975. }
  976. }
  977. }
  978. return hr;
  979. }
  980. STDAPI SHGetFolderPathA(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPSTR pszPath)
  981. {
  982. HRESULT hr = E_INVALIDARG;
  983. if (pszPath)
  984. {
  985. WCHAR wsz[MAX_PATH];
  986. pszPath[0] = 0;
  987. hr = SHGetFolderPathW(hwnd, csidl, NULL, 0, wsz);
  988. if (SUCCEEDED(hr))
  989. {
  990. if (!_SHUnicodeToAnsi(wsz, pszPath, MAX_PATH))
  991. {
  992. hr = HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION);
  993. }
  994. }
  995. }
  996. return hr;
  997. }
  998. BOOL APIENTRY DllMain(IN HANDLE hDll, IN DWORD dwReason, IN LPVOID lpReserved)
  999. {
  1000. switch(dwReason)
  1001. {
  1002. case DLL_PROCESS_ATTACH:
  1003. DisableThreadLibraryCalls(hDll);
  1004. g_hinst = hDll;
  1005. break;
  1006. default:
  1007. break;
  1008. }
  1009. return TRUE;
  1010. }
  1011. BOOL _AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid)
  1012. {
  1013. //
  1014. // First verify that the SID is valid on this platform
  1015. //
  1016. WCHAR szName[MAX_PATH], szDomain[MAX_PATH];
  1017. DWORD cbName = ARRAYSIZE(szName);
  1018. DWORD cbDomain = ARRAYSIZE(szDomain);
  1019. SID_NAME_USE snu;
  1020. if (LookupAccountSidW(NULL, pSid, szName, &cbName, szDomain, &cbDomain, &snu))
  1021. {
  1022. //
  1023. // Yes, it's valid; now add the ACE
  1024. //
  1025. return AddAccessAllowedAce(pAcl, dwAceRevision, AccessMask, pSid);
  1026. }
  1027. return FALSE;
  1028. }
  1029. BOOL _AddAces(PACL pAcl, const ACEPARAMLIST* papl, ULONG cPapl)
  1030. {
  1031. ULONG i;
  1032. for (i = 0; i < cPapl; i++)
  1033. {
  1034. PSID psid = &c_StaticSids[papl[i].dwSidIndex];
  1035. if (_AddAccessAllowedAce(pAcl, ACL_REVISION, papl[i].AccessMask, psid))
  1036. {
  1037. if (papl[i].dwAceFlags)
  1038. {
  1039. ACE_HEADER* pAceHeader;
  1040. if (GetAce(pAcl, i, &pAceHeader))
  1041. {
  1042. pAceHeader->AceFlags |= papl[i].dwAceFlags;
  1043. }
  1044. else
  1045. {
  1046. return FALSE;
  1047. }
  1048. }
  1049. }
  1050. else
  1051. {
  1052. return FALSE;
  1053. }
  1054. }
  1055. return TRUE;
  1056. }
  1057. PACL _CreateAcl(ULONG cPapl)
  1058. {
  1059. // Allocate space for the ACL
  1060. DWORD cbAcl = (cPapl * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + sizeof(c_StaticSids[0])))
  1061. + sizeof(ACL);
  1062. PACL pAcl = (PACL) GlobalAlloc(GPTR, cbAcl);
  1063. if (pAcl)
  1064. {
  1065. InitializeAcl(pAcl, cbAcl, ACL_REVISION);
  1066. }
  1067. return pAcl;
  1068. }
  1069. BOOL _SetDirAccess(LPCWSTR pszDir, const ACEPARAMLIST* papl, ULONG cPapl)
  1070. {
  1071. BOOL bRetVal = FALSE;
  1072. PACL pAcl;
  1073. ASSERT(RunningOnNT());
  1074. pAcl = _CreateAcl(cPapl);
  1075. if (pAcl)
  1076. {
  1077. if (_AddAces(pAcl, papl, cPapl))
  1078. {
  1079. SECURITY_DESCRIPTOR sd;
  1080. // Put together the security descriptor
  1081. if (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
  1082. {
  1083. if (SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE))
  1084. {
  1085. // Set the security
  1086. bRetVal = SetFileSecurityW(pszDir, DACL_SECURITY_INFORMATION, &sd);
  1087. }
  1088. }
  1089. }
  1090. GlobalFree(pAcl);
  1091. }
  1092. return bRetVal;
  1093. }