[PATCH 2/2] shell32: Create user folder symlinks on lookup and only if it's missing.

Olivier F. R. Dierick o.dierick at piezo-forte.be
Sun Feb 16 18:26:49 CST 2020


Updating a prefix should not mangle existing user folders. Some people
want to use real directories or customized symbolic links. Forcibly
resetting empty dirs or symlinks on each update is annoying at best.
The only reason to create user folders is when they are really missing
from the prefix. This automatic repair of the prefix should be done not
only on prefix creation or update, but whenever a user folder is looked
up, and that repair should have consistent behaviour.

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 | 66 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 48 insertions(+), 18 deletions(-)

diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c
index 293c51b..334cc7e 100644
--- a/dlls/shell32/shellpath.c
+++ b/dlls/shell32/shellpath.c
@@ -4115,8 +4115,8 @@ static void _SHCreateMyDocumentsSymbolicLink(void)
     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,
+    /* Get the unix path of the profile sub-dirs up to 'My Documents'. */
+    hr = SHGetFolderPathW(NULL, CSIDL_PERSONAL|CSIDL_FLAG_DONT_VERIFY, NULL,
                           SHGFP_TYPE_DEFAULT, wszTempPath);
     if (FAILED(hr)) return;
     pszPersonal = wine_get_unix_file_name(wszTempPath);
@@ -4169,8 +4169,8 @@ static void _SHCreateMyDocumentsSymbolicLink(void)
             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
@@ -4248,8 +4248,8 @@ static void _SHCreateMyStuffSymbolicLink(int nFolder)
 
     while (1)
     {
-        /* Create the current 'My Whatever' folder and get its unix path. */
-        hr = SHGetFolderPathW(NULL, acsidlMyStuff[i]|CSIDL_FLAG_CREATE, NULL,
+        /* Get the current 'My Whatever' folder unix path. */
+        hr = SHGetFolderPathW(NULL, acsidlMyStuff[i]|CSIDL_FLAG_DONT_VERIFY, NULL,
                               SHGFP_TYPE_DEFAULT, wszTempPath);
         if (FAILED(hr)) break;
 
@@ -4285,7 +4285,6 @@ static void _SHCreateMyStuffSymbolicLink(int nFolder)
             strcpy(szMyStuffTarget, szPersonalTarget);
             break;
         }
-        remove(pszMyStuff);
         symlink(szMyStuffTarget, pszMyStuff);
         heap_free(pszMyStuff);
         break;
@@ -4343,11 +4342,10 @@ static void _SHCreateDesktopSymbolicLink(void)
         (_SHAppendToUnixPath(szDesktopTarget, DesktopW) &&
         !stat(szDesktopTarget, &statFolder) && S_ISDIR(statFolder.st_mode)))
     {
-        hr = SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, NULL,
+        hr = SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_DONT_VERIFY, 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
@@ -4366,6 +4364,36 @@ 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)
+{
+    DWORD folder = nFolder & CSIDL_FOLDER_MASK;
+
+    switch (folder) {
+        case CSIDL_PERSONAL:
+            _SHCreateMyDocumentsSymbolicLink();
+            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
@@ -4391,16 +4419,10 @@ static void _SHCreateDesktopSymbolicLink(void)
 static void _SHCreateSymbolicLinks(void)
 {
     UINT i;
-    int acsidlMyStuff[] = { CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES };
-
-    _SHCreateMyDocumentsSymbolicLink();
+    int acsidl[] = { CSIDL_PERSONAL, CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC, CSIDL_DOWNLOADS, CSIDL_TEMPLATES, CSIDL_DESKTOPDIRECTORY };
 
-    /* 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();
+    for (i=0; i < ARRAY_SIZE(acsidl); i++)
+        _SHCreateSymbolicLink(acsidl[i]);
 }
 
 /*************************************************************************
@@ -4527,6 +4549,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)
@@ -5160,6 +5186,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)
-- 
2.1.4




More information about the wine-devel mailing list