[PATCH 13/13] setupapi/tests: Add tests for source media path resolution.
Zebediah Figura
z.figura12 at gmail.com
Wed May 1 18:24:14 CDT 2019
Signed-off-by: Zebediah Figura <z.figura12 at 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);
--
2.21.0
More information about the wine-devel
mailing list