diff --git a/dlls/qmgr/file.c b/dlls/qmgr/file.c index f1ae06a053f..a874062c6c0 100644 --- a/dlls/qmgr/file.c +++ b/dlls/qmgr/file.c @@ -170,3 +170,91 @@ HRESULT BackgroundCopyFileConstructor(BackgroundCopyJobImpl *owner, *ppObj = &This->lpVtbl; return S_OK; } + +static DWORD CALLBACK copyProgressCallback(LARGE_INTEGER totalSize, + LARGE_INTEGER totalTransferred, + LARGE_INTEGER streamSize, + LARGE_INTEGER streamTransferred, + DWORD streamNum, + DWORD reason, + HANDLE srcFile, + HANDLE dstFile, + LPVOID obj) +{ + BackgroundCopyFileImpl *file = (BackgroundCopyFileImpl *) obj; + BackgroundCopyJobImpl *job = file->owner; + ULONG64 diff; + + EnterCriticalSection(&job->cs); + diff = (file->fileProgress.BytesTotal == BG_SIZE_UNKNOWN + ? totalTransferred.QuadPart + : totalTransferred.QuadPart - file->fileProgress.BytesTransferred); + file->fileProgress.BytesTotal = totalSize.QuadPart; + file->fileProgress.BytesTransferred = totalTransferred.QuadPart; + job->jobProgress.BytesTransferred += diff; + LeaveCriticalSection(&job->cs); + + return (job->state == BG_JOB_STATE_TRANSFERRING + ? PROGRESS_CONTINUE + : PROGRESS_CANCEL); +} + +BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job) +{ + static WCHAR prefix[] = {'B','I','T', 0}; + WCHAR tmpDir[MAX_PATH]; + WCHAR tmpName[MAX_PATH]; + + if (!GetTempPathW(MAX_PATH, tmpDir)) + { + ERR("Couldn't create temp file name: %d\n", GetLastError()); + /* Guessing on what state this should give us */ + transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSIENT_ERROR); + return FALSE; + } + + if (!GetTempFileNameW(tmpDir, prefix, 0, tmpName)) + { + ERR("Couldn't create temp file: %d\n", GetLastError()); + /* Guessing on what state this should give us */ + transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSIENT_ERROR); + return FALSE; + } + + EnterCriticalSection(&job->cs); + file->fileProgress.BytesTotal = BG_SIZE_UNKNOWN; + file->fileProgress.BytesTransferred = 0; + file->fileProgress.Completed = FALSE; + LeaveCriticalSection(&job->cs); + + TRACE("Transferring: %s -> %s -> %s\n", + debugstr_w(file->info.RemoteName), + debugstr_w(tmpName), + debugstr_w(file->info.LocalName)); + + transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRING); + if (!CopyFileExW(file->info.RemoteName, tmpName, copyProgressCallback, + file, NULL, 0)) + { + ERR("Local file copy failed: error %d\n", GetLastError()); + transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR); + return FALSE; + } + + if (transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_QUEUED)) + { + lstrcpyW(file->tempFileName, tmpName); + + EnterCriticalSection(&job->cs); + file->fileProgress.Completed = TRUE; + job->jobProgress.FilesTransferred++; + LeaveCriticalSection(&job->cs); + + return TRUE; + } + else + { + DeleteFileW(tmpName); + return FALSE; + } +} diff --git a/dlls/qmgr/job.c b/dlls/qmgr/job.c index 2fbf1bc2a06..3b94a79c710 100644 --- a/dlls/qmgr/job.c +++ b/dlls/qmgr/job.c @@ -98,6 +98,7 @@ static HRESULT WINAPI BITS_IBackgroundCopyJob_AddFile( file = (BackgroundCopyFileImpl *) pFile; EnterCriticalSection(&This->cs); list_add_head(&This->files, &file->entryFromJob); + This->jobProgress.BytesTotal = BG_SIZE_UNKNOWN; ++This->jobProgress.FilesTotal; LeaveCriticalSection(&This->cs); @@ -485,3 +486,29 @@ HRESULT BackgroundCopyJobConstructor(LPCWSTR displayName, BG_JOB_TYPE type, *ppObj = &This->lpVtbl; return S_OK; } + +void processJob(BackgroundCopyJobImpl *job) +{ + for (;;) + { + BackgroundCopyFileImpl *file; + BOOL done = TRUE; + + EnterCriticalSection(&job->cs); + LIST_FOR_EACH_ENTRY(file, &job->files, BackgroundCopyFileImpl, entryFromJob) + if (!file->fileProgress.Completed) + { + done = FALSE; + break; + } + LeaveCriticalSection(&job->cs); + if (done) + { + transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRED); + return; + } + + if (!processFile(file, job)) + return; + } +} diff --git a/dlls/qmgr/qmgr.c b/dlls/qmgr/qmgr.c index 608e01a3e2d..4e3d259e079 100644 --- a/dlls/qmgr/qmgr.c +++ b/dlls/qmgr/qmgr.c @@ -189,11 +189,6 @@ DWORD WINAPI fileTransfer(void *param) LeaveCriticalSection(&qmgr->cs); if (haveJob) - { - FIXME("Actually process job %p; setting error state\n", job); - EnterCriticalSection(&qmgr->cs); - job->state = BG_JOB_STATE_ERROR; - LeaveCriticalSection(&qmgr->cs); - } + processJob(job); } } diff --git a/dlls/qmgr/qmgr.h b/dlls/qmgr/qmgr.h index fce84d942dd..9530b97c295 100644 --- a/dlls/qmgr/qmgr.h +++ b/dlls/qmgr/qmgr.h @@ -73,6 +73,7 @@ typedef struct LONG ref; BG_FILE_INFO info; BG_FILE_PROGRESS fileProgress; + WCHAR tempFileName[MAX_PATH]; struct list entryFromJob; BackgroundCopyJobImpl *owner; } BackgroundCopyFileImpl; @@ -107,6 +108,8 @@ HRESULT BackgroundCopyFileConstructor(BackgroundCopyJobImpl *owner, HRESULT EnumBackgroundCopyFilesConstructor(LPVOID *ppObj, IBackgroundCopyJob* copyJob); DWORD WINAPI fileTransfer(void *param); +void processJob(BackgroundCopyJobImpl *job); +BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job); /* Little helper functions */ static inline char * @@ -117,4 +120,19 @@ qmgr_strdup(const char *s) return d ? memcpy(d, s, n) : NULL; } +static inline BOOL +transitionJobState(BackgroundCopyJobImpl *job, BG_JOB_STATE fromState, + BG_JOB_STATE toState) +{ + BOOL rv = FALSE; + EnterCriticalSection(&globalMgr.cs); + if (job->state == fromState) + { + job->state = toState; + rv = TRUE; + } + LeaveCriticalSection(&globalMgr.cs); + return rv; +} + #endif /* __QMGR_H__ */