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