Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47107 Signed-off-by: Zebediah Figura z.figura12@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 ); }