[PATCH 1/2] shell32: Move and split _SHCreateSymbolicLinks()
Olivier F. R. Dierick
o.dierick at piezo-forte.be
Sun Feb 16 18:26:48 CST 2020
Prepare the helper function for rework by moving it above the function
that will use it and splitting it by kind of directories.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22974
Signed-off-by: Olivier F. R. Dierick <o.dierick at piezo-forte.be>
---
dlls/shell32/shellpath.c | 638 +++++++++++++++++++++++++++--------------------
1 file changed, 373 insertions(+), 265 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c
index b6350ea..293c51b 100644
--- a/dlls/shell32/shellpath.c
+++ b/dlls/shell32/shellpath.c
@@ -4030,6 +4030,379 @@ cleanup:
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, 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;
+}
+
+/******************************************************************************
+ * _SHCreateMyDocumentsSymbolicLink [Internal]
+ *
+ * Sets up a symbolic link for the 'My Documents' shell folder to point into
+ * the users home directory.
+ */
+static void _SHCreateMyDocumentsSymbolicLink(void)
+{
+ UINT aidsMyStuff[] = { IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC, IDS_DOWNLOADS, IDS_TEMPLATES };
+ static const char * const xdg_dirs[] = { "DOCUMENTS" };
+ static const unsigned int num = ARRAY_SIZE(xdg_dirs);
+ WCHAR wszTempPath[MAX_PATH];
+ char szPersonalTarget[FILENAME_MAX], *pszPersonal;
+ char szMyStuffTarget[FILENAME_MAX];
+ struct stat statFolder;
+ const char *pszHome;
+ HRESULT hr;
+ char ** xdg_results;
+ 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 'My Pictures',
+ * 'My Videos' and 'My Music' subfolders 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[0] &&
+ !stat(xdg_results[0], &statFolder) &&
+ S_ISDIR(statFolder.st_mode))
+ {
+ strcpy(szPersonalTarget, xdg_results[0]);
+ 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 'My Pictures', 'My Videos' and 'My Music' subdirs
+ * 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);
+ }
+ }
+
+ heap_free(pszPersonal);
+
+ /* Free resources allocated by XDG_UserDirLookup() */
+ if (xdg_results)
+ {
+ for (i = 0; i < num; i++)
+ heap_free(xdg_results[i]);
+ heap_free(xdg_results);
+ }
+}
+
+/******************************************************************************
+ * _SHCreateMyStuffSymbolicLink [Internal]
+ *
+ * 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 _SHCreateMyStuffSymbolicLink(int nFolder)
+{
+ UINT aidsMyStuff[] = { IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC, IDS_DOWNLOADS, IDS_TEMPLATES };
+ const WCHAR* MyOSXStuffW[] = { PicturesW, MoviesW, MusicW, DownloadsW, TemplatesW };
+ int acsidlMyStuff[] = { CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES };
+ static const char * const xdg_dirs[] = { "PICTURES", "VIDEOS", "MUSIC", "DOWNLOAD", "TEMPLATES" };
+ static const unsigned int num = ARRAY_SIZE(xdg_dirs);
+ WCHAR wszTempPath[MAX_PATH];
+ char szPersonalTarget[FILENAME_MAX], *pszPersonal;
+ char szMyStuffTarget[FILENAME_MAX], *pszMyStuff;
+ struct stat statFolder;
+ const char *pszHome;
+ HRESULT hr;
+ char ** xdg_results;
+ DWORD folder = nFolder & CSIDL_FOLDER_MASK;
+ UINT i;
+
+ for (i = 0; i < ARRAY_SIZE(acsidlMyStuff) && acsidlMyStuff[i] != folder; i++);
+ if (i >= ARRAY_SIZE(acsidlMyStuff)) return;
+
+ /* Get the real path of the existing 'My Documents' shell folder. */
+ 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;
+
+ 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';
+ }
+ heap_free(pszPersonal);
+
+ hr = XDG_UserDirLookup(xdg_dirs, num, &xdg_results);
+ if (FAILED(hr)) xdg_results = NULL;
+
+ pszHome = getenv("HOME");
+
+ while (1)
+ {
+ /* 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)) break;
+
+ pszMyStuff = wine_get_unix_file_name(wszTempPath);
+ if (!pszMyStuff) break;
+
+ 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);
+ break;
+ }
+
+ /* Free resources allocated by XDG_UserDirLookup() */
+ if (xdg_results)
+ {
+ for (i = 0; i < num; i++)
+ heap_free(xdg_results[i]);
+ heap_free(xdg_results);
+ }
+}
+
+/******************************************************************************
+ * _SHCreateDesktopSymbolicLink [Internal]
+ *
+ * Sets up a symbolic link for the 'Desktop' shell folder to point into the
+ * users home directory.
+ */
+static void _SHCreateDesktopSymbolicLink(void)
+{
+ UINT i;
+ static const char * const xdg_dirs[] = { "DESKTOP" };
+ static const unsigned int num = ARRAY_SIZE(xdg_dirs);
+ WCHAR wszTempPath[MAX_PATH];
+ char *pszPersonal;
+ char szDesktopTarget[FILENAME_MAX], *pszDesktop;
+ struct stat statFolder;
+ const char *pszHome;
+ HRESULT hr;
+ char ** xdg_results;
+ char * xdg_desktop_dir;
+
+ /* 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)
+ strcpy(szDesktopTarget, pszHome);
+ else
+ strcpy(szDesktopTarget, pszPersonal);
+ heap_free(pszPersonal);
+
+ xdg_desktop_dir = xdg_results ? xdg_results[0] : 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);
+ }
+}
+
+/******************************************************************************
+ * _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)
+{
+ UINT i;
+ int acsidlMyStuff[] = { CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES };
+
+ _SHCreateMyDocumentsSymbolicLink();
+
+ /* Create symbolic links for 'My Pictures', 'My Videos', 'My Music', 'Downloads' and 'Templates'. */
+ for (i=0; i < ARRAY_SIZE(acsidlMyStuff); i++)
+ _SHCreateMyStuffSymbolicLink(acsidlMyStuff[i]);
+
+ /* Last but not least, the Desktop folder */
+ _SHCreateDesktopSymbolicLink();
+}
+
/*************************************************************************
* SHGetFolderPathAndSubDirW [SHELL32.@]
*/
@@ -4382,271 +4755,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.
--
2.1.4
More information about the wine-devel
mailing list