Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/install.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/dlls/setupapi/install.c b/dlls/setupapi/install.c index 05dda816ed..8ebea56d9c 100644 --- a/dlls/setupapi/install.c +++ b/dlls/setupapi/install.c @@ -155,11 +155,20 @@ static WCHAR *dup_section_line_field( HINF hinf, const WCHAR *section, const WCH static BOOL copy_files_callback( HINF hinf, PCWSTR field, void *arg ) { struct files_callback_info *info = arg; + WCHAR src_root[MAX_PATH], *p; + + if (!info->src_root) + { + strcpyW( src_root, PARSER_get_inf_filename( hinf ) ); + if ((p = strrchrW( src_root, '\' ))) *p = 0; + }
if (field[0] == '@') /* special case: copy single file */ - SetupQueueDefaultCopyW( info->queue, info->layout ? info->layout : hinf, info->src_root, NULL, field+1, info->copy_flags ); + SetupQueueDefaultCopyW( info->queue, info->layout ? info->layout : hinf, + info->src_root ? info->src_root : src_root, NULL, field+1, info->copy_flags ); else - SetupQueueCopySectionW( info->queue, info->src_root, info->layout ? info->layout : hinf, hinf, field, info->copy_flags ); + SetupQueueCopySectionW( info->queue, info->src_root ? info->src_root : src_root, + info->layout ? info->layout : hinf, hinf, field, info->copy_flags ); return TRUE; }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/queue.c | 95 +++++++++++++++++++++++++++++------ dlls/setupapi/tests/install.c | 4 +- 2 files changed, 83 insertions(+), 16 deletions(-)
diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c index f033ef75da..d9204a48e4 100644 --- a/dlls/setupapi/queue.c +++ b/dlls/setupapi/queue.c @@ -33,9 +33,12 @@ #include "setupapi_private.h" #include "winver.h" #include "wine/debug.h" +#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
+static const WCHAR backslashW[] = {'\',0}; + /* context structure for the default queue callback */ struct default_callback_context { @@ -329,6 +332,52 @@ static void get_src_file_info( HINF hinf, struct file_op *op ) if (!op->src_root) op->src_root = PARSER_get_src_root(hinf); }
+static void get_source_info( HINF hinf, const WCHAR *src_file, SP_FILE_COPY_PARAMS_W *params, + WCHAR *src_root, WCHAR *src_path) +{ + static const WCHAR SourceDisksNames[] = + {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0}; + static const WCHAR SourceDisksFiles[] = + {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0}; + + INFCONTEXT file_ctx, disk_ctx; + INT id, diskid; + DWORD len; + + /* find the SourceDisksFiles entry */ + if (!SetupFindFirstLineW( hinf, SourceDisksFiles, src_file, &file_ctx )) return; + if (!SetupGetIntField( &file_ctx, 1, &diskid )) return; + + /* now find the diskid in the SourceDisksNames section */ + if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return; + for (;;) + { + if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break; + if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return; + } + + if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) && len > sizeof(WCHAR) + && (params->SourceDescription = heap_alloc( len * sizeof(WCHAR) ))) + SetupGetStringFieldW( &disk_ctx, 1, (WCHAR *)params->SourceDescription, len, NULL ); + + if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) && len > sizeof(WCHAR) + && (params->SourceTagfile = heap_alloc( len * sizeof(WCHAR) ))) + SetupGetStringFieldW( &disk_ctx, 2, (WCHAR *)params->SourceTagfile, len, NULL ); + + if (SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len ) && len > sizeof(WCHAR) + && len < MAX_PATH - strlenW( src_root ) - 1) + { + strcatW( src_root, backslashW ); + SetupGetStringFieldW( &disk_ctx, 4, src_root + strlenW( src_root ), + MAX_PATH - strlenW( src_root ), NULL ); + } + + if (SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len ) && len > sizeof(WCHAR) && len < MAX_PATH) + { + SetupGetStringFieldW( &file_ctx, 2, src_path, MAX_PATH, NULL ); + params->SourcePath = src_path; + } +}
/*********************************************************************** * get_destination_dir @@ -742,48 +791,66 @@ BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, H return ret; }
- /*********************************************************************** * SetupQueueCopySectionW (SETUPAPI.@) */ BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist, PCWSTR section, DWORD style ) { - SP_FILE_COPY_PARAMS_W params; + WCHAR src_root_buffer[MAX_PATH], src_path[MAX_PATH], src_file[MAX_PATH], dst_file[MAX_PATH], *dest_dir; INFCONTEXT context; - WCHAR dest[MAX_PATH], src[MAX_PATH], *dest_dir; + SP_FILE_COPY_PARAMS_W params; INT flags; BOOL ret = FALSE;
- TRACE( "hinf=%p/%p section=%s root=%s\n", - hinf, hlist, debugstr_w(section), debugstr_w(src_root) ); + TRACE("queue %p, src_root %s, hinf %p, hlist %p, section %s, style %#x.\n", + queue, debugstr_w(src_root), hinf, hlist, debugstr_w(section), style); + + if (!src_root) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + }
params.cbSize = sizeof(params); params.QueueHandle = queue; - params.SourceRootPath = src_root; - params.SourcePath = NULL; - params.SourceDescription = NULL; - params.SourceTagfile = NULL; - params.TargetFilename = dest; + params.SourceRootPath = src_root_buffer; + params.SourceFilename = src_file; + params.TargetFilename = dst_file; params.CopyStyle = style; - params.LayoutInf = hinf; + params.LayoutInf = NULL; params.SecurityDescriptor = NULL;
+ strcpyW( src_root_buffer, src_root ); + if (!hlist) hlist = hinf; if (!hinf) hinf = hlist; if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE; if (!(params.TargetDirectory = dest_dir = get_destination_dir( hinf, section ))) return FALSE; do { - if (!SetupGetStringFieldW( &context, 1, dest, ARRAY_SIZE( dest ), NULL )) + params.SourcePath = NULL; + params.SourceDescription = NULL; + params.SourceTagfile = NULL; + strcpyW( src_root_buffer, src_root ); + src_path[0] = 0; + + if (!SetupGetStringFieldW( &context, 1, dst_file, ARRAY_SIZE( dst_file ), NULL )) goto end; - if (!SetupGetStringFieldW( &context, 2, src, ARRAY_SIZE( src ), NULL )) *src = 0; + if (!SetupGetStringFieldW( &context, 2, src_file, ARRAY_SIZE( src_file ), NULL )) + strcpyW( src_file, dst_file ); + if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
- params.SourceFilename = *src ? src : NULL; + get_source_info( hinf, src_file, ¶ms, src_root_buffer, src_path ); + if (!SetupQueueCopyIndirectW( ¶ms )) goto end; + + heap_free( (WCHAR *)params.SourceDescription ); + heap_free( (WCHAR *)params.SourceTagfile ); } while (SetupFindNextLine( &context, &context )); ret = TRUE; + end: HeapFree(GetProcessHeap(), 0, dest_dir); return ret; diff --git a/dlls/setupapi/tests/install.c b/dlls/setupapi/tests/install.c index 7c614c7f90..32002a97b9 100644 --- a/dlls/setupapi/tests/install.c +++ b/dlls/setupapi/tests/install.c @@ -1065,8 +1065,8 @@ static void test_install_files_queue(void) ok(delete_file("dst/four.txt"), "Destination file should exist.\n"); ok(delete_file("dst/five.txt"), "Destination file should exist.\n"); ok(delete_file("dst/six.txt"), "Destination file should exist.\n"); - todo_wine ok(delete_file("dst/seven.txt"), "Destination file should exist.\n"); - todo_wine ok(delete_file("dst/eight.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/seven.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/eight.txt"), "Destination file should exist.\n");
SetupTermDefaultQueueCallback(context); ret = SetupCloseFileQueue(queue);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51705
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 Task: Patch failed to apply
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/queue.c | 57 +++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 21 deletions(-)
diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c index d9204a48e4..d0e591662a 100644 --- a/dlls/setupapi/queue.c +++ b/dlls/setupapi/queue.c @@ -392,7 +392,7 @@ static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section ) WCHAR systemdir[MAX_PATH], *dir; BOOL ret;
- if (!(ret = SetupFindFirstLineW( hinf, Dest, section, &context ))) + if (!section || !(ret = SetupFindFirstLineW( hinf, Dest, section, &context ))) ret = SetupFindFirstLineW( hinf, Dest, Def, &context );
if (ret && (dir = PARSER_get_dest_dir( &context ))) @@ -626,24 +626,21 @@ BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, P /*********************************************************************** * SetupQueueDefaultCopyA (SETUPAPI.@) */ -BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file, - PCSTR dst_file, DWORD style ) +BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, const char *src_rootA, + const char *src_fileA, const char *dst_fileA, DWORD style ) { - SP_FILE_COPY_PARAMS_A params; + WCHAR src_rootW[MAX_PATH], src_fileW[MAX_PATH], dst_fileW[MAX_PATH];
- params.cbSize = sizeof(params); - params.QueueHandle = queue; - params.SourceRootPath = src_root; - params.SourcePath = NULL; - params.SourceFilename = src_file; - params.SourceDescription = NULL; - params.SourceTagfile = NULL; - params.TargetDirectory = NULL; - params.TargetFilename = dst_file; - params.CopyStyle = style; - params.LayoutInf = hinf; - params.SecurityDescriptor = NULL; - return SetupQueueCopyIndirectA( ¶ms ); + if (!src_rootA || !src_fileA || !dst_fileA) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + MultiByteToWideChar( CP_ACP, 0, src_rootA, -1, src_rootW, ARRAY_SIZE(src_rootW) ); + MultiByteToWideChar( CP_ACP, 0, src_fileA, -1, src_fileW, ARRAY_SIZE(src_fileW) ); + MultiByteToWideChar( CP_ACP, 0, dst_fileA, -1, dst_fileW, ARRAY_SIZE(dst_fileW) ); + return SetupQueueDefaultCopyW( queue, hinf, src_rootW, src_fileW, dst_fileW, style ); }
@@ -653,21 +650,39 @@ BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, P BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file, PCWSTR dst_file, DWORD style ) { + WCHAR src_root_buffer[MAX_PATH], src_path[MAX_PATH]; SP_FILE_COPY_PARAMS_W params; + BOOL ret; + + if (!src_root || !src_file || !dst_file) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + }
params.cbSize = sizeof(params); params.QueueHandle = queue; - params.SourceRootPath = src_root; + params.SourceRootPath = src_root_buffer; params.SourcePath = NULL; params.SourceFilename = src_file; params.SourceDescription = NULL; params.SourceTagfile = NULL; - params.TargetDirectory = NULL; params.TargetFilename = dst_file; params.CopyStyle = style; - params.LayoutInf = hinf; + params.LayoutInf = NULL; params.SecurityDescriptor = NULL; - return SetupQueueCopyIndirectW( ¶ms ); + + strcpyW( src_root_buffer, src_root ); + src_path[0] = 0; + if (!(params.TargetDirectory = get_destination_dir( hinf, NULL ))) return FALSE; + get_source_info( hinf, src_file, ¶ms, src_root_buffer, src_path ); + + ret = SetupQueueCopyIndirectW( ¶ms ); + + heap_free( (WCHAR *)params.TargetDirectory ); + heap_free( (WCHAR *)params.SourceDescription ); + heap_free( (WCHAR *)params.SourceTagfile ); + return ret; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51706
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 Task: Patch failed to apply
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/queue.c | 57 +++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 29 deletions(-)
diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c index d0e591662a..c87d33bd1d 100644 --- a/dlls/setupapi/queue.c +++ b/dlls/setupapi/queue.c @@ -504,36 +504,35 @@ BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle ) /*********************************************************************** * SetupQueueCopyIndirectA (SETUPAPI.@) */ -BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params ) +BOOL WINAPI SetupQueueCopyIndirectA( SP_FILE_COPY_PARAMS_A *paramsA ) { - struct file_queue *queue = params->QueueHandle; - struct file_op *op; - - if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; - op->style = params->CopyStyle; - op->src_root = strdupAtoW( params->SourceRootPath ); - op->src_path = strdupAtoW( params->SourcePath ); - op->src_file = strdupAtoW( params->SourceFilename ); - op->src_descr = strdupAtoW( params->SourceDescription ); - op->src_tag = strdupAtoW( params->SourceTagfile ); - op->dst_path = strdupAtoW( params->TargetDirectory ); - op->dst_file = strdupAtoW( params->TargetFilename ); - - /* some defaults */ - if (!op->src_file) op->src_file = op->dst_file; - if (params->LayoutInf) - { - get_src_file_info( params->LayoutInf, op ); - if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file ); - } - - TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n", - debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file), - debugstr_w(op->dst_path), debugstr_w(op->dst_file), - debugstr_w(op->src_descr), debugstr_w(op->src_tag) ); - - queue_file_op( &queue->copy_queue, op ); - return TRUE; + SP_FILE_COPY_PARAMS_W paramsW; + BOOL ret; + + paramsW.cbSize = sizeof(paramsW); + paramsW.QueueHandle = paramsA->QueueHandle; + paramsW.SourceRootPath = strdupAtoW( paramsA->SourceRootPath ); + paramsW.SourcePath = strdupAtoW( paramsA->SourcePath ); + paramsW.SourceFilename = strdupAtoW( paramsA->SourceFilename ); + paramsW.SourceDescription = strdupAtoW( paramsA->SourceDescription ); + paramsW.SourceTagfile = strdupAtoW( paramsA->SourceTagfile ); + paramsW.TargetDirectory = strdupAtoW( paramsA->TargetDirectory ); + paramsW.TargetFilename = strdupAtoW( paramsA->TargetFilename ); + paramsW.CopyStyle = paramsA->CopyStyle; + paramsW.LayoutInf = paramsA->LayoutInf; + paramsW.SecurityDescriptor = strdupAtoW( paramsA->SecurityDescriptor ); + + ret = SetupQueueCopyIndirectW( ¶msW ); + + heap_free( (WCHAR *)paramsW.SourceRootPath ); + heap_free( (WCHAR *)paramsW.SourcePath ); + heap_free( (WCHAR *)paramsW.SourceFilename ); + heap_free( (WCHAR *)paramsW.SourceDescription ); + heap_free( (WCHAR *)paramsW.SourceTagfile ); + heap_free( (WCHAR *)paramsW.TargetDirectory ); + heap_free( (WCHAR *)paramsW.TargetFilename ); + heap_free( (WCHAR *)paramsW.SecurityDescriptor ); + return ret; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51707
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 Task: Patch failed to apply
Tests demonstrate that the existing implementation is not correct, and I was unable to find an arrangement of parameters such that it was respected on Windows. Most likely it has to do with the undocumented parameters used in the "master" C:\windows\inf\layout.inf.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/parser.c | 20 -------- dlls/setupapi/queue.c | 81 +------------------------------- dlls/setupapi/setupapi_private.h | 1 - 3 files changed, 1 insertion(+), 101 deletions(-)
diff --git a/dlls/setupapi/parser.c b/dlls/setupapi/parser.c index 5cde5ebcfa..c1086895d0 100644 --- a/dlls/setupapi/parser.c +++ b/dlls/setupapi/parser.c @@ -1055,26 +1055,6 @@ const WCHAR *PARSER_get_inf_filename( HINF hinf ) return file->filename; }
- -/*********************************************************************** - * PARSER_get_src_root - * - * Retrieve the source directory of an inf file. - */ -WCHAR *PARSER_get_src_root( HINF hinf ) -{ - unsigned int len; - const WCHAR *dir = get_inf_dir( hinf, &len ); - WCHAR *ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ); - if (ret) - { - memcpy( ret, dir, len * sizeof(WCHAR) ); - ret[len] = 0; - } - return ret; -} - - /*********************************************************************** * PARSER_get_dest_dir * diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c index c87d33bd1d..ae50ee6878 100644 --- a/dlls/setupapi/queue.c +++ b/dlls/setupapi/queue.c @@ -256,82 +256,6 @@ UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification, return ret; }
- -/*********************************************************************** - * get_src_file_info - * - * Retrieve the source file information for a given file. - */ -static void get_src_file_info( HINF hinf, struct file_op *op ) -{ - static const WCHAR SourceDisksNames[] = - {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0}; - static const WCHAR SourceDisksFiles[] = - {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0}; - - INFCONTEXT file_ctx, disk_ctx; - INT id, diskid; - DWORD len, len2; - - /* find the SourceDisksFiles entry */ - if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx )) - { - if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return; - /* no specific info, use .inf file source directory */ - if (!op->src_root) op->src_root = PARSER_get_src_root( hinf ); - return; - } - if (!SetupGetIntField( &file_ctx, 1, &diskid )) return; - - /* now find the diskid in the SourceDisksNames section */ - if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return; - for (;;) - { - if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break; - if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return; - } - - /* and fill in the missing info */ - - if (!op->src_descr) - { - if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) && - (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ))) - SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL ); - } - if (!op->src_tag) - { - if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) && - (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ))) - SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL ); - } - if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE)) - { - len = len2 = 0; - if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE)) - { - /* retrieve relative path for this disk */ - if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0; - } - /* retrieve relative path for this file */ - if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0; - - if ((len || len2) && - (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) ))) - { - WCHAR *ptr = op->src_path; - if (len) - { - SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL ); - ptr = op->src_path + strlenW(op->src_path); - if (len2 && ptr > op->src_path && ptr[-1] != '\') *ptr++ = '\'; - } - if (!SetupGetStringFieldW( &file_ctx, 2, ptr, len2, NULL )) *ptr = 0; - } - } - if (!op->src_root) op->src_root = PARSER_get_src_root(hinf); -} - static void get_source_info( HINF hinf, const WCHAR *src_file, SP_FILE_COPY_PARAMS_W *params, WCHAR *src_root, WCHAR *src_path) { @@ -557,10 +481,7 @@ BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params ) /* some defaults */ if (!op->src_file) op->src_file = op->dst_file; if (params->LayoutInf) - { - get_src_file_info( params->LayoutInf, op ); - if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file ); - } + FIXME("Unhandled LayoutInf %p.\n", params->LayoutInf);
TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n", debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file), diff --git a/dlls/setupapi/setupapi_private.h b/dlls/setupapi/setupapi_private.h index 1df96b1e7d..f4685ab2b4 100644 --- a/dlls/setupapi/setupapi_private.h +++ b/dlls/setupapi/setupapi_private.h @@ -90,7 +90,6 @@ static inline WCHAR *strdupAtoW( const char *str ) struct inf_file; extern const WCHAR *DIRID_get_string( int dirid ) DECLSPEC_HIDDEN; extern const WCHAR *PARSER_get_inf_filename( HINF hinf ) DECLSPEC_HIDDEN; -extern WCHAR *PARSER_get_src_root( HINF hinf ) DECLSPEC_HIDDEN; extern WCHAR *PARSER_get_dest_dir( INFCONTEXT *context ) DECLSPEC_HIDDEN;
/* support for Ascii queue callback functions */
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51708
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 Task: Patch failed to apply
So as to centralize SPFILENOTIFY_COPYERROR callbacks into one place.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/queue.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-)
diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c index ae50ee6878..872cd6a4ea 100644 --- a/dlls/setupapi/queue.c +++ b/dlls/setupapi/queue.c @@ -1228,6 +1228,24 @@ BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source return SetupInstallFileExW( hinf, inf_context, source, root, dest, style, handler, context, NULL ); }
+static BOOL queue_copy_file( const WCHAR *source, const WCHAR *dest, + const struct file_op *op, PSP_FILE_CALLBACK_W handler, void *context ) +{ + TRACE("copying file %s -> %s\n", debugstr_w(source), debugstr_w(dest)); + + if (op->dst_path && !create_full_pathW(op->dst_path)) + return FALSE; + + if (do_file_copyW(source, dest, op->style, handler, context)) + return TRUE; + + /* try to extract it from the cabinet file */ + if (op->src_tag && extract_cabinet_file(op->src_tag, op->src_root, op->src_file, dest)) + return TRUE; + + return FALSE; +} + /*********************************************************************** * SetupCommitFileQueueW (SETUPAPI.@) */ @@ -1312,27 +1330,10 @@ BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBAC if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT; while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH) { - TRACE( "copying file %s -> %s\n", - debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ), - debugstr_w(paths.Target) ); - if (op->dst_path) - { - if (!create_full_pathW( op->dst_path )) - { - paths.Win32Error = GetLastError(); - op_result = handler( context, SPFILENOTIFY_COPYERROR, - (UINT_PTR)&paths, (UINT_PTR)newpath ); - if (op_result == FILEOP_ABORT) goto done; - } - } - if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source, - paths.Target, op->style, handler, context )) break; /* success */ - /* try to extract it from the cabinet file */ - if (op->src_tag) - { - if (extract_cabinet_file( op->src_tag, op->src_root, - op->src_file, paths.Target )) break; - } + if (queue_copy_file( op_result == FILEOP_NEWPATH ? newpath : paths.Source, + paths.Target, op, handler, context )) + break; + paths.Win32Error = GetLastError(); op_result = handler( context, SPFILENOTIFY_COPYERROR, (UINT_PTR)&paths, (UINT_PTR)newpath );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51709
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 Task: Patch failed to apply
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/queue.c | 122 ++++++++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 51 deletions(-)
diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c index 872cd6a4ea..fce8336aa1 100644 --- a/dlls/setupapi/queue.c +++ b/dlls/setupapi/queue.c @@ -51,17 +51,21 @@ struct default_callback_context DWORD_PTR unk3[5]; };
+struct source_media +{ + WCHAR root[MAX_PATH]; + WCHAR *desc, *tag; +}; + struct file_op { struct file_op *next; UINT style; - WCHAR *src_root; WCHAR *src_path; WCHAR *src_file; - WCHAR *src_descr; - WCHAR *src_tag; WCHAR *dst_path; WCHAR *dst_file; + struct source_media *media; };
struct file_op_queue @@ -76,7 +80,9 @@ struct file_queue struct file_op_queue copy_queue; struct file_op_queue delete_queue; struct file_op_queue rename_queue; - DWORD flags; + DWORD flags; + struct source_media **sources; + unsigned int source_count; };
@@ -97,11 +103,8 @@ static void free_file_op_queue( struct file_op_queue *queue )
while( op ) { - HeapFree( GetProcessHeap(), 0, op->src_root ); HeapFree( GetProcessHeap(), 0, op->src_path ); HeapFree( GetProcessHeap(), 0, op->src_file ); - HeapFree( GetProcessHeap(), 0, op->src_descr ); - HeapFree( GetProcessHeap(), 0, op->src_tag ); HeapFree( GetProcessHeap(), 0, op->dst_path ); if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file ); t = op; @@ -145,7 +148,7 @@ static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths ) unsigned int src_len = 1, dst_len = 1; WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
- if (op->src_root) src_len += strlenW(op->src_root) + 1; + if (op->media) src_len += strlenW(op->media->root) + 1; if (op->src_path) src_len += strlenW(op->src_path) + 1; if (op->src_file) src_len += strlenW(op->src_file) + 1; if (op->dst_path) dst_len += strlenW(op->dst_path) + 1; @@ -164,7 +167,7 @@ static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths ) paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len ); } if (!source || !target) return FALSE; - concat_W( source, op->src_root, op->src_path, op->src_file ); + concat_W( source, op->media ? op->media->root : NULL, op->src_path, op->src_file ); concat_W( target, NULL, op->dst_path, op->dst_file ); paths->Win32Error = 0; paths->Flags = 0; @@ -416,10 +419,18 @@ HSPFILEQ WINAPI SetupOpenFileQueue(void) BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle ) { struct file_queue *queue = handle; + unsigned int i;
free_file_op_queue( &queue->copy_queue ); free_file_op_queue( &queue->rename_queue ); free_file_op_queue( &queue->delete_queue ); + for (i = 0; i < queue->source_count; ++i) + { + heap_free( queue->sources[i]->desc ); + heap_free( queue->sources[i]->tag ); + heap_free( queue->sources[i] ); + } + heap_free( queue->sources ); HeapFree( GetProcessHeap(), 0, queue ); return TRUE; } @@ -459,22 +470,48 @@ BOOL WINAPI SetupQueueCopyIndirectA( SP_FILE_COPY_PARAMS_A *paramsA ) return ret; }
+static BOOL equal_str(const WCHAR *a, const WCHAR *b) +{ + return (!a && !b) || (a && b && !strcmpW(a, b)); +} + +static struct source_media *get_source_media(struct file_queue *queue, + const WCHAR *root, const WCHAR *desc, const WCHAR *tag) +{ + unsigned int i; + + for (i = 0; i < queue->source_count; ++i) + { + if (!strcmpW(root, queue->sources[i]->root) + && equal_str(desc, queue->sources[i]->desc) + && equal_str(tag, queue->sources[i]->tag)) + { + return queue->sources[i]; + } + } + + queue->sources = heap_realloc( queue->sources, ++queue->source_count * sizeof(*queue->sources) ); + queue->sources[i] = heap_alloc( sizeof(*queue->sources[i]) ); + strcpyW(queue->sources[i]->root, root); + queue->sources[i]->desc = strdupW(desc); + queue->sources[i]->tag = strdupW(tag); + + return queue->sources[i]; +}
/*********************************************************************** * SetupQueueCopyIndirectW (SETUPAPI.@) */ BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params ) { + static const WCHAR emptyW[] = {0}; struct file_queue *queue = params->QueueHandle; struct file_op *op;
if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; op->style = params->CopyStyle; - op->src_root = strdupW( params->SourceRootPath ); op->src_path = strdupW( params->SourcePath ); op->src_file = strdupW( params->SourceFilename ); - op->src_descr = strdupW( params->SourceDescription ); - op->src_tag = strdupW( params->SourceTagfile ); op->dst_path = strdupW( params->TargetDirectory ); op->dst_file = strdupW( params->TargetFilename );
@@ -483,10 +520,13 @@ BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params ) if (params->LayoutInf) FIXME("Unhandled LayoutInf %p.\n", params->LayoutInf);
+ op->media = get_source_media( queue, params->SourceRootPath ? params->SourceRootPath : emptyW, + params->SourceDescription, params->SourceTagfile ); + TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n", - debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file), + debugstr_w(op->media->root), debugstr_w(op->src_path), debugstr_w(op->src_file), debugstr_w(op->dst_path), debugstr_w(op->dst_file), - debugstr_w(op->src_descr), debugstr_w(op->src_tag) ); + debugstr_w(op->media->desc), debugstr_w(op->media->tag) );
queue_file_op( &queue->copy_queue, op ); return TRUE; @@ -614,15 +654,9 @@ BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 ) struct file_queue *queue = handle; struct file_op *op;
- if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; - op->style = 0; - op->src_root = NULL; - op->src_path = NULL; - op->src_file = NULL; - op->src_descr = NULL; - op->src_tag = NULL; - op->dst_path = strdupAtoW( part1 ); - op->dst_file = strdupAtoW( part2 ); + if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE; + op->dst_path = strdupAtoW( part1 ); + op->dst_file = strdupAtoW( part2 ); queue_file_op( &queue->delete_queue, op ); return TRUE; } @@ -636,15 +670,9 @@ BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 ) struct file_queue *queue = handle; struct file_op *op;
- if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; - op->style = 0; - op->src_root = NULL; - op->src_path = NULL; - op->src_file = NULL; - op->src_descr = NULL; - op->src_tag = NULL; - op->dst_path = strdupW( part1 ); - op->dst_file = strdupW( part2 ); + if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE; + op->dst_path = strdupW( part1 ); + op->dst_file = strdupW( part2 ); queue_file_op( &queue->delete_queue, op ); return TRUE; } @@ -659,15 +687,11 @@ BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFi struct file_queue *queue = handle; struct file_op *op;
- if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; - op->style = 0; - op->src_root = NULL; - op->src_path = strdupAtoW( SourcePath ); - op->src_file = strdupAtoW( SourceFilename ); - op->src_descr = NULL; - op->src_tag = NULL; - op->dst_path = strdupAtoW( TargetPath ); - op->dst_file = strdupAtoW( TargetFilename ); + if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE; + op->src_path = strdupAtoW( SourcePath ); + op->src_file = strdupAtoW( SourceFilename ); + op->dst_path = strdupAtoW( TargetPath ); + op->dst_file = strdupAtoW( TargetFilename ); queue_file_op( &queue->rename_queue, op ); return TRUE; } @@ -682,15 +706,11 @@ BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR Source struct file_queue *queue = handle; struct file_op *op;
- if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; - op->style = 0; - op->src_root = NULL; - op->src_path = strdupW( SourcePath ); - op->src_file = strdupW( SourceFilename ); - op->src_descr = NULL; - op->src_tag = NULL; - op->dst_path = strdupW( TargetPath ); - op->dst_file = strdupW( TargetFilename ); + if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE; + op->src_path = strdupW( SourcePath ); + op->src_file = strdupW( SourceFilename ); + op->dst_path = strdupW( TargetPath ); + op->dst_file = strdupW( TargetFilename ); queue_file_op( &queue->rename_queue, op ); return TRUE; } @@ -1240,7 +1260,7 @@ static BOOL queue_copy_file( const WCHAR *source, const WCHAR *dest, return TRUE;
/* try to extract it from the cabinet file */ - if (op->src_tag && extract_cabinet_file(op->src_tag, op->src_root, op->src_file, dest)) + if (op->media->tag && extract_cabinet_file(op->media->tag, op->media->root, op->src_file, dest)) return TRUE;
return FALSE;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51710
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 Task: Patch failed to apply
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/queue.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c index fce8336aa1..b7b7210d5a 100644 --- a/dlls/setupapi/queue.c +++ b/dlls/setupapi/queue.c @@ -1601,8 +1601,12 @@ UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification, debugstr_a(paths->Source), debugstr_a(paths->Target) ); return FILEOP_SKIP; case SPFILENOTIFY_NEEDMEDIA: - TRACE( "need media\n" ); - return FILEOP_SKIP; + { + const SOURCE_MEDIA_A *media = (const SOURCE_MEDIA_A *)param1; + TRACE( "need media %s %s\n", debugstr_a(media->SourcePath), debugstr_a(media->SourceFile) ); + strcpy( (char *)param2, media->SourcePath ); + return FILEOP_DOIT; + } default: FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 ); break; @@ -1666,8 +1670,12 @@ UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification, debugstr_w(paths->Source), debugstr_w(paths->Target) ); return FILEOP_SKIP; case SPFILENOTIFY_NEEDMEDIA: - TRACE( "need media\n" ); - return FILEOP_SKIP; + { + const SOURCE_MEDIA_W *media = (const SOURCE_MEDIA_W *)param1; + TRACE( "need media %s %s\n", debugstr_w(media->SourcePath), debugstr_w(media->SourceFile) ); + strcpyW( (WCHAR *)param2, media->SourcePath ); + return FILEOP_DOIT; + } default: FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 ); break;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51711
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 Task: Patch failed to apply
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/queue.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c index b7b7210d5a..f6621b7217 100644 --- a/dlls/setupapi/queue.c +++ b/dlls/setupapi/queue.c @@ -247,7 +247,27 @@ UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification, break;
case SPFILENOTIFY_NEEDMEDIA: - FIXME("mapping for %d not implemented\n",notification); + { + const SOURCE_MEDIA_W *mediaW = (const SOURCE_MEDIA_W *)param1; + char path[MAX_PATH] = {0}; + SOURCE_MEDIA_A mediaA; + + mediaA.Tagfile = strdupWtoA(mediaW->Tagfile); + mediaA.Description = strdupWtoA(mediaW->Description); + mediaA.SourcePath = strdupWtoA(mediaW->SourcePath); + mediaA.SourceFile = strdupWtoA(mediaW->SourceFile); + mediaA.Flags = mediaW->Flags; + + ret = callback_ctx->orig_handler(callback_ctx->orig_context, notification, + (UINT_PTR)&mediaA, (UINT_PTR)&path); + MultiByteToWideChar(CP_ACP, 0, path, -1, (WCHAR *)param2, MAX_PATH); + + heap_free((char *)mediaA.Tagfile); + heap_free((char *)mediaA.Description); + heap_free((char *)mediaA.SourcePath); + heap_free((char *)mediaA.SourceFile); + break; + } case SPFILENOTIFY_STARTQUEUE: case SPFILENOTIFY_ENDQUEUE: case SPFILENOTIFY_STARTSUBQUEUE:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51712
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 Task: Patch failed to apply
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/queue.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c index f6621b7217..9e22c409a7 100644 --- a/dlls/setupapi/queue.c +++ b/dlls/setupapi/queue.c @@ -122,6 +122,7 @@ static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const strcpyW( buffer, src1 ); buffer += strlenW(buffer ); if (buffer[-1] != '\') *buffer++ = '\'; + *buffer = 0; if (src2) while (*src2 == '\') src2++; }
@@ -130,6 +131,7 @@ static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const strcpyW( buffer, src2 ); buffer += strlenW(buffer ); if (buffer[-1] != '\') *buffer++ = '\'; + *buffer = 0; if (src3) while (*src3 == '\') src3++; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51713
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 Task: Patch failed to apply
Do not do the reverse. Windows crashes if SourceFilename is NULL.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c index 9e22c409a7..675462f09c 100644 --- a/dlls/setupapi/queue.c +++ b/dlls/setupapi/queue.c @@ -538,7 +538,7 @@ BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params ) op->dst_file = strdupW( params->TargetFilename );
/* some defaults */ - if (!op->src_file) op->src_file = op->dst_file; + if (!op->dst_file) op->dst_file = op->src_file; if (params->LayoutInf) FIXME("Unhandled LayoutInf %p.\n", params->LayoutInf);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51714
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 Task: Patch failed to apply
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 ); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51715
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 error: patch failed: dlls/setupapi/queue.c:55 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 error: patch failed: dlls/setupapi/queue.c:55 Task: Patch failed to apply
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/tests/install.c | 728 ++++++++++++++++++++++++++++++++++ 1 file changed, 728 insertions(+)
diff --git a/dlls/setupapi/tests/install.c b/dlls/setupapi/tests/install.c index 32002a97b9..15b789fe82 100644 --- a/dlls/setupapi/tests/install.c +++ b/dlls/setupapi/tests/install.c @@ -1088,6 +1088,733 @@ static void test_install_files_queue(void) ok(ret, "Failed to delete INF file, error %u.\n", GetLastError()); }
+static unsigned int got_need_media, got_copy_error; +static unsigned int testmode; + +static UINT WINAPI need_media_cb(void *context, UINT message, UINT_PTR param1, UINT_PTR param2) +{ + if (winetest_debug > 1) trace("%p, %#x, %#lx, %#lx\n", context, message, param1, param2); + + if (message == SPFILENOTIFY_NEEDMEDIA) + { + const SOURCE_MEDIA_A *media = (const SOURCE_MEDIA_A *)param1; + char *path = (char *)param2; + UINT ret; + + /* The default callback will fill out SourcePath, but as long as DOIT + * is returned, it's ignored. */ + ok(!path[0], "Test %u: got path '%s'.\n", testmode, path); + ret = SetupDefaultQueueCallbackA(context, message, param1, param2); + ok(!strcmp(path, media->SourcePath), "Test %u: got path '%s'.\n", testmode, path); + ok(ret == FILEOP_DOIT, "Got unexpected return value %u.\n", ret); + path[0] = 0; + + if (testmode == 0) + ok(media->Flags == SP_COPY_WARNIFSKIP, "Got Flags %#x.\n", media->Flags); + else + ok(!media->Flags, "Got Flags %#x for test %u.\n", media->Flags, testmode); + + switch (testmode) + { + case 0: + ok(!media->Tagfile, "Got Tagfile '%s'.\n", media->Tagfile); + ok(!strcmp(media->Description, "File One"), "Got Description '%s'.\n", media->Description); + ok(!strcmp(media->SourcePath, "src"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "one.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + case 1: + ok(!media->Tagfile, "Got Tagfile '%s'.\n", media->Tagfile); + ok(!media->Description, "Got Description '%s'.\n", media->Description); + ok(!strcmp(media->SourcePath, "src\beta"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "two.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + case 2: + ok(!strcmp(media->Tagfile, "faketag"), "Got Tagfile '%s'.\n", media->Tagfile); + ok(!strcmp(media->Description, "desc"), "Got Description '%s'.\n", media->Description); + ok(!strcmp(media->SourcePath, "src\beta"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "two.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + case 3: + ok(!media->Tagfile, "Got Tagfile '%s'.\n", media->Tagfile); + ok(!strcmp(media->Description, "heis"), "Got Description '%s'.\n", media->Description); + ok(!strcmp(media->SourcePath, "src"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "one.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + case 4: + ok(!media->Tagfile, "Got Tagfile '%s'.\n", media->Tagfile); + ok(!strcmp(media->Description, "heis"), "Got Description '%s'.\n", media->Description); + ok(!strcmp(media->SourcePath, "src\beta"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "two.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + case 5: + ok(!media->Tagfile, "Got Tagfile '%s'.\n", media->Tagfile); + ok(!strcmp(media->Description, "duo"), "Got Description '%s'.\n", media->Description); + ok(!strcmp(media->SourcePath, "src\alpha"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "three.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + case 6: + ok(!strcmp(media->SourcePath, "src"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "one.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + testmode = 7; + break; + case 7: + ok(!strcmp(media->SourcePath, "src/alpha"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "three.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + case 8: + ok(!strcmp(media->SourcePath, "src"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "one.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + testmode = 9; + break; + case 9: + ok(!strcmp(media->SourcePath, "src\alpha"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "three.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + case 10: + ok(!strcmp(media->Description, "desc1"), "Got description '%s'.\n", media->Description); + ok(!strcmp(media->SourcePath, "src"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "one.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + testmode = 11; + break; + case 11: + ok(!media->Description, "Got description '%s'.\n", media->Description); + ok(!strcmp(media->SourcePath, "src\beta"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "two.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + case 12: + ok(!strcmp(media->Description, "desc1"), "Got description '%s'.\n", media->Description); + ok(!strcmp(media->Tagfile, "faketag"), "Got Tagfile '%s'.\n", media->Tagfile); + ok(!strcmp(media->SourcePath, "src"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "one.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + testmode = 13; + break; + case 13: + ok(!strcmp(media->Description, "desc1"), "Got description '%s'.\n", media->Description); + ok(!strcmp(media->Tagfile, "faketag2"), "Got Tagfile '%s'.\n", media->Tagfile); + ok(!strcmp(media->SourcePath, "src\beta"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "two.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + case 14: + ok(!strcmp(media->Description, "desc"), "Got description '%s'.\n", media->Description); + ok(!strcmp(media->Tagfile, "treis.cab"), "Got Tagfile '%s'.\n", media->Tagfile); + ok(!strcmp(media->SourcePath, "src"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "four.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + case 15: + ok(!strcmp(media->Description, "desc"), "Got description '%s'.\n", media->Description); + ok(!strcmp(media->Tagfile, "tessares.cab"), "Got Tagfile '%s'.\n", media->Tagfile); + ok(!strcmp(media->SourcePath, "src\alpha"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "seven.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + case 16: + ok(!media->Description, "Got description '%s'.\n", media->Description); + ok(!strcmp(media->SourcePath, "src/alpha"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "six.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + break; + } + + ++got_need_media; + + return ret; + } + else if (message == SPFILENOTIFY_COPYERROR) + { + const FILEPATHS_A *paths = (const FILEPATHS_A *)param1; + ok(0, "Got unexpected copy error %s -> %s.\n", paths->Source, paths->Target); + } + + return SetupDefaultQueueCallbackA(context, message, param1, param2); +} + +static UINT WINAPI need_media_newpath_cb(void *context, UINT message, UINT_PTR param1, UINT_PTR param2) +{ + if (winetest_debug > 1) trace("%p, %#x, %#lx, %#lx\n", context, message, param1, param2); + + if (message == SPFILENOTIFY_NEEDMEDIA) + { + const SOURCE_MEDIA_A *media = (const SOURCE_MEDIA_A *)param1; + char *path = (char *)param2; + + ++got_need_media; + + if (testmode == 1) + strcpy(path, "src\alpha"); + else if (testmode == 2) + { + if (got_need_media == 1) + strcpy(path, "src\alpha"); + else + { + ok(!strcmp(media->SourcePath, "src\alpha"), "Got SourcePath '%s'.\n", media->SourcePath); + strcpy(path, "src"); + } + } + else if (testmode == 5) + { + if (got_need_media == 1) + { + ok(!strcmp(media->SourcePath, "fake"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "one.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + return FILEOP_SKIP; + } + else + { + ok(!strcmp(media->SourcePath, "fake\alpha"), "Got SourcePath '%s'.\n", media->SourcePath); + ok(!strcmp(media->SourceFile, "three.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + strcpy(path, "src\alpha"); + } + } + else if (testmode == 6) + { + /* SourcePath is not really consistent here, but it's not supplied + * from the INF file. Usually it's a drive root, but not always. */ + ok(!strcmp(media->SourceFile, "one.txt"), "Got SourceFile '%s'.\n", media->SourceFile); + ok(!media->Description, "Got Description '%s'.\n", media->Description); + ok(!media->Tagfile, "Got Tagfile '%s'.\n", media->Tagfile); + strcpy(path, "src"); + } + else + strcpy(path, "src"); + + return FILEOP_NEWPATH; + } + else if (message == SPFILENOTIFY_COPYERROR) + { + char *path = (char *)param2; + + ++got_copy_error; + + if (testmode == 3) + { + strcpy(path, "src\alpha"); + return FILEOP_NEWPATH; + } + else if (testmode == 4) + { + if (got_copy_error == 1) + strcpy(path, "fake2"); + else + strcpy(path, "src\alpha"); + return FILEOP_NEWPATH; + } + else + return FILEOP_SKIP; + } + + return SetupDefaultQueueCallbackA(context, message, param1, param2); +} + +#define run_queue(a,b) run_queue_(__LINE__,a,b) +static void run_queue_(unsigned int line, HSPFILEQ queue, PSP_FILE_CALLBACK_A cb) +{ + void *context = SetupInitDefaultQueueCallbackEx(NULL, INVALID_HANDLE_VALUE, 0, 0, 0); + BOOL ret; + ok_(__FILE__,line)(!!context, "Failed to create callback context, error %#x.\n", GetLastError()); + ret = SetupCommitFileQueueA(NULL, queue, cb, context); + ok_(__FILE__,line)(ret, "Failed to commit queue, error %#x.\n", GetLastError()); + SetupTermDefaultQueueCallback(context); + ret = SetupCloseFileQueue(queue); + ok_(__FILE__,line)(ret, "Failed to close queue, error %#x.\n", GetLastError()); +} + +static void test_need_media(void) +{ + static const char inf_data[] = "[Version]\n" + "Signature="$Chicago$"\n" + "[section1]\n" + "one.txt\n" + "[section2]\n" + "two.txt\n" + "[section3]\n" + "three.txt\n" + "[section4]\n" + "one.txt\n" + "two.txt\n" + "three.txt\n" + "[install_section]\n" + "CopyFiles=section1\n" + "[SourceDisksNames]\n" + "1=heis\n" + "2=duo,,,alpha\n" + "[SourceDisksFiles]\n" + "one.txt=1\n" + "two.txt=1,beta\n" + "three.txt=2\n" + "[DestinationDirs]\n" + "DefaultDestDir=40000,dst\n"; + + SP_FILE_COPY_PARAMS_A copy_params = {sizeof(copy_params)}; + char path[MAX_PATH]; + HSPFILEQ queue; + HINF hinf; + BOOL ret; + + create_inf_file(inffile, inf_data); + + sprintf(path, "%s\%s", CURR_DIR, inffile); + hinf = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL); + ok(hinf != INVALID_HANDLE_VALUE, "Failed to open INF file, error %#x.\n", GetLastError()); + + ret = CreateDirectoryA("src", NULL); + ok(ret, "Failed to create test directory, error %u.\n", GetLastError()); + ret = CreateDirectoryA("src/alpha", NULL); + ok(ret, "Failed to create test directory, error %u.\n", GetLastError()); + ret = CreateDirectoryA("src/beta", NULL); + ok(ret, "Failed to create test directory, error %u.\n", GetLastError()); + ret = CreateDirectoryA("dst", NULL); + ok(ret, "Failed to create test directory, error %u.\n", GetLastError()); + create_file("src/one.txt"); + create_file("src/beta/two.txt"); + create_file("src/alpha/three.txt"); + create_file("src/alpha/six.txt"); + create_cab_file("src/treis.cab", "four.txt\0five.txt\0"); + create_cab_file("src/alpha/tessares.cab", "seven.txt\0eight.txt\0"); + + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", NULL, "one.txt", "File One", NULL, "dst", NULL, SP_COPY_WARNIFSKIP); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + + /* Test with a subdirectory. */ + + got_need_media = 0; + testmode = 1; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", "beta", "two.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/two.txt"), "Destination file should exist.\n"); + + /* Test with a tag file. */ + + got_need_media = 0; + testmode = 2; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", "beta", "two.txt", "desc", "faketag", "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/two.txt"), "Destination file should exist.\n"); + + /* Test from INF file. */ + + got_need_media = 0; + testmode = 3; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopySectionA(queue, "src", hinf, NULL, "section1", 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + + got_need_media = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupInstallFilesFromInfSectionA(hinf, NULL, queue, "install_section", "src", 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + + got_need_media = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + + ret = SetupQueueDefaultCopyA(queue, hinf, "src", NULL, "one.txt", 0); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got error %#x.\n", GetLastError()); + + ret = SetupQueueDefaultCopyA(queue, hinf, "src", "one.txt", "one.txt", 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + + got_need_media = 0; + testmode = 4; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopySectionA(queue, "src", hinf, NULL, "section2", 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/two.txt"), "Destination file should exist.\n"); + + got_need_media = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueDefaultCopyA(queue, hinf, "src", "two.txt", "two.txt", 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/two.txt"), "Destination file should exist.\n"); + + got_need_media = 0; + testmode = 5; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopySectionA(queue, "src", hinf, NULL, "section3", 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + + got_need_media = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueDefaultCopyA(queue, hinf, "src", "three.txt", "three.txt", 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + + /* One callback is sent per source directory. */ + + got_need_media = 0; + testmode = 6; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", NULL, "one.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", "beta", "two.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src/alpha", NULL, "three.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 2, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/two.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + + /* The same rules apply to INF files. Here the subdir specified in the + * SourceDisksNames counts as part of the root directory, but the subdir in + * SourceDisksFiles does not. */ + + got_need_media = 0; + testmode = 8; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopySectionA(queue, "src", hinf, NULL, "section4", 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError());\ + run_queue(queue, need_media_cb); + ok(got_need_media == 2, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/two.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + + /* Descriptions and tag files also distinguish source paths. */ + + got_need_media = 0; + testmode = 10; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", NULL, "one.txt", "desc1", NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", "beta", "two.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 2, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/two.txt"), "Destination file should exist.\n"); + + got_need_media = 0; + testmode = 12; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", NULL, "one.txt", "desc1", "faketag", "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", "beta", "two.txt", "desc1", "faketag2", "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 2, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/two.txt"), "Destination file should exist.\n"); + + /* Test from cabinets. Subdir is only relevant for the first argument. */ + + got_need_media = 0; + testmode = 14; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", NULL, "four.txt", "desc", "treis.cab", "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", "alpha", "five.txt", "desc", "treis.cab", "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/four.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/five.txt"), "Destination file should exist.\n"); + + got_need_media = 0; + testmode = 15; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", "alpha", "seven.txt", "desc", "tessares.cab", "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", NULL, "eight.txt", "desc", "tessares.cab", "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/seven.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/eight.txt"), "Destination file should exist.\n"); + + got_need_media = 0; + testmode = 16; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueDefaultCopyA(queue, hinf, "src/alpha", "six.txt", "six.txt", 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/six.txt"), "Destination file should exist.\n"); + + /* Test absolute paths. */ + + got_need_media = 0; + testmode = 1; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", "beta", "two.txt", NULL, NULL, "dst", NULL, SP_COPY_SOURCE_ABSOLUTE); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/two.txt"), "Destination file should exist.\n"); + + got_need_media = 0; + testmode = 1; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", "beta", "two.txt", NULL, NULL, "dst", NULL, SP_COPY_SOURCEPATH_ABSOLUTE); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/two.txt"), "Destination file should exist.\n"); + + got_need_media = 0; + testmode = 5; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopySectionA(queue, "src", hinf, NULL, "section3", SP_COPY_SOURCE_ABSOLUTE); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + + got_need_media = 0; + testmode = 5; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopySectionA(queue, "src", hinf, NULL, "section3", SP_COPY_SOURCEPATH_ABSOLUTE); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + + /* Test returning a new path from the NEEDMEDIA callback. */ + + testmode = 0; + got_need_media = got_copy_error = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "one.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", "alpha", "three.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_newpath_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(!got_copy_error, "Got %u copy errors.\n", got_copy_error); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + + /* setupapi expects the callback to return the path including the subdir + * for the first file. It then strips off the final element. If the final + * element doesn't match the given subdir exactly, then it's not stripped. + * To make matters even stranger, the first file copied effectively has its + * subdir removed. */ + + testmode = 1; + got_need_media = got_copy_error = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", "alpha", "three.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", "beta", "two.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_newpath_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(!got_copy_error, "Got %u copy errors.\n", got_copy_error); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/two.txt"), "Destination file should exist.\n"); + + got_need_media = got_copy_error = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", "alpha\", "three.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "six.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_newpath_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(!got_copy_error, "Got %u copy errors.\n", got_copy_error); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/six.txt"), "Destination file should exist.\n"); + + /* If the source file does not exist (even if the path is valid), + * SPFILENOTIFY_NEEDMEDIA is resent until it does. */ + + testmode = 2; + got_need_media = got_copy_error = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "one.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", "alpha", "three.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_newpath_cb); + ok(got_need_media == 2, "Got %u callbacks.\n", got_need_media); + ok(!got_copy_error, "Got %u copy errors.\n", got_copy_error); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + + /* If a following file doesn't exist, it results in a copy error instead. */ + + testmode = 0; + got_need_media = got_copy_error = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "one.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "fake.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_newpath_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(got_copy_error == 1, "Got %u copy errors.\n", got_copy_error); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + + /* Test providing a new path from SPFILENOTIFY_COPYERROR. */ + + testmode = 3; + got_need_media = got_copy_error = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "one.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "three.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "six.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_newpath_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(got_copy_error == 1, "Got %u copy errors.\n", got_copy_error); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/six.txt"), "Destination file should exist.\n"); + + /* SPFILENOTIFY_COPYERROR will also be resent until the copy is successful. */ + + testmode = 4; + got_need_media = got_copy_error = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "one.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "three.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "six.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_newpath_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(got_copy_error == 2, "Got %u copy errors.\n", got_copy_error); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/six.txt"), "Destination file should exist.\n"); + + /* Test with cabinet. As above, subdir only matters for the first file. */ + + testmode = 0; + got_need_media = got_copy_error = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "four.txt", "desc", "treis.cab", "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", "alpha", "five.txt", "desc", "treis.cab", "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_newpath_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(!got_copy_error, "Got %u copy errors.\n", got_copy_error); + ok(delete_file("dst/four.txt"), "Destination file should exist.\n"); + ok(delete_file("dst/five.txt"), "Destination file should exist.\n"); + + /* Test returning FILEOP_SKIP from the NEEDMEDIA handler. */ + + testmode = 5; + got_need_media = got_copy_error = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", NULL, "one.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "fake", "alpha", "three.txt", NULL, NULL, "dst", NULL, 0); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_newpath_cb); + ok(got_need_media == 2, "Got %u callbacks.\n", got_need_media); + ok(!got_copy_error, "Got %u copy errors.\n", got_copy_error); + ok(!file_exists("dst/one.txt"), "Destination file should not exist.\n"); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + + testmode = 6; + got_need_media = got_copy_error = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + copy_params.QueueHandle = queue; + copy_params.SourceFilename = "one.txt"; + /* Leaving TargetDirectory NULL causes it to be filled with garbage on + * Windows, so the copy may succeed or fail. In any case it's not supplied + * from LayoutInf. */ + copy_params.TargetDirectory = "dst"; + ret = SetupQueueCopyIndirectA(©_params); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_newpath_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(!got_copy_error, "Got %u copy errors.\n", got_copy_error); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + + got_need_media = got_copy_error = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + copy_params.LayoutInf = hinf; + /* In fact this fails with ERROR_INVALID_PARAMETER on 8+. */ + if (SetupQueueCopyIndirectA(©_params)) + { + run_queue(queue, need_media_newpath_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(!got_copy_error, "Got %u copy errors.\n", got_copy_error); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + } + else + SetupCloseFileQueue(queue); + + SetupCloseInfFile(hinf); + delete_file("src/one.txt"); + delete_file("src/beta/two.txt"); + delete_file("src/beta/"); + delete_file("src/alpha/six.txt"); + delete_file("src/alpha/three.txt"); + delete_file("src/alpha/tessares.cab"); + delete_file("src/alpha/"); + delete_file("src/treis.cab"); + delete_file("src/"); + delete_file("dst/"); + ret = DeleteFileA(inffile); + ok(ret, "Failed to delete INF file, error %u.\n", GetLastError()); +} + START_TEST(install) { char temp_path[MAX_PATH], prev_path[MAX_PATH]; @@ -1113,6 +1840,7 @@ START_TEST(install) test_driver_install(); test_dirid(); test_install_files_queue(); + test_need_media();
UnhookWindowsHookEx(hhook);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51716
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 error: patch failed: dlls/setupapi/queue.c:55 error: patch failed: dlls/setupapi/tests/install.c:1088 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/setupapi/tests/install.c:1065 error: patch failed: dlls/setupapi/queue.c:1312 error: patch failed: dlls/setupapi/queue.c:1240 error: patch failed: dlls/setupapi/queue.c:55 error: patch failed: dlls/setupapi/tests/install.c:1088 Task: Patch failed to apply