[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