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 const IBindStatusCallbackVtbl
*lpVtbl
;
217 BackgroundCopyFileImpl
*file
;
219 } DLBindStatusCallback
;
221 static ULONG WINAPI
DLBindStatusCallback_AddRef(IBindStatusCallback
*iface
)
223 DLBindStatusCallback
*This
= (DLBindStatusCallback
*) iface
;
224 return InterlockedIncrement(&This
->ref
);
227 static ULONG WINAPI
DLBindStatusCallback_Release(IBindStatusCallback
*iface
)
229 DLBindStatusCallback
*This
= (DLBindStatusCallback
*) iface
;
230 ULONG ref
= InterlockedDecrement(&This
->ref
);
234 IBackgroundCopyFile_Release((IBackgroundCopyFile
*) This
->file
);
235 HeapFree(GetProcessHeap(), 0, This
);
241 static HRESULT WINAPI
DLBindStatusCallback_QueryInterface(
242 IBindStatusCallback
*iface
,
246 DLBindStatusCallback
*This
= (DLBindStatusCallback
*) iface
;
248 if (IsEqualGUID(riid
, &IID_IUnknown
)
249 || IsEqualGUID(riid
, &IID_IBindStatusCallback
))
251 *ppvObject
= &This
->lpVtbl
;
252 DLBindStatusCallback_AddRef(iface
);
257 return E_NOINTERFACE
;
260 static HRESULT WINAPI
DLBindStatusCallback_GetBindInfo(
261 IBindStatusCallback
*iface
,
268 static HRESULT WINAPI
DLBindStatusCallback_GetPriority(
269 IBindStatusCallback
*iface
,
275 static HRESULT WINAPI
DLBindStatusCallback_OnDataAvailable(
276 IBindStatusCallback
*iface
,
279 FORMATETC
*pformatetc
,
285 static HRESULT WINAPI
DLBindStatusCallback_OnLowResource(
286 IBindStatusCallback
*iface
,
292 static HRESULT WINAPI
DLBindStatusCallback_OnObjectAvailable(
293 IBindStatusCallback
*iface
,
300 static HRESULT WINAPI
DLBindStatusCallback_OnProgress(
301 IBindStatusCallback
*iface
,
307 DLBindStatusCallback
*This
= (DLBindStatusCallback
*) iface
;
308 BackgroundCopyFileImpl
*file
= This
->file
;
309 BackgroundCopyJobImpl
*job
= file
->owner
;
312 EnterCriticalSection(&job
->cs
);
313 diff
= (file
->fileProgress
.BytesTotal
== BG_SIZE_UNKNOWN
315 : progress
- file
->fileProgress
.BytesTransferred
);
316 file
->fileProgress
.BytesTotal
= progressMax
? progressMax
: BG_SIZE_UNKNOWN
;
317 file
->fileProgress
.BytesTransferred
= progress
;
318 job
->jobProgress
.BytesTransferred
+= diff
;
319 LeaveCriticalSection(&job
->cs
);
324 static HRESULT WINAPI
DLBindStatusCallback_OnStartBinding(
325 IBindStatusCallback
*iface
,
332 static HRESULT WINAPI
DLBindStatusCallback_OnStopBinding(
333 IBindStatusCallback
*iface
,
340 static const IBindStatusCallbackVtbl DLBindStatusCallback_Vtbl
=
342 DLBindStatusCallback_QueryInterface
,
343 DLBindStatusCallback_AddRef
,
344 DLBindStatusCallback_Release
,
345 DLBindStatusCallback_OnStartBinding
,
346 DLBindStatusCallback_GetPriority
,
347 DLBindStatusCallback_OnLowResource
,
348 DLBindStatusCallback_OnProgress
,
349 DLBindStatusCallback_OnStopBinding
,
350 DLBindStatusCallback_GetBindInfo
,
351 DLBindStatusCallback_OnDataAvailable
,
352 DLBindStatusCallback_OnObjectAvailable
355 static DLBindStatusCallback
*DLBindStatusCallbackConstructor(
356 BackgroundCopyFileImpl
*file
)
358 DLBindStatusCallback
*This
= HeapAlloc(GetProcessHeap(), 0, sizeof *This
);
362 This
->lpVtbl
= &DLBindStatusCallback_Vtbl
;
363 IBackgroundCopyFile_AddRef((IBackgroundCopyFile
*) file
);
369 BOOL
processFile(BackgroundCopyFileImpl
*file
, BackgroundCopyJobImpl
*job
)
371 static const WCHAR prefix
[] = {'B','I','T', 0};
372 IBindStatusCallback
*callbackObj
;
373 WCHAR tmpDir
[MAX_PATH
];
374 WCHAR tmpName
[MAX_PATH
];
377 if (!GetTempPathW(MAX_PATH
, tmpDir
))
379 ERR("Couldn't create temp file name: %d\n", GetLastError());
380 /* Guessing on what state this should give us */
381 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
385 if (!GetTempFileNameW(tmpDir
, prefix
, 0, tmpName
))
387 ERR("Couldn't create temp file: %d\n", GetLastError());
388 /* Guessing on what state this should give us */
389 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
393 callbackObj
= (IBindStatusCallback
*) DLBindStatusCallbackConstructor(file
);
396 ERR("Out of memory\n");
397 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSIENT_ERROR
);
401 EnterCriticalSection(&job
->cs
);
402 file
->fileProgress
.BytesTotal
= BG_SIZE_UNKNOWN
;
403 file
->fileProgress
.BytesTransferred
= 0;
404 file
->fileProgress
.Completed
= FALSE
;
405 LeaveCriticalSection(&job
->cs
);
407 TRACE("Transferring: %s -> %s -> %s\n",
408 debugstr_w(file
->info
.RemoteName
),
410 debugstr_w(file
->info
.LocalName
));
412 transitionJobState(job
, BG_JOB_STATE_QUEUED
, BG_JOB_STATE_TRANSFERRING
);
414 DeleteUrlCacheEntryW(file
->info
.RemoteName
);
415 hr
= URLDownloadToFileW(NULL
, file
->info
.RemoteName
, tmpName
, 0, callbackObj
);
416 IBindStatusCallback_Release(callbackObj
);
417 if (hr
== INET_E_DOWNLOAD_FAILURE
)
419 TRACE("URLDownload failed, trying local file copy\n");
420 if (!CopyFileExW(file
->info
.RemoteName
, tmpName
, copyProgressCallback
,
423 ERR("Local file copy failed: error %d\n", GetLastError());
424 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
430 ERR("URLDownload failed: eh 0x%08x\n", hr
);
431 transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_ERROR
);
435 if (transitionJobState(job
, BG_JOB_STATE_TRANSFERRING
, BG_JOB_STATE_QUEUED
))
437 lstrcpyW(file
->tempFileName
, tmpName
);
439 EnterCriticalSection(&job
->cs
);
440 file
->fileProgress
.Completed
= TRUE
;
441 job
->jobProgress
.FilesTransferred
++;
442 LeaveCriticalSection(&job
->cs
);
448 DeleteFileW(tmpName
);