[PATCH 12/13] setupapi: Implement source media path resolution.

Zebediah Figura z.figura12 at gmail.com
Wed May 1 18:24:13 CDT 2019


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47107
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/setupapi/queue.c | 110 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 98 insertions(+), 12 deletions(-)

diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c
index 675462f09c..d90047c9c3 100644
--- a/dlls/setupapi/queue.c
+++ b/dlls/setupapi/queue.c
@@ -55,6 +55,8 @@ struct source_media
 {
     WCHAR root[MAX_PATH];
     WCHAR *desc, *tag;
+    BOOL resolved;
+    BOOL cabinet;
 };
 
 struct file_op
@@ -517,6 +519,8 @@ static struct source_media *get_source_media(struct file_queue *queue,
     strcpyW(queue->sources[i]->root, root);
     queue->sources[i]->desc = strdupW(desc);
     queue->sources[i]->tag = strdupW(tag);
+    queue->sources[i]->resolved = FALSE;
+    queue->sources[i]->cabinet = FALSE;
 
     return queue->sources[i];
 }
@@ -1283,7 +1287,10 @@ static BOOL queue_copy_file( const WCHAR *source, const WCHAR *dest,
 
     /* try to extract it from the cabinet file */
     if (op->media->tag && extract_cabinet_file(op->media->tag, op->media->root, op->src_file, dest))
+    {
+        op->media->cabinet = TRUE;
         return TRUE;
+    }
 
     return FALSE;
 }
@@ -1366,22 +1373,101 @@ BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBAC
         {
             WCHAR newpath[MAX_PATH];
 
-            build_filepathsW( op, &paths );
-            op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
-            if (op_result == FILEOP_ABORT) goto done;
-            if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
-            while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
+            if (!op->media->resolved)
             {
-                if (queue_copy_file( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
-                                     paths.Target, op, handler, context ))
+                /* The NEEDMEDIA callback asks for the folder containing the
+                 * first file, but that might be in a subdir of the source
+                 * disk's root directory. We have to do some contortions to
+                 * correct for this. Pretend that the file we're using
+                 * actually isn't in a subdirectory, but keep track of what it
+                 * was, and then later strip it from the root path that we
+                 * ultimately resolve the source disk to. */
+                WCHAR *src_path = op->src_path;
+
+                op->src_path = NULL;
+                if (src_path)
+                {
+                    strcatW(op->media->root, backslashW);
+                    strcatW(op->media->root, src_path);
+                }
+
+                for (;;)
+                {
+                    SOURCE_MEDIA_W media;
+                    media.Reserved = NULL;
+                    media.Tagfile = op->media->tag;
+                    media.Description = op->media->desc;
+                    media.SourcePath = op->media->root;
+                    media.SourceFile = op->src_file;
+                    media.Flags = op->style & (SP_COPY_WARNIFSKIP | SP_COPY_NOSKIP | SP_FLAG_CABINETCONTINUATION | SP_COPY_NOBROWSE);
+
+                    newpath[0] = 0;
+                    op_result = handler( context, SPFILENOTIFY_NEEDMEDIA, (UINT_PTR)&media, (UINT_PTR)newpath );
+
+                    if (op_result == FILEOP_ABORT)
+                        goto done;
+                    else if (op_result == FILEOP_SKIP)
+                        break;
+                    else if (op_result == FILEOP_NEWPATH)
+                        strcpyW(op->media->root, newpath);
+                    else if (op_result != FILEOP_DOIT)
+                        FIXME("Unhandled return value %#x.\n", op_result);
+
+                    build_filepathsW( op, &paths );
+                    op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
+                    if (op_result == FILEOP_ABORT)
+                        goto done;
+                    else if (op_result == FILEOP_SKIP)
+                        break;
+                    else if (op_result != FILEOP_DOIT)
+                        FIXME("Unhandled return value %#x.\n", op_result);
+
+                    if (queue_copy_file( paths.Source, paths.Target, op, handler, context ))
+                    {
+                        if (src_path && !op->media->cabinet)
+                        {
+                            size_t root_len = strlenW(op->media->root), path_len = strlenW(src_path);
+                            if (path_len <= root_len && !strncmpiW(op->media->root + root_len - path_len, src_path, path_len))
+                                op->media->root[root_len - path_len - 1] = 0;
+                            heap_free( src_path );
+                        }
+                        op->media->resolved = TRUE;
+                        handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                build_filepathsW( op, &paths );
+                op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
+                if (op_result == FILEOP_ABORT)
+                    goto done;
+                else if (op_result == FILEOP_SKIP)
                     break;
+                else if (op_result != FILEOP_DOIT)
+                    FIXME("Unhandled return value %#x.\n", op_result);
 
-                paths.Win32Error = GetLastError();
-                op_result = handler( context, SPFILENOTIFY_COPYERROR,
-                                     (UINT_PTR)&paths, (UINT_PTR)newpath );
-                if (op_result == FILEOP_ABORT) goto done;
+                while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
+                {
+                    if (queue_copy_file( paths.Source, paths.Target, op, handler, context ))
+                        break;
+
+                    paths.Win32Error = GetLastError();
+                    newpath[0] = 0;
+                    op_result = handler( context, SPFILENOTIFY_COPYERROR, (UINT_PTR)&paths, (UINT_PTR)newpath );
+                    if (op_result == FILEOP_ABORT)
+                        goto done;
+                    else if (op_result == FILEOP_NEWPATH)
+                    {
+                        strcpyW(op->media->root, newpath);
+                        build_filepathsW(op, &paths);
+                    }
+                    else if (op_result != FILEOP_SKIP && op_result != FILEOP_DOIT)
+                        FIXME("Unhandled return value %#x.\n", op_result);
+                }
+                handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
             }
-            handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
         }
         handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
     }
-- 
2.21.0




More information about the wine-devel mailing list