diff --git a/dll/win32/setupapi/queue.c b/dll/win32/setupapi/queue.c index 1371d406df7..1db159308b5 100644 --- a/dll/win32/setupapi/queue.c +++ b/dll/win32/setupapi/queue.c @@ -19,6 +19,7 @@ */ #include "setupapi_private.h" +#include "wine/heap.h" #ifdef __REACTOS__ #include @@ -29,6 +30,8 @@ static const WCHAR DotSecurity[] = {'.','S','e','c','u','r','i','t','y',0}; #endif +static const WCHAR backslashW[] = {'\\',0}; + /* context structure for the default queue callback */ struct default_callback_context { @@ -333,6 +336,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 @@ -347,7 +396,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 ))) @@ -466,39 +515,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; + SP_FILE_COPY_PARAMS_W paramsW; + BOOL ret; - 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 ); -#ifdef __REACTOS__ - op->dst_sd = NULL; -#endif + 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 ); - /* 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 ); - } + ret = SetupQueueCopyIndirectW( ¶msW ); - 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; + 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; } @@ -596,24 +641,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 ); } @@ -623,21 +665,43 @@ 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; +#ifdef __REACTOS__ params.LayoutInf = hinf; +#else + params.LayoutInf = NULL; +#endif 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; } @@ -773,25 +837,30 @@ 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; #ifdef __REACTOS__ LPWSTR security_key, security_descriptor = NULL; INFCONTEXT security_context; #endif INFCONTEXT context; - WCHAR dest[MAX_PATH], src[MAX_PATH], *dest_dir; + SP_FILE_COPY_PARAMS_W params; INT flags; BOOL ret; - 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; + } #ifdef __REACTOS__ /* Check for .Security section */ @@ -827,30 +896,47 @@ BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, 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; +#ifdef __REACTOS__ params.LayoutInf = hinf; +#else + params.LayoutInf = NULL; +#endif params.SecurityDescriptor = security_descriptor; + strcpyW( src_root_buffer, src_root ); + if (!hlist) hlist = hinf; if (!hinf) hinf = hlist; if (!SetupFindFirstLineW( hlist, section, NULL, &context )) goto done; if (!(params.TargetDirectory = dest_dir = get_destination_dir( hinf, section ))) goto done; 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); done: diff --git a/modules/rostests/winetests/setupapi/CMakeLists.txt b/modules/rostests/winetests/setupapi/CMakeLists.txt index 3292f3243df..630f5cba5f7 100644 --- a/modules/rostests/winetests/setupapi/CMakeLists.txt +++ b/modules/rostests/winetests/setupapi/CMakeLists.txt @@ -20,7 +20,7 @@ list(APPEND SOURCE add_executable(setupapi_winetest ${SOURCE} setupapi.rc) set_module_type(setupapi_winetest win32cui) target_link_libraries(setupapi_winetest uuid) -add_importlibs(setupapi_winetest advapi32 setupapi user32 shell32 msvcrt kernel32 ntdll) +add_importlibs(setupapi_winetest advapi32 cabinet setupapi user32 shell32 msvcrt kernel32 ntdll) add_rostests_file(TARGET setupapi_winetest) if(CMAKE_C_COMPILER_ID STREQUAL "GNU") diff --git a/modules/rostests/winetests/setupapi/install.c b/modules/rostests/winetests/setupapi/install.c index 42322125156..32002a97b92 100644 --- a/modules/rostests/winetests/setupapi/install.c +++ b/modules/rostests/winetests/setupapi/install.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "windef.h" #include "winbase.h" @@ -31,6 +31,7 @@ #include "winsvc.h" #include "setupapi.h" #include "shlobj.h" +#include "fci.h" #include "wine/test.h" @@ -59,12 +60,231 @@ static void create_inf_file(LPCSTR filename, const char *data) BOOL ret; HANDLE handle = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - assert(handle != INVALID_HANDLE_VALUE); + ok(handle != INVALID_HANDLE_VALUE, "Failed to create %s, error %u.\n", filename, GetLastError()); ret = WriteFile(handle, data, strlen(data), &res, NULL); - assert(ret != 0); + ok(ret, "Failed to write file, error %u.\n", GetLastError()); CloseHandle(handle); } +static void create_file(const char *filename) +{ + create_inf_file(filename, "dummy"); +} + +static BOOL delete_file(const char *filename) +{ + if (GetFileAttributesA(filename) & FILE_ATTRIBUTE_DIRECTORY) + return RemoveDirectoryA(filename); + else + return DeleteFileA(filename); +} + +static BOOL file_exists(const char *path) +{ + return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES; +} + +static void * CDECL mem_alloc(ULONG cb) +{ + return HeapAlloc(GetProcessHeap(), 0, cb); +} + +static void CDECL mem_free(void *memory) +{ + HeapFree(GetProcessHeap(), 0, memory); +} + +static BOOL CDECL get_next_cabinet(PCCAB pccab, ULONG cbPrevCab, void *pv) +{ + sprintf(pccab->szCab, pv, pccab->iCab); + return TRUE; +} + +static LONG CDECL progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv) +{ + return 0; +} + +static int CDECL file_placed(PCCAB pccab, char *pszFile, LONG cbFile, + BOOL fContinuation, void *pv) +{ + return 0; +} + +static INT_PTR CDECL fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) +{ + HANDLE handle; + DWORD dwAccess = 0; + DWORD dwShareMode = 0; + DWORD dwCreateDisposition = OPEN_EXISTING; + + dwAccess = GENERIC_READ | GENERIC_WRITE; + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + + if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES) + dwCreateDisposition = OPEN_EXISTING; + else + dwCreateDisposition = CREATE_NEW; + + handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL, + dwCreateDisposition, 0, NULL); + + ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszFile); + + return (INT_PTR)handle; +} + +static UINT CDECL fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) +{ + HANDLE handle = (HANDLE)hf; + DWORD dwRead; + BOOL res; + + res = ReadFile(handle, memory, cb, &dwRead, NULL); + ok(res, "Failed to ReadFile\n"); + + return dwRead; +} + +static UINT CDECL fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) +{ + HANDLE handle = (HANDLE)hf; + DWORD dwWritten; + BOOL res; + + res = WriteFile(handle, memory, cb, &dwWritten, NULL); + ok(res, "Failed to WriteFile\n"); + + return dwWritten; +} + +static int CDECL fci_close(INT_PTR hf, int *err, void *pv) +{ + HANDLE handle = (HANDLE)hf; + ok(CloseHandle(handle), "Failed to CloseHandle\n"); + + return 0; +} + +static LONG CDECL fci_seek(INT_PTR hf, LONG dist, int seektype, int *err, void *pv) +{ + HANDLE handle = (HANDLE)hf; + DWORD ret; + + ret = SetFilePointer(handle, dist, NULL, seektype); + ok(ret != INVALID_SET_FILE_POINTER, "Failed to SetFilePointer\n"); + + return ret; +} + +static int CDECL fci_delete(char *pszFile, int *err, void *pv) +{ + BOOL ret = DeleteFileA(pszFile); + ok(ret, "Failed to DeleteFile %s\n", pszFile); + + return 0; +} + +static BOOL CDECL get_temp_file(char *pszTempName, int cbTempName, void *pv) +{ + LPSTR tempname; + + tempname = HeapAlloc(GetProcessHeap(), 0, MAX_PATH); + GetTempFileNameA(".", "xx", 0, tempname); + + if (tempname && (strlen(tempname) < (unsigned)cbTempName)) + { + lstrcpyA(pszTempName, tempname); + HeapFree(GetProcessHeap(), 0, tempname); + return TRUE; + } + + HeapFree(GetProcessHeap(), 0, tempname); + + return FALSE; +} + +static INT_PTR CDECL get_open_info(char *pszName, USHORT *pdate, USHORT *ptime, + USHORT *pattribs, int *err, void *pv) +{ + BY_HANDLE_FILE_INFORMATION finfo; + FILETIME filetime; + HANDLE handle; + DWORD attrs; + BOOL res; + + handle = CreateFileA(pszName, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + + ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszName); + + res = GetFileInformationByHandle(handle, &finfo); + ok(res, "Expected GetFileInformationByHandle to succeed\n"); + + FileTimeToLocalFileTime(&finfo.ftLastWriteTime, &filetime); + FileTimeToDosDateTime(&filetime, pdate, ptime); + + attrs = GetFileAttributesA(pszName); + ok(attrs != INVALID_FILE_ATTRIBUTES, "Failed to GetFileAttributes\n"); + + return (INT_PTR)handle; +} + +static BOOL add_file(HFCI hfci, const char *file, TCOMP compress) +{ + char path[MAX_PATH]; + char filename[MAX_PATH]; + + lstrcpyA(path, CURR_DIR); + lstrcatA(path, "\\"); + lstrcatA(path, file); + + lstrcpyA(filename, file); + + return FCIAddFile(hfci, path, filename, FALSE, get_next_cabinet, + progress, get_open_info, compress); +} + +static void create_cab_file(const CHAR *name, const CHAR *files) +{ + CCAB cabParams = {0}; + LPCSTR ptr; + HFCI hfci; + ERF erf; + BOOL res; + + cabParams.cb = INT_MAX; + cabParams.cbFolderThresh = 900000; + cabParams.setID = 0xbeef; + cabParams.iCab = 1; + lstrcpyA(cabParams.szCabPath, CURR_DIR); + lstrcatA(cabParams.szCabPath, "\\"); + lstrcpyA(cabParams.szCab, name); + + hfci = FCICreate(&erf, file_placed, mem_alloc, mem_free, fci_open, + fci_read, fci_write, fci_close, fci_seek, fci_delete, + get_temp_file, &cabParams, NULL); + + ok(hfci != NULL, "Failed to create an FCI context\n"); + + ptr = files; + while (*ptr) + { + create_file(ptr); + res = add_file(hfci, ptr, tcompTYPE_MSZIP); + ok(res, "Failed to add file: %s\n", ptr); + res = DeleteFileA(ptr); + ok(res, "Failed to delete file %s, error %u\n", ptr, GetLastError()); + ptr += lstrlenA(ptr) + 1; + } + + res = FCIFlushCabinet(hfci, FALSE, get_next_cabinet, progress); + ok(res, "Failed to flush the cabinet\n"); + + res = FCIDestroy(hfci); + ok(res, "Failed to destroy the cabinet\n"); +} + /* CBT hook to ensure a window (e.g., MessageBox) cannot be created */ static HHOOK hhook; static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) @@ -761,6 +981,113 @@ static void test_dirid(void) check_dirid(40, expected); } +static void test_install_files_queue(void) +{ + static const char inf_data[] = "[Version]\n" + "Signature=\"$Chicago$\"\n" + "[DefaultInstall]\n" + "CopyFiles=files_section\n" + "[files_section]\n" + "one.txt\n" + "two.txt\n" + "three.txt\n" + "four.txt\n" + "five.txt\n" + "six.txt\n" + "seven.txt\n" + "eight.txt\n" + "[SourceDisksNames]\n" + "1=heis\n" + "2=duo,,,alpha\n" + "3=treis,treis.cab\n" + "4=tessares,tessares.cab,,alpha\n" + "[SourceDisksFiles]\n" + "one.txt=1\n" + "two.txt=1,beta\n" + "three.txt=2\n" + "four.txt=2,beta\n" + "five.txt=3\n" + "six.txt=3,beta\n" + "seven.txt=4\n" + "eight.txt=4,beta\n" + "[DestinationDirs]\n" + "files_section=40000,dst\n"; + + char path[MAX_PATH]; + HSPFILEQ queue; + void *context; + 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/alpha/beta", 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 = SetupSetDirectoryIdA(hinf, 40000, CURR_DIR); + ok(ret, "Failed to set directory ID, 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/beta/four.txt"); + create_cab_file("src/treis.cab", "src\\beta\\five.txt\0six.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()); + + context = SetupInitDefaultQueueCallbackEx(NULL, INVALID_HANDLE_VALUE, 0, 0, 0); + ok(!!context, "Failed to create callback context, error %#x.\n", GetLastError()); + + ret = SetupInstallFilesFromInfSectionA(hinf, NULL, queue, "DefaultInstall", "src", 0); + ok(ret, "Failed to install files, error %#x.\n", GetLastError()); + + ok(file_exists("src/one.txt"), "Source file should exist.\n"); + ok(!file_exists("dst/one.txt"), "Destination file should not exist.\n"); + + ret = SetupCommitFileQueueA(NULL, queue, SetupDefaultQueueCallbackA, context); + ok(ret, "Failed to commit queue, error %#x.\n", GetLastError()); + + ok(file_exists("src/one.txt"), "Source file should exist.\n"); + 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"); + 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"); + 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); + ok(ret, "Failed to close queue, error %#x.\n", GetLastError()); + + SetupCloseInfFile(hinf); + delete_file("src/one.txt"); + delete_file("src/beta/two.txt"); + delete_file("src/alpha/three.txt"); + delete_file("src/alpha/beta/four.txt"); + delete_file("src/treis.cab"); + delete_file("src/alpha/tessares.cab"); + delete_file("src/alpha/beta/"); + delete_file("src/alpha/"); + delete_file("src/beta/"); + 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]; @@ -777,7 +1104,7 @@ START_TEST(install) /* Set CBT hook to disallow MessageBox creation in current thread */ hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId()); - assert(hhook != 0); + ok(!!hhook, "Failed to set hook, error %u.\n", GetLastError()); test_cmdline(); test_registry(); @@ -785,6 +1112,7 @@ START_TEST(install) test_install_svc_from(); test_driver_install(); test_dirid(); + test_install_files_queue(); UnhookWindowsHookEx(hhook); diff --git a/sdk/tools/winesync/setupapi.cfg b/sdk/tools/winesync/setupapi.cfg index 06994318d06..07da3cde7d5 100644 --- a/sdk/tools/winesync/setupapi.cfg +++ b/sdk/tools/winesync/setupapi.cfg @@ -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: fccb7552ebe81ea2c0c17bc747a920f90e2537a5 + wine: 466b80786fbf7ced695358af3ee87302ed00eb1b