taskschd: Add initial version of the task definition XML writer.
[wine.git] / dlls / qmgr / file.c
blob6d3cca98abd7d1cb54fcc43cef06cab22f2952b2
1 /*
2 * Queue Manager (BITS) File
4 * Copyright 2007, 2008 Google (Roy Shea, Dan Hipschman)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "ole2.h"
30 #include "urlmon.h"
31 #include "wininet.h"
33 #include "qmgr.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(qmgr);
38 static inline BackgroundCopyFileImpl *impl_from_IBackgroundCopyFile(IBackgroundCopyFile *iface)
40 return CONTAINING_RECORD(iface, BackgroundCopyFileImpl, IBackgroundCopyFile_iface);
43 static HRESULT WINAPI BackgroundCopyFile_QueryInterface(
44 IBackgroundCopyFile* iface,
45 REFIID riid,
46 void **obj)
48 BackgroundCopyFileImpl *This = impl_from_IBackgroundCopyFile(iface);
50 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
52 if (IsEqualGUID(riid, &IID_IUnknown)
53 || IsEqualGUID(riid, &IID_IBackgroundCopyFile))
55 *obj = iface;
56 IBackgroundCopyFile_AddRef(iface);
57 return S_OK;
60 *obj = NULL;
61 return E_NOINTERFACE;
64 static ULONG WINAPI BackgroundCopyFile_AddRef(IBackgroundCopyFile* iface)
66 BackgroundCopyFileImpl *This = impl_from_IBackgroundCopyFile(iface);
67 ULONG ref = InterlockedIncrement(&This->ref);
68 TRACE("(%p)->(%d)\n", This, ref);
69 return ref;
72 static ULONG WINAPI BackgroundCopyFile_Release(
73 IBackgroundCopyFile* iface)
75 BackgroundCopyFileImpl *This = impl_from_IBackgroundCopyFile(iface);
76 ULONG ref = InterlockedDecrement(&This->ref);
78 TRACE("(%p)->(%d)\n", This, ref);
80 if (ref == 0)
82 IBackgroundCopyJob2_Release(&This->owner->IBackgroundCopyJob2_iface);
83 HeapFree(GetProcessHeap(), 0, This->info.LocalName);
84 HeapFree(GetProcessHeap(), 0, This->info.RemoteName);
85 HeapFree(GetProcessHeap(), 0, This);
88 return ref;
91 /* Get the remote name of a background copy file */
92 static HRESULT WINAPI BackgroundCopyFile_GetRemoteName(
93 IBackgroundCopyFile* iface,
94 LPWSTR *pVal)
96 BackgroundCopyFileImpl *This = impl_from_IBackgroundCopyFile(iface);
98 TRACE("(%p)->(%p)\n", This, pVal);
100 return return_strval(This->info.RemoteName, pVal);
103 static HRESULT WINAPI BackgroundCopyFile_GetLocalName(
104 IBackgroundCopyFile* iface,
105 LPWSTR *pVal)
107 BackgroundCopyFileImpl *This = impl_from_IBackgroundCopyFile(iface);
109 TRACE("(%p)->(%p)\n", This, pVal);
111 return return_strval(This->info.LocalName, pVal);
114 static HRESULT WINAPI BackgroundCopyFile_GetProgress(
115 IBackgroundCopyFile* iface,
116 BG_FILE_PROGRESS *pVal)
118 BackgroundCopyFileImpl *This = impl_from_IBackgroundCopyFile(iface);
120 TRACE("(%p)->(%p)\n", This, pVal);
122 EnterCriticalSection(&This->owner->cs);
123 pVal->BytesTotal = This->fileProgress.BytesTotal;
124 pVal->BytesTransferred = This->fileProgress.BytesTransferred;
125 pVal->Completed = This->fileProgress.Completed;
126 LeaveCriticalSection(&This->owner->cs);
128 return S_OK;
131 static const IBackgroundCopyFileVtbl BackgroundCopyFileVtbl =
133 BackgroundCopyFile_QueryInterface,
134 BackgroundCopyFile_AddRef,
135 BackgroundCopyFile_Release,
136 BackgroundCopyFile_GetRemoteName,
137 BackgroundCopyFile_GetLocalName,
138 BackgroundCopyFile_GetProgress
141 HRESULT BackgroundCopyFileConstructor(BackgroundCopyJobImpl *owner,
142 LPCWSTR remoteName, LPCWSTR localName,
143 BackgroundCopyFileImpl **file)
145 BackgroundCopyFileImpl *This;
146 int n;
148 TRACE("(%s, %s, %p)\n", debugstr_w(remoteName), debugstr_w(localName), file);
150 This = HeapAlloc(GetProcessHeap(), 0, sizeof *This);
151 if (!This)
152 return E_OUTOFMEMORY;
154 n = (lstrlenW(remoteName) + 1) * sizeof(WCHAR);
155 This->info.RemoteName = HeapAlloc(GetProcessHeap(), 0, n);
156 if (!This->info.RemoteName)
158 HeapFree(GetProcessHeap(), 0, This);
159 return E_OUTOFMEMORY;
161 memcpy(This->info.RemoteName, remoteName, n);
163 n = (lstrlenW(localName) + 1) * sizeof(WCHAR);
164 This->info.LocalName = HeapAlloc(GetProcessHeap(), 0, n);
165 if (!This->info.LocalName)
167 HeapFree(GetProcessHeap(), 0, This->info.RemoteName);
168 HeapFree(GetProcessHeap(), 0, This);
169 return E_OUTOFMEMORY;
171 memcpy(This->info.LocalName, localName, n);
173 This->IBackgroundCopyFile_iface.lpVtbl = &BackgroundCopyFileVtbl;
174 This->ref = 1;
176 This->fileProgress.BytesTotal = BG_SIZE_UNKNOWN;
177 This->fileProgress.BytesTransferred = 0;
178 This->fileProgress.Completed = FALSE;
179 This->owner = owner;
180 IBackgroundCopyJob2_AddRef(&owner->IBackgroundCopyJob2_iface);
182 *file = This;
183 return S_OK;
186 static DWORD CALLBACK copyProgressCallback(LARGE_INTEGER totalSize,
187 LARGE_INTEGER totalTransferred,
188 LARGE_INTEGER streamSize,
189 LARGE_INTEGER streamTransferred,
190 DWORD streamNum,
191 DWORD reason,
192 HANDLE srcFile,
193 HANDLE dstFile,
194 LPVOID obj)
196 BackgroundCopyFileImpl *file = obj;
197 BackgroundCopyJobImpl *job = file->owner;
198 ULONG64 diff;
200 EnterCriticalSection(&job->cs);
201 diff = (file->fileProgress.BytesTotal == BG_SIZE_UNKNOWN
202 ? totalTransferred.QuadPart
203 : totalTransferred.QuadPart - file->fileProgress.BytesTransferred);
204 file->fileProgress.BytesTotal = totalSize.QuadPart;
205 file->fileProgress.BytesTransferred = totalTransferred.QuadPart;
206 job->jobProgress.BytesTransferred += diff;
207 LeaveCriticalSection(&job->cs);
209 return (job->state == BG_JOB_STATE_TRANSFERRING
210 ? PROGRESS_CONTINUE
211 : PROGRESS_CANCEL);
214 typedef struct
216 IBindStatusCallback IBindStatusCallback_iface;
217 BackgroundCopyFileImpl *file;
218 LONG ref;
219 } DLBindStatusCallback;
221 static inline DLBindStatusCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
223 return CONTAINING_RECORD(iface, DLBindStatusCallback, IBindStatusCallback_iface);
226 static HRESULT WINAPI DLBindStatusCallback_QueryInterface(
227 IBindStatusCallback *iface,
228 REFIID riid,
229 void **ppvObject)
231 DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
233 if (IsEqualGUID(riid, &IID_IUnknown)
234 || IsEqualGUID(riid, &IID_IBindStatusCallback))
236 *ppvObject = &This->IBindStatusCallback_iface;
237 IBindStatusCallback_AddRef(iface);
238 return S_OK;
241 *ppvObject = NULL;
242 return E_NOINTERFACE;
245 static ULONG WINAPI DLBindStatusCallback_AddRef(IBindStatusCallback *iface)
247 DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
248 return InterlockedIncrement(&This->ref);
251 static ULONG WINAPI DLBindStatusCallback_Release(IBindStatusCallback *iface)
253 DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
254 ULONG ref = InterlockedDecrement(&This->ref);
256 if (ref == 0)
258 IBackgroundCopyFile_Release(&This->file->IBackgroundCopyFile_iface);
259 HeapFree(GetProcessHeap(), 0, This);
262 return ref;
265 static HRESULT WINAPI DLBindStatusCallback_GetBindInfo(
266 IBindStatusCallback *iface,
267 DWORD *grfBINDF,
268 BINDINFO *pbindinfo)
270 return E_NOTIMPL;
273 static HRESULT WINAPI DLBindStatusCallback_GetPriority(
274 IBindStatusCallback *iface,
275 LONG *pnPriority)
277 return E_NOTIMPL;
280 static HRESULT WINAPI DLBindStatusCallback_OnDataAvailable(
281 IBindStatusCallback *iface,
282 DWORD grfBSCF,
283 DWORD dwSize,
284 FORMATETC *pformatetc,
285 STGMEDIUM *pstgmed)
287 return E_NOTIMPL;
290 static HRESULT WINAPI DLBindStatusCallback_OnLowResource(
291 IBindStatusCallback *iface,
292 DWORD reserved)
294 return E_NOTIMPL;
297 static HRESULT WINAPI DLBindStatusCallback_OnObjectAvailable(
298 IBindStatusCallback *iface,
299 REFIID riid,
300 IUnknown *punk)
302 return E_NOTIMPL;
305 static HRESULT WINAPI DLBindStatusCallback_OnProgress(
306 IBindStatusCallback *iface,
307 ULONG progress,
308 ULONG progressMax,
309 ULONG statusCode,
310 LPCWSTR statusText)
312 DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
313 BackgroundCopyFileImpl *file = This->file;
314 BackgroundCopyJobImpl *job = file->owner;
315 ULONG64 diff;
317 EnterCriticalSection(&job->cs);
318 diff = (file->fileProgress.BytesTotal == BG_SIZE_UNKNOWN
319 ? progress
320 : progress - file->fileProgress.BytesTransferred);
321 file->fileProgress.BytesTotal = progressMax ? progressMax : BG_SIZE_UNKNOWN;
322 file->fileProgress.BytesTransferred = progress;
323 job->jobProgress.BytesTransferred += diff;
324 LeaveCriticalSection(&job->cs);
326 return S_OK;
329 static HRESULT WINAPI DLBindStatusCallback_OnStartBinding(
330 IBindStatusCallback *iface,
331 DWORD dwReserved,
332 IBinding *pib)
334 return E_NOTIMPL;
337 static HRESULT WINAPI DLBindStatusCallback_OnStopBinding(
338 IBindStatusCallback *iface,
339 HRESULT hresult,
340 LPCWSTR szError)
342 return E_NOTIMPL;
345 static const IBindStatusCallbackVtbl DLBindStatusCallback_Vtbl =
347 DLBindStatusCallback_QueryInterface,
348 DLBindStatusCallback_AddRef,
349 DLBindStatusCallback_Release,
350 DLBindStatusCallback_OnStartBinding,
351 DLBindStatusCallback_GetPriority,
352 DLBindStatusCallback_OnLowResource,
353 DLBindStatusCallback_OnProgress,
354 DLBindStatusCallback_OnStopBinding,
355 DLBindStatusCallback_GetBindInfo,
356 DLBindStatusCallback_OnDataAvailable,
357 DLBindStatusCallback_OnObjectAvailable
360 static DLBindStatusCallback *DLBindStatusCallbackConstructor(
361 BackgroundCopyFileImpl *file)
363 DLBindStatusCallback *This = HeapAlloc(GetProcessHeap(), 0, sizeof *This);
364 if (!This)
365 return NULL;
367 This->IBindStatusCallback_iface.lpVtbl = &DLBindStatusCallback_Vtbl;
368 IBackgroundCopyFile_AddRef(&file->IBackgroundCopyFile_iface);
369 This->file = file;
370 This->ref = 1;
371 return This;
374 BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
376 static const WCHAR prefix[] = {'B','I','T', 0};
377 DLBindStatusCallback *callbackObj;
378 WCHAR tmpDir[MAX_PATH];
379 WCHAR tmpName[MAX_PATH];
380 HRESULT hr;
382 if (!GetTempPathW(MAX_PATH, tmpDir))
384 ERR("Couldn't create temp file name: %d\n", GetLastError());
385 /* Guessing on what state this should give us */
386 transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSIENT_ERROR);
387 return FALSE;
390 if (!GetTempFileNameW(tmpDir, prefix, 0, tmpName))
392 ERR("Couldn't create temp file: %d\n", GetLastError());
393 /* Guessing on what state this should give us */
394 transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSIENT_ERROR);
395 return FALSE;
398 callbackObj = DLBindStatusCallbackConstructor(file);
399 if (!callbackObj)
401 ERR("Out of memory\n");
402 transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSIENT_ERROR);
403 return FALSE;
406 EnterCriticalSection(&job->cs);
407 file->fileProgress.BytesTotal = BG_SIZE_UNKNOWN;
408 file->fileProgress.BytesTransferred = 0;
409 file->fileProgress.Completed = FALSE;
410 LeaveCriticalSection(&job->cs);
412 TRACE("Transferring: %s -> %s -> %s\n",
413 debugstr_w(file->info.RemoteName),
414 debugstr_w(tmpName),
415 debugstr_w(file->info.LocalName));
417 transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRING);
419 DeleteUrlCacheEntryW(file->info.RemoteName);
420 hr = URLDownloadToFileW(NULL, file->info.RemoteName, tmpName, 0,
421 &callbackObj->IBindStatusCallback_iface);
422 IBindStatusCallback_Release(&callbackObj->IBindStatusCallback_iface);
423 if (hr == INET_E_DOWNLOAD_FAILURE)
425 TRACE("URLDownload failed, trying local file copy\n");
426 if (!CopyFileExW(file->info.RemoteName, tmpName, copyProgressCallback,
427 file, NULL, 0))
429 ERR("Local file copy failed: error %d\n", GetLastError());
430 transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
431 return FALSE;
434 else if (FAILED(hr))
436 ERR("URLDownload failed: eh 0x%08x\n", hr);
437 transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
438 return FALSE;
441 if (transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_QUEUED))
443 lstrcpyW(file->tempFileName, tmpName);
445 EnterCriticalSection(&job->cs);
446 file->fileProgress.Completed = TRUE;
447 job->jobProgress.FilesTransferred++;
448 LeaveCriticalSection(&job->cs);
450 return TRUE;
452 else
454 DeleteFileW(tmpName);
455 return FALSE;