- Move target folder initialization to a dedicated function.
- Use this function in BindToObject (should be faster).
- Special handling for FolderShortcut objects in Initialize method.
- Removed a todo_wine from a no longer failing unit test.

diff --git a/dlls/shell32/shfldr_unixfs.c b/dlls/shell32/shfldr_unixfs.c
index 2288950..7c93f7e 100644
--- a/dlls/shell32/shfldr_unixfs.c
+++ b/dlls/shell32/shfldr_unixfs.c
@@ -190,8 +190,8 @@
     const IPersistPropertyBagVtbl *lpIPersistPropertyBagVtbl;
     const ISFHelperVtbl *lpISFHelperVtbl;
     LONG m_cRef;
-    CHAR *m_pszPath;
-    LPITEMIDLIST m_pidlLocation;
+    CHAR *m_pszPath;             /* Target path of the shell folder */
+    LPITEMIDLIST m_pidlLocation; /* Location in the shell namespace */
     DWORD m_dwPathMode;
     DWORD m_dwAttributes;
     const CLSID *m_pCLSID;
@@ -582,6 +582,71 @@
 }
 
 /******************************************************************************
+ * UNIXFS_initialize_target_folder [Internal]
+ *
+ *  Initialize the m_pszPath member of an UnixFolder, given an absolute unix
+ *  base path and a relative ITEMIDLIST. Leave the m_pidlLocation member, which
+ *  specifies the location in the shell namespace alone. 
+ * 
+ * PARAMS
+ *  This          [IO] The UnixFolder, whose target path is to be initialized
+ *  szBasePath    [I]  The absolute base path
+ *  pidlSubFolder [I]  Relative part of the path, given as an ITEMIDLIST
+ *  dwAttributes  [I]  Attributes to add to the Folders m_dwAttributes member 
+ *                     (Used to pass the SFGAO_FILESYSTEM flag down the path)
+ * RETURNS
+ *  Success: S_OK,
+ *  Failure: E_FAIL
+ */
+static HRESULT UNIXFS_initialize_target_folder(UnixFolder *This, const char *szBasePath,
+    LPCITEMIDLIST pidlSubFolder, DWORD dwAttributes)
+{
+    LPCITEMIDLIST current = pidlSubFolder;
+    DWORD dwPathLen = strlen(szBasePath)+1;
+    struct stat statPrefix;
+    char *pNextDir;
+        
+    /* Determine the path's length bytes */
+    while (current && current->mkid.cb) {
+        dwPathLen += NAME_LEN_FROM_LPSHITEMID(current) + 1; /* For the '/' */
+        current = ILGetNext(current);
+    };
+
+    /* Build the path and compute the attributes*/
+    This->m_dwAttributes = 
+            dwAttributes|SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|SFGAO_CANRENAME;
+    This->m_pszPath = pNextDir = SHAlloc(dwPathLen);
+    if (!This->m_pszPath) {
+        WARN("SHAlloc failed!\n");
+        return E_FAIL;
+    }
+    current = pidlSubFolder;
+    strcpy(pNextDir, szBasePath);
+    pNextDir += strlen(szBasePath);
+    if (This->m_dwPathMode == PATHMODE_UNIX || IsEqualCLSID(&CLSID_MyDocuments, This->m_pCLSID))
+        This->m_dwAttributes |= SFGAO_FILESYSTEM;
+    if (!(This->m_dwAttributes & SFGAO_FILESYSTEM)) {
+        *pNextDir = '\0';
+        if (!stat(This->m_pszPath, &statPrefix) && UNIXFS_is_dos_device(&statPrefix))
+            This->m_dwAttributes |= SFGAO_FILESYSTEM;
+    }
+    while (current && current->mkid.cb) {
+        memcpy(pNextDir, _ILGetTextPointer(current), NAME_LEN_FROM_LPSHITEMID(current));
+        pNextDir += NAME_LEN_FROM_LPSHITEMID(current);
+        if (!(This->m_dwAttributes & SFGAO_FILESYSTEM)) {
+            *pNextDir = '\0';
+            if (!stat(This->m_pszPath, &statPrefix) && UNIXFS_is_dos_device(&statPrefix))
+                This->m_dwAttributes |= SFGAO_FILESYSTEM;
+        }
+        *pNextDir++ = '/';
+        current = ILGetNext(current);
+    }
+    *pNextDir='\0';
+ 
+    return S_OK;
+}
+
+/******************************************************************************
  * UnixFolder
  *
  * Class whose heap based instances represent unix filesystem directories.
@@ -707,23 +772,33 @@
     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
     IPersistFolder3 *persistFolder;
     HRESULT hr;
+    const CLSID *clsidChild;
         
     TRACE("(iface=%p, pidl=%p, pbcReserver=%p, riid=%p, ppvOut=%p)\n", 
             iface, pidl, pbcReserved, riid, ppvOut);
 
     if (!pidl || !pidl->mkid.cb)
         return E_INVALIDARG;
-       
-    hr = CreateUnixFolder(NULL, &IID_IPersistFolder3, (void**)&persistFolder, This->m_pCLSID);
+   
+    if (IsEqualCLSID(This->m_pCLSID, &CLSID_FolderShortcut)) {
+        /* Children of FolderShortcuts are ShellFSFolders on Windows. 
+         * Unixfs' counterpart is UnixDosFolder. */
+        clsidChild = &CLSID_UnixDosFolder;    
+    } else {
+        clsidChild = This->m_pCLSID;
+    }
+    
+    hr = CreateUnixFolder(NULL, &IID_IPersistFolder3, (void**)&persistFolder, clsidChild);
     if (!SUCCEEDED(hr)) return hr;
     hr = IPersistFolder_QueryInterface(persistFolder, riid, (void**)ppvOut);
    
     if (SUCCEEDED(hr)) {
-        LPITEMIDLIST pidlSubFolder = ILCombine(This->m_pidlLocation, pidl);
-        hr = IPersistFolder3_Initialize(persistFolder, pidlSubFolder);
-        ILFree(pidlSubFolder);
-    }
-    
+        UnixFolder *subfolder = ADJUST_THIS(UnixFolder, IPersistFolder3, persistFolder);
+        subfolder->m_pidlLocation = ILCombine(This->m_pidlLocation, pidl);
+        hr = UNIXFS_initialize_target_folder(subfolder, This->m_pszPath, pidl,
+                                             This->m_dwAttributes & SFGAO_FILESYSTEM);
+    } 
+
     IPersistFolder3_Release(persistFolder);
     
     return hr;
@@ -1221,10 +1296,8 @@
 static HRESULT WINAPI UnixFolder_IPersistFolder3_Initialize(IPersistFolder3* iface, LPCITEMIDLIST pidl)
 {
     UnixFolder *This = ADJUST_THIS(UnixFolder, IPersistFolder3, iface);
-    struct stat statPrefix;
-    LPCITEMIDLIST current = pidl, root;
-    DWORD dwPathLen;
-    char *pNextDir, szBasePath[FILENAME_MAX] = "/";
+    LPCITEMIDLIST current = pidl;
+    char szBasePath[FILENAME_MAX] = "/";
     
     TRACE("(iface=%p, pidl=%p)\n", iface, pidl);
 
@@ -1243,11 +1316,8 @@
             PathAddBackslashW(wszMyDocumentsPath);
             if (!UNIXFS_get_unix_path(wszMyDocumentsPath, szBasePath))
                 return E_FAIL;
-            dwPathLen = strlen(szBasePath) + 1;
-        } else {
-            dwPathLen = 2; /* For the '/' prefix and the terminating '\0' */
-        }
-        root = current = ILGetNext(current);
+        } 
+        current = ILGetNext(current);
     } else if (_ILIsDesktop(pidl) || _ILIsValue(pidl) || _ILIsFolder(pidl)) {
         /* Path rooted at Desktop */
         WCHAR wszDesktopPath[MAX_PATH];
@@ -1256,52 +1326,21 @@
         PathAddBackslashW(wszDesktopPath);
         if (!UNIXFS_get_unix_path(wszDesktopPath, szBasePath))
             return E_FAIL;
-        dwPathLen = strlen(szBasePath) + 1;
-        root = current = pidl;
+        current = pidl;
+    } else if (IsEqualCLSID(This->m_pCLSID, &CLSID_FolderShortcut)) {
+        /* FolderShortcuts' Initialize method only sets the ITEMIDLIST, which
+         * specifies the location in the shell namespace, but leaves the
+         * target folder (m_pszPath) alone. See unit tests in tests/shlfolder.c */
+        This->m_pidlLocation = ILClone(pidl);
+        return S_OK;
     } else {
         ERR("Unknown pidl type!\n");
         pdump(pidl);
         return E_INVALIDARG;
     }
-    
-    /* Determine the path's length bytes */
-    while (current && current->mkid.cb) {
-        dwPathLen += NAME_LEN_FROM_LPSHITEMID(current) + 1; /* For the '/' */
-        current = ILGetNext(current);
-    };
-
-    /* Build the path */
-    This->m_dwAttributes = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|SFGAO_CANRENAME;
+  
     This->m_pidlLocation = ILClone(pidl);
-    This->m_pszPath = pNextDir = SHAlloc(dwPathLen);
-    if (!This->m_pszPath || !This->m_pidlLocation) {
-        WARN("SHAlloc failed!\n");
-        return E_FAIL;
-    }
-    current = root;
-    strcpy(pNextDir, szBasePath);
-    pNextDir += strlen(szBasePath);
-    if (This->m_dwPathMode == PATHMODE_UNIX || IsEqualCLSID(&CLSID_MyDocuments, This->m_pCLSID))
-        This->m_dwAttributes |= SFGAO_FILESYSTEM;
-    if (!(This->m_dwAttributes & SFGAO_FILESYSTEM)) {
-        *pNextDir = '\0';
-        if (!stat(This->m_pszPath, &statPrefix) && UNIXFS_is_dos_device(&statPrefix))
-            This->m_dwAttributes |= SFGAO_FILESYSTEM;
-    }
-    while (current && current->mkid.cb) {
-        memcpy(pNextDir, _ILGetTextPointer(current), NAME_LEN_FROM_LPSHITEMID(current));
-        pNextDir += NAME_LEN_FROM_LPSHITEMID(current);
-        if (!(This->m_dwAttributes & SFGAO_FILESYSTEM)) {
-            *pNextDir = '\0';
-            if (!stat(This->m_pszPath, &statPrefix) && UNIXFS_is_dos_device(&statPrefix))
-                This->m_dwAttributes |= SFGAO_FILESYSTEM;
-        }
-        *pNextDir++ = '/';
-        current = ILGetNext(current);
-    }
-    *pNextDir='\0';
- 
-    return S_OK;
+    return UNIXFS_initialize_target_folder(This, szBasePath, current, 0); 
 }
 
 static HRESULT WINAPI UnixFolder_IPersistFolder3_GetCurFolder(IPersistFolder3* iface, LPITEMIDLIST* ppidl)
@@ -1336,7 +1375,9 @@
             return E_FAIL;
         }
     } else if (*ppfti->szTargetParsingName) {
-        if (!UNIXFS_get_unix_path(ppfti->szTargetParsingName, szTargetPath)) {
+        lstrcpyW(wszTargetDosPath, ppfti->szTargetParsingName);
+        PathAddBackslashW(wszTargetDosPath);
+        if (!UNIXFS_get_unix_path(wszTargetDosPath, szTargetPath)) {
             return E_FAIL;
         }
     } else if (ppfti->pidlTargetFolder) {
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c
index 4605cbb..d4f92b2 100644
--- a/dlls/shell32/tests/shlfolder.c
+++ b/dlls/shell32/tests/shlfolder.c
@@ -876,7 +876,9 @@
         ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
         'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
     WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
-       
+    static const GUID CLSID_UnixDosFolder = 
+        {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
+
     if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) return;
    
     /* These tests basically show, that CLSID_FolderShortcuts are initialized
@@ -945,7 +947,7 @@
     if (FAILED(hr)) return;
 
     hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
-    todo_wine { ok (SUCCEEDED(hr), "IPersistFolder3::Initialize failed! hr = %08lx\n", hr); }
+    ok (SUCCEEDED(hr), "IPersistFolder3::Initialize failed! hr = %08lx\n", hr);
     if (FAILED(hr)) {
         IPersistFolder3_Release(pPersistFolder3);
         ILFree(pidlWineTestFolder);
@@ -985,7 +987,7 @@
     
     hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL, 
                                        &pidlSubFolder, NULL);
-    RemoveDirectoryW(wszSomeSubFolder);
+    RemoveDirectoryW(wszDesktopPath);
     ok (SUCCEEDED(hr), "IShellFolder::ParseDisplayName failed! hr = %08lx\n", hr);
     if (FAILED(hr)) {
         IShellFolder_Release(pShellFolder);
@@ -1000,9 +1002,12 @@
     if (FAILED(hr)) 
         return;
 
+    /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
+     * a little bit and also allow CLSID_UnixDosFolder. */
     hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
     ok(SUCCEEDED(hr), "IPersistFolder3_GetClassID failed! hr=0x%08lx\n", hr);
-    ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder), "Unexpected CLSID!\n");
+    ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
+        "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
 
     IPersistFolder3_Release(pPersistFolder3);
 }