Fix some bugs which were preventing enumeration of all deleted files
[reactos.git] / reactos / lib / recyclebin / recyclebin_generic.c
1 /*
2 * PROJECT: Recycle bin management
3 * LICENSE: GPL v2 - See COPYING in the top level directory
4 * FILE: lib/recyclebin/recyclebin_generic.c
5 * PURPOSE: Deals with a system-wide recycle bin
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 struct RecycleBinGeneric
14 {
15 ULONG ref;
16 IRecycleBin recycleBinImpl;
17 };
18
19 static HRESULT STDMETHODCALLTYPE
20 RecycleBinGenericVtbl_RecycleBin_QueryInterface(
21 IRecycleBin *This,
22 REFIID riid,
23 void **ppvObject)
24 {
25 struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
26
27 if (!ppvObject)
28 return E_POINTER;
29
30 if (IsEqualIID(riid, &IID_IUnknown))
31 *ppvObject = &s->recycleBinImpl;
32 else if (IsEqualIID(riid, &IID_IRecycleBin))
33 *ppvObject = &s->recycleBinImpl;
34 else
35 {
36 *ppvObject = NULL;
37 return E_NOINTERFACE;
38 }
39
40 IUnknown_AddRef(This);
41 return S_OK;
42 }
43
44 static ULONG STDMETHODCALLTYPE
45 RecycleBinGenericVtbl_RecycleBin_AddRef(
46 IRecycleBin *This)
47 {
48 struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
49 ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
50 return refCount;
51 }
52
53 static ULONG STDMETHODCALLTYPE
54 RecycleBinGenericVtbl_RecycleBin_Release(
55 IRecycleBin *This)
56 {
57 struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
58 ULONG refCount;
59
60 if (!This)
61 return E_POINTER;
62
63 refCount = InterlockedDecrement((PLONG)&s->ref);
64
65 if (refCount == 0)
66 CoTaskMemFree(s);
67
68 return refCount;
69 }
70
71 static HRESULT STDMETHODCALLTYPE
72 RecycleBinGenericVtbl_RecycleBin_DeleteFile(
73 IN IRecycleBin *This,
74 IN LPCWSTR szFileName)
75 {
76 IRecycleBin *prb;
77 LPWSTR szFullName = NULL;
78 DWORD dwBufferLength = 0;
79 DWORD len;
80 WCHAR szVolume[MAX_PATH];
81 HRESULT hr;
82
83 /* Get full file name */
84 while (TRUE)
85 {
86 len = GetFullPathNameW(szFileName, dwBufferLength, szFullName, NULL);
87 if (len == 0)
88 {
89 if (szFullName)
90 CoTaskMemFree(szFullName);
91 return HRESULT_FROM_WIN32(GetLastError());
92 }
93 else if (len < dwBufferLength)
94 break;
95 if (szFullName)
96 CoTaskMemFree(szFullName);
97 dwBufferLength = len;
98 szFullName = CoTaskMemAlloc(dwBufferLength * sizeof(WCHAR));
99 if (!szFullName)
100 return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
101 }
102
103 /* Get associated volume path */
104 #ifndef __REACTOS__
105 if (!GetVolumePathNameW(szFullName, szVolume, MAX_PATH))
106 {
107 CoTaskMemFree(szFullName);
108 return HRESULT_FROM_WIN32(GetLastError());
109 }
110 #else
111 swprintf(szVolume, L"%c:\\", szFullName[0]);
112 #endif
113
114 /* Skip namespace (if any) */
115 if (szVolume[0] == '\\'
116 && szVolume[1] == '\\'
117 && (szVolume[2] == '.' || szVolume[2] == '?')
118 && szVolume[3] == '\\')
119 {
120 MoveMemory(szVolume, &szVolume[4], (MAX_PATH - 4) * sizeof(WCHAR));
121 }
122
123 hr = GetDefaultRecycleBin(szVolume, &prb);
124 if (!SUCCEEDED(hr))
125 {
126 CoTaskMemFree(szFullName);
127 return hr;
128 }
129
130 hr = IRecycleBin_DeleteFile(prb, szFullName);
131 CoTaskMemFree(szFullName);
132 IRecycleBin_Release(prb);
133 return hr;
134 }
135
136 static HRESULT STDMETHODCALLTYPE
137 RecycleBinGenericVtbl_RecycleBin_EmptyRecycleBin(
138 IN IRecycleBin *This)
139 {
140 WCHAR szVolumeName[MAX_PATH];
141 DWORD dwLogicalDrives, i;
142 IRecycleBin *prb;
143 HRESULT hr;
144
145 dwLogicalDrives = GetLogicalDrives();
146 if (dwLogicalDrives == 0)
147 return HRESULT_FROM_WIN32(GetLastError());
148
149 for (i = 0; i < 26; i++)
150 {
151 if (!(dwLogicalDrives & (1 << i)))
152 continue;
153 swprintf(szVolumeName, L"%c:\\", 'A' + i);
154 if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED)
155 continue;
156
157 hr = GetDefaultRecycleBin(szVolumeName, &prb);
158 if (!SUCCEEDED(hr))
159 return hr;
160
161 hr = IRecycleBin_EmptyRecycleBin(prb);
162 IRecycleBin_Release(prb);
163 }
164
165 return S_OK;
166 }
167
168 static HRESULT STDMETHODCALLTYPE
169 RecycleBinGenericVtbl_RecycleBin_EnumObjects(
170 IN IRecycleBin *This,
171 OUT IRecycleBinEnumList **ppEnumList)
172 {
173 return RecycleBinGeneric_Enumerator_Constructor(ppEnumList);
174 }
175
176 CONST_VTBL struct IRecycleBinVtbl RecycleBinGenericVtbl =
177 {
178 RecycleBinGenericVtbl_RecycleBin_QueryInterface,
179 RecycleBinGenericVtbl_RecycleBin_AddRef,
180 RecycleBinGenericVtbl_RecycleBin_Release,
181 RecycleBinGenericVtbl_RecycleBin_DeleteFile,
182 RecycleBinGenericVtbl_RecycleBin_EmptyRecycleBin,
183 RecycleBinGenericVtbl_RecycleBin_EnumObjects,
184 };
185
186 HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown)
187 {
188 /* This RecycleBin implementation was introduced to be able to manage all
189 * drives at once, and instanciate the 'real' implementations when needed */
190 struct RecycleBinGeneric *s;
191
192 s = CoTaskMemAlloc(sizeof(struct RecycleBinGeneric));
193 if (!s)
194 return E_OUTOFMEMORY;
195 s->ref = 1;
196 s->recycleBinImpl.lpVtbl = &RecycleBinGenericVtbl;
197
198 *ppUnknown = (IUnknown *)&s->recycleBinImpl;
199 return S_OK;
200 }