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