[WINESYNC] setupapi/tests: Add tests for source media path resolution.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>

wine commit id d5a6a2675c250cffd7b37a27d61fc2031b1d7b21 by Zebediah Figura <z.figura12@gmail.com>

[WINESYNC] setupapi: Add magic bytes to struct file_queue and validate them in SetupCloseFileQueue().

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=12332
Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>

wine commit id c65d98065c0038e0919f40bec4a9dc978fb2ade9 by Zebediah Figura <z.figura12@gmail.com>
This commit is contained in:
winesync 2023-09-14 19:50:29 +02:00 committed by Hermès Bélusca-Maïto
parent 07b9b00664
commit 1a68e54d1b
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
3 changed files with 756 additions and 1 deletions

View file

@ -75,6 +75,7 @@ struct file_op_queue
struct file_queue
{
DWORD magic;
struct file_op_queue copy_queue;
struct file_op_queue delete_queue;
struct file_op_queue rename_queue;
@ -83,6 +84,7 @@ struct file_queue
unsigned int source_count;
};
#define FILE_QUEUE_MAGIC 0x21514653
/* append a file operation to a queue */
static inline void queue_file_op( struct file_op_queue *queue, struct file_op *op )
@ -522,6 +524,7 @@ HSPFILEQ WINAPI SetupOpenFileQueue(void)
if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
return INVALID_HANDLE_VALUE;
queue->magic = FILE_QUEUE_MAGIC;
return queue;
}
@ -534,6 +537,14 @@ BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
struct file_queue *queue = handle;
unsigned int i;
/* Windows XP DDK installer passes the handle returned from
* SetupInitDefaultQueueCallback() to this function. */
if (queue->magic != FILE_QUEUE_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
free_file_op_queue( &queue->copy_queue );
free_file_op_queue( &queue->rename_queue );
free_file_op_queue( &queue->delete_queue );

View file

@ -1088,6 +1088,748 @@ 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(&copy_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(&copy_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());
}
static void test_close_queue(void)
{
void *context;
BOOL ret;
context = SetupInitDefaultQueueCallback(NULL);
ok(!!context, "Failed to create callback context, error %#x.\n", GetLastError());
ret = SetupCloseFileQueue(context);
ok(!ret, "Expected failure.\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected error %u.\n", GetLastError());
SetupTermDefaultQueueCallback(context);
}
START_TEST(install)
{
char temp_path[MAX_PATH], prev_path[MAX_PATH];
@ -1113,6 +1855,8 @@ START_TEST(install)
test_driver_install();
test_dirid();
test_install_files_queue();
test_need_media();
test_close_queue();
UnhookWindowsHookEx(hhook);

View file

@ -8,4 +8,4 @@ files:
dlls/setupapi/setupcab.c: dll/win32/setupapi/setupcab.c
dlls/setupapi/stringtable.c: dll/win32/setupapi/stringtable_wine.c
tags:
wine: 3e5c9798a80641e0e39e95e4467c60405b22b062
wine: c65d98065c0038e0919f40bec4a9dc978fb2ade9