Module: wine Branch: refs/heads/master Commit: 77474f8a1464f81d273b33283a1b66a300860231 URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=77474f8a1464f81d273b3328...
Author: Michael Jung mjung@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))