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