Looking up shell folders creates real directories when the folder is inexistant, but the intended behavior for some folders is to create symbolic links by default. Prepare that change by moving the helper function above shell folders lookup functions. Also fix whitespace issues in the moved code.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22974 Signed-off-by: Olivier F. R. Dierick o.dierick@piezo-forte.be --- dlls/shell32/shellpath.c | 534 +++++++++++++++++++++++------------------------ 1 file changed, 267 insertions(+), 267 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index b6350ea..9bec709 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -3949,9 +3949,274 @@ end: }
/************************************************************************* + * _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, DocumentsW); + break; + case IDS_MYMUSIC: + lstrcpyW(wszSubPath, My_MusicW); + break; + case IDS_MYPICTURES: + lstrcpyW(wszSubPath, My_PicturesW); + break; + case IDS_MYVIDEOS: + lstrcpyW(wszSubPath, My_VideosW); + break; + case IDS_DOWNLOADS: + lstrcpyW(wszSubPath, DownloadsW); + break; + case IDS_TEMPLATES: + lstrcpyW(wszSubPath, TemplatesW); + 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 user's 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 infer that the user + * is a Windows lover and has no problem with wine creating subfolders for + * 'My Pictures', 'My Music', 'My Videos' etc. under '$HOME/My Documents', if + * those do not already exist. 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, then we check XDG_MUSIC_DIR - "well known" + * directory, and try to link to that. If that fails, then we symlink to + * $HOME directly. The same holds for 'My Pictures', 'My Videos' etc. + * - The Desktop shell folder is symlinked to XDG_DESKTOP_DIR. If that does not + * exist, then we try '$HOME/Desktop'. If that does not exist, then we leave + * it alone. + * ('My Music',... above in fact means LoadString(IDS_MYMUSIC)) + */ +static void _SHCreateSymbolicLinks(void) +{ + static const UINT aidsMyStuff[] = { + IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC, IDS_DOWNLOADS, IDS_TEMPLATES + }; + static const WCHAR * const MyOSXStuffW[] = { + PicturesW, MoviesW, MusicW, DownloadsW, TemplatesW + }; + static const int acsidlMyStuff[] = { + CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES + }; + static const char * const xdg_dirs[] = { + "PICTURES", "VIDEOS", "MUSIC", "DOWNLOAD", "TEMPLATES", "DOCUMENTS", "DESKTOP" + }; + static const unsigned int num = ARRAY_SIZE(xdg_dirs); + 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; + char ** xdg_results; + char * xdg_desktop_dir; + UINT i; + + /* 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; + + hr = XDG_UserDirLookup(xdg_dirs, num, &xdg_results); + if (FAILED(hr)) xdg_results = NULL; + + pszHome = getenv("HOME"); + if (pszHome && !stat(pszHome, &statFolder) && S_ISDIR(statFolder.st_mode)) + { + while (1) + { + /* Check if there's already a Wine-specific 'My Documents' folder */ + strcpy(szPersonalTarget, pszHome); + if (_SHAppendToUnixPath(szPersonalTarget, MAKEINTRESOURCEW(IDS_PERSONAL)) && + !stat(szPersonalTarget, &statFolder) && S_ISDIR(statFolder.st_mode)) + { + /* '$HOME/My Documents' exists. Create subfolders for + * 'My Pictures', 'My Videos', 'My Music' etc. or fail silently + * if they already exist. + */ + for (i = 0; i < ARRAY_SIZE(aidsMyStuff); i++) + { + strcpy(szMyStuffTarget, szPersonalTarget); + if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i]))) + mkdir(szMyStuffTarget, 0777); + } + break; + } + + /* Try to point to the XDG Documents folder */ + if (xdg_results && xdg_results[num-2] && + !stat(xdg_results[num-2], &statFolder) && + S_ISDIR(statFolder.st_mode)) + { + strcpy(szPersonalTarget, xdg_results[num-2]); + break; + } + + /* Or the hardcoded / OS X Documents folder */ + strcpy(szPersonalTarget, pszHome); + if (_SHAppendToUnixPath(szPersonalTarget, DocumentsW) && + !stat(szPersonalTarget, &statFolder) && + S_ISDIR(statFolder.st_mode)) + break; + + /* As a last resort point to $HOME. */ + strcpy(szPersonalTarget, pszHome); + break; + } + + /* Replace 'My Documents' directory with a symlink or fail silently if not empty. */ + remove(pszPersonal); + symlink(szPersonalTarget, pszPersonal); + } + else + { + /* '$HOME' doesn't exist. Create subdirs for 'My Pictures', 'My Videos', + * 'My Music' etc. in '%USERPROFILE%\My Documents' or fail silently if + * they already exist. */ + pszHome = NULL; + strcpy(szPersonalTarget, pszPersonal); + for (i = 0; i < ARRAY_SIZE(aidsMyStuff); i++) { + strcpy(szMyStuffTarget, szPersonalTarget); + if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i]))) + mkdir(szMyStuffTarget, 0777); + } + } + + /* Create symbolic links for 'My Pictures', 'My Videos', 'My Music' etc. */ + for (i=0; i < ARRAY_SIZE(aidsMyStuff); i++) + { + /* Create the current 'My Whatever' folder and get its 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; + + while (1) + { + /* Check for the Wine-specific '$HOME/My Documents' subfolder */ + strcpy(szMyStuffTarget, szPersonalTarget); + if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i])) && + !stat(szMyStuffTarget, &statFolder) && S_ISDIR(statFolder.st_mode)) + break; + + /* Try the XDG_XXX_DIR folder */ + if (xdg_results && xdg_results[i]) + { + strcpy(szMyStuffTarget, xdg_results[i]); + break; + } + + /* Or the OS X folder (these are never localized) */ + if (pszHome) + { + strcpy(szMyStuffTarget, pszHome); + if (_SHAppendToUnixPath(szMyStuffTarget, MyOSXStuffW[i]) && + !stat(szMyStuffTarget, &statFolder) && + S_ISDIR(statFolder.st_mode)) + break; + } + + /* As a last resort point to the same location as 'My Documents' */ + strcpy(szMyStuffTarget, szPersonalTarget); + break; + } + remove(pszMyStuff); + symlink(szMyStuffTarget, pszMyStuff); + heap_free(pszMyStuff); + } + + /* Last but not least, the Desktop folder */ + if (pszHome) + strcpy(szDesktopTarget, pszHome); + else + strcpy(szDesktopTarget, pszPersonal); + heap_free(pszPersonal); + + xdg_desktop_dir = xdg_results ? xdg_results[num - 1] : NULL; + if (xdg_desktop_dir || + (_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))) + { + remove(pszDesktop); + if (xdg_desktop_dir) + symlink(xdg_desktop_dir, pszDesktop); + else + symlink(szDesktopTarget, pszDesktop); + heap_free(pszDesktop); + } + } + + /* Free resources allocated by XDG_UserDirLookup() */ + if (xdg_results) + { + for (i = 0; i < num; i++) + heap_free(xdg_results[i]); + heap_free(xdg_results); + } +} + +/****************************************************************************** * SHGetFolderPathW [SHELL32.@] * - * Convert nFolder to path. + * Convert nFolder to path. * * RETURNS * Success: S_OK @@ -4046,7 +4311,7 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW( DWORD folder = nFolder & CSIDL_FOLDER_MASK; CSIDL_Type type; int ret; - + TRACE("%p,%#x,%p,%#x,%s,%p\n", hwndOwner, nFolder, hToken, dwFlags, debugstr_w(pszSubPath), pszPath);
/* Windows always NULL-terminates the resulting path regardless of success @@ -4382,271 +4647,6 @@ static HRESULT _SHRegisterCommonShellFolders(void) }
/****************************************************************************** - * _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, DocumentsW); - break; - case IDS_MYMUSIC: - lstrcpyW(wszSubPath, My_MusicW); - break; - case IDS_MYPICTURES: - lstrcpyW(wszSubPath, My_PicturesW); - break; - case IDS_MYVIDEOS: - lstrcpyW(wszSubPath, My_VideosW); - break; - case IDS_DOWNLOADS: - lstrcpyW(wszSubPath, DownloadsW); - break; - case IDS_TEMPLATES: - lstrcpyW(wszSubPath, TemplatesW); - 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 user's 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 infer that the user - * is a Windows lover and has no problem with wine creating subfolders for - * 'My Pictures', 'My Music', 'My Videos' etc. under '$HOME/My Documents', if - * those do not already exist. 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, then we check XDG_MUSIC_DIR - "well known" - * directory, and try to link to that. If that fails, then we symlink to - * $HOME directly. The same holds for 'My Pictures', 'My Videos' etc. - * - The Desktop shell folder is symlinked to XDG_DESKTOP_DIR. If that does not - * exist, then we try '$HOME/Desktop'. If that does not exist, then we leave - * it alone. - * ('My Music',... above in fact means LoadString(IDS_MYMUSIC)) - */ -static void _SHCreateSymbolicLinks(void) -{ - static const UINT aidsMyStuff[] = { - IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC, IDS_DOWNLOADS, IDS_TEMPLATES - }; - static const WCHAR * const MyOSXStuffW[] = { - PicturesW, MoviesW, MusicW, DownloadsW, TemplatesW - }; - static const int acsidlMyStuff[] = { - CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES - }; - static const char * const xdg_dirs[] = { - "PICTURES", "VIDEOS", "MUSIC", "DOWNLOAD", "TEMPLATES", "DOCUMENTS", "DESKTOP" - }; - static const unsigned int num = ARRAY_SIZE(xdg_dirs); - 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; - char ** xdg_results; - char * xdg_desktop_dir; - UINT i; - - /* 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; - - hr = XDG_UserDirLookup(xdg_dirs, num, &xdg_results); - if (FAILED(hr)) xdg_results = NULL; - - pszHome = getenv("HOME"); - if (pszHome && !stat(pszHome, &statFolder) && S_ISDIR(statFolder.st_mode)) - { - while (1) - { - /* Check if there's already a Wine-specific 'My Documents' folder */ - strcpy(szPersonalTarget, pszHome); - if (_SHAppendToUnixPath(szPersonalTarget, MAKEINTRESOURCEW(IDS_PERSONAL)) && - !stat(szPersonalTarget, &statFolder) && S_ISDIR(statFolder.st_mode)) - { - /* '$HOME/My Documents' exists. Create subfolders for - * 'My Pictures', 'My Videos', 'My Music' etc. or fail silently - * if they already exist. - */ - for (i = 0; i < ARRAY_SIZE(aidsMyStuff); i++) - { - strcpy(szMyStuffTarget, szPersonalTarget); - if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i]))) - mkdir(szMyStuffTarget, 0777); - } - break; - } - - /* Try to point to the XDG Documents folder */ - if (xdg_results && xdg_results[num-2] && - !stat(xdg_results[num-2], &statFolder) && - S_ISDIR(statFolder.st_mode)) - { - strcpy(szPersonalTarget, xdg_results[num-2]); - break; - } - - /* Or the hardcoded / OS X Documents folder */ - strcpy(szPersonalTarget, pszHome); - if (_SHAppendToUnixPath(szPersonalTarget, DocumentsW) && - !stat(szPersonalTarget, &statFolder) && - S_ISDIR(statFolder.st_mode)) - break; - - /* As a last resort point to $HOME. */ - strcpy(szPersonalTarget, pszHome); - break; - } - - /* Replace 'My Documents' directory with a symlink or fail silently if not empty. */ - remove(pszPersonal); - symlink(szPersonalTarget, pszPersonal); - } - else - { - /* '$HOME' doesn't exist. Create subdirs for 'My Pictures', 'My Videos', - * 'My Music' etc. in '%USERPROFILE%\My Documents' or fail silently if - * they already exist. */ - pszHome = NULL; - strcpy(szPersonalTarget, pszPersonal); - for (i = 0; i < ARRAY_SIZE(aidsMyStuff); i++) { - strcpy(szMyStuffTarget, szPersonalTarget); - if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i]))) - mkdir(szMyStuffTarget, 0777); - } - } - - /* Create symbolic links for 'My Pictures', 'My Videos', 'My Music' etc. */ - for (i=0; i < ARRAY_SIZE(aidsMyStuff); i++) - { - /* Create the current 'My Whatever' folder and get its 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; - - while (1) - { - /* Check for the Wine-specific '$HOME/My Documents' subfolder */ - strcpy(szMyStuffTarget, szPersonalTarget); - if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i])) && - !stat(szMyStuffTarget, &statFolder) && S_ISDIR(statFolder.st_mode)) - break; - - /* Try the XDG_XXX_DIR folder */ - if (xdg_results && xdg_results[i]) - { - strcpy(szMyStuffTarget, xdg_results[i]); - break; - } - - /* Or the OS X folder (these are never localized) */ - if (pszHome) - { - strcpy(szMyStuffTarget, pszHome); - if (_SHAppendToUnixPath(szMyStuffTarget, MyOSXStuffW[i]) && - !stat(szMyStuffTarget, &statFolder) && - S_ISDIR(statFolder.st_mode)) - break; - } - - /* As a last resort point to the same location as 'My Documents' */ - strcpy(szMyStuffTarget, szPersonalTarget); - break; - } - remove(pszMyStuff); - symlink(szMyStuffTarget, pszMyStuff); - heap_free(pszMyStuff); - } - - /* Last but not least, the Desktop folder */ - if (pszHome) - strcpy(szDesktopTarget, pszHome); - else - strcpy(szDesktopTarget, pszPersonal); - heap_free(pszPersonal); - - xdg_desktop_dir = xdg_results ? xdg_results[num - 1] : NULL; - if (xdg_desktop_dir || - (_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))) - { - remove(pszDesktop); - if (xdg_desktop_dir) - symlink(xdg_desktop_dir, pszDesktop); - else - symlink(szDesktopTarget, pszDesktop); - heap_free(pszDesktop); - } - } - - /* Free resources allocated by XDG_UserDirLookup() */ - if (xdg_results) - { - for (i = 0; i < num; i++) - heap_free(xdg_results[i]); - heap_free(xdg_results); - } -} - -/****************************************************************************** * create_extra_folders [Internal] * * Create some extra folders that don't have a standard CSIDL definition.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22974 Signed-off-by: Olivier F. R. Dierick o.dierick@piezo-forte.be --- dlls/shell32/shellpath.c | 48 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index 9bec709..8caf68d 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -3949,6 +3949,43 @@ end: }
/************************************************************************* + * _SHGetXDGUserDirs [Internal] + * + * Get XDG directories paths from XDG configuration. + * + * PARAMS + * xdg_dirs [I] Array of XDG directories to look for. + * num_dirs [I] Number of elements in xdg_dirs. + * xdg_results [O] An array of the XDG directories paths. + */ +static inline void _SHGetXDGUserDirs(const char * const *xdg_dirs, const unsigned int num_dirs, char *** xdg_results) { + HRESULT hr; + + hr = XDG_UserDirLookup(xdg_dirs, num_dirs, xdg_results); + if (FAILED(hr)) *xdg_results = NULL; +} + +/************************************************************************* + * _SHFreeXDGUserDirs [Internal] + * + * Free resources allocated by XDG_UserDirLookup(). + * + * PARAMS + * num_dirs [I] Number of elements in xdg_results. + * xdg_results [I] An array of the XDG directories paths. + */ +static inline void _SHFreeXDGUserDirs(const unsigned int num_dirs, char ** xdg_results) { + UINT i; + + if (xdg_results) + { + for (i = 0; i < num_dirs; i++) + heap_free(xdg_results[i]); + heap_free(xdg_results); + } +} + +/************************************************************************* * _SHAppendToUnixPath [Internal] * * Helper function for _SHCreateSymbolicLinks. Appends pwszSubPath (or the @@ -4069,8 +4106,7 @@ static void _SHCreateSymbolicLinks(void) pszPersonal = wine_get_unix_file_name(wszTempPath); if (!pszPersonal) return;
- hr = XDG_UserDirLookup(xdg_dirs, num, &xdg_results); - if (FAILED(hr)) xdg_results = NULL; + _SHGetXDGUserDirs(xdg_dirs, num, &xdg_results);
pszHome = getenv("HOME"); if (pszHome && !stat(pszHome, &statFolder) && S_ISDIR(statFolder.st_mode)) @@ -4204,13 +4240,7 @@ static void _SHCreateSymbolicLinks(void) } }
- /* Free resources allocated by XDG_UserDirLookup() */ - if (xdg_results) - { - for (i = 0; i < num; i++) - heap_free(xdg_results[i]); - heap_free(xdg_results); - } + _SHFreeXDGUserDirs(num, xdg_results); }
/******************************************************************************
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22974 Signed-off-by: Olivier F. R. Dierick o.dierick@piezo-forte.be --- dlls/shell32/shellpath.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index 8caf68d..0a31ee7 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -4051,6 +4051,33 @@ static inline BOOL _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) { }
/****************************************************************************** + * _SHCreateMyDocumentsSubDirs [Internal] + * + * Create real directories for various shell folders under 'My Documents'. For + * Windows and homeless styles. Fails silently for already existing sub dirs. + * + * PARAMS + * aidsMyStuff [I] Array of IDS_* resources to create sub dirs for. + * num [I] Number of elements in aidsMyStuff. + * szPersonalTarget [I] Unix path to 'My Documents' directory. + */ +static void _SHCreateMyDocumentsSubDirs(const UINT * aidsMyStuff, const UINT num, const char * szPersonalTarget) +{ + char szMyStuffTarget[FILENAME_MAX]; + UINT i; + + if (aidsMyStuff && szPersonalTarget) + { + for (i = 0; i < num; i++) + { + strcpy(szMyStuffTarget, szPersonalTarget); + if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i]))) + mkdir(szMyStuffTarget, 0777); + } + } +} + +/****************************************************************************** * _SHCreateSymbolicLinks [Internal] * * Sets up symbol links for various shell folders to point into the user's home @@ -4122,12 +4149,7 @@ static void _SHCreateSymbolicLinks(void) * 'My Pictures', 'My Videos', 'My Music' etc. or fail silently * if they already exist. */ - for (i = 0; i < ARRAY_SIZE(aidsMyStuff); i++) - { - strcpy(szMyStuffTarget, szPersonalTarget); - if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i]))) - mkdir(szMyStuffTarget, 0777); - } + _SHCreateMyDocumentsSubDirs(aidsMyStuff, ARRAY_SIZE(aidsMyStuff), szPersonalTarget); break; }
@@ -4163,11 +4185,7 @@ static void _SHCreateSymbolicLinks(void) * they already exist. */ pszHome = NULL; strcpy(szPersonalTarget, pszPersonal); - for (i = 0; i < ARRAY_SIZE(aidsMyStuff); i++) { - strcpy(szMyStuffTarget, szPersonalTarget); - if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i]))) - mkdir(szMyStuffTarget, 0777); - } + _SHCreateMyDocumentsSubDirs(aidsMyStuff, ARRAY_SIZE(aidsMyStuff), szPersonalTarget); }
/* Create symbolic links for 'My Pictures', 'My Videos', 'My Music' etc. */
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22974 Signed-off-by: Olivier F. R. Dierick o.dierick@piezo-forte.be --- dlls/shell32/shellpath.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index 0a31ee7..428b3be 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -4051,6 +4051,26 @@ static inline BOOL _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) { }
/****************************************************************************** + * _SHGetFolderUnixPath [Internal] + * + * Create a shell folder and get its unix path. + * + * PARAMS + * nFolder [I] CSIDL identifying the folder. + */ +static inline char * _SHGetFolderUnixPath(const int nFolder) +{ + WCHAR wszTempPath[MAX_PATH]; + HRESULT hr; + + hr = SHGetFolderPathW(NULL, nFolder, NULL, + SHGFP_TYPE_DEFAULT, wszTempPath); + if (FAILED(hr)) return NULL; + + return wine_get_unix_file_name(wszTempPath); +} + +/****************************************************************************** * _SHCreateMyDocumentsSubDirs [Internal] * * Create real directories for various shell folders under 'My Documents'. For @@ -4115,22 +4135,17 @@ static void _SHCreateSymbolicLinks(void) "PICTURES", "VIDEOS", "MUSIC", "DOWNLOAD", "TEMPLATES", "DOCUMENTS", "DESKTOP" }; static const unsigned int num = ARRAY_SIZE(xdg_dirs); - 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; char ** xdg_results; char * xdg_desktop_dir; UINT i;
/* 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); + pszPersonal = _SHGetFolderUnixPath(CSIDL_PERSONAL|CSIDL_FLAG_CREATE); if (!pszPersonal) return;
_SHGetXDGUserDirs(xdg_dirs, num, &xdg_results); @@ -4192,11 +4207,7 @@ static void _SHCreateSymbolicLinks(void) for (i=0; i < ARRAY_SIZE(aidsMyStuff); i++) { /* Create the current 'My Whatever' folder and get its 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); + pszMyStuff = _SHGetFolderUnixPath(acsidlMyStuff[i]|CSIDL_FLAG_CREATE); if (!pszMyStuff) continue;
while (1) @@ -4245,9 +4256,8 @@ static void _SHCreateSymbolicLinks(void) (_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))) + pszDesktop = _SHGetFolderUnixPath(CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE); + if (pszDesktop) { remove(pszDesktop); if (xdg_desktop_dir)
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22974 Signed-off-by: Olivier F. R. Dierick o.dierick@piezo-forte.be --- dlls/shell32/shellpath.c | 125 +++++++++++++++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 42 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index 428b3be..f790afa 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -4098,51 +4098,23 @@ static void _SHCreateMyDocumentsSubDirs(const UINT * aidsMyStuff, const UINT num }
/****************************************************************************** - * _SHCreateSymbolicLinks [Internal] + * _SHCreateMyDocumentsSymbolicLink [Internal] * - * Sets up symbol links for various shell folders to point into the user's 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 infer that the user - * is a Windows lover and has no problem with wine creating subfolders for - * 'My Pictures', 'My Music', 'My Videos' etc. under '$HOME/My Documents', if - * those do not already exist. 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, then we check XDG_MUSIC_DIR - "well known" - * directory, and try to link to that. If that fails, then we symlink to - * $HOME directly. The same holds for 'My Pictures', 'My Videos' etc. - * - The Desktop shell folder is symlinked to XDG_DESKTOP_DIR. If that does not - * exist, then we try '$HOME/Desktop'. If that does not exist, then we leave - * it alone. - * ('My Music',... above in fact means LoadString(IDS_MYMUSIC)) + * Sets up a symbolic link for the 'My Documents' shell folder to point into + * the users home directory. + * + * PARAMS + * aidsMyStuff [I] Array of IDS_* resources to create sub dirs for. + * aids_num [I] Number of elements in aidsMyStuff. */ -static void _SHCreateSymbolicLinks(void) +static void _SHCreateMyDocumentsSymbolicLink(const UINT * aidsMyStuff, const UINT aids_num) { - static const UINT aidsMyStuff[] = { - IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC, IDS_DOWNLOADS, IDS_TEMPLATES - }; - static const WCHAR * const MyOSXStuffW[] = { - PicturesW, MoviesW, MusicW, DownloadsW, TemplatesW - }; - static const int acsidlMyStuff[] = { - CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES - }; - static const char * const xdg_dirs[] = { - "PICTURES", "VIDEOS", "MUSIC", "DOWNLOAD", "TEMPLATES", "DOCUMENTS", "DESKTOP" - }; + static const char * const xdg_dirs[] = { "DOCUMENTS" }; static const unsigned int num = ARRAY_SIZE(xdg_dirs); char szPersonalTarget[FILENAME_MAX], *pszPersonal; - char szMyStuffTarget[FILENAME_MAX], *pszMyStuff; - char szDesktopTarget[FILENAME_MAX], *pszDesktop; struct stat statFolder; const char *pszHome; char ** xdg_results; - char * xdg_desktop_dir; - UINT i;
/* Create all necessary profile sub-dirs up to 'My Documents' and get the unix path. */ pszPersonal = _SHGetFolderUnixPath(CSIDL_PERSONAL|CSIDL_FLAG_CREATE); @@ -4164,16 +4136,16 @@ static void _SHCreateSymbolicLinks(void) * 'My Pictures', 'My Videos', 'My Music' etc. or fail silently * if they already exist. */ - _SHCreateMyDocumentsSubDirs(aidsMyStuff, ARRAY_SIZE(aidsMyStuff), szPersonalTarget); + _SHCreateMyDocumentsSubDirs(aidsMyStuff, aids_num, szPersonalTarget); break; }
/* Try to point to the XDG Documents folder */ - if (xdg_results && xdg_results[num-2] && - !stat(xdg_results[num-2], &statFolder) && + if (xdg_results && xdg_results[0] && + !stat(xdg_results[0], &statFolder) && S_ISDIR(statFolder.st_mode)) { - strcpy(szPersonalTarget, xdg_results[num-2]); + strcpy(szPersonalTarget, xdg_results[0]); break; }
@@ -4200,9 +4172,78 @@ static void _SHCreateSymbolicLinks(void) * they already exist. */ pszHome = NULL; strcpy(szPersonalTarget, pszPersonal); - _SHCreateMyDocumentsSubDirs(aidsMyStuff, ARRAY_SIZE(aidsMyStuff), szPersonalTarget); + _SHCreateMyDocumentsSubDirs(aidsMyStuff, aids_num, szPersonalTarget); }
+ heap_free(pszPersonal); + + _SHFreeXDGUserDirs(num, xdg_results); +} + +/****************************************************************************** + * _SHCreateSymbolicLinks [Internal] + * + * Sets up symbol links for various shell folders to point into the user's 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 infer that the user + * is a Windows lover and has no problem with wine creating subfolders for + * 'My Pictures', 'My Music', 'My Videos' etc. under '$HOME/My Documents', if + * those do not already exist. 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, then we check XDG_MUSIC_DIR - "well known" + * directory, and try to link to that. If that fails, then we symlink to + * $HOME directly. The same holds for 'My Pictures', 'My Videos' etc. + * - The Desktop shell folder is symlinked to XDG_DESKTOP_DIR. If that does not + * exist, then we try '$HOME/Desktop'. If that does not exist, then we leave + * it alone. + * ('My Music',... above in fact means LoadString(IDS_MYMUSIC)) + */ +static void _SHCreateSymbolicLinks(void) +{ + static const UINT aidsMyStuff[] = { + IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC, IDS_DOWNLOADS, IDS_TEMPLATES + }; + static const WCHAR * const MyOSXStuffW[] = { + PicturesW, MoviesW, MusicW, DownloadsW, TemplatesW + }; + static const int acsidlMyStuff[] = { + CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES + }; + static const char * const xdg_dirs[] = { + "PICTURES", "VIDEOS", "MUSIC", "DOWNLOAD", "TEMPLATES", "DESKTOP" + }; + static const unsigned int num = ARRAY_SIZE(xdg_dirs); + char szPersonalTarget[FILENAME_MAX], *pszPersonal; + char szMyStuffTarget[FILENAME_MAX], *pszMyStuff; + char szDesktopTarget[FILENAME_MAX], *pszDesktop; + struct stat statFolder; + const char *pszHome; + char ** xdg_results; + char * xdg_desktop_dir; + UINT i; + + _SHCreateMyDocumentsSymbolicLink(aidsMyStuff, ARRAY_SIZE(aidsMyStuff)); + + /* Create all necessary profile sub-dirs up to 'My Documents' and get the unix path. */ + pszPersonal = _SHGetFolderUnixPath(CSIDL_PERSONAL|CSIDL_FLAG_CREATE); + if (!pszPersonal) return; + + strcpy(szPersonalTarget, pszPersonal); + if (!stat(pszPersonal, &statFolder) && S_ISLNK(statFolder.st_mode)) + { + int cLen = readlink(pszPersonal, szPersonalTarget, FILENAME_MAX-1); + if (cLen >= 0) szPersonalTarget[cLen] = '\0'; + } + + _SHGetXDGUserDirs(xdg_dirs, num, &xdg_results); + + pszHome = getenv("HOME"); + /* Create symbolic links for 'My Pictures', 'My Videos', 'My Music' etc. */ for (i=0; i < ARRAY_SIZE(aidsMyStuff); i++) {
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22974 Signed-off-by: Olivier F. R. Dierick o.dierick@piezo-forte.be --- dlls/shell32/shellpath.c | 101 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 73 insertions(+), 28 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index f790afa..e9835db 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -4181,29 +4181,15 @@ static void _SHCreateMyDocumentsSymbolicLink(const UINT * aidsMyStuff, const UIN }
/****************************************************************************** - * _SHCreateSymbolicLinks [Internal] + * _SHCreateMyStuffSymbolicLink [Internal] * - * Sets up symbol links for various shell folders to point into the user's 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 infer that the user - * is a Windows lover and has no problem with wine creating subfolders for - * 'My Pictures', 'My Music', 'My Videos' etc. under '$HOME/My Documents', if - * those do not already exist. 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, then we check XDG_MUSIC_DIR - "well known" - * directory, and try to link to that. If that fails, then we symlink to - * $HOME directly. The same holds for 'My Pictures', 'My Videos' etc. - * - The Desktop shell folder is symlinked to XDG_DESKTOP_DIR. If that does not - * exist, then we try '$HOME/Desktop'. If that does not exist, then we leave - * it alone. - * ('My Music',... above in fact means LoadString(IDS_MYMUSIC)) + * Sets up a symbolic link for one of the 'My Whatever' shell folders to point + * into the users home directory. + * + * PARAMS + * nFolder [I] CSIDL identifying the folder. */ -static void _SHCreateSymbolicLinks(void) +static void _SHCreateMyStuffSymbolicLink(int nFolder) { static const UINT aidsMyStuff[] = { IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC, IDS_DOWNLOADS, IDS_TEMPLATES @@ -4215,19 +4201,19 @@ static void _SHCreateSymbolicLinks(void) CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES }; static const char * const xdg_dirs[] = { - "PICTURES", "VIDEOS", "MUSIC", "DOWNLOAD", "TEMPLATES", "DESKTOP" + "PICTURES", "VIDEOS", "MUSIC", "DOWNLOAD", "TEMPLATES" }; static const unsigned int num = ARRAY_SIZE(xdg_dirs); char szPersonalTarget[FILENAME_MAX], *pszPersonal; char szMyStuffTarget[FILENAME_MAX], *pszMyStuff; - char szDesktopTarget[FILENAME_MAX], *pszDesktop; struct stat statFolder; const char *pszHome; char ** xdg_results; - char * xdg_desktop_dir; + DWORD folder = nFolder & CSIDL_FOLDER_MASK; UINT i;
- _SHCreateMyDocumentsSymbolicLink(aidsMyStuff, ARRAY_SIZE(aidsMyStuff)); + for (i = 0; i < ARRAY_SIZE(acsidlMyStuff) && acsidlMyStuff[i] != folder; i++); + if (i >= ARRAY_SIZE(acsidlMyStuff)) return;
/* Create all necessary profile sub-dirs up to 'My Documents' and get the unix path. */ pszPersonal = _SHGetFolderUnixPath(CSIDL_PERSONAL|CSIDL_FLAG_CREATE); @@ -4239,17 +4225,17 @@ static void _SHCreateSymbolicLinks(void) int cLen = readlink(pszPersonal, szPersonalTarget, FILENAME_MAX-1); if (cLen >= 0) szPersonalTarget[cLen] = '\0'; } + heap_free(pszPersonal);
_SHGetXDGUserDirs(xdg_dirs, num, &xdg_results);
pszHome = getenv("HOME");
- /* Create symbolic links for 'My Pictures', 'My Videos', 'My Music' etc. */ - for (i=0; i < ARRAY_SIZE(aidsMyStuff); i++) + while (1) { /* Create the current 'My Whatever' folder and get its unix path. */ pszMyStuff = _SHGetFolderUnixPath(acsidlMyStuff[i]|CSIDL_FLAG_CREATE); - if (!pszMyStuff) continue; + if (!pszMyStuff) break;
while (1) { @@ -4283,8 +4269,67 @@ static void _SHCreateSymbolicLinks(void) remove(pszMyStuff); symlink(szMyStuffTarget, pszMyStuff); heap_free(pszMyStuff); + break; }
+ _SHFreeXDGUserDirs(num, xdg_results); +} + +/****************************************************************************** + * _SHCreateSymbolicLinks [Internal] + * + * Sets up symbol links for various shell folders to point into the user's 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 infer that the user + * is a Windows lover and has no problem with wine creating subfolders for + * 'My Pictures', 'My Music', 'My Videos' etc. under '$HOME/My Documents', if + * those do not already exist. 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, then we check XDG_MUSIC_DIR - "well known" + * directory, and try to link to that. If that fails, then we symlink to + * $HOME directly. The same holds for 'My Pictures', 'My Videos' etc. + * - The Desktop shell folder is symlinked to XDG_DESKTOP_DIR. If that does not + * exist, then we try '$HOME/Desktop'. If that does not exist, then we leave + * it alone. + * ('My Music',... above in fact means LoadString(IDS_MYMUSIC)) + */ +static void _SHCreateSymbolicLinks(void) +{ + static const UINT aidsMyStuff[] = { + IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC, IDS_DOWNLOADS, IDS_TEMPLATES + }; + static const int acsidlMyStuff[] = { + CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES + }; + static const char * const xdg_dirs[] = { "DESKTOP" }; + static const unsigned int num = ARRAY_SIZE(xdg_dirs); + char *pszPersonal; + char szDesktopTarget[FILENAME_MAX], *pszDesktop; + struct stat statFolder; + const char *pszHome; + char ** xdg_results; + char * xdg_desktop_dir; + UINT i; + + _SHCreateMyDocumentsSymbolicLink(aidsMyStuff, ARRAY_SIZE(aidsMyStuff)); + + /* Create symbolic links for 'My Pictures', 'My Videos', 'My Music' etc. */ + for (i=0; i < ARRAY_SIZE(acsidlMyStuff); i++) + _SHCreateMyStuffSymbolicLink(acsidlMyStuff[i]); + + /* Create all necessary profile sub-dirs up to 'My Documents' and get the unix path. */ + pszPersonal = _SHGetFolderUnixPath(CSIDL_PERSONAL|CSIDL_FLAG_CREATE); + if (!pszPersonal) return; + + _SHGetXDGUserDirs(xdg_dirs, num, &xdg_results); + + pszHome = getenv("HOME"); + /* Last but not least, the Desktop folder */ if (pszHome) strcpy(szDesktopTarget, pszHome);
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22974 Signed-off-by: Olivier F. R. Dierick o.dierick@piezo-forte.be --- dlls/shell32/shellpath.c | 84 +++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 36 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index e9835db..2012ecb 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -4276,36 +4276,13 @@ static void _SHCreateMyStuffSymbolicLink(int nFolder) }
/****************************************************************************** - * _SHCreateSymbolicLinks [Internal] + * _SHCreateDesktopSymbolicLink [Internal] * - * Sets up symbol links for various shell folders to point into the user's 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 infer that the user - * is a Windows lover and has no problem with wine creating subfolders for - * 'My Pictures', 'My Music', 'My Videos' etc. under '$HOME/My Documents', if - * those do not already exist. 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, then we check XDG_MUSIC_DIR - "well known" - * directory, and try to link to that. If that fails, then we symlink to - * $HOME directly. The same holds for 'My Pictures', 'My Videos' etc. - * - The Desktop shell folder is symlinked to XDG_DESKTOP_DIR. If that does not - * exist, then we try '$HOME/Desktop'. If that does not exist, then we leave - * it alone. - * ('My Music',... above in fact means LoadString(IDS_MYMUSIC)) + * Sets up a symbolic link for the 'Desktop' shell folder to point into the + * users home directory. */ -static void _SHCreateSymbolicLinks(void) +static void _SHCreateDesktopSymbolicLink(void) { - static const UINT aidsMyStuff[] = { - IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC, IDS_DOWNLOADS, IDS_TEMPLATES - }; - static const int acsidlMyStuff[] = { - CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES - }; static const char * const xdg_dirs[] = { "DESKTOP" }; static const unsigned int num = ARRAY_SIZE(xdg_dirs); char *pszPersonal; @@ -4314,13 +4291,6 @@ static void _SHCreateSymbolicLinks(void) const char *pszHome; char ** xdg_results; char * xdg_desktop_dir; - UINT i; - - _SHCreateMyDocumentsSymbolicLink(aidsMyStuff, ARRAY_SIZE(aidsMyStuff)); - - /* Create symbolic links for 'My Pictures', 'My Videos', 'My Music' etc. */ - for (i=0; i < ARRAY_SIZE(acsidlMyStuff); i++) - _SHCreateMyStuffSymbolicLink(acsidlMyStuff[i]);
/* Create all necessary profile sub-dirs up to 'My Documents' and get the unix path. */ pszPersonal = _SHGetFolderUnixPath(CSIDL_PERSONAL|CSIDL_FLAG_CREATE); @@ -4330,14 +4300,13 @@ static void _SHCreateSymbolicLinks(void)
pszHome = getenv("HOME");
- /* Last but not least, the Desktop folder */ if (pszHome) strcpy(szDesktopTarget, pszHome); else strcpy(szDesktopTarget, pszPersonal); heap_free(pszPersonal);
- xdg_desktop_dir = xdg_results ? xdg_results[num - 1] : NULL; + xdg_desktop_dir = xdg_results ? xdg_results[0] : NULL; if (xdg_desktop_dir || (_SHAppendToUnixPath(szDesktopTarget, DesktopW) && !stat(szDesktopTarget, &statFolder) && S_ISDIR(statFolder.st_mode))) @@ -4358,6 +4327,49 @@ static void _SHCreateSymbolicLinks(void) }
/****************************************************************************** + * _SHCreateSymbolicLinks [Internal] + * + * Sets up symbol links for various shell folders to point into the user's 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 infer that the user + * is a Windows lover and has no problem with wine creating subfolders for + * 'My Pictures', 'My Music', 'My Videos' etc. under '$HOME/My Documents', if + * those do not already exist. 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, then we check XDG_MUSIC_DIR - "well known" + * directory, and try to link to that. If that fails, then we symlink to + * $HOME directly. The same holds for 'My Pictures', 'My Videos' etc. + * - The Desktop shell folder is symlinked to XDG_DESKTOP_DIR. If that does not + * exist, then we try '$HOME/Desktop'. If that does not exist, then we leave + * it alone. + * ('My Music',... above in fact means LoadString(IDS_MYMUSIC)) + */ +static void _SHCreateSymbolicLinks(void) +{ + static const UINT aidsMyStuff[] = { + IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC, IDS_DOWNLOADS, IDS_TEMPLATES + }; + static const int acsidlMyStuff[] = { + CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES + }; + UINT i; + + _SHCreateMyDocumentsSymbolicLink(aidsMyStuff, ARRAY_SIZE(aidsMyStuff)); + + /* Create symbolic links for 'My Pictures', 'My Videos', 'My Music' etc. */ + for (i=0; i < ARRAY_SIZE(acsidlMyStuff); i++) + _SHCreateMyStuffSymbolicLink(acsidlMyStuff[i]); + + /* Last but not least, the Desktop folder */ + _SHCreateDesktopSymbolicLink(); +} + +/****************************************************************************** * SHGetFolderPathW [SHELL32.@] * * Convert nFolder to path.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22974 Signed-off-by: Olivier F. R. Dierick o.dierick@piezo-forte.be --- dlls/shell32/shellpath.c | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index 2012ecb..d32529b 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -4327,6 +4327,39 @@ static void _SHCreateDesktopSymbolicLink(void) }
/****************************************************************************** + * _SHCreateSymbolicLink [Internal] + * + * Sets up a symbolic link for one of the special shell folders to point into + * the users home directory. + * + * PARAMS + * nFolder [I] CSIDL identifying the folder. + */ +static void _SHCreateSymbolicLink(int nFolder) +{ + static const UINT aidsMyStuff[] = { + IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC, IDS_DOWNLOADS, IDS_TEMPLATES + }; + DWORD folder = nFolder & CSIDL_FOLDER_MASK; + + switch (folder) { + case CSIDL_PERSONAL: + _SHCreateMyDocumentsSymbolicLink(aidsMyStuff, ARRAY_SIZE(aidsMyStuff)); + break; + case CSIDL_MYPICTURES: + case CSIDL_MYVIDEO: + case CSIDL_MYMUSIC: + case CSIDL_DOWNLOADS: + case CSIDL_TEMPLATES: + _SHCreateMyStuffSymbolicLink(folder); + break; + case CSIDL_DESKTOPDIRECTORY: + _SHCreateDesktopSymbolicLink(); + break; + } +} + +/****************************************************************************** * _SHCreateSymbolicLinks [Internal] * * Sets up symbol links for various shell folders to point into the user's home @@ -4351,22 +4384,13 @@ static void _SHCreateDesktopSymbolicLink(void) */ static void _SHCreateSymbolicLinks(void) { - static const UINT aidsMyStuff[] = { - IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC, IDS_DOWNLOADS, IDS_TEMPLATES - }; static const int acsidlMyStuff[] = { - CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES + CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES, CSIDL_PERSONAL, CSIDL_DESKTOPDIRECTORY }; UINT i;
- _SHCreateMyDocumentsSymbolicLink(aidsMyStuff, ARRAY_SIZE(aidsMyStuff)); - - /* Create symbolic links for 'My Pictures', 'My Videos', 'My Music' etc. */ for (i=0; i < ARRAY_SIZE(acsidlMyStuff); i++) - _SHCreateMyStuffSymbolicLink(acsidlMyStuff[i]); - - /* Last but not least, the Desktop folder */ - _SHCreateDesktopSymbolicLink(); + _SHCreateSymbolicLink(acsidlMyStuff[i]); }
/******************************************************************************
Change the logic so that when a user folder already exists in the prefix, as a real directory or symbolic link, it's left as-is. Also create a symbolic link, instead of a real directory, when looking up a user folder that is currently missing.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22974 Signed-off-by: Olivier F. R. Dierick o.dierick@piezo-forte.be --- dlls/shell32/shellpath.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index d32529b..71267ec 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -4116,8 +4116,8 @@ static void _SHCreateMyDocumentsSymbolicLink(const UINT * aidsMyStuff, const UIN const char *pszHome; char ** xdg_results;
- /* Create all necessary profile sub-dirs up to 'My Documents' and get the unix path. */ - pszPersonal = _SHGetFolderUnixPath(CSIDL_PERSONAL|CSIDL_FLAG_CREATE); + /* Get the unix path of 'My Documents'. */ + pszPersonal = _SHGetFolderUnixPath(CSIDL_PERSONAL|CSIDL_FLAG_DONT_VERIFY); if (!pszPersonal) return;
_SHGetXDGUserDirs(xdg_dirs, num, &xdg_results); @@ -4161,8 +4161,8 @@ static void _SHCreateMyDocumentsSymbolicLink(const UINT * aidsMyStuff, const UIN break; }
- /* Replace 'My Documents' directory with a symlink or fail silently if not empty. */ - remove(pszPersonal); + /* Create symbolic link to 'My Documents' or fail silently if a directory + * or symlink exists. */ symlink(szPersonalTarget, pszPersonal); } else @@ -4233,8 +4233,8 @@ static void _SHCreateMyStuffSymbolicLink(int nFolder)
while (1) { - /* Create the current 'My Whatever' folder and get its unix path. */ - pszMyStuff = _SHGetFolderUnixPath(acsidlMyStuff[i]|CSIDL_FLAG_CREATE); + /* Get the current 'My Whatever' folder unix path. */ + pszMyStuff = _SHGetFolderUnixPath(acsidlMyStuff[i]|CSIDL_FLAG_DONT_VERIFY); if (!pszMyStuff) break;
while (1) @@ -4266,7 +4266,6 @@ static void _SHCreateMyStuffSymbolicLink(int nFolder) strcpy(szMyStuffTarget, szPersonalTarget); break; } - remove(pszMyStuff); symlink(szMyStuffTarget, pszMyStuff); heap_free(pszMyStuff); break; @@ -4311,10 +4310,9 @@ static void _SHCreateDesktopSymbolicLink(void) (_SHAppendToUnixPath(szDesktopTarget, DesktopW) && !stat(szDesktopTarget, &statFolder) && S_ISDIR(statFolder.st_mode))) { - pszDesktop = _SHGetFolderUnixPath(CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE); + pszDesktop = _SHGetFolderUnixPath(CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_DONT_VERIFY); if (pszDesktop) { - remove(pszDesktop); if (xdg_desktop_dir) symlink(xdg_desktop_dir, pszDesktop); else @@ -4599,6 +4597,10 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW( goto end; }
+ /* create symbolic links rather than directories for specific + * user shell folders */ + _SHCreateSymbolicLink(folder); + /* create directory/directories */ ret = SHCreateDirectoryExW(hwndOwner, szBuildPath, NULL); if (ret && ret != ERROR_ALREADY_EXISTS) @@ -5232,6 +5234,10 @@ HRESULT WINAPI SHGetKnownFolderPath(REFKNOWNFOLDERID rfid, DWORD flags, HANDLE t goto failed; }
+ /* create symbolic links rather than directories for specific + * user shell folders */ + _SHCreateSymbolicLink(folder); + /* create directory/directories */ ret = SHCreateDirectoryExW(NULL, pathW, NULL); if (ret && ret != ERROR_ALREADY_EXISTS)