Module: wine
Branch: refs/heads/master
Commit: 77474f8a1464f81d273b33283a1b66a300860231
URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=77474f8a1464f81d273b332…
Author: Michael Jung <mjung(a)iss.tu-darmstadt.de>
Date: Thu Feb 2 13:28:29 2006 +0100
shell32: Create $HOME targeted symbolic links during SHELL_RegisterFolders.
---
dlls/shell32/shellpath.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 188 insertions(+), 1 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c
index f60397e..4c18539 100644
--- a/dlls/shell32/shellpath.c
+++ b/dlls/shell32/shellpath.c
@@ -27,6 +27,7 @@
#include "config.h"
#include "wine/port.h"
+#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
@@ -1926,13 +1927,199 @@ static HRESULT _SHRegisterCommonShellFol
return hr;
}
+/******************************************************************************
+ * _SHAppendToUnixPath [Internal]
+ *
+ * Helper function for _SHCreateSymbolicLinks. Appends pwszSubPath (or the
+ * corresponding resource, if IS_INTRESOURCE) to the unix base path 'szBasePath'
+ * and replaces backslashes with slashes.
+ *
+ * PARAMS
+ * szBasePath [IO] The unix base path, which will be appended to (CP_UNXICP).
+ * pwszSubPath [I] Sub-path or resource id (use MAKEINTRESOURCEW).
+ *
+ * RETURNS
+ * Success: TRUE,
+ * Failure: FALSE
+ */
+static inline BOOL _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) {
+ WCHAR wszSubPath[MAX_PATH];
+ int cLen = strlen(szBasePath);
+ char *pBackslash;
+
+ if (IS_INTRESOURCE(pwszSubPath)) {
+ if (!LoadStringW(shell32_hInstance, LOWORD(pwszSubPath), wszSubPath, MAX_PATH)) {
+ /* Fall back to hard coded defaults. */
+ switch (LOWORD(pwszSubPath)) {
+ case IDS_PERSONAL:
+ lstrcpyW(wszSubPath, PersonalW);
+ break;
+ case IDS_MYMUSIC:
+ lstrcpyW(wszSubPath, My_MusicW);
+ break;
+ case IDS_MYPICTURES:
+ lstrcpyW(wszSubPath, My_PicturesW);
+ break;
+ case IDS_MYVIDEO:
+ lstrcpyW(wszSubPath, My_VideoW);
+ break;
+ default:
+ ERR("LoadString(%d) failed!\n", LOWORD(pwszSubPath));
+ return FALSE;
+ }
+ }
+ } else {
+ lstrcpyW(wszSubPath, pwszSubPath);
+ }
+
+ if (szBasePath[cLen-1] != '/') szBasePath[cLen++] = '/';
+
+ if (!WideCharToMultiByte(CP_UNIXCP, 0, wszSubPath, -1, szBasePath + cLen,
+ FILENAME_MAX - cLen, NULL, NULL))
+ {
+ return FALSE;
+ }
+
+ pBackslash = szBasePath + cLen;
+ while ((pBackslash = strchr(pBackslash, '\\'))) *pBackslash = '/';
+
+ return TRUE;
+}
+
+/******************************************************************************
+ * _SHCreateSymbolicLinks [Internal]
+ *
+ * Sets up symbol links for various shell folders to point into the users home
+ * directory. We do an educated guess about what the user would probably want:
+ * - If there is a 'My Documents' directory in $HOME, the user probably wants
+ * wine's 'My Documents' to point there. Furthermore, we imply that the user
+ * is a Windows lover and has no problem with wine creating 'My Pictures',
+ * 'My Music' and 'My Video' subfolders under '$HOME/My Documents', if those
+ * do not already exits. We put appropriate symbolic links in place for those,
+ * too.
+ * - If there is no 'My Documents' directory in $HOME, we let 'My Documents'
+ * point directly to $HOME. We assume the user to be a unix hacker who does not
+ * want wine to create anything anywhere besides the .wine directory. So, if
+ * there already is a 'My Music' directory in $HOME, we symlink the 'My Music'
+ * shell folder to it. But if not, we symlink it to $HOME directly. The same
+ * holds fo 'My Pictures' and 'My Video'.
+ * - The Desktop shell folder is symlinked to '$HOME/Desktop', if that does
+ * exists and left alone if not.
+ * ('My Music',... above in fact means LoadString(IDS_MYMUSIC))
+ */
+static void _SHCreateSymbolicLinks()
+{
+ UINT aidsMyStuff[] = { IDS_MYPICTURES, IDS_MYVIDEO, IDS_MYMUSIC }, i;
+ int acsidlMyStuff[] = { CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC };
+ WCHAR wszTempPath[MAX_PATH];
+ char szPersonalTarget[FILENAME_MAX], *pszPersonal;
+ char szMyStuffTarget[FILENAME_MAX], *pszMyStuff;
+ char szDesktopTarget[FILENAME_MAX], *pszDesktop;
+ struct stat statFolder;
+ const char *pszHome;
+ HRESULT hr;
+
+ /* Create all necessary profile sub-dirs up to 'My Documents' and get the unix path. */
+ hr = SHGetFolderPathW(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL,
+ SHGFP_TYPE_DEFAULT, wszTempPath);
+ if (FAILED(hr)) return;
+ pszPersonal = wine_get_unix_file_name(wszTempPath);
+ if (!pszPersonal) return;
+
+ pszHome = getenv("HOME");
+ if (pszHome && !stat(pszHome, &statFolder) && S_ISDIR(statFolder.st_mode)) {
+ strcpy(szPersonalTarget, pszHome);
+ if (_SHAppendToUnixPath(szPersonalTarget, MAKEINTRESOURCEW(IDS_PERSONAL)) &&
+ !stat(szPersonalTarget, &statFolder) && S_ISDIR(statFolder.st_mode))
+ {
+ /* '$HOME/My Documents' exists. Create 'My Pictures', 'My Videos' and
+ * 'My Music' subfolders or fail silently if they already exist. */
+ for (i = 0; i < sizeof(aidsMyStuff)/sizeof(aidsMyStuff[0]); i++) {
+ strcpy(szMyStuffTarget, szPersonalTarget);
+ if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i])))
+ mkdir(szMyStuffTarget, S_IRWXU|S_IRWXG|S_IRWXO);
+ }
+ }
+ else
+ {
+ /* '$HOME/My Documents' doesn't exists, but '$HOME' does. */
+ strcpy(szPersonalTarget, pszHome);
+ }
+
+ /* Replace 'My Documents' directory with a symlink of fail silently if not empty. */
+ rmdir(pszPersonal);
+ symlink(szPersonalTarget, pszPersonal);
+ }
+ else
+ {
+ /* '$HOME' doesn't exist. Create 'My Pictures', 'My Videos' and 'My Music' subdirs
+ * in '%USERPROFILE%\\My Documents' or fail silently if they already exist. */
+ strcpy(szPersonalTarget, pszPersonal);
+ for (i = 0; i < sizeof(aidsMyStuff)/sizeof(aidsMyStuff[0]); i++) {
+ strcpy(szMyStuffTarget, szPersonalTarget);
+ if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i])))
+ mkdir(szMyStuffTarget, S_IRWXU|S_IRWXG|S_IRWXO);
+ }
+ }
+
+ HeapFree(GetProcessHeap(), 0, pszPersonal);
+
+ /* Create symbolic links for 'My Pictures', 'My Video' and 'My Music'. */
+ for (i=0; i < sizeof(aidsMyStuff)/sizeof(aidsMyStuff[0]); i++) {
+ /* Create the current 'My Whatever' folder and get it's unix path. */
+ hr = SHGetFolderPathW(NULL, acsidlMyStuff[i]|CSIDL_FLAG_CREATE, NULL,
+ SHGFP_TYPE_DEFAULT, wszTempPath);
+ if (FAILED(hr)) continue;
+ pszMyStuff = wine_get_unix_file_name(wszTempPath);
+ if (!pszMyStuff) continue;
+
+ strcpy(szMyStuffTarget, szPersonalTarget);
+ if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i])) &&
+ !stat(szMyStuffTarget, &statFolder) && S_ISDIR(statFolder.st_mode))
+ {
+ /* If there's a 'My Whatever' directory where 'My Documents' links to, link to it. */
+ rmdir(pszMyStuff);
+ symlink(szMyStuffTarget, pszMyStuff);
+ }
+ else
+ {
+ /* Else link to where 'My Documents' itself links to. */
+ rmdir(pszMyStuff);
+ symlink(szPersonalTarget, pszMyStuff);
+ }
+ HeapFree(GetProcessHeap(), 0, pszMyStuff);
+ }
+
+ /* Last but not least, the Desktop folder */
+ strcpy(szDesktopTarget, pszHome);
+ if (_SHAppendToUnixPath(szDesktopTarget, DesktopW) &&
+ !stat(szDesktopTarget, &statFolder) && S_ISDIR(statFolder.st_mode))
+ {
+ hr = SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, NULL,
+ SHGFP_TYPE_DEFAULT, wszTempPath);
+ if (SUCCEEDED(hr) && (pszDesktop = wine_get_unix_file_name(wszTempPath)))
+ {
+ rmdir(pszDesktop);
+ symlink(szDesktopTarget, pszDesktop);
+ HeapFree(GetProcessHeap(), 0, pszDesktop);
+ }
+ }
+}
+
/* Register the default values in the registry, as some apps seem to depend
* on their presence. The set registered was taken from Windows XP.
*/
HRESULT SHELL_RegisterShellFolders(void)
{
- HRESULT hr = _SHRegisterUserShellFolders(TRUE);
+ HRESULT hr;
+ /* Set up '$HOME' targeted symlinks for 'My Documents', 'My Pictures',
+ * 'My Video', 'My Music' and 'Desktop' in advance, so that the
+ * _SHRegister*ShellFolders() functions will find everything nice and clean
+ * and thus will not attempt to create them in the profile directory. */
+ _SHCreateSymbolicLinks();
+
+ hr = _SHRegisterUserShellFolders(TRUE);
if (SUCCEEDED(hr))
hr = _SHRegisterUserShellFolders(FALSE);
if (SUCCEEDED(hr))