Better compatibility with MS Windows recycle bin
[reactos.git] / reactos / lib / recyclebin / recyclebin_generic_enumerator.c
1 /*
2 * PROJECT: Recycle bin management
3 * LICENSE: GPL v2 - See COPYING in the top level directory
4 * FILE: lib/recyclebin/recyclebin_generic_enumerator.c
5 * PURPOSE: Enumerates contents of all recycle bins
6 * PROGRAMMERS: Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
7 */
8
9 #define COBJMACROS
10 #include "recyclebin_private.h"
11 #include <stdio.h>
12
13 WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
14
15 struct RecycleBinGenericEnum
16 {
17 ULONG ref;
18 IRecycleBinEnumList recycleBinEnumImpl;
19 IRecycleBinEnumList *current;
20 DWORD dwLogicalDrives;
21 SIZE_T skip;
22 };
23
24 static HRESULT STDMETHODCALLTYPE
25 RecycleBinGenericEnum_RecycleBinEnumList_QueryInterface(
26 IN IRecycleBinEnumList *This,
27 IN REFIID riid,
28 OUT void **ppvObject)
29 {
30 struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
31
32 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
33
34 if (!ppvObject)
35 return E_POINTER;
36
37 if (IsEqualIID(riid, &IID_IUnknown))
38 *ppvObject = &s->recycleBinEnumImpl;
39 else if (IsEqualIID(riid, &IID_IRecycleBinEnumList))
40 *ppvObject = &s->recycleBinEnumImpl;
41 else
42 {
43 *ppvObject = NULL;
44 return E_NOINTERFACE;
45 }
46
47 IUnknown_AddRef(This);
48 return S_OK;
49 }
50
51 static ULONG STDMETHODCALLTYPE
52 RecycleBinGenericEnum_RecycleBinEnumList_AddRef(
53 IN IRecycleBinEnumList *This)
54 {
55 struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
56 ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
57 TRACE("(%p)\n", This);
58 return refCount;
59 }
60
61 static VOID
62 RecycleBinGenericEnum_Destructor(
63 struct RecycleBinGenericEnum *s)
64 {
65 TRACE("(%p)\n", s);
66
67 if (s->current)
68 IRecycleBinEnumList_Release(s->current);
69 CoTaskMemFree(s);
70 }
71
72 static ULONG STDMETHODCALLTYPE
73 RecycleBinGenericEnum_RecycleBinEnumList_Release(
74 IN IRecycleBinEnumList *This)
75 {
76 struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
77 ULONG refCount;
78
79 TRACE("(%p)\n", This);
80
81 refCount = InterlockedDecrement((PLONG)&s->ref);
82
83 if (refCount == 0)
84 RecycleBinGenericEnum_Destructor(s);
85
86 return refCount;
87 }
88
89 static HRESULT STDMETHODCALLTYPE
90 RecycleBinGenericEnum_RecycleBinEnumList_Next(
91 IN IRecycleBinEnumList *This,
92 IN DWORD celt,
93 IN OUT IRecycleBinFile **rgelt,
94 OUT DWORD *pceltFetched)
95 {
96 struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
97 IRecycleBin *prb;
98 DWORD i;
99 DWORD fetched = 0, newFetched;
100 HRESULT hr;
101
102 TRACE("(%p, %u, %p, %p)\n", This, celt, rgelt, pceltFetched);
103
104 if (!rgelt)
105 return E_POINTER;
106 if (!pceltFetched && celt > 1)
107 return E_INVALIDARG;
108
109 while (TRUE)
110 {
111 /* Get enumerator implementation */
112 if (!s->current && s->dwLogicalDrives)
113 {
114 for (i = 0; i < 26; i++)
115 if (s->dwLogicalDrives & (1 << i))
116 {
117 WCHAR szVolumeName[4];
118 szVolumeName[0] = (WCHAR)('A' + i);
119 szVolumeName[1] = ':';
120 szVolumeName[2] = '\\';
121 szVolumeName[3] = UNICODE_NULL;
122 if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED)
123 {
124 s->dwLogicalDrives &= ~(1 << i);
125 continue;
126 }
127 hr = GetDefaultRecycleBin(szVolumeName, &prb);
128 if (!SUCCEEDED(hr))
129 return hr;
130 hr = IRecycleBin_EnumObjects(prb, &s->current);
131 IRecycleBin_Release(prb);
132 if (!SUCCEEDED(hr))
133 return hr;
134 s->dwLogicalDrives &= ~(1 << i);
135 break;
136 }
137 }
138 if (!s->current)
139 {
140 /* Nothing more to enumerate */
141 if (pceltFetched)
142 *pceltFetched = fetched;
143 return S_FALSE;
144 }
145
146 /* Skip some elements */
147 while (s->skip > 0)
148 {
149 IRecycleBinFile *rbf;
150 hr = IRecycleBinEnumList_Next(s->current, 1, &rbf, NULL);
151 if (hr == S_OK)
152 hr = IRecycleBinFile_Release(rbf);
153 else if (hr == S_FALSE)
154 break;
155 else if (!SUCCEEDED(hr))
156 return hr;
157 }
158 if (s->skip > 0)
159 continue;
160
161 /* Fill area */
162 hr = IRecycleBinEnumList_Next(s->current, celt - fetched, &rgelt[fetched], &newFetched);
163 if (SUCCEEDED(hr))
164 fetched += newFetched;
165 if (hr == S_FALSE || newFetched == 0)
166 {
167 hr = IRecycleBinEnumList_Release(s->current);
168 s->current = NULL;
169 }
170 else if (!SUCCEEDED(hr))
171 return hr;
172 if (fetched == celt)
173 {
174 if (pceltFetched)
175 *pceltFetched = fetched;
176 return S_OK;
177 }
178 }
179
180 /* Never go here */
181 }
182
183 static HRESULT STDMETHODCALLTYPE
184 RecycleBinGenericEnum_RecycleBinEnumList_Skip(
185 IN IRecycleBinEnumList *This,
186 IN DWORD celt)
187 {
188 struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
189 TRACE("(%p, %u)\n", This, celt);
190 s->skip += celt;
191 return S_OK;
192 }
193
194 static HRESULT STDMETHODCALLTYPE
195 RecycleBinGenericEnum_RecycleBinEnumList_Reset(
196 IN IRecycleBinEnumList *This)
197 {
198 struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
199
200 TRACE("(%p)\n", This);
201
202 if (s->current)
203 {
204 IRecycleBinEnumList_Release(s->current);
205 s->current = NULL;
206 s->skip = 0;
207 }
208 s->dwLogicalDrives = GetLogicalDrives();
209 return S_OK;
210 }
211
212 CONST_VTBL struct IRecycleBinEnumListVtbl RecycleBinGenericEnumVtbl =
213 {
214 RecycleBinGenericEnum_RecycleBinEnumList_QueryInterface,
215 RecycleBinGenericEnum_RecycleBinEnumList_AddRef,
216 RecycleBinGenericEnum_RecycleBinEnumList_Release,
217 RecycleBinGenericEnum_RecycleBinEnumList_Next,
218 RecycleBinGenericEnum_RecycleBinEnumList_Skip,
219 RecycleBinGenericEnum_RecycleBinEnumList_Reset,
220 };
221
222 HRESULT
223 RecycleBinGenericEnum_Constructor(
224 OUT IRecycleBinEnumList **pprbel)
225 {
226 struct RecycleBinGenericEnum *s;
227
228 s = CoTaskMemAlloc(sizeof(struct RecycleBinGenericEnum));
229 if (!s)
230 return E_OUTOFMEMORY;
231 ZeroMemory(s, sizeof(struct RecycleBinGenericEnum));
232 s->ref = 1;
233 s->recycleBinEnumImpl.lpVtbl = &RecycleBinGenericEnumVtbl;
234
235 *pprbel = &s->recycleBinEnumImpl;
236 return IRecycleBinEnumList_Reset(*pprbel);
237 }