[4/5] qmgr: Implement local file background "downloads." [take 2]
Dan Hipschman
dsh at linux.ucla.edu
Mon Mar 10 18:33:28 CDT 2008
This implements some actual file transfer.
---
dlls/qmgr/file.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
dlls/qmgr/job.c | 23 +++++++++
dlls/qmgr/qmgr.c | 2 +-
dlls/qmgr/qmgr.h | 11 +++++
4 files changed, 166 insertions(+), 1 deletions(-)
diff --git a/dlls/qmgr/file.c b/dlls/qmgr/file.c
index 3e0e115..413169f 100644
--- a/dlls/qmgr/file.c
+++ b/dlls/qmgr/file.c
@@ -171,3 +171,134 @@ HRESULT BackgroundCopyFileConstructor(LPCWSTR remoteName,
*ppObj = &This->lpVtbl;
return S_OK;
}
+
+BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
+{
+ static WCHAR prefix[] = {'B','I','T', 0};
+ WCHAR tmpDir[MAX_PATH];
+ WCHAR tmpName[MAX_PATH];
+ HANDLE src, dst;
+ LARGE_INTEGER lgint;
+ ULONG64 size;
+ char buf[4096];
+ DWORD n;
+
+ /* FIXME: assuming local file transfer */
+ src = CreateFileW(file->info.RemoteName, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (src == INVALID_HANDLE_VALUE)
+ {
+ setJobStateAtomic(job, BG_JOB_STATE_ERROR);
+ return FALSE;
+ }
+
+ if (!GetTempPathW(MAX_PATH, tmpDir))
+ {
+ ERR("Couldn't create temp file name: %d\n", GetLastError());
+ CloseHandle(src);
+ /* Guessing on what state this should give us */
+ setJobStateAtomic(job, BG_JOB_STATE_TRANSIENT_ERROR);
+ return FALSE;
+ }
+
+ if (!GetTempFileNameW(tmpDir, prefix, 0, tmpName))
+ {
+ ERR("Couldn't create temp file: %d\n", GetLastError());
+ CloseHandle(src);
+ /* Guessing on what state this should give us */
+ setJobStateAtomic(job, BG_JOB_STATE_TRANSIENT_ERROR);
+ return FALSE;
+ }
+
+ dst = CreateFileW(tmpName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (dst == INVALID_HANDLE_VALUE)
+ {
+ ERR("Couldn't open temp file: %d\n", GetLastError());
+ CloseHandle(src);
+ DeleteFileW(tmpName);
+ /* Guessing on what state this should give us */
+ setJobStateAtomic(job, BG_JOB_STATE_TRANSIENT_ERROR);
+ return FALSE;
+ }
+
+ if (GetFileSizeEx(src, &lgint))
+ size = lgint.QuadPart;
+ else
+ size = BG_SIZE_UNKNOWN;
+
+ EnterCriticalSection(&file->cs);
+ file->fileProgress.BytesTotal = size;
+ file->fileProgress.BytesTransferred = 0;
+ file->fileProgress.Completed = FALSE;
+ LeaveCriticalSection(&file->cs);
+
+ TRACE("Temp file name: %s -> %s -> %s\n",
+ debugstr_w(file->info.RemoteName),
+ debugstr_w(tmpName),
+ debugstr_w(file->info.LocalName));
+ setJobStateAtomic(job, BG_JOB_STATE_TRANSFERRING);
+
+ /* Don't think we need a mutex on enumeration reads */
+ while (job->state == BG_JOB_STATE_TRANSFERRING)
+ {
+ DWORD written;
+
+ if (!ReadFile(src, buf, sizeof buf, &n, NULL))
+ {
+ ERR("Error reading file: %d\n", GetLastError());
+ setJobStateAtomic(job, BG_JOB_STATE_ERROR);
+ break;
+ }
+
+ if (n == 0)
+ {
+ setJobStateAtomic(job, BG_JOB_STATE_QUEUED);
+ break;
+ }
+
+ if (!WriteFile(dst, buf, n, &written, NULL) || written != n)
+ {
+ ERR("Error writing file: %d\n", GetLastError());
+ setJobStateAtomic(job, BG_JOB_STATE_ERROR);
+ break;
+ }
+
+ EnterCriticalSection(&file->cs);
+ file->fileProgress.BytesTransferred += n;
+ LeaveCriticalSection(&file->cs);
+
+ /* This is not accurate since file progress and job progress don't
+ match up at this one point, but we cannot enter both critical
+ sections without additional gross hacks to avoid possible
+ deadlocks, and it is a minor point. */
+ EnterCriticalSection(&job->cs);
+ job->jobProgress.BytesTransferred += n;
+ LeaveCriticalSection(&job->cs);
+ }
+
+ CloseHandle(dst);
+ CloseHandle(src);
+ if (job->state == BG_JOB_STATE_ERROR || job->state == BG_JOB_STATE_CANCELLED)
+ {
+ DeleteFileW(tmpName);
+ return FALSE;
+ }
+
+ /* Don't rename until the user calls Complete */
+ lstrcpyW(file->tempFileName, tmpName);
+
+ EnterCriticalSection(&file->cs);
+ file->fileProgress.Completed = TRUE;
+ LeaveCriticalSection(&file->cs);
+
+ /* This is not accurate since file progress and job progress don't
+ match up at this one point, but we cannot enter both critical
+ sections without additional gross hacks to avoid possible
+ deadlocks, and it is a minor point. */
+ EnterCriticalSection(&job->cs);
+ job->jobProgress.FilesTransferred++;
+ LeaveCriticalSection(&job->cs);
+
+ return TRUE;
+}
diff --git a/dlls/qmgr/job.c b/dlls/qmgr/job.c
index faa882e..70cbdd9 100644
--- a/dlls/qmgr/job.c
+++ b/dlls/qmgr/job.c
@@ -484,3 +484,26 @@ 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)
+ return;
+
+ if (!processFile(file, job))
+ return;
+ }
+}
diff --git a/dlls/qmgr/qmgr.c b/dlls/qmgr/qmgr.c
index 1218870..acc3766 100644
--- a/dlls/qmgr/qmgr.c
+++ b/dlls/qmgr/qmgr.c
@@ -177,7 +177,7 @@ DWORD WINAPI fileTransfer(void *param)
}
else
{
- /* Process job */
+ processJob(job);
}
}
else
diff --git a/dlls/qmgr/qmgr.h b/dlls/qmgr/qmgr.h
index cb6ea1b..ae13e59 100644
--- a/dlls/qmgr/qmgr.h
+++ b/dlls/qmgr/qmgr.h
@@ -73,6 +73,7 @@ typedef struct
BG_FILE_INFO info;
BG_FILE_PROGRESS fileProgress;
CRITICAL_SECTION cs;
+ WCHAR tempFileName[MAX_PATH];
struct list entryFromJob;
} BackgroundCopyFileImpl;
@@ -101,6 +102,8 @@ HRESULT BackgroundCopyFileConstructor(LPCWSTR remoteName,
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 *
@@ -111,4 +114,12 @@ qmgr_strdup(const char *s)
return d ? memcpy(d, s, n) : NULL;
}
+static inline void
+setJobStateAtomic(BackgroundCopyJobImpl *job, BG_JOB_STATE state)
+{
+ EnterCriticalSection(&job->cs);
+ job->state = state;
+ LeaveCriticalSection(&job->cs);
+}
+
#endif /* __QMGR_H__ */
More information about the wine-patches
mailing list