Added SystemHandleInformation tests.
[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 "config.h"
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <limits.h>
25 #include <dirent.h>
26 #ifdef HAVE_SYS_STAT_H
27 # include <sys/stat.h>
28 #endif
29 #ifdef HAVE_PWD_H
30 # include <pwd.h>
31 #endif
32 #include <grp.h>
33 #include <limits.h>
34
35 #define COBJMACROS
36 #define NONAMELESSUNION
37 #define NONAMELESSSTRUCT
38
39 #include "windef.h"
40 #include "winbase.h"
41 #include "winuser.h"
42 #include "objbase.h"
43 #include "winreg.h"
44 #include "winternl.h"
45 #include "wine/debug.h"
46
47 #include "shell32_main.h"
48 #include "shfldr.h"
49 #include "shresdef.h"
50 #include "pidl.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(shell);
53
54 const GUID CLSID_UnixFolder = {0xcc702eb2, 0x7dc5, 0x11d9, {0xc6, 0x87, 0x00, 0x04, 0x23, 0x8a, 0x01, 0xcd}};
55
56 #define ADJUST_THIS(c,m,p) ((c*)(((long)p)-(long)&(((c*)0)->lp##m##Vtbl)))
57 #define STATIC_CAST(i,p) ((i*)&p->lp##i##Vtbl)
58
59 /* FileStruct reserves one byte for szNames, thus we don't have to 
60  * alloc a byte for the terminating '\0' of 'name'. Two of the
61  * additional bytes are for SHITEMID's cb field. One is for IDLDATA's
62  * type field. One is for FileStruct's szNames field, to terminate
63  * the alternate DOS name, which we don't use here. And then there's
64  * the additional StatStruct.
65  */
66 #define SHITEMID_LEN_FROM_NAME_LEN(n) \
67     (sizeof(USHORT)+sizeof(PIDLTYPE)+sizeof(FileStruct)+(n)+sizeof(char)+sizeof(StatStruct))
68 #define NAME_LEN_FROM_LPSHITEMID(s) \
69     (((LPSHITEMID)s)->cb-sizeof(USHORT)-sizeof(PIDLTYPE)-sizeof(FileStruct)-sizeof(char)-sizeof(StatStruct))
70 #define LPSTATSTRUCT_FROM_LPSHITEMID(s) ((StatStruct*)(((LPBYTE)s)+((LPSHITEMID)s)->cb-sizeof(StatStruct)))
71
72 /* This structure is appended to shell32's FileStruct type in IDLs to store unix
73  * filesystem specific informationen extracted with the stat system call.
74  */
75 typedef struct tagStatStruct {
76     mode_t st_mode;
77     uid_t  st_uid;
78     gid_t  st_gid;
79 } StatStruct;
80
81 /******************************************************************************
82  * UNIXFS_is_pidl_of_type [INTERNAL]
83  *
84  * Checks for the first SHITEMID of an ITEMIDLIST if it passes a filter.
85  *
86  * PARAMS
87  *  pIDL    [I] The ITEMIDLIST to be checked.
88  *  fFilter [I] Shell condition flags, which specify the filter.
89  *
90  * RETURNS
91  *  TRUE, if pIDL is accepted by fFilter
92  *  FALSE, otherwise
93  */
94 static inline BOOL UNIXFS_is_pidl_of_type(LPITEMIDLIST pIDL, SHCONTF fFilter) {
95     LPSTR pszText = _ILGetTextPointer(pIDL);
96     if (!pszText) return FALSE;
97     if (pszText[0] == '.' && !(fFilter & SHCONTF_INCLUDEHIDDEN)) return FALSE;
98     if (_ILIsFolder(pIDL) && (fFilter & SHCONTF_FOLDERS)) return TRUE;
99     if (_ILIsValue(pIDL) && (fFilter & SHCONTF_NONFOLDERS)) return TRUE;
100     return FALSE;
101 }
102
103 /******************************************************************************
104  * UNIXFS_build_shitemid [Internal]
105  *
106  * Constructs a new SHITEMID for a single path item (up to the next '/' or 
107  * '\0') into a buffer. Decorates the SHITEMID with information from a stat 
108  * system call.
109  *
110  * PARAMS
111  *  name   [I] The name of the next path item. Terminated by either '\0' or '/'.
112  *  pStat  [I] A stat struct variable obtained by a stat system call on the file.
113  *  buffer [O] SHITEMID will be constructed here.
114  *
115  * RETURNS
116  *  A pointer to the next '/' or '\0' character in name.
117  *  
118  * NOTES
119  *  Minimum size of buffer is SHITEMID_LEN_FROM_NAME_LEN(strlen(name)).
120  *  If what you need is a PIDLLIST with a single SHITEMID, don't forget to append
121  *  a 0 USHORT value.
122  */
123 static char* UNIXFS_build_shitemid(char *name, struct stat *pStat, void *buffer) {
124     LARGE_INTEGER time;
125     FILETIME fileTime;
126     LPPIDLDATA pIDLData;
127     StatStruct *pStatStruct;
128     int cNameLen;
129     char *pSlash;
130
131     TRACE("(name=%s, buffer=%p)\n", debugstr_a(name), buffer);
132
133     pSlash = strchr(name, '/');
134     cNameLen = pSlash ? pSlash - name : strlen(name); 
135     
136     memset(buffer, 0, SHITEMID_LEN_FROM_NAME_LEN(cNameLen));
137     ((LPSHITEMID)buffer)->cb = SHITEMID_LEN_FROM_NAME_LEN(cNameLen) ;
138     
139     pIDLData = _ILGetDataPointer((LPCITEMIDLIST)buffer);
140     pIDLData->type = S_ISDIR(pStat->st_mode) ? PT_FOLDER : PT_VALUE;
141     pIDLData->u.file.dwFileSize = (DWORD)pStat->st_size;
142     RtlSecondsSince1970ToTime( pStat->st_mtime, &time );
143     fileTime.dwLowDateTime = time.u.LowPart;
144     fileTime.dwHighDateTime = time.u.HighPart;
145     FileTimeToDosDateTime(&fileTime, &pIDLData->u.file.uFileDate, &pIDLData->u.file.uFileTime);
146     pIDLData->u.file.uFileAttribs = 
147         (S_ISDIR(pStat->st_mode) ? FILE_ATTRIBUTE_DIRECTORY : 0) |
148         (name[0] == '.' ? FILE_ATTRIBUTE_HIDDEN : 0);
149     memcpy(pIDLData->u.file.szNames, name, cNameLen);
150
151     pStatStruct = LPSTATSTRUCT_FROM_LPSHITEMID(buffer);
152     pStatStruct->st_mode = pStat->st_mode;
153     pStatStruct->st_uid = pStat->st_uid;
154     pStatStruct->st_gid = pStat->st_gid;
155
156     return pSlash ? pSlash+1 : (name + cNameLen);
157 }
158
159 /******************************************************************************
160  * UNIXFS_path_to_pidl [Internal]
161  *
162  * PARAMS
163  *  base  [I] Path prefix. May be NULL if "path" parameter is absolute
164  *  path  [I] An absolute unix path or a path relativ to "base"
165  *  ppidl [O] The corresponding ITEMIDLIST. Release with SHFree/ILFree
166  *  
167  * RETURNS
168  *  Success: TRUE
169  *  Failure: FALSE, invalid params or out of memory
170  */
171 static BOOL UNIXFS_path_to_pidl(const char *base, const char *path, LPITEMIDLIST *ppidl) {
172     LPITEMIDLIST pidl;
173     struct stat fileStat;
174     int cSubDirs, cPidlLen, res;
175     char *pSlash, *pCompletePath, *pNextPathElement;
176
177     TRACE("path=%s, ppidl=%p", debugstr_a(path), ppidl);
178     
179     /* Fail, if base + path is not an absolute path */
180     if (!ppidl || !path || (path[0] != '/' && (!base || base[0] != '/'))) return FALSE;
181
182     /* Build an absolute path and let pNextPathElement point to the interesting relativ path. */
183     if (path[0] != '/') {
184         pCompletePath = SHAlloc(strlen(base)+strlen(path)+1);
185         if (!pCompletePath) return FALSE;
186         sprintf(pCompletePath, "%s%s", base, path);
187         pNextPathElement = pCompletePath + strlen(base);
188     } else {
189         pCompletePath = SHAlloc(strlen(path)+1);
190         if (!pCompletePath) return FALSE;
191         memcpy(pCompletePath, path, strlen(path)+1);
192         pNextPathElement = pCompletePath + 1;
193     }
194     
195     /* Count the number of sub-directories in the path */
196     cSubDirs = 1; /* Path may not be terminated with '/', thus start with 1 */
197     pSlash = strchr(pNextPathElement, '/');
198     while (pSlash) {
199         cSubDirs++;
200         pSlash = strchr(pSlash+1, '/');
201     }
202    
203     /* Allocate enough memory to hold the path. The -cSubDirs is for the '/' 
204      * characters, which are not stored in the ITEMIDLIST. */
205     cPidlLen = strlen(pCompletePath) - cSubDirs + cSubDirs * SHITEMID_LEN_FROM_NAME_LEN(0) + sizeof(USHORT);
206     *ppidl = pidl = (LPITEMIDLIST)SHAlloc(cPidlLen);
207     if (!pidl) {
208         SHFree(pCompletePath);
209         return FALSE;
210     }
211
212     /* Concatenate the SHITEMIDs of the sub-directories. */
213     while (*pNextPathElement) {
214         pSlash = strchr(pNextPathElement, '/');
215         if (pSlash) {
216             *pSlash = '\0';
217             res = stat(pCompletePath, &fileStat);
218             *pSlash = '/';
219             if (res) {
220                 SHFree(pCompletePath);
221                 SHFree(pidl);
222                 return FALSE;
223             }
224         } else {
225             if (stat(pCompletePath, &fileStat)) {
226                 SHFree(pCompletePath);
227                 SHFree(pidl);
228                 return FALSE;
229             }
230         }
231                 
232         pNextPathElement = UNIXFS_build_shitemid(pNextPathElement, &fileStat, pidl);
233         pidl = ILGetNext(pidl);
234     }
235     pidl->mkid.cb = 0; /* Terminate the ITEMIDLIST */
236  
237     SHFree(pCompletePath);
238     return TRUE;
239 }
240
241 /******************************************************************************
242  * UNIXFS_pidl_to_path [Internal]
243  *
244  * Construct the unix path that corresponds to a fully qualified ITEMIDLIST
245  *
246  * PARAMS
247  *  pidl [I] ITEMIDLIST that specifies the absolute location of the folder
248  *  path [O] The corresponding unix path as a zero terminated ascii string
249  *
250  * RETURNS
251  *  Success: TRUE
252  *  Failure: FALSE, pidl doesn't specify a unix path or out of memory
253  */
254 static BOOL UNIXFS_pidl_to_path(LPCITEMIDLIST pidl, PSZ *path) {
255     LPCITEMIDLIST current = pidl, root;
256     DWORD dwPathLen;
257     char *pNextDir;
258
259     TRACE("(pidl=%p, path=%p)\n", pidl, path);
260     
261     *path = NULL;
262
263     /* Find the UnixFolderClass root */
264     while (current->mkid.cb) {
265         LPPIDLDATA pData = _ILGetDataPointer(current);
266         if (!pData) return FALSE;
267         if (pData->type == PT_GUID && IsEqualIID(&CLSID_UnixFolder, &pData->u.guid.guid)) break;
268         current = ILGetNext(current);
269     }
270     root = current = ILGetNext(current);
271     
272     /* Determine the path's length bytes */
273     dwPathLen = 2; /* For the '/' prefix and the terminating '\0' */
274     while (current->mkid.cb) {
275         dwPathLen += NAME_LEN_FROM_LPSHITEMID(current) + 1; /* For the '/' */
276         current = ILGetNext(current);
277     };
278
279     /* Build the path */
280     *path = pNextDir = SHAlloc(dwPathLen);
281     if (!path) {
282         WARN("SHAlloc failed!\n");
283         return FALSE;
284     }
285     current = root;
286     *pNextDir++ = '/';
287     while (current->mkid.cb) {
288         memcpy(pNextDir, _ILGetTextPointer(current), NAME_LEN_FROM_LPSHITEMID(current));
289         pNextDir += NAME_LEN_FROM_LPSHITEMID(current);
290         *pNextDir++ = '/';
291         current = ILGetNext(current);
292     }
293     *pNextDir='\0';
294     
295     TRACE("resulting path: %s\n", *path);
296     return TRUE;
297 }
298
299 /******************************************************************************
300  * UNIXFS_build_subfolder_pidls [Internal]
301  *
302  * Builds an array of subfolder PIDLs relative to a unix directory
303  *
304  * PARAMS
305  *  path   [I] Name of a unix directory as a zero terminated ascii string
306  *  apidl  [O] The array of PIDLs
307  *  pCount [O] Size of apidl
308  *
309  * RETURNS
310  *  Success: TRUE
311  *  Failure: FALSE, path is not a valid unix directory or out of memory
312  *
313  * NOTES
314  *  The array of PIDLs and each PIDL are allocated with SHAlloc. You'll have
315  *  to release each PIDL as well as the array itself with SHFree.
316  */
317 static BOOL UNIXFS_build_subfolder_pidls(const char *path, LPITEMIDLIST **apidl, DWORD *pCount)
318 {
319     struct dirent *pDirEntry;
320     struct stat fileStat;
321     DIR *dir;
322     DWORD cDirEntries, i;
323     USHORT sLen;
324     char *pszFQPath;
325
326     TRACE("(path=%s, apidl=%p, pCount=%p)\n", debugstr_a(path), apidl, pCount);
327     
328     *apidl = NULL;
329     *pCount = 0;
330   
331     dir = opendir(path);
332     if (!dir) {
333         WARN("Failed to open directory '%s'.\n", path);
334         return FALSE;
335     }
336
337     /* Allocate space for fully qualified paths */
338     pszFQPath = SHAlloc(strlen(path) + PATH_MAX);
339     if (!pszFQPath) {
340         WARN("SHAlloc failed!\n");
341         return FALSE;
342     }
343  
344     /* Count number of directory entries. */
345     for (cDirEntries = 0, pDirEntry = readdir(dir); pDirEntry; pDirEntry = readdir(dir)) { 
346         if (!strcmp(pDirEntry->d_name, ".") || !strcmp(pDirEntry->d_name, "..")) continue;
347         sprintf(pszFQPath, "%s%s", path, pDirEntry->d_name);
348         if (!stat(pszFQPath, &fileStat) && (S_ISDIR(fileStat.st_mode) || S_ISREG(fileStat.st_mode))) cDirEntries++;
349     }
350
351     /* If there are no entries, we are done. */
352     if (cDirEntries == 0) {
353         closedir(dir);
354         SHFree(pszFQPath);
355         return TRUE;
356     }
357
358     /* Allocate the array of PIDLs */
359     *apidl = SHAlloc(cDirEntries * sizeof(LPITEMIDLIST));
360     if (!apidl) {
361         WARN("SHAlloc failed!\n");
362         return FALSE;
363     }
364   
365     /* Allocate and initialize one SHITEMID per sub-directory. */
366     for (rewinddir(dir), pDirEntry = readdir(dir), i = 0; pDirEntry; pDirEntry = readdir(dir)) {
367         LPSHITEMID pid;
368             
369         if (!strcmp(pDirEntry->d_name, ".") || !strcmp(pDirEntry->d_name, "..")) continue;
370
371         sprintf(pszFQPath, "%s%s", path, pDirEntry->d_name);
372         if (stat(pszFQPath, &fileStat)) continue;
373         if (!S_ISDIR(fileStat.st_mode) && !S_ISREG(fileStat.st_mode)) continue;
374    
375         sLen = strlen(pDirEntry->d_name);
376         pid = (LPSHITEMID)SHAlloc(SHITEMID_LEN_FROM_NAME_LEN(sLen)+sizeof(USHORT));
377         if (!pid) {
378             WARN("SHAlloc failed!\n");
379             return FALSE;
380         }
381         UNIXFS_build_shitemid(pDirEntry->d_name, &fileStat, pid);
382         memset(((PBYTE)pid)+pid->cb, 0, sizeof(USHORT));
383
384         (*apidl)[i++] = (LPITEMIDLIST)pid;
385     }
386     
387     *pCount = i;    
388     closedir(dir);
389     SHFree(pszFQPath);
390
391     return TRUE;
392 }
393
394 /******************************************************************************
395  * UnixFolderIcon 
396  *
397  * Singleton class, which is used by the shell to extract icons to represent
398  * folders in tree- and listviews. Currently, all this singleton does is to
399  * provide the shell with the absolute path to "shell32.dll" and with the 
400  * indices of the closed and opened folder icons in the resources of this dll.
401  */
402
403 /* UnixFolderIcon object layout and typedef.
404  */
405 typedef struct _UnixFolderIcon {
406     const IExtractIconWVtbl *lpIExtractIconWVtbl;
407     BOOL bFolder;
408 } UnixFolderIcon;
409
410 static HRESULT WINAPI UnixFolderIcon_IExtractIconW_QueryInterface(IExtractIconW *iface, REFIID riid, 
411     void **ppv) 
412 {
413     TRACE("(iface=%p, riid=%p, ppv=%p)\n", iface, riid, ppv);
414     
415     if (!ppv) return E_INVALIDARG;
416     
417     if (IsEqualIID(&IID_IUnknown, riid) ||
418         IsEqualIID(&IID_IExtractIconW, riid))
419     {
420         *ppv = iface;
421     } else {
422         *ppv = NULL;
423         return E_NOINTERFACE;
424     }
425
426     IExtractIconW_AddRef(iface);
427     return S_OK;
428 }
429
430 static ULONG WINAPI UnixFolderIcon_IExtractIconW_AddRef(IExtractIconW *iface) {
431     TRACE("(iface=%p)\n", iface);
432     return 2;
433 }
434
435 static ULONG WINAPI UnixFolderIcon_IExtractIconW_Release(IExtractIconW *iface) {
436     TRACE("(iface=%p)\n", iface);
437     return 1;
438 }
439
440 static HRESULT WINAPI UnixFolderIcon_IExtractIconW_GetIconLocation(IExtractIconW *iface, 
441     UINT uFlags, LPWSTR szIconFile, UINT cchMax, INT* piIndex, UINT* pwFlags)
442 {
443     UnixFolderIcon *This = ADJUST_THIS(UnixFolderIcon, IExtractIconW, iface);
444         
445     TRACE("(iface=%p, uFlags=%u, szIconFile=%s, cchMax=%u, piIndex=%p, pwFlags=%p)\n",
446             iface, uFlags, debugstr_w(szIconFile), cchMax, piIndex, pwFlags);
447     
448     lstrcpynW(szIconFile, swShell32Name, cchMax);
449     if (This->bFolder) {
450         *piIndex = (uFlags & GIL_OPENICON) ? -IDI_SHELL_FOLDER_OPEN : -IDI_SHELL_FOLDER;
451     } else {
452         *piIndex = -IDI_SHELL_DOCUMENT;
453     }
454     *pwFlags = 0;
455
456     return S_OK;
457 }
458
459 static HRESULT WINAPI UnixFolderIcon_IExtractIconW_Extract(
460     IExtractIconW *iface, LPCWSTR pszFile, UINT nIconIndex, HICON* phiconLarge, HICON* phiconSmall, 
461     UINT nIconSize)
462 {
463     TRACE("(iface=%p, pszFile=%s, nIconIndex=%u, phiconLarge=%p, phiconSmall=%p, nIconSize=%u)"
464           "stub\n", iface, debugstr_w(pszFile), nIconIndex, phiconLarge, phiconSmall, nIconSize);
465
466     return E_NOTIMPL;
467 }
468
469 /* VTable for the IExtractIconW interface of the UnixFolderIcon class. 
470  */
471 static const IExtractIconWVtbl UnixFolderIcon_IExtractIconW_Vtbl = {
472     UnixFolderIcon_IExtractIconW_QueryInterface,
473     UnixFolderIcon_IExtractIconW_AddRef,
474     UnixFolderIcon_IExtractIconW_Release,
475     UnixFolderIcon_IExtractIconW_GetIconLocation,
476     UnixFolderIcon_IExtractIconW_Extract
477 };
478
479 /* The singleton instance
480  */
481 UnixFolderIcon UnixFolderIconSingleton = { &UnixFolderIcon_IExtractIconW_Vtbl, TRUE };
482 UnixFolderIcon UnixDocumentIconSingleton = { &UnixFolderIcon_IExtractIconW_Vtbl, FALSE };
483
484 /******************************************************************************
485  * UnixFolder
486  *
487  * Class whose heap based instances represent unix filesystem directories.
488  */
489
490 /* UnixFolder object layout and typedef.
491  */
492 typedef struct _UnixFolder {
493     const IShellFolder2Vtbl  *lpIShellFolder2Vtbl;
494     const IPersistFolderVtbl *lpIPersistFolderVtbl;
495     ULONG m_cRef;
496     CHAR *m_pszPath;
497     LPITEMIDLIST m_pidlLocation;
498     LPITEMIDLIST *m_apidlSubDirs;
499     DWORD m_cSubDirs;
500 } UnixFolder;
501
502 static void UnixFolder_Destroy(UnixFolder *pUnixFolder) {
503     DWORD i;
504
505     TRACE("(pUnixFolder=%p)\n", pUnixFolder);
506     
507     if (pUnixFolder->m_apidlSubDirs) 
508         for (i=0; i < pUnixFolder->m_cSubDirs; i++) 
509             SHFree(pUnixFolder->m_apidlSubDirs[i]);
510     SHFree(pUnixFolder->m_apidlSubDirs);
511     SHFree(pUnixFolder->m_pszPath);
512     ILFree(pUnixFolder->m_pidlLocation);
513     SHFree(pUnixFolder);
514 }
515
516 static HRESULT WINAPI UnixFolder_IShellFolder2_QueryInterface(IShellFolder2 *iface, REFIID riid, 
517     void **ppv) 
518 {
519     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
520         
521     TRACE("(iface=%p, riid=%p, ppv=%p)\n", iface, riid, ppv);
522     
523     if (!ppv) return E_INVALIDARG;
524     
525     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IShellFolder, riid) || 
526         IsEqualIID(&IID_IShellFolder2, riid)) 
527     {
528         *ppv = &This->lpIShellFolder2Vtbl;
529     } else if (IsEqualIID(&IID_IPersistFolder, riid) || IsEqualIID(&IID_IPersist, riid)) {
530         *ppv = &This->lpIPersistFolderVtbl;
531     } else {
532         *ppv = NULL;
533         return E_NOINTERFACE;
534     }
535
536     IUnknown_AddRef((IUnknown*)*ppv);
537     return S_OK;
538 }
539
540 static ULONG WINAPI UnixFolder_IShellFolder2_AddRef(IShellFolder2 *iface) {
541     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
542
543     TRACE("(iface=%p)\n", iface);
544
545     return InterlockedIncrement(&This->m_cRef);
546 }
547
548 static ULONG WINAPI UnixFolder_IShellFolder2_Release(IShellFolder2 *iface) {
549     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
550     ULONG cRef;
551     
552     TRACE("(iface=%p)\n", iface);
553
554     cRef = InterlockedDecrement(&This->m_cRef);
555     
556     if (!cRef) 
557         UnixFolder_Destroy(This);
558
559     return cRef;
560 }
561
562 static HRESULT WINAPI UnixFolder_IShellFolder2_ParseDisplayName(IShellFolder2* iface, HWND hwndOwner, 
563     LPBC pbcReserved, LPOLESTR lpszDisplayName, ULONG* pchEaten, LPITEMIDLIST* ppidl, 
564     ULONG* pdwAttributes)
565 {
566     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
567     int cPathLen;
568     char *pszAnsiPath;
569     BOOL result;
570
571     TRACE("(iface=%p, hwndOwner=%p, pbcReserved=%p, lpszDisplayName=%s, pchEaten=%p, ppidl=%p, "
572           "pdwAttributes=%p) stub\n", iface, hwndOwner, pbcReserved, debugstr_w(lpszDisplayName), 
573           pchEaten, ppidl, pdwAttributes);
574
575     cPathLen = lstrlenW(lpszDisplayName);
576     pszAnsiPath = (char*)SHAlloc(cPathLen+1);
577     WideCharToMultiByte(CP_ACP, 0, lpszDisplayName, -1, pszAnsiPath, cPathLen+1, NULL, NULL);
578
579     result = UNIXFS_path_to_pidl(This->m_pszPath, pszAnsiPath, ppidl);
580     if (result && pdwAttributes) 
581         SHELL32_GetItemAttributes((IShellFolder*)iface, *ppidl, pdwAttributes);        
582
583     SHFree(pszAnsiPath);
584    
585     if (!result) TRACE("FAILED!\n");
586     
587     return result ? S_OK : E_FAIL;
588 }
589
590 static IUnknown *UnixSubFolderIterator_Construct(UnixFolder *pUnixFolder, SHCONTF fFilter);
591
592 static HRESULT WINAPI UnixFolder_IShellFolder2_EnumObjects(IShellFolder2* iface, HWND hwndOwner, 
593     SHCONTF grfFlags, IEnumIDList** ppEnumIDList)
594 {
595     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
596     IUnknown *newIterator;
597     HRESULT hr;
598     
599     TRACE("(iface=%p, hwndOwner=%p, grfFlags=%08lx, ppEnumIDList=%p)\n", 
600             iface, hwndOwner, grfFlags, ppEnumIDList);
601
602     newIterator = UnixSubFolderIterator_Construct(This, grfFlags);
603     hr = IUnknown_QueryInterface(newIterator, &IID_IEnumIDList, (void**)ppEnumIDList);
604     IUnknown_Release(newIterator);
605     
606     return hr;
607 }
608
609 static HRESULT WINAPI UnixFolder_IShellFolder2_BindToObject(IShellFolder2* iface, LPCITEMIDLIST pidl,
610     LPBC pbcReserved, REFIID riid, void** ppvOut)
611 {
612     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
613     IPersistFolder *persistFolder;
614     LPITEMIDLIST pidlSubFolder;
615     HRESULT hr;
616         
617     TRACE("(iface=%p, pidl=%p, pbcReserver=%p, riid=%p, ppvOut=%p)\n", 
618             iface, pidl, pbcReserved, riid, ppvOut);
619
620     hr = UnixFolder_Constructor(NULL, &IID_IPersistFolder, (void**)&persistFolder);
621     if (!SUCCEEDED(hr)) return hr;
622     hr = IPersistFolder_QueryInterface(persistFolder, riid, (void**)ppvOut);
623     
624     pidlSubFolder = ILCombine(This->m_pidlLocation, pidl);
625     IPersistFolder_Initialize(persistFolder, pidlSubFolder);
626     IPersistFolder_Release(persistFolder);
627     ILFree(pidlSubFolder);
628
629     return hr;
630 }
631
632 static HRESULT WINAPI UnixFolder_IShellFolder2_BindToStorage(IShellFolder2* This, LPCITEMIDLIST pidl, 
633     LPBC pbcReserved, REFIID riid, void** ppvObj)
634 {
635     TRACE("stub\n");
636     return E_NOTIMPL;
637 }
638
639 static HRESULT WINAPI UnixFolder_IShellFolder2_CompareIDs(IShellFolder2* iface, LPARAM lParam, 
640     LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
641 {
642     BOOL isEmpty1, isEmpty2;
643     HRESULT hr = E_FAIL;
644     LPITEMIDLIST firstpidl;
645     IShellFolder2 *psf;
646     int compare;
647
648     TRACE("(iface=%p, lParam=%ld, pidl1=%p, pidl2=%p)\n", iface, lParam, pidl1, pidl2);
649     
650     isEmpty1 = !pidl1 || !pidl1->mkid.cb;
651     isEmpty2 = !pidl2 || !pidl2->mkid.cb;
652
653     if (isEmpty1 && isEmpty2) 
654         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
655     else if (isEmpty1)
656         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD)-1);
657     else if (isEmpty2)
658         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD)1);
659
660     if (_ILIsFolder(pidl1) && !_ILIsFolder(pidl2)) 
661         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD)-1);
662     if (!_ILIsFolder(pidl1) && _ILIsFolder(pidl2))
663         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD)1);
664
665     compare = CompareStringA(LOCALE_USER_DEFAULT, NORM_IGNORECASE, 
666                              _ILGetTextPointer(pidl1), NAME_LEN_FROM_LPSHITEMID(pidl1),
667                              _ILGetTextPointer(pidl2), NAME_LEN_FROM_LPSHITEMID(pidl2));
668     
669     if ((compare == CSTR_LESS_THAN) || (compare == CSTR_GREATER_THAN)) 
670         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD)(compare == CSTR_LESS_THAN)?-1:1);
671
672     if (pidl1->mkid.cb < pidl2->mkid.cb)
673         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD)-1);
674     else if (pidl1->mkid.cb > pidl2->mkid.cb)
675         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD)1);
676
677     firstpidl = ILCloneFirst(pidl1);
678     pidl1 = ILGetNext(pidl1);
679     pidl2 = ILGetNext(pidl2);
680     
681     hr = IShellFolder2_BindToObject(iface, firstpidl, NULL, &IID_IShellFolder, (LPVOID*)&psf);
682     if (SUCCEEDED(hr)) {
683         hr = IShellFolder_CompareIDs(psf, lParam, pidl1, pidl2);
684         IShellFolder2_Release(psf);
685     }
686
687     ILFree(firstpidl);
688     return hr;
689 }
690
691 static HRESULT WINAPI UnixFolder_IShellFolder2_CreateViewObject(IShellFolder2* iface, HWND hwndOwner,
692     REFIID riid, void** ppv)
693 {
694     HRESULT hr = E_INVALIDARG;
695         
696     TRACE("(iface=%p, hwndOwner=%p, riid=%p, ppv=%p) stub\n", iface, hwndOwner, riid, ppv);
697     
698     if (!ppv) return E_INVALIDARG;
699     *ppv = NULL;
700     
701     if (IsEqualIID(&IID_IShellView, riid)) {
702         LPSHELLVIEW pShellView;
703         
704         pShellView = IShellView_Constructor((IShellFolder*)iface);
705         if (pShellView) {
706             hr = IShellView_QueryInterface(pShellView, riid, ppv);
707             IShellView_Release(pShellView);
708         }
709     } 
710     
711     return hr;
712 }
713
714 static HRESULT WINAPI UnixFolder_IShellFolder2_GetAttributesOf(IShellFolder2* iface, UINT cidl, 
715     LPCITEMIDLIST* apidl, SFGAOF* rgfInOut)
716 {
717     UINT i;
718     SFGAOF flags= ~(SFGAOF)0;
719         
720     TRACE("(iface=%p, cidl=%u, apidl=%p, rgfInOut=%p) semi-stub\n", iface, cidl, apidl, rgfInOut);
721    
722     for (i=0; i<cidl; i++) {
723         LPPIDLDATA pData = _ILGetDataPointer(apidl[i]);
724         if (!pData) continue;
725         if (pData->type == PT_FOLDER) flags &= (SFGAO_FILESYSTEM|SFGAO_FOLDER|SFGAO_HASSUBFOLDER);
726         if (pData->type == PT_VALUE) flags &= SFGAO_FILESYSTEM;
727     }
728     
729     *rgfInOut = *rgfInOut & flags;
730             
731     return S_OK;
732 }
733
734 static HRESULT WINAPI UnixFolder_IShellFolder2_GetUIObjectOf(IShellFolder2* iface, HWND hwndOwner, 
735     UINT cidl, LPCITEMIDLIST* apidl, REFIID riid, UINT* prgfInOut, void** ppvOut)
736 {
737     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
738     
739     TRACE("(iface=%p, hwndOwner=%p, cidl=%d, apidl=%p, riid=%s, prgfInOut=%p, ppv=%p)\n",
740         iface, hwndOwner, cidl, apidl, debugstr_guid(riid), prgfInOut, ppvOut);
741
742     if (IsEqualIID(&IID_IContextMenu, riid)) {
743         *ppvOut = ISvItemCm_Constructor((IShellFolder*)iface, This->m_pidlLocation, apidl, cidl);
744         return S_OK;
745     } else if (IsEqualIID(&IID_IDataObject, riid)) {
746         *ppvOut = IDataObject_Constructor(hwndOwner, This->m_pidlLocation, apidl, cidl);
747         return S_OK;
748     } else if (IsEqualIID(&IID_IExtractIconA, riid)) {
749         FIXME("IExtractIconA\n");
750         return E_FAIL;
751     } else if (IsEqualIID(&IID_IExtractIconW, riid)) {
752         if (cidl != 1) return E_FAIL;
753         if (_ILIsFolder(apidl[0])) 
754             *ppvOut = &UnixFolderIconSingleton;
755         else
756             *ppvOut = &UnixDocumentIconSingleton;
757         return S_OK;
758     } else if (IsEqualIID(&IID_IDropTarget, riid)) {
759         FIXME("IDropTarget\n");
760         return E_FAIL;
761     } else if (IsEqualIID(&IID_IShellLinkW, riid)) {
762         FIXME("IShellLinkW\n");
763         return E_FAIL;
764     } else if (IsEqualIID(&IID_IShellLinkA, riid)) {
765         FIXME("IShellLinkA\n");
766         return E_FAIL;
767     } else {
768         FIXME("Unknown interface %s in GetUIObjectOf\n", debugstr_guid(riid));
769         return E_NOINTERFACE;
770     }
771 }
772
773 static HRESULT WINAPI UnixFolder_IShellFolder2_GetDisplayNameOf(IShellFolder2* iface, 
774     LPCITEMIDLIST pidl, SHGDNF uFlags, STRRET* lpName)
775 {
776     UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
777     HRESULT hr = S_OK;    
778
779     TRACE("(iface=%p, pidl=%p, uFlags=%lx, lpName=%p)\n", iface, pidl, uFlags, lpName);
780     
781     if ((GET_SHGDN_FOR(uFlags) == SHGDN_FORPARSING) &&
782         (GET_SHGDN_RELATION(uFlags) != SHGDN_INFOLDER))
783     {
784         if (!pidl->mkid.cb) {
785             lpName->uType = STRRET_CSTR;
786             strcpy(lpName->u.cStr, This->m_pszPath);
787         } else {
788             IShellFolder *pSubFolder;
789             USHORT emptyIDL = 0;
790
791             hr = IShellFolder_BindToObject(iface, pidl, NULL, &IID_IShellFolder, (void**)&pSubFolder);
792             if (!SUCCEEDED(hr)) return hr;
793        
794             hr = IShellFolder_GetDisplayNameOf(pSubFolder, (LPITEMIDLIST)&emptyIDL, uFlags, lpName);
795             IShellFolder_Release(pSubFolder);
796         }
797     } else {
798         char *pszFileName = _ILGetTextPointer(pidl);
799         lpName->uType = STRRET_CSTR;
800         strcpy(lpName->u.cStr, pszFileName ? pszFileName : "");
801     }
802
803     return hr;
804 }
805
806 static HRESULT WINAPI UnixFolder_IShellFolder2_SetNameOf(IShellFolder2* This, HWND hwnd, 
807     LPCITEMIDLIST pidl, LPCOLESTR lpszName, SHGDNF uFlags, LPITEMIDLIST* ppidlOut)
808 {
809     TRACE("stub\n");
810     return E_NOTIMPL;
811 }
812
813 static HRESULT WINAPI UnixFolder_IShellFolder2_EnumSearches(IShellFolder2* iface, 
814     IEnumExtraSearch **ppEnum) 
815 {
816     TRACE("stub\n");
817     return E_NOTIMPL;
818 }
819
820 static HRESULT WINAPI UnixFolder_IShellFolder2_GetDefaultColumn(IShellFolder2* iface, 
821     DWORD dwReserved, ULONG *pSort, ULONG *pDisplay) 
822 {
823     TRACE("stub\n");
824     return E_NOTIMPL;
825 }
826
827 static HRESULT WINAPI UnixFolder_IShellFolder2_GetDefaultColumnState(IShellFolder2* iface, 
828     UINT iColumn, SHCOLSTATEF *pcsFlags)
829 {
830     TRACE("stub\n");
831     return E_NOTIMPL;
832 }
833
834 static HRESULT WINAPI UnixFolder_IShellFolder2_GetDefaultSearchGUID(IShellFolder2* iface, 
835     GUID *pguid)
836 {
837     TRACE("stub\n");
838     return E_NOTIMPL;
839 }
840
841 static HRESULT WINAPI UnixFolder_IShellFolder2_GetDetailsEx(IShellFolder2* iface, 
842     LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
843 {
844     TRACE("stub\n");
845     return E_NOTIMPL;
846 }
847
848 #define SHELLVIEWCOLUMNS 6 
849
850 static HRESULT WINAPI UnixFolder_IShellFolder2_GetDetailsOf(IShellFolder2* iface, 
851     LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
852 {
853     HRESULT hr = E_FAIL;
854     struct passwd *pPasswd;
855     struct group *pGroup;
856     static const shvheader SFHeader[SHELLVIEWCOLUMNS] = {
857         {IDS_SHV_COLUMN1,  SHCOLSTATE_TYPE_STR  | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
858         {IDS_SHV_COLUMN5,  SHCOLSTATE_TYPE_STR  | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
859         {IDS_SHV_COLUMN10, SHCOLSTATE_TYPE_STR  | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 7},
860         {IDS_SHV_COLUMN11, SHCOLSTATE_TYPE_STR  | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 7},
861         {IDS_SHV_COLUMN2,  SHCOLSTATE_TYPE_STR  | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 8},
862         {IDS_SHV_COLUMN4,  SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}
863     };
864
865     TRACE("(iface=%p, pidl=%p, iColumn=%d, psd=%p) stub\n", iface, pidl, iColumn, psd);
866     
867     if (!psd || iColumn >= SHELLVIEWCOLUMNS)
868         return E_INVALIDARG;
869
870     if (!pidl) {
871         psd->fmt = SFHeader[iColumn].fmt;
872         psd->cxChar = SFHeader[iColumn].cxChar;
873         psd->str.uType = STRRET_CSTR;
874         LoadStringA(shell32_hInstance, SFHeader[iColumn].colnameid, psd->str.u.cStr, MAX_PATH);
875         return S_OK;
876     } else {
877         StatStruct *pStatStruct = LPSTATSTRUCT_FROM_LPSHITEMID(pidl);
878         psd->str.u.cStr[0] = '\0';
879         psd->str.uType = STRRET_CSTR;
880         switch (iColumn) {
881             case 0:
882                 hr = IShellFolder2_GetDisplayNameOf(iface, pidl, SHGDN_NORMAL|SHGDN_INFOLDER, &psd->str);
883                 break;
884             case 1:
885                 psd->str.u.cStr[0] = S_ISDIR(pStatStruct->st_mode) ? 'd' : '-';
886                 psd->str.u.cStr[1] = (pStatStruct->st_mode & S_IRUSR) ? 'r' : '-';
887                 psd->str.u.cStr[2] = (pStatStruct->st_mode & S_IWUSR) ? 'w' : '-';
888                 psd->str.u.cStr[3] = (pStatStruct->st_mode & S_IXUSR) ? 'x' : '-';
889                 psd->str.u.cStr[4] = (pStatStruct->st_mode & S_IRGRP) ? 'r' : '-';
890                 psd->str.u.cStr[5] = (pStatStruct->st_mode & S_IWGRP) ? 'w' : '-';
891                 psd->str.u.cStr[6] = (pStatStruct->st_mode & S_IXGRP) ? 'x' : '-';
892                 psd->str.u.cStr[7] = (pStatStruct->st_mode & S_IROTH) ? 'r' : '-';
893                 psd->str.u.cStr[8] = (pStatStruct->st_mode & S_IWOTH) ? 'w' : '-';
894                 psd->str.u.cStr[9] = (pStatStruct->st_mode & S_IXOTH) ? 'x' : '-';
895                 psd->str.u.cStr[10] = '\0';
896                 break;
897             case 2:
898                 pPasswd = getpwuid(pStatStruct->st_uid);
899                 if (pPasswd) strcpy(psd->str.u.cStr, pPasswd->pw_name);
900                 break;
901             case 3:
902                 pGroup = getgrgid(pStatStruct->st_gid);
903                 if (pGroup) strcpy(psd->str.u.cStr, pGroup->gr_name);
904                 break;
905             case 4:
906                 _ILGetFileSize(pidl, psd->str.u.cStr, MAX_PATH);
907                 break;
908             case 5:
909                 _ILGetFileDate(pidl, psd->str.u.cStr, MAX_PATH);
910                 break;
911         }
912     }
913     
914     return hr;
915 }
916
917 static HRESULT WINAPI UnixFolder_IShellFolder2_MapColumnToSCID(IShellFolder2* iface, UINT iColumn,
918     SHCOLUMNID *pscid) 
919 {
920     TRACE("stub\n");
921     return E_NOTIMPL;
922 }
923
924 /* VTable for UnixFolder's IShellFolder2 interface.
925  */
926 static const IShellFolder2Vtbl UnixFolder_IShellFolder2_Vtbl = {
927     UnixFolder_IShellFolder2_QueryInterface,
928     UnixFolder_IShellFolder2_AddRef,
929     UnixFolder_IShellFolder2_Release,
930     UnixFolder_IShellFolder2_ParseDisplayName,
931     UnixFolder_IShellFolder2_EnumObjects,
932     UnixFolder_IShellFolder2_BindToObject,
933     UnixFolder_IShellFolder2_BindToStorage,
934     UnixFolder_IShellFolder2_CompareIDs,
935     UnixFolder_IShellFolder2_CreateViewObject,
936     UnixFolder_IShellFolder2_GetAttributesOf,
937     UnixFolder_IShellFolder2_GetUIObjectOf,
938     UnixFolder_IShellFolder2_GetDisplayNameOf,
939     UnixFolder_IShellFolder2_SetNameOf,
940     UnixFolder_IShellFolder2_GetDefaultSearchGUID,
941     UnixFolder_IShellFolder2_EnumSearches,
942     UnixFolder_IShellFolder2_GetDefaultColumn,
943     UnixFolder_IShellFolder2_GetDefaultColumnState,
944     UnixFolder_IShellFolder2_GetDetailsEx,
945     UnixFolder_IShellFolder2_GetDetailsOf,
946     UnixFolder_IShellFolder2_MapColumnToSCID
947 };
948
949 static HRESULT WINAPI UnixFolder_IPersistFolder_QueryInterface(IPersistFolder* This, REFIID riid, 
950     void** ppvObject)
951 {
952     return UnixFolder_IShellFolder2_QueryInterface(
953                 (IShellFolder2*)ADJUST_THIS(UnixFolder, IPersistFolder, This), riid, ppvObject);
954 }
955
956 static ULONG WINAPI UnixFolder_IPersistFolder_AddRef(IPersistFolder* This)
957 {
958     return UnixFolder_IShellFolder2_AddRef(
959                 (IShellFolder2*)ADJUST_THIS(UnixFolder, IPersistFolder, This));
960 }
961
962 static ULONG WINAPI UnixFolder_IPersistFolder_Release(IPersistFolder* This)
963 {
964     return UnixFolder_IShellFolder2_Release(
965                 (IShellFolder2*)ADJUST_THIS(UnixFolder, IPersistFolder, This));
966 }
967
968 static HRESULT WINAPI UnixFolder_IPersistFolder_GetClassID(IPersistFolder* This, CLSID* pClassID)
969 {
970     TRACE("stub\n");
971     return E_NOTIMPL;
972 }
973
974 static HRESULT WINAPI UnixFolder_IPersistFolder_Initialize(IPersistFolder* iface, LPCITEMIDLIST pidl)
975 {
976     UnixFolder *This = ADJUST_THIS(UnixFolder, IPersistFolder, iface);
977     
978     TRACE("(iface=%p, pidl=%p)\n", iface, pidl);
979
980     This->m_pidlLocation = ILClone(pidl);
981     UNIXFS_pidl_to_path(pidl, &This->m_pszPath);
982     UNIXFS_build_subfolder_pidls(This->m_pszPath, &This->m_apidlSubDirs, &This->m_cSubDirs);
983     
984     return S_OK;
985 }
986
987 /* VTable for UnixFolder's IPersistFolder interface.
988  */
989 static const IPersistFolderVtbl UnixFolder_IPersistFolder_Vtbl = {
990     UnixFolder_IPersistFolder_QueryInterface,
991     UnixFolder_IPersistFolder_AddRef,
992     UnixFolder_IPersistFolder_Release,
993     UnixFolder_IPersistFolder_GetClassID,
994     UnixFolder_IPersistFolder_Initialize
995 };
996
997 /******************************************************************************
998  * UnixFolder_Constructor [Internal]
999  *
1000  * PARAMS
1001  *  pUnkOuter [I] Outer class for aggregation. Currently ignored.
1002  *  riid      [I] Interface asked for by the client.
1003  *  ppv       [O] Pointer to an riid interface to the UnixFolder object.
1004  *
1005  * NOTES
1006  *  This is the only function exported from shfldr_unixfs.c. It's called from
1007  *  shellole.c's default class factory and thus has to exhibit a LPFNCREATEINSTANCE
1008  *  compatible signature.
1009  */
1010 HRESULT WINAPI UnixFolder_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv) {
1011     HRESULT hr;
1012     UnixFolder *pUnixFolder;
1013     
1014     TRACE("(pUnkOuter=%p, riid=%p, ppv=%p)\n", pUnkOuter, riid, ppv);
1015
1016     pUnixFolder = SHAlloc((ULONG)sizeof(UnixFolder));
1017     pUnixFolder->lpIShellFolder2Vtbl = &UnixFolder_IShellFolder2_Vtbl;
1018     pUnixFolder->lpIPersistFolderVtbl = &UnixFolder_IPersistFolder_Vtbl;
1019     pUnixFolder->m_cRef = 0;
1020     pUnixFolder->m_pszPath = NULL;
1021     pUnixFolder->m_apidlSubDirs = NULL;
1022     pUnixFolder->m_cSubDirs = 0;
1023
1024     UnixFolder_IShellFolder2_AddRef(STATIC_CAST(IShellFolder2, pUnixFolder));
1025     hr = UnixFolder_IShellFolder2_QueryInterface(STATIC_CAST(IShellFolder2, pUnixFolder), riid, ppv);
1026     UnixFolder_IShellFolder2_Release(STATIC_CAST(IShellFolder2, pUnixFolder));
1027     return hr;
1028 }
1029
1030 /******************************************************************************
1031  * UnixSubFolderIterator
1032  *
1033  * Class whose heap based objects represent iterators over the sub-directories
1034  * of a given UnixFolder object. 
1035  */
1036
1037 /* UnixSubFolderIterator object layout and typedef.
1038  */
1039 typedef struct _UnixSubFolderIterator {
1040     const IEnumIDListVtbl *lpIEnumIDListVtbl;
1041     ULONG m_cRef;
1042     UnixFolder *m_pUnixFolder;
1043     ULONG m_cIdx;
1044     SHCONTF m_fFilter;
1045 } UnixSubFolderIterator;
1046
1047 static void UnixSubFolderIterator_Destroy(UnixSubFolderIterator *iterator) {
1048     TRACE("(iterator=%p)\n", iterator);
1049         
1050     UnixFolder_IShellFolder2_Release((IShellFolder2*)iterator->m_pUnixFolder);
1051     SHFree(iterator);
1052 }
1053
1054 static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_QueryInterface(IEnumIDList* iface, 
1055     REFIID riid, void** ppv)
1056 {
1057     TRACE("(iface=%p, riid=%p, ppv=%p)\n", iface, riid, ppv);
1058     
1059     if (!ppv) return E_INVALIDARG;
1060     
1061     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumIDList, riid)) {
1062         *ppv = iface;
1063     } else {
1064         *ppv = NULL;
1065         return E_NOINTERFACE;
1066     }
1067
1068     IEnumIDList_AddRef(iface);
1069     return S_OK;
1070 }
1071                             
1072 static ULONG WINAPI UnixSubFolderIterator_IEnumIDList_AddRef(IEnumIDList* iface)
1073 {
1074     UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface);
1075
1076     TRACE("(iface=%p)\n", iface);
1077    
1078     return InterlockedIncrement(&This->m_cRef);
1079 }
1080
1081 static ULONG WINAPI UnixSubFolderIterator_IEnumIDList_Release(IEnumIDList* iface)
1082 {
1083     UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface);
1084     ULONG cRef;
1085     
1086     TRACE("(iface=%p)\n", iface);
1087
1088     cRef = InterlockedDecrement(&This->m_cRef);
1089     
1090     if (!cRef) 
1091         UnixSubFolderIterator_Destroy(This);
1092
1093     return cRef;
1094 }
1095
1096 static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Next(IEnumIDList* iface, ULONG celt, 
1097     LPITEMIDLIST* rgelt, ULONG* pceltFetched)
1098 {
1099     UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface);
1100     ULONG i;
1101
1102     TRACE("(iface=%p, celt=%ld, rgelt=%p, pceltFetched=%p)\n", iface, celt, rgelt, pceltFetched);
1103    
1104     for (i=0; (i < celt) && (This->m_cIdx < This->m_pUnixFolder->m_cSubDirs); This->m_cIdx++) {
1105         LPITEMIDLIST pCurrent = This->m_pUnixFolder->m_apidlSubDirs[This->m_cIdx];
1106         if (UNIXFS_is_pidl_of_type(pCurrent, This->m_fFilter)) {
1107             rgelt[i] = ILClone(pCurrent);
1108             i++;
1109         }
1110     }
1111
1112     if (pceltFetched)
1113         *pceltFetched = i;
1114
1115     return i == celt ? S_OK : S_FALSE;
1116 }
1117
1118 static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Skip(IEnumIDList* iface, ULONG celt)
1119 {
1120     UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface);
1121     ULONG i;
1122     
1123     TRACE("(iface=%p, celt=%ld)\n", iface, celt);
1124
1125     for (i=0; i < celt; i++) {
1126         while (This->m_cIdx < This->m_pUnixFolder->m_cSubDirs &&
1127                !UNIXFS_is_pidl_of_type(This->m_pUnixFolder->m_apidlSubDirs[This->m_cIdx], This->m_fFilter)) 
1128         {
1129             This->m_cIdx++;
1130         }
1131         This->m_cIdx++;
1132     }
1133     
1134     if (This->m_cIdx > This->m_pUnixFolder->m_cSubDirs) {
1135         This->m_cIdx = This->m_pUnixFolder->m_cSubDirs;
1136         return S_FALSE;
1137     } else {
1138         return S_OK;
1139     }
1140 }
1141
1142 static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Reset(IEnumIDList* iface)
1143 {
1144     UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface);
1145         
1146     TRACE("(iface=%p)\n", iface);
1147
1148     This->m_cIdx = 0;
1149     
1150     return S_OK;
1151 }
1152
1153 static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Clone(IEnumIDList* This, 
1154     IEnumIDList** ppenum)
1155 {
1156     TRACE("stub\n");
1157     return E_NOTIMPL;
1158 }
1159
1160 /* VTable for UnixSubFolderIterator's IEnumIDList interface.
1161  */
1162 static const IEnumIDListVtbl UnixSubFolderIterator_IEnumIDList_Vtbl = {
1163     UnixSubFolderIterator_IEnumIDList_QueryInterface,
1164     UnixSubFolderIterator_IEnumIDList_AddRef,
1165     UnixSubFolderIterator_IEnumIDList_Release,
1166     UnixSubFolderIterator_IEnumIDList_Next,
1167     UnixSubFolderIterator_IEnumIDList_Skip,
1168     UnixSubFolderIterator_IEnumIDList_Reset,
1169     UnixSubFolderIterator_IEnumIDList_Clone
1170 };
1171
1172 static IUnknown *UnixSubFolderIterator_Construct(UnixFolder *pUnixFolder, SHCONTF fFilter) {
1173     UnixSubFolderIterator *iterator;
1174
1175     TRACE("(pUnixFolder=%p)\n", pUnixFolder);
1176     
1177     iterator = SHAlloc((ULONG)sizeof(UnixSubFolderIterator));
1178     iterator->lpIEnumIDListVtbl = &UnixSubFolderIterator_IEnumIDList_Vtbl;
1179     iterator->m_cRef = 0;
1180     iterator->m_cIdx = 0;
1181     iterator->m_pUnixFolder = pUnixFolder;
1182     iterator->m_fFilter = fFilter;
1183
1184     UnixSubFolderIterator_IEnumIDList_AddRef((IEnumIDList*)iterator);
1185     UnixFolder_IShellFolder2_AddRef((IShellFolder2*)pUnixFolder);
1186     
1187     return (IUnknown*)iterator;
1188 }