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.

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