Assorted spelling fixes.
[wine] / dlls / shell32 / shfldr_unixfs.c
1 /*
2  * UNIXFS - Shell namespace extension for the unix filesystem
3  *
4  * Copyright (C) 2005 Michael Jung
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <dirent.h>
24
25 #define COBJMACROS
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "objbase.h"
33 #include "wine/debug.h"
34
35 #include "shell32_main.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(shell);
38
39 const GUID CLSID_UnixFolder = {0xcc702eb2, 0x7dc5, 0x11d9, {0xc6, 0x87, 0x00, 0x04, 0x23, 0x8a, 0x01, 0xcd}};
40
41 #define ADJUST_THIS(c,m,p) ((c*)(((long)p)-(long)&(((c*)0)->lp##m##Vtbl)))
42 #define STATIC_CAST(i,p) ((i*)&p->lp##i##Vtbl)
43
44 /******************************************************************************
45  * UNIXFS_path_to_pidl [Internal]
46  *
47  * PARAMS
48  *  path  [I] An absolute unix path 
49  *  ppidl [O] The corresponding ITEMIDLIST. Release with SHFree/ILFree
50  *  
51  * RETURNS
52  *  Success: TRUE
53  *  Failure: FALSE, invalid params, path not absolute or out of memory
54  *
55  * NOTES
56  *  'path' has to be an absolute unix filesystem path starting and
57  *  ending with a slash ('/'). Currently, only directories (no files)
58  *  are accepted.
59  */
60 static BOOL UNIXFS_path_to_pidl(char *path, LPITEMIDLIST *ppidl) {
61     LPITEMIDLIST pidl;
62     int cSubDirs, cPidlLen;
63     char *pSlash, *pSubDir;
64
65     /* Fail, if no absolute path given */
66     if (!ppidl || !path || path[0] != '/') return FALSE;
67    
68     /* Count the number of sub-directories in the path */
69     cSubDirs = 0;
70     pSlash = strchr(path, '/');
71     while (pSlash) {
72         cSubDirs++;
73         pSlash = strchr(pSlash+1, '/');
74     }
75    
76     /* Allocate enough memory to hold the path */
77     cPidlLen = strlen(path) + cSubDirs * sizeof(USHORT) + sizeof(USHORT);
78     *ppidl = pidl = (LPITEMIDLIST)SHAlloc(cPidlLen);
79     if (!pidl) return FALSE;
80
81     /* Start with a SHITEMID for the root directory */
82     pidl->mkid.cb = 3;
83     pidl->mkid.abID[0] = '/';
84     pidl = ILGetNext(pidl);
85
86     /* Append SHITEMIDs for the sub-directories */
87     pSubDir = path + 1;
88     pSlash = strchr(pSubDir, '/');
89     while (pSlash) {
90         pidl->mkid.cb = (USHORT)(pSlash+3-pSubDir);
91         memcpy(pidl->mkid.abID, pSubDir, pidl->mkid.cb);
92         pSubDir = pSlash + 1;
93         pSlash = strchr(pSubDir, '/');
94         pidl = ILGetNext(pidl);
95     }
96     pidl->mkid.cb = 0; /* Terminate the ITEMIDLIST */
97    
98     /* Path doesn't end with a '/' */
99     if (*pSubDir) 
100         WARN("Path '%s' not in canonical form.\n", path);
101     
102     return TRUE;
103 }
104
105 /******************************************************************************
106  * UNIXFS_pidl_to_path [Internal]
107  *
108  * Construct the unix path that corresponds to a fully qualified ITEMIDLIST
109  *
110  * PARAMS
111  *  pidl [I] ITEMIDLIST that specifies the absolute location of the folder
112  *  path [O] The corresponding unix path as a zero terminated ascii string
113  *
114  * RETURNS
115  *  Success: TRUE
116  *  Failure: FALSE, pidl doesn't specify a unix path or out of memory
117  */
118 static BOOL UNIXFS_pidl_to_path(LPCITEMIDLIST pidl, PSZ *path) {
119     LPCITEMIDLIST current = pidl, root;
120     DWORD dwPathLen;
121     char *pNextDir;
122
123     *path = NULL;
124
125     /* Find the UnixFolderClass root */
126     while (current->mkid.cb) {
127         if (current->mkid.cb < sizeof(GUID)+4) return FALSE;
128         if (IsEqualIID(&CLSID_UnixFolder, &current->mkid.abID[2])) break;
129         current = ILGetNext(current);
130     }
131     if (!current->mkid.cb) return FALSE;
132     root = ILGetNext(current);
133
134     /* Determine the path's length bytes */
135     dwPathLen = 1; /* For the terminating '\0' */
136     current = root;
137     while (current->mkid.cb) {
138         dwPathLen += current->mkid.cb - sizeof(USHORT);
139         current = ILGetNext(current);
140     };
141
142     /* Build the path */
143     *path = pNextDir = SHAlloc(dwPathLen);
144     if (!path) {
145         WARN("SHAlloc failed!\n");
146         return FALSE;
147     }
148     current = root;
149     while (current->mkid.cb) {
150         memcpy(pNextDir, current->mkid.abID, current->mkid.cb - sizeof(USHORT));
151         pNextDir += current->mkid.cb - sizeof(USHORT);
152         current = ILGetNext(current);
153     }
154     *pNextDir='\0';
155     
156     TRACE("resulting path: %s\n", *path);
157     return TRUE;
158 }
159
160 /******************************************************************************
161  * UNIXFS_build_subfolder_pidls [Internal]
162  *
163  * Builds an array of subfolder PIDLs relative to a unix directory
164  *
165  * PARAMS
166  *  path   [I] Name of a unix directory as a zero terminated ascii string
167  *  apidl  [O] The array of PIDLs
168  *  pCount [O] Size of apidl
169  *
170  * RETURNS
171  *  Success: TRUE
172  *  Failure: FALSE, path is not a valid unix directory or out of memory
173  *
174  * NOTES
175  *  The array of PIDLs and each PIDL are allocated with SHAlloc. You'll have
176  *  to release each PIDL as well as the array itself with SHFree.
177  */
178 static BOOL UNIXFS_build_subfolder_pidls(const char *path, LPITEMIDLIST **apidl, DWORD *pCount)
179 {
180     DIR *dir;
181     struct dirent *pSubDir;
182     DWORD cSubDirs, i;
183     USHORT sLen;
184
185     *apidl = NULL;
186     *pCount = 0;
187    
188     /* Special case for 'My UNIX Filesystem' shell folder:
189      * The unix root directory is the only child of 'My UNIX Filesystem'. 
190      */
191     if (!strlen(path)) {
192         LPSHITEMID pid;
193         
194         pid = (LPSHITEMID)SHAlloc(1 + 2 * sizeof(USHORT));
195         pid->cb = 3;
196         pid->abID[0] = '/';
197         memset(((PBYTE)pid)+pid->cb, 0, sizeof(USHORT));
198         
199         *apidl = SHAlloc(sizeof(LPITEMIDLIST));
200         (*apidl)[0] = (LPITEMIDLIST)pid;
201         *pCount = 1;
202     
203         return TRUE;
204     }
205     
206     dir = opendir(path);
207     if (!dir) {
208         WARN("Failed to open directory '%s'.\n", path);
209         return FALSE;
210     }
211
212     /* Count number of sub directories.
213      */
214     for (cSubDirs = 0, pSubDir = readdir(dir); pSubDir; pSubDir = readdir(dir)) { 
215         if (strcmp(pSubDir->d_name, ".") && 
216             strcmp(pSubDir->d_name, "..") && 
217             pSubDir->d_type == DT_DIR) 
218         {
219             cSubDirs++;
220         }
221     }
222
223     /* If there are no subdirectories, we are done. */
224     if (cSubDirs == 0) {
225         closedir(dir);
226         return TRUE;
227     }
228
229     /* Allocate the array of PIDLs */
230     *apidl = SHAlloc(cSubDirs * sizeof(LPITEMIDLIST));
231     if (!apidl) {
232         WARN("SHAlloc failed!\n");
233         return FALSE;
234     }
235    
236     /* Allocate and initialize one SHITEMID per sub-directory. */
237     for (rewinddir(dir), pSubDir = readdir(dir), i = 0; pSubDir; pSubDir = readdir(dir)) {
238         LPSHITEMID pid;
239             
240         if (!strcmp(pSubDir->d_name, ".") ||
241             !strcmp(pSubDir->d_name, "..") || 
242             pSubDir->d_type != DT_DIR) 
243         {
244             continue;
245         }
246     
247         sLen = strlen(pSubDir->d_name)+1; /* For the trailing '/' */
248         pid = (LPSHITEMID)SHAlloc(sLen + 2 * sizeof(USHORT));
249         if (!pid) {
250             WARN("SHAlloc failed!\n");
251             return FALSE;
252         }
253
254         pid->cb = (USHORT)(sLen + sizeof(USHORT));
255         memcpy(pid->abID, pSubDir->d_name, sLen-1);
256         pid->abID[sLen-1] = '/';
257         memset(((PBYTE)pid)+pid->cb, 0, sizeof(USHORT));
258
259         (*apidl)[i++] = (LPITEMIDLIST)pid;
260     }
261     
262     *pCount = i;    
263     closedir(dir);
264
265     return TRUE;
266 }
267
268 /******************************************************************************
269  * UnixFolderIcon 
270  *
271  * Singleton class, which is used by the shell to extract icons to represent
272  * folders in tree- and listviews. Currently, all this singleton does is to
273  * provide the shell with the absolute path to "shell32.dll" and with the 
274  * indices of the closed and opened folder icons in the resources of this dll.
275  */
276
277 /* UnixFolderIcon object layout and typedef.
278  */
279 typedef struct _UnixFolderIcon {
280     const IExtractIconWVtbl *lpIExtractIconWVtbl;
281 } UnixFolderIcon;
282
283 static HRESULT WINAPI UnixFolderIcon_IExtractIconW_QueryInterface(IExtractIconW *iface, REFIID riid, 
284     void **ppv) 
285 {
286     TRACE("(iface=%p, riid=%p, ppv=%p)\n", iface, riid, ppv);
287     
288     if (!ppv) return E_INVALIDARG;
289     
290     if (IsEqualIID(&IID_IUnknown, riid) ||
291         IsEqualIID(&IID_IExtractIconW, riid))
292     {
293         *ppv = iface;
294     } else {
295         *ppv = NULL;
296         return E_NOINTERFACE;
297     }
298
299     IExtractIconW_AddRef(iface);
300     return S_OK;
301 }
302
303 static ULONG WINAPI UnixFolderIcon_IExtractIconW_AddRef(IExtractIconW *iface) {
304     TRACE("(iface=%p)\n", iface);
305     return 2;
306 }
307
308 static ULONG WINAPI UnixFolderIcon_IExtractIconW_Release(IExtractIconW *iface) {
309     TRACE("(iface=%p)\n", iface);
310     return 1;
311 }
312
313 static HRESULT WINAPI UnixFolderIcon_IExtractIconW_GetIconLocation(IExtractIconW *iface, 
314     UINT uFlags, LPWSTR szIconFile, UINT cchMax, INT* piIndex, UINT* pwFlags)
315 {
316     TRACE("(iface=%p, uFlags=%u, szIconFile=%s, cchMax=%u, piIndex=%p, pwFlags=%p)\n",
317             iface, uFlags, debugstr_w(szIconFile), cchMax, piIndex, pwFlags);
318     
319     lstrcpynW(szIconFile, swShell32Name, cchMax);
320     *piIndex = (uFlags & GIL_OPENICON) ? 4 : 3;
321     *pwFlags = 0;
322
323     return S_OK;
324 }
325
326 static HRESULT WINAPI UnixFolderIcon_IExtractIconW_Extract(
327     IExtractIconW *iface, LPCWSTR pszFile, UINT nIconIndex, HICON* phiconLarge, HICON* phiconSmall, 
328     UINT nIconSize)
329 {
330     TRACE("(iface=%p, pszFile=%s, nIconIndex=%u, phiconLarge=%p, phiconSmall=%p, nIconSize=%u)"
331           "stub\n", iface, debugstr_w(pszFile), nIconIndex, phiconLarge, phiconSmall, nIconSize);
332
333     return E_NOTIMPL;
334 }
335
336 /* VTable for the IExtractIconW interface of the UnixFolderIcon class. 
337  */
338 static const IExtractIconWVtbl UnixFolderIcon_IExtractIconW_Vtbl = {
339     UnixFolderIcon_IExtractIconW_QueryInterface,
340     UnixFolderIcon_IExtractIconW_AddRef,
341     UnixFolderIcon_IExtractIconW_Release,
342     UnixFolderIcon_IExtractIconW_GetIconLocation,
343     UnixFolderIcon_IExtractIconW_Extract
344 };
345
346 /* The singleton instance
347  */
348 UnixFolderIcon UnixFolderIconSingleton = { &UnixFolderIcon_IExtractIconW_Vtbl };
349
350 /******************************************************************************
351  * UnixFolder
352  *
353  * Class whose heap based instances represent unix filesystem directories.
354  */
355
356 /* UnixFolder object layout and typedef.
357  */
358 typedef struct _UnixFolder {
359     const IShellFolderVtbl   *lpIShellFolderVtbl;
360     const IPersistFolderVtbl *lpIPersistFolderVtbl;
361     ULONG m_cRef;
362     CHAR *m_pszPath;
363     LPITEMIDLIST m_pidlLocation;
364     LPITEMIDLIST *m_apidlSubDirs;
365     DWORD m_cSubDirs;
366 } UnixFolder;
367
368 static void UnixFolder_Destroy(UnixFolder *pUnixFolder) {
369     DWORD i;
370
371     TRACE("(pUnixFolder=%p)\n", pUnixFolder);
372     
373     if (pUnixFolder->m_apidlSubDirs) 
374         for (i=0; i < pUnixFolder->m_cSubDirs; i++) 
375             SHFree(pUnixFolder->m_apidlSubDirs[i]);
376     SHFree(pUnixFolder->m_apidlSubDirs);
377     SHFree(pUnixFolder->m_pszPath);
378     ILFree(pUnixFolder->m_pidlLocation);
379     SHFree(pUnixFolder);
380 }
381
382 static HRESULT WINAPI UnixFolder_IShellFolder_QueryInterface(IShellFolder *iface, REFIID riid, 
383     void **ppv) 
384 {
385     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder, iface);
386         
387     TRACE("(iface=%p, riid=%p, ppv=%p)\n", iface, riid, ppv);
388     
389     if (!ppv) return E_INVALIDARG;
390     
391     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IShellFolder, riid)) {
392         *ppv = &This->lpIShellFolderVtbl;
393     } else if (IsEqualIID(&IID_IPersistFolder, riid) || IsEqualIID(&IID_IPersist, riid)) {
394         *ppv = &This->lpIPersistFolderVtbl;
395     } else {
396         *ppv = NULL;
397         return E_NOINTERFACE;
398     }
399
400     IUnknown_AddRef((IUnknown*)*ppv);
401     return S_OK;
402 }
403
404 static ULONG WINAPI UnixFolder_IShellFolder_AddRef(IShellFolder *iface) {
405     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder, iface);
406
407     TRACE("(iface=%p)\n", iface);
408
409     return InterlockedIncrement(&This->m_cRef);
410 }
411
412 static ULONG WINAPI UnixFolder_IShellFolder_Release(IShellFolder *iface) {
413     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder, iface);
414     ULONG cRef;
415     
416     TRACE("(iface=%p)\n", iface);
417
418     cRef = InterlockedDecrement(&This->m_cRef);
419     
420     if (!cRef) 
421         UnixFolder_Destroy(This);
422
423     return cRef;
424 }
425
426 static HRESULT WINAPI UnixFolder_IShellFolder_ParseDisplayName(IShellFolder* iface, HWND hwndOwner, 
427     LPBC pbcReserved, LPOLESTR lpszDisplayName, ULONG* pchEaten, LPITEMIDLIST* ppidl, 
428     ULONG* pdwAttributes)
429 {
430     int cPathLen;
431     char *pszAnsiPath;
432     BOOL result;
433
434     TRACE("(iface=%p, hwndOwner=%p, pbcReserved=%p, lpszDisplayName=%s, pchEaten=%p, ppidl=%p, "
435           "pdwAttributes=%p) stub\n", iface, hwndOwner, pbcReserved, debugstr_w(lpszDisplayName), 
436           pchEaten, ppidl, pdwAttributes);
437
438     cPathLen = lstrlenW(lpszDisplayName);
439     pszAnsiPath = (char*)SHAlloc(cPathLen+1);
440     WideCharToMultiByte(CP_ACP, 0, lpszDisplayName, -1, pszAnsiPath, cPathLen+1, NULL, NULL);
441
442     result = UNIXFS_path_to_pidl(pszAnsiPath, ppidl);
443
444     SHFree(pszAnsiPath);
445     
446     return result ? S_OK : E_FAIL;
447 }
448
449 static IUnknown *UnixSubFolderIterator_Construct(UnixFolder *pUnixFolder);
450
451 static HRESULT WINAPI UnixFolder_IShellFolder_EnumObjects(IShellFolder* iface, HWND hwndOwner, 
452     SHCONTF grfFlags, IEnumIDList** ppEnumIDList)
453 {
454     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder, iface);
455     IUnknown *newIterator;
456     HRESULT hr;
457     
458     TRACE("(iface=%p, hwndOwner=%p, grfFlags=%08lx, ppEnumIDList=%p)\n", 
459             iface, hwndOwner, grfFlags, ppEnumIDList);
460
461     newIterator = UnixSubFolderIterator_Construct(This);
462     hr = IUnknown_QueryInterface(newIterator, &IID_IEnumIDList, (void**)ppEnumIDList);
463     IUnknown_Release(newIterator);
464     
465     return hr;
466 }
467
468 static HRESULT WINAPI UnixFolder_IShellFolder_BindToObject(IShellFolder* iface, LPCITEMIDLIST pidl,
469     LPBC pbcReserved, REFIID riid, void** ppvOut)
470 {
471     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder, iface);
472     IPersistFolder *persistFolder;
473     LPITEMIDLIST pidlSubFolder;
474     HRESULT hr;
475         
476     TRACE("(iface=%p, pidl=%p, pbcReserver=%p, riid=%p, ppvOut=%p)\n", 
477             iface, pidl, pbcReserved, riid, ppvOut);
478
479     hr = UnixFolder_Constructor(NULL, &IID_IPersistFolder, (void**)&persistFolder);
480     if (!SUCCEEDED(hr)) return hr;
481     hr = IPersistFolder_QueryInterface(persistFolder, riid, (void**)ppvOut);
482     
483     pidlSubFolder = ILCombine(This->m_pidlLocation, pidl);
484     IPersistFolder_Initialize(persistFolder, pidlSubFolder);
485     IPersistFolder_Release(persistFolder);
486     ILFree(pidlSubFolder);
487
488     return hr;
489 }
490
491 static HRESULT WINAPI UnixFolder_IShellFolder_BindToStorage(IShellFolder* This, LPCITEMIDLIST pidl, 
492     LPBC pbcReserved, REFIID riid, void** ppvObj)
493 {
494     TRACE("stub\n");
495     return E_NOTIMPL;
496 }
497
498 static HRESULT WINAPI UnixFolder_IShellFolder_CompareIDs(IShellFolder* This, LPARAM lParam, 
499     LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
500 {
501     TRACE("stub\n");
502     return E_NOTIMPL;
503 }
504
505 static HRESULT WINAPI UnixFolder_IShellFolder_CreateViewObject(IShellFolder* This, HWND hwndOwner,
506     REFIID riid, void** ppvOut)
507 {
508     TRACE("stub\n");
509     return E_NOTIMPL;
510 }
511
512 static HRESULT WINAPI UnixFolder_IShellFolder_GetAttributesOf(IShellFolder* iface, UINT cidl, 
513     LPCITEMIDLIST* apidl, SFGAOF* rgfInOut)
514 {
515     TRACE("(iface=%p, cidl=%u, apidl=%p, rgfInOut=%p) semi-stub\n", iface, cidl, apidl, rgfInOut);
516     
517     *rgfInOut = *rgfInOut & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
518             
519     return S_OK;
520 }
521
522 static HRESULT WINAPI UnixFolder_IShellFolder_GetUIObjectOf(IShellFolder* iface, HWND hwndOwner, 
523     UINT cidl, LPCITEMIDLIST* apidl, REFIID riid, UINT* prgfInOut, void** ppvOut)
524 {
525     TRACE("(iface=%p, hwndOwner=%p, cidl=%d, apidl=%p, riid=%s, prgfInOut=%p, ppv=%p)\n",
526         iface, hwndOwner, cidl, apidl, debugstr_guid(riid), prgfInOut, ppvOut);
527
528     if (IsEqualIID(&IID_IExtractIconW, riid)) {
529         *ppvOut = &UnixFolderIconSingleton;
530         return S_OK;
531     } 
532     
533     return E_NOTIMPL;
534 }
535
536 static HRESULT WINAPI UnixFolder_IShellFolder_GetDisplayNameOf(IShellFolder* iface, 
537     LPCITEMIDLIST pidl, SHGDNF uFlags, STRRET* lpName)
538 {
539     LPCSHITEMID pSHItem = (LPCSHITEMID)pidl;
540     char szName[MAX_PATH];
541
542     lpName->uType = STRRET_CSTR;
543     if (!pidl->mkid.cb) {
544         strcpy(lpName->u.cStr, "");
545         return S_OK;
546     }
547
548     memcpy(szName, pSHItem->abID, pSHItem->cb-sizeof(USHORT));
549     szName[pSHItem->cb-sizeof(USHORT)] = '\0';
550     
551     TRACE("(iface=%p, pidl=%p, uFlags=%lx, lpName=%p)\n", iface, pidl, uFlags, lpName);
552    
553     if ((uFlags & SHGDN_FORPARSING) && !(uFlags & SHGDN_INFOLDER)) {
554         STRRET strSubfolderName;
555         IShellFolder *pSubFolder;
556         HRESULT hr;
557         LPITEMIDLIST pidlFirst;
558
559         pidlFirst = ILCloneFirst(pidl);
560         if (!pidlFirst) {
561             WARN("ILCloneFirst failed!\n");
562             return E_FAIL;
563         }
564
565         hr = IShellFolder_BindToObject(iface, pidlFirst, NULL, &IID_IShellFolder, 
566                                        (void**)&pSubFolder);
567         if (!SUCCEEDED(hr)) {
568             WARN("BindToObject failed!\n");
569             ILFree(pidlFirst);
570             return hr;
571         }
572
573         ILFree(pidlFirst);
574         
575         hr = IShellFolder_GetDisplayNameOf(pSubFolder, ILGetNext(pidl), uFlags, &strSubfolderName);
576         if (!SUCCEEDED(hr)) {
577             WARN("GetDisplayNameOf failed!\n");
578             return hr;
579         }
580         
581         snprintf(lpName->u.cStr, MAX_PATH, "%s%s", szName, strSubfolderName.u.cStr);
582
583         IShellFolder_Release(pSubFolder);
584     } else {
585         size_t len;
586         strcpy(lpName->u.cStr, szName);
587         len = strlen(lpName->u.cStr);
588         if (len > 1) lpName->u.cStr[len-1] = '\0';
589     }
590
591     return S_OK;
592 }
593
594 static HRESULT WINAPI UnixFolder_IShellFolder_SetNameOf(IShellFolder* This, HWND hwnd, 
595     LPCITEMIDLIST pidl, LPCOLESTR lpszName, SHGDNF uFlags, LPITEMIDLIST* ppidlOut)
596 {
597     TRACE("stub\n");
598     return E_NOTIMPL;
599 }
600
601 /* VTable for UnixFolder's IShellFolder interface.
602  */
603 static const IShellFolderVtbl UnixFolder_IShellFolder_Vtbl = {
604     UnixFolder_IShellFolder_QueryInterface,
605     UnixFolder_IShellFolder_AddRef,
606     UnixFolder_IShellFolder_Release,
607     UnixFolder_IShellFolder_ParseDisplayName,
608     UnixFolder_IShellFolder_EnumObjects,
609     UnixFolder_IShellFolder_BindToObject,
610     UnixFolder_IShellFolder_BindToStorage,
611     UnixFolder_IShellFolder_CompareIDs,
612     UnixFolder_IShellFolder_CreateViewObject,
613     UnixFolder_IShellFolder_GetAttributesOf,
614     UnixFolder_IShellFolder_GetUIObjectOf,
615     UnixFolder_IShellFolder_GetDisplayNameOf,
616     UnixFolder_IShellFolder_SetNameOf
617 };
618
619 static HRESULT WINAPI UnixFolder_IPersistFolder_QueryInterface(IPersistFolder* This, REFIID riid, 
620     void** ppvObject)
621 {
622     return UnixFolder_IShellFolder_QueryInterface(
623                 (IShellFolder*)ADJUST_THIS(UnixFolder, IPersistFolder, This), riid, ppvObject);
624 }
625
626 static ULONG WINAPI UnixFolder_IPersistFolder_AddRef(IPersistFolder* This)
627 {
628     return UnixFolder_IShellFolder_AddRef(
629                 (IShellFolder*)ADJUST_THIS(UnixFolder, IPersistFolder, This));
630 }
631
632 static ULONG WINAPI UnixFolder_IPersistFolder_Release(IPersistFolder* This)
633 {
634     return UnixFolder_IShellFolder_Release(
635                 (IShellFolder*)ADJUST_THIS(UnixFolder, IPersistFolder, This));
636 }
637
638 static HRESULT WINAPI UnixFolder_IPersistFolder_GetClassID(IPersistFolder* This, CLSID* pClassID)
639 {
640     TRACE("stub\n");
641     return E_NOTIMPL;
642 }
643
644 static HRESULT WINAPI UnixFolder_IPersistFolder_Initialize(IPersistFolder* iface, LPCITEMIDLIST pidl)
645 {
646     UnixFolder *This = ADJUST_THIS(UnixFolder, IPersistFolder, iface);
647     
648     TRACE("(iface=%p, pidl=%p)\n", iface, pidl);
649
650     This->m_pidlLocation = ILClone(pidl);
651     UNIXFS_pidl_to_path(pidl, &This->m_pszPath);
652     UNIXFS_build_subfolder_pidls(This->m_pszPath, &This->m_apidlSubDirs, &This->m_cSubDirs);
653     
654     return S_OK;
655 }
656
657 /* VTable for UnixFolder's IPersistFolder interface.
658  */
659 static const IPersistFolderVtbl UnixFolder_IPersistFolder_Vtbl = {
660     UnixFolder_IPersistFolder_QueryInterface,
661     UnixFolder_IPersistFolder_AddRef,
662     UnixFolder_IPersistFolder_Release,
663     UnixFolder_IPersistFolder_GetClassID,
664     UnixFolder_IPersistFolder_Initialize
665 };
666
667 /******************************************************************************
668  * UnixFolder_Constructor [Internal]
669  *
670  * PARAMS
671  *  pUnkOuter [I] Outer class for aggregation. Currently ignored.
672  *  riid      [I] Interface asked for by the client.
673  *  ppv       [O] Pointer to an riid interface to the UnixFolder object.
674  *
675  * NOTES
676  *  This is the only function exported from shfldr_unixfs.c. It's called from
677  *  shellole.c's default class factory and thus has to exhibit a LPFNCREATEINSTANCE
678  *  compatible signature.
679  */
680 HRESULT WINAPI UnixFolder_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv) {
681     HRESULT hr;
682     UnixFolder *pUnixFolder;
683     
684     TRACE("(pUnkOuter=%p, riid=%p, ppv=%p)\n", pUnkOuter, riid, ppv);
685
686     pUnixFolder = SHAlloc((ULONG)sizeof(UnixFolder));
687     pUnixFolder->lpIShellFolderVtbl = &UnixFolder_IShellFolder_Vtbl;
688     pUnixFolder->lpIPersistFolderVtbl = &UnixFolder_IPersistFolder_Vtbl;
689     pUnixFolder->m_cRef = 0;
690     pUnixFolder->m_pszPath = NULL;
691     pUnixFolder->m_apidlSubDirs = NULL;
692     pUnixFolder->m_cSubDirs = 0;
693
694     UnixFolder_IShellFolder_AddRef(STATIC_CAST(IShellFolder, pUnixFolder));
695     hr = UnixFolder_IShellFolder_QueryInterface(STATIC_CAST(IShellFolder, pUnixFolder), riid, ppv);
696     UnixFolder_IShellFolder_Release(STATIC_CAST(IShellFolder, pUnixFolder));
697     return hr;
698 }
699
700 /******************************************************************************
701  * UnixSubFolderIterator
702  *
703  * Class whose heap based objects represent iterators over the sub-directories
704  * of a given UnixFolder object. 
705  */
706
707 /* UnixSubFolderIterator object layout and typedef.
708  */
709 typedef struct _UnixSubFolderIterator {
710     const IEnumIDListVtbl *lpIEnumIDListVtbl;
711     ULONG m_cRef;
712     UnixFolder *m_pUnixFolder;
713     ULONG m_cIdx;
714 } UnixSubFolderIterator;
715
716 static void UnixSubFolderIterator_Destroy(UnixSubFolderIterator *iterator) {
717     TRACE("(iterator=%p)\n", iterator);
718         
719     UnixFolder_IShellFolder_Release((IShellFolder*)iterator->m_pUnixFolder);
720     SHFree(iterator);
721 }
722
723 static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_QueryInterface(IEnumIDList* iface, 
724     REFIID riid, void** ppv)
725 {
726     TRACE("(iface=%p, riid=%p, ppv=%p)\n", iface, riid, ppv);
727     
728     if (!ppv) return E_INVALIDARG;
729     
730     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumIDList, riid)) {
731         *ppv = iface;
732     } else {
733         *ppv = NULL;
734         return E_NOINTERFACE;
735     }
736
737     IEnumIDList_AddRef(iface);
738     return S_OK;
739 }
740                             
741 static ULONG WINAPI UnixSubFolderIterator_IEnumIDList_AddRef(IEnumIDList* iface)
742 {
743     UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface);
744
745     TRACE("(iface=%p)\n", iface);
746    
747     return InterlockedIncrement(&This->m_cRef);
748 }
749
750 static ULONG WINAPI UnixSubFolderIterator_IEnumIDList_Release(IEnumIDList* iface)
751 {
752     UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface);
753     ULONG cRef;
754     
755     TRACE("(iface=%p)\n", iface);
756
757     cRef = InterlockedDecrement(&This->m_cRef);
758     
759     if (!cRef) 
760         UnixSubFolderIterator_Destroy(This);
761
762     return cRef;
763 }
764
765 static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Next(IEnumIDList* iface, ULONG celt, 
766     LPITEMIDLIST* rgelt, ULONG* pceltFetched)
767 {
768     UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface);
769     ULONG i;
770
771     TRACE("(iface=%p, celt=%ld, rgelt=%p, pceltFetched=%p)\n", iface, celt, rgelt, pceltFetched);
772     
773     for (i=0; (i < celt) && (This->m_cIdx < This->m_pUnixFolder->m_cSubDirs); i++, This->m_cIdx++) {
774         rgelt[i] = ILClone(This->m_pUnixFolder->m_apidlSubDirs[This->m_cIdx]);
775     }
776
777     if (pceltFetched)
778         *pceltFetched = i;
779
780     return i == celt ? S_OK : S_FALSE;
781 }
782
783 static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Skip(IEnumIDList* iface, ULONG celt)
784 {
785     UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface);
786     
787     TRACE("(iface=%p, celt=%ld)\n", iface, celt);
788
789     if (This->m_cIdx + celt > This->m_pUnixFolder->m_cSubDirs) {
790         This->m_cIdx = This->m_pUnixFolder->m_cSubDirs;
791         return S_FALSE;
792     } else {
793         This->m_cIdx += celt;
794         return S_OK;
795     }
796 }
797
798 static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Reset(IEnumIDList* iface)
799 {
800     UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface);
801         
802     TRACE("(iface=%p)\n", iface);
803
804     This->m_cIdx = 0;
805     
806     return S_OK;
807 }
808
809 static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Clone(IEnumIDList* This, 
810     IEnumIDList** ppenum)
811 {
812     TRACE("stub\n");
813     return E_NOTIMPL;
814 }
815
816 /* VTable for UnixSubFolderIterator's IEnumIDList interface.
817  */
818 static const IEnumIDListVtbl UnixSubFolderIterator_IEnumIDList_Vtbl = {
819     UnixSubFolderIterator_IEnumIDList_QueryInterface,
820     UnixSubFolderIterator_IEnumIDList_AddRef,
821     UnixSubFolderIterator_IEnumIDList_Release,
822     UnixSubFolderIterator_IEnumIDList_Next,
823     UnixSubFolderIterator_IEnumIDList_Skip,
824     UnixSubFolderIterator_IEnumIDList_Reset,
825     UnixSubFolderIterator_IEnumIDList_Clone
826 };
827
828 static IUnknown *UnixSubFolderIterator_Construct(UnixFolder *pUnixFolder) {
829     UnixSubFolderIterator *iterator;
830
831     TRACE("(pUnixFolder=%p)\n", pUnixFolder);
832     
833     iterator = SHAlloc((ULONG)sizeof(UnixSubFolderIterator));
834     iterator->lpIEnumIDListVtbl = &UnixSubFolderIterator_IEnumIDList_Vtbl;
835     iterator->m_cRef = 0;
836     iterator->m_cIdx = 0;
837     iterator->m_pUnixFolder = pUnixFolder;
838
839     UnixSubFolderIterator_IEnumIDList_AddRef((IEnumIDList*)iterator);
840     UnixFolder_IShellFolder_AddRef((IShellFolder*)pUnixFolder);
841     
842     return (IUnknown*)iterator;
843 }