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
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(qmgr
);
38 static void BackgroundCopyFileDestructor(BackgroundCopyFileImpl
*This
)
40 IBackgroundCopyJob_Release((IBackgroundCopyJob
*) This
->owner
);
41 HeapFree(GetProcessHeap(), 0, This
->info
.LocalName
);
42 HeapFree(GetProcessHeap(), 0, This
->info
.RemoteName
);
43 HeapFree(GetProcessHeap(), 0, This
);
46 static ULONG WINAPI
BITS_IBackgroundCopyFile_AddRef(IBackgroundCopyFile
* iface
)
48 BackgroundCopyFileImpl
*This
= (BackgroundCopyFileImpl
*) iface
;
49 return InterlockedIncrement(&This
->ref
);
52 static HRESULT WINAPI
BITS_IBackgroundCopyFile_QueryInterface(
53 IBackgroundCopyFile
* iface
,
57 BackgroundCopyFileImpl
*This
= (BackgroundCopyFileImpl
*) iface
;
59 if (IsEqualGUID(riid
, &IID_IUnknown
)
60 || IsEqualGUID(riid
, &IID_IBackgroundCopyFile
))
62 *ppvObject
= &This
->lpVtbl
;
63 BITS_IBackgroundCopyFile_AddRef(iface
);
72 static ULONG WINAPI
BITS_IBackgroundCopyFile_Release(
73 IBackgroundCopyFile
* iface
)
75 BackgroundCopyFileImpl
*This
= (BackgroundCopyFileImpl
*) iface
;
76 ULONG ref
= InterlockedDecrement(&This
->ref
);
79 BackgroundCopyFileDestructor(This
);
84 /* Get the remote name of a background copy file */
85 static HRESULT WINAPI
BITS_IBackgroundCopyFile_GetRemoteName(
86 IBackgroundCopyFile
* iface
,
89 BackgroundCopyFileImpl
*This
= (BackgroundCopyFileImpl
*) iface
;
90 int n
= (lstrlenW(This
->info
.RemoteName
) + 1) * sizeof(WCHAR
);
92 *pVal
= CoTaskMemAlloc(n
);
96 memcpy(*pVal
, This
->info
.RemoteName
, n
);
100 static HRESULT WINAPI
BITS_IBackgroundCopyFile_GetLocalName(
101 IBackgroundCopyFile
* iface
,
104 BackgroundCopyFileImpl
*This
= (BackgroundCopyFileImpl
*) iface
;
105 int n
= (lstrlenW(This
->info
.LocalName
) + 1) * sizeof(WCHAR
);
107 *pVal
= CoTaskMemAlloc(n
);
109 return E_OUTOFMEMORY
;
111 memcpy(*pVal
, This
->info
.LocalName
, n
);
115 static HRESULT WINAPI
BITS_IBackgroundCopyFile_GetProgress(
116 IBackgroundCopyFile
* iface
,
117 BG_FILE_PROGRESS
*pVal
)
119 BackgroundCopyFileImpl
*This
= (BackgroundCopyFileImpl
*) iface
;
121 EnterCriticalSection(&This
->owner
->cs
);
122 pVal
->BytesTotal
= This
->fileProgress
.BytesTotal
;
123 pVal
->BytesTransferred
= This
->fileProgress
.BytesTransferred
;
124 pVal
->Completed
= This
->fileProgress
.Completed
;
125 LeaveCriticalSection(&This
->owner
->cs
);
130 static const IBackgroundCopyFileVtbl BITS_IBackgroundCopyFile_Vtbl
=
132 BITS_IBackgroundCopyFile_QueryInterface
,
133 BITS_IBackgroundCopyFile_AddRef
,
134 BITS_IBackgroundCopyFile_Release
,
135 BITS_IBackgroundCopyFile_GetRemoteName
,
136 BITS_IBackgroundCopyFile_GetLocalName
,
137 BITS_IBackgroundCopyFile_GetProgress
140 HRESULT
BackgroundCopyFileConstructor(BackgroundCopyJobImpl
*owner
,
141 LPCWSTR remoteName
, LPCWSTR localName
,
144 BackgroundCopyFileImpl
*This
;
147 TRACE("(%s,%s,%p)\n", debugstr_w(remoteName
),
148 debugstr_w(localName
), ppObj
);
150 This
= HeapAlloc(GetProcessHeap(), 0, sizeof *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
->lpVtbl
= &BITS_IBackgroundCopyFile_Vtbl
;
176 This
->fileProgress
.BytesTotal
= BG_SIZE_UNKNOWN
;
177 This
->fileProgress
.BytesTransferred
= 0;
178 This
->fileProgress
.Completed
= FALSE
;
180 IBackgroundCopyJob_AddRef((IBackgroundCopyJob
*) owner
);
182 *ppObj
= &This
->lpVtbl
;
186 static DWORD CALLBACK
copyProgressCallback(LARGE_INTEGER totalSize
,
187 LARGE_INTEGER totalTransferred
,
188 LARGE_INTEGER streamSize
,
189 LARGE_INTEGER streamTransferred
,
196 BackgroundCopyFileImpl
*file
= obj
;
197 BackgroundCopyJobImpl
*job
= file
->owner
;
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
216 IBindStatusCallback IBindStatusCallback_iface
;
217 BackgroundCopyFileImpl
*file
;
219 } DLBindStatusCallback
;
221 static inline DLBindStatusCallback
*impl_from_IBindStatusCallback(IBindStatusCallback
*iface
)
223 return CONTAINING_RECORD(iface
, DLBindStatusCallback
, IBindStatusCallback_iface
);
226 static ULONG WINAPI
DLBindStatusCallback_AddRef(IBindStatusCallback
*iface
)
228 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
229 return InterlockedIncrement(&This
->ref
);
232 static ULONG WINAPI
DLBindStatusCallback_Release(IBindStatusCallback
*iface
)
234 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
235 ULONG ref
= InterlockedDecrement(&This
->ref
);
239 IBackgroundCopyFile_Release((IBackgroundCopyFile
*) This
->file
);
240 HeapFree(GetProcessHeap(), 0, This
);
246 static HRESULT WINAPI
DLBindStatusCallback_QueryInterface(
247 IBindStatusCallback
*iface
,
251 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
253 if (IsEqualGUID(riid
, &IID_IUnknown
)
254 || IsEqualGUID(riid
, &IID_IBindStatusCallback
))
256 *ppvObject
= &This
->IBindStatusCallback_iface
;
257 DLBindStatusCallback_AddRef(iface
);
262 return E_NOINTERFACE
;
265 static HRESULT WINAPI
DLBindStatusCallback_GetBindInfo(
266 IBindStatusCallback
*iface
,
273 static HRESULT WINAPI
DLBindStatusCallback_GetPriority(
274 IBindStatusCallback
*iface
,
280 static HRESULT WINAPI
DLBindStatusCallback_OnDataAvailable(
281 IBindStatusCallback
*iface
,
284 FORMATETC
*pformatetc
,
290 static HRESULT WINAPI
DLBindStatusCallback_OnLowResource(
291 IBindStatusCallback
*iface
,
297 static HRESULT WINAPI
DLBindStatusCallback_OnObjectAvailable(
298 IBindStatusCallback
*iface
,
305 static HRESULT WINAPI
DLBindStatusCallback_OnProgress(
306 IBindStatusCallback
*iface
,
312 DLBindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
313 BackgroundCopyFileImpl
*file
= This
->file
;
314 BackgroundCopyJobImpl
*job
= file
->owner
;
317 EnterCriticalSection(&job
->cs
);
318 diff
= (file
->fileProgress
.BytesTotal
== BG_SIZE_UNKNOWN
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
);
329 static HRESULT WINAPI
DLBindStatusCallback_OnStartBinding(
330 IBindStatusCallback
*iface
,
337 static HRESULT WINAPI
DLBindStatusCallback_OnStopBinding(
338 IBindStatusCallback
*iface
,
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
);
367 This
->IBindStatusCallback_iface
.lpVtbl
= &DLBindStatusCallback_Vtbl
;
368 IBackgroundCopyFile_AddRef((IBackgroundCopyFile
*) file
);
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
];
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
);
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
);
398 callbackObj
= DLBindStatusCallbackConstructor(file
);
401 ERR("Out of memory\n");
402 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
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
),
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
,
429 ERR("Local file copy failed: error %d\n", GetLastError());
430 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
436 ERR("URLDownload failed: eh 0x%08x\n", hr
);
437 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
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
);
454 DeleteFileW(tmpName
);