Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=42424 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45455
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/setupapi/devinst.c | 318 +++++++++++++++++++++++++++++++++++++++ dlls/setupapi/misc.c | 320 +--------------------------------------- 2 files changed, 319 insertions(+), 319 deletions(-)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 9bbc1afb3ac..89e8bb7cf8c 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -31,6 +31,9 @@ #include "winnls.h" #include "winsvc.h" #include "setupapi.h" +#include "softpub.h" +#include "mscat.h" +#include "shlwapi.h" #include "wine/debug.h" #include "wine/list.h" #include "cfgmgr32.h" @@ -5347,3 +5350,318 @@ BOOL WINAPI SetupDiGetCustomDevicePropertyW(HDEVINFO devinfo, SP_DEVINFO_DATA *d SetLastError(ERROR_INVALID_DATA); return FALSE; } + +/*********************************************************************** + * SetupCopyOEMInfA (SETUPAPI.@) + */ +BOOL WINAPI SetupCopyOEMInfA( PCSTR source, PCSTR location, + DWORD media_type, DWORD style, PSTR dest, + DWORD buffer_size, PDWORD required_size, PSTR *component ) +{ + BOOL ret = FALSE; + LPWSTR destW = NULL, sourceW = NULL, locationW = NULL; + DWORD size; + + TRACE("%s, %s, %ld, %ld, %p, %ld, %p, %p\n", debugstr_a(source), debugstr_a(location), + media_type, style, dest, buffer_size, required_size, component); + + if (dest && !(destW = MyMalloc( buffer_size * sizeof(WCHAR) ))) return FALSE; + if (source && !(sourceW = strdupAtoW( source ))) goto done; + if (location && !(locationW = strdupAtoW( location ))) goto done; + + ret = SetupCopyOEMInfW( sourceW, locationW, media_type, style, destW, buffer_size, &size, NULL ); + + if (required_size) *required_size = size; + + if (dest) + { + if (buffer_size >= size) + { + WideCharToMultiByte( CP_ACP, 0, destW, -1, dest, buffer_size, NULL, NULL ); + if (component) *component = strrchr( dest, '\' ) + 1; + } + else + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + } + +done: + MyFree( destW ); + free( sourceW ); + free( locationW ); + if (ret) SetLastError(ERROR_SUCCESS); + return ret; +} + +static int compare_files(HANDLE file1, HANDLE file2) +{ + char buffer1[2048]; + char buffer2[2048]; + DWORD size1; + DWORD size2; + + while (ReadFile(file1, buffer1, sizeof(buffer1), &size1, NULL) + && ReadFile(file2, buffer2, sizeof(buffer2), &size2, NULL)) + { + int ret; + if (size1 != size2) + return size1 > size2 ? 1 : -1; + if (!size1) + return 0; + ret = memcmp( buffer1, buffer2, size1 ); + if (ret) + return ret; + } + + return 0; +} + +static BOOL find_existing_inf(const WCHAR *source, WCHAR *target) +{ + LARGE_INTEGER source_file_size, dest_file_size; + HANDLE source_file, dest_file; + WIN32_FIND_DATAW find_data; + HANDLE find_handle; + + source_file = CreateFileW(source, FILE_READ_DATA | FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); + if (source_file == INVALID_HANDLE_VALUE) + return FALSE; + + if (!GetFileSizeEx(source_file, &source_file_size)) + { + CloseHandle(source_file); + return FALSE; + } + + GetWindowsDirectoryW(target, MAX_PATH); + wcscat(target, L"\inf\*"); + if ((find_handle = FindFirstFileW(target, &find_data)) != INVALID_HANDLE_VALUE) + { + do + { + GetWindowsDirectoryW(target, MAX_PATH); + wcscat(target, L"\inf\"); + wcscat(target, find_data.cFileName); + dest_file = CreateFileW(target, FILE_READ_DATA | FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); + if (dest_file == INVALID_HANDLE_VALUE) + continue; + + SetFilePointer(source_file, 0, NULL, FILE_BEGIN); + + if (GetFileSizeEx(dest_file, &dest_file_size) + && dest_file_size.QuadPart == source_file_size.QuadPart + && !compare_files(source_file, dest_file)) + { + CloseHandle(dest_file); + CloseHandle(source_file); + FindClose(find_handle); + return TRUE; + } + CloseHandle(dest_file); + } while (FindNextFileW(find_handle, &find_data)); + + FindClose(find_handle); + } + + CloseHandle(source_file); + return FALSE; +} + +/* arbitrary limit not related to what native actually uses */ +#define OEM_INDEX_LIMIT 999 + +/*********************************************************************** + * SetupCopyOEMInfW (SETUPAPI.@) + */ +BOOL WINAPI SetupCopyOEMInfW(const WCHAR *source, const WCHAR *location, DWORD media_type, + DWORD style, WCHAR *dest, DWORD buffer_size, DWORD *required_size, WCHAR **filepart) +{ + WCHAR target[MAX_PATH], catalog_file[MAX_PATH], pnf_path[MAX_PATH], *p; + BOOL ret = FALSE; + FILE *pnf_file; + unsigned int i; + DWORD size; + HINF hinf; + + TRACE("source %s, location %s, media_type %lu, style %#lx, dest %p, buffer_size %lu, required_size %p, filepart %p.\n", + debugstr_w(source), debugstr_w(location), media_type, style, dest, buffer_size, required_size, filepart); + + if (!source) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* check for a relative path */ + if (!(*source == '\' || (*source && source[1] == ':'))) + { + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } + + if (find_existing_inf(source, target)) + { + TRACE("Found existing INF %s.\n", debugstr_w(target)); + if (style & SP_COPY_NOOVERWRITE) + { + SetLastError(ERROR_FILE_EXISTS); + ret = FALSE; + } + else + ret = TRUE; + goto done; + } + + GetWindowsDirectoryW(target, ARRAY_SIZE(target)); + wcscat(target, L"\inf\"); + wcscat(target, wcsrchr(source, '\') + 1); + if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) + { + for (i = 0; i < OEM_INDEX_LIMIT; i++) + { + GetWindowsDirectoryW(target, ARRAY_SIZE(target)); + wcscat(target, L"\inf\"); + swprintf(target + wcslen(target), ARRAY_SIZE(target) - wcslen(target), L"oem%u.inf", i); + + if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES) + break; + } + if (i == OEM_INDEX_LIMIT) + { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + return FALSE; + } + } + + hinf = SetupOpenInfFileW(source, NULL, INF_STYLE_WIN4, NULL); + if (hinf == INVALID_HANDLE_VALUE) + return FALSE; + + if (SetupGetLineTextW(NULL, hinf, L"Version", L"CatalogFile", + catalog_file, ARRAY_SIZE(catalog_file), NULL)) + { + GUID msguid = DRIVER_ACTION_VERIFY; + WCHAR source_cat[MAX_PATH]; + HCATADMIN handle; + HCATINFO cat; + + SetupCloseInfFile(hinf); + + wcscpy(source_cat, source); + p = wcsrchr(source_cat, '\'); + if (p) + p++; + else + p = source_cat; + wcscpy(p, catalog_file); + + TRACE("Installing catalog file %s.\n", debugstr_w(source_cat)); + + if (!CryptCATAdminAcquireContext(&handle, &msguid, 0)) + { + ERR("Failed to acquire security context, error %lu.\n", GetLastError()); + return FALSE; + } + + if (!(cat = CryptCATAdminAddCatalog(handle, source_cat, catalog_file, 0))) + { + ERR("Failed to add catalog, error %lu.\n", GetLastError()); + CryptCATAdminReleaseContext(handle, 0); + return FALSE; + } + + CryptCATAdminReleaseCatalogContext(handle, cat, 0); + CryptCATAdminReleaseContext(handle, 0); + } + else + { + SetupCloseInfFile(hinf); + } + + if (!(ret = CopyFileW(source, target, TRUE))) + return ret; + + wcscpy(pnf_path, target); + PathRemoveExtensionW(pnf_path); + PathAddExtensionW(pnf_path, L".pnf"); + if ((pnf_file = _wfopen(pnf_path, L"w"))) + { + fputws(PNF_HEADER, pnf_file); + fputws(source, pnf_file); + fclose(pnf_file); + } + +done: + if (style & SP_COPY_DELETESOURCE) + DeleteFileW(source); + + size = wcslen(target) + 1; + if (dest) + { + if (buffer_size >= size) + { + wcscpy(dest, target); + if (filepart) + *filepart = wcsrchr(dest, '\') + 1; + } + else + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + ret = FALSE; + } + } + + if (required_size) + *required_size = size; + if (ret) + SetLastError(ERROR_SUCCESS); + + return ret; +} + +/*********************************************************************** + * SetupUninstallOEMInfA (SETUPAPI.@) + */ +BOOL WINAPI SetupUninstallOEMInfA(const char *inf_file, DWORD flags, void *reserved) +{ + WCHAR *inf_fileW = NULL; + BOOL ret; + + TRACE("inf_file %s, flags %#lx, reserved %p.\n", debugstr_a(inf_file), flags, reserved); + + if (inf_file && !(inf_fileW = strdupAtoW(inf_file))) + return FALSE; + ret = SetupUninstallOEMInfW(inf_fileW, flags, reserved); + free(inf_fileW); + return ret; +} + +/*********************************************************************** + * SetupUninstallOEMInfW (SETUPAPI.@) + */ +BOOL WINAPI SetupUninstallOEMInfW(const WCHAR *inf_file, DWORD flags, void *reserved) +{ + WCHAR target[MAX_PATH]; + + TRACE("inf_file %s, flags %#lx, reserved %p.\n", debugstr_w(inf_file), flags, reserved); + + if (!inf_file) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!GetWindowsDirectoryW( target, ARRAY_SIZE( target ))) + return FALSE; + + wcscat(target, L"\inf\"); + wcscat(target, inf_file); + + if (flags & SUOI_FORCEDELETE) + return DeleteFileW(target); + + FIXME("not deleting %s\n", debugstr_w(target)); + + return TRUE; +} diff --git a/dlls/setupapi/misc.c b/dlls/setupapi/misc.c index b1083fca665..3a44f3f4c60 100644 --- a/dlls/setupapi/misc.c +++ b/dlls/setupapi/misc.c @@ -26,12 +26,11 @@ #include "wingdi.h" #include "winuser.h" #include "winreg.h" +#include "wincrypt.h" #include "setupapi.h" #include "lzexpand.h" -#include "softpub.h" #include "mscat.h" #include "shlobj.h" -#include "shlwapi.h"
#include "wine/debug.h"
@@ -39,9 +38,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
-/* arbitrary limit not related to what native actually uses */ -#define OEM_INDEX_LIMIT 999 - /* Handles and critical sections for the SetupLog API */ static HANDLE setupact = INVALID_HANDLE_VALUE; static HANDLE setuperr = INVALID_HANDLE_VALUE; @@ -834,320 +830,6 @@ void WINAPI AssertFail(LPCSTR lpFile, UINT uLine, LPCSTR lpMessage) FIXME("%s %u %s\n", lpFile, uLine, lpMessage); }
-/*********************************************************************** - * SetupCopyOEMInfA (SETUPAPI.@) - */ -BOOL WINAPI SetupCopyOEMInfA( PCSTR source, PCSTR location, - DWORD media_type, DWORD style, PSTR dest, - DWORD buffer_size, PDWORD required_size, PSTR *component ) -{ - BOOL ret = FALSE; - LPWSTR destW = NULL, sourceW = NULL, locationW = NULL; - DWORD size; - - TRACE("%s, %s, %ld, %ld, %p, %ld, %p, %p\n", debugstr_a(source), debugstr_a(location), - media_type, style, dest, buffer_size, required_size, component); - - if (dest && !(destW = MyMalloc( buffer_size * sizeof(WCHAR) ))) return FALSE; - if (source && !(sourceW = strdupAtoW( source ))) goto done; - if (location && !(locationW = strdupAtoW( location ))) goto done; - - ret = SetupCopyOEMInfW( sourceW, locationW, media_type, style, destW, buffer_size, &size, NULL ); - - if (required_size) *required_size = size; - - if (dest) - { - if (buffer_size >= size) - { - WideCharToMultiByte( CP_ACP, 0, destW, -1, dest, buffer_size, NULL, NULL ); - if (component) *component = strrchr( dest, '\' ) + 1; - } - else - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - } - -done: - MyFree( destW ); - free( sourceW ); - free( locationW ); - if (ret) SetLastError(ERROR_SUCCESS); - return ret; -} - -static int compare_files( HANDLE file1, HANDLE file2 ) -{ - char buffer1[2048]; - char buffer2[2048]; - DWORD size1; - DWORD size2; - - while( ReadFile(file1, buffer1, sizeof(buffer1), &size1, NULL) && - ReadFile(file2, buffer2, sizeof(buffer2), &size2, NULL) ) - { - int ret; - if (size1 != size2) - return size1 > size2 ? 1 : -1; - if (!size1) - return 0; - ret = memcmp( buffer1, buffer2, size1 ); - if (ret) - return ret; - } - - return 0; -} - -static BOOL find_existing_inf(const WCHAR *source, WCHAR *target) -{ - static const WCHAR infW[] = {'\','i','n','f','\',0}; - static const WCHAR wildcardW[] = {'*',0}; - - LARGE_INTEGER source_file_size, dest_file_size; - HANDLE source_file, dest_file; - WIN32_FIND_DATAW find_data; - HANDLE find_handle; - - source_file = CreateFileW( source, FILE_READ_DATA | FILE_READ_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, 0, NULL ); - if (source_file == INVALID_HANDLE_VALUE) - return FALSE; - - if (!GetFileSizeEx( source_file, &source_file_size )) - { - CloseHandle( source_file ); - return FALSE; - } - - GetWindowsDirectoryW( target, MAX_PATH ); - lstrcatW( target, infW ); - lstrcatW( target, wildcardW ); - if ((find_handle = FindFirstFileW( target, &find_data )) != INVALID_HANDLE_VALUE) - { - do { - GetWindowsDirectoryW( target, MAX_PATH ); - lstrcatW( target, infW ); - lstrcatW( target, find_data.cFileName ); - dest_file = CreateFileW( target, FILE_READ_DATA | FILE_READ_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, 0, NULL ); - if (dest_file == INVALID_HANDLE_VALUE) - continue; - - SetFilePointer( source_file, 0, NULL, FILE_BEGIN ); - - if (GetFileSizeEx( dest_file, &dest_file_size ) - && dest_file_size.QuadPart == source_file_size.QuadPart - && !compare_files( source_file, dest_file )) - { - CloseHandle( dest_file ); - CloseHandle( source_file ); - FindClose( find_handle ); - return TRUE; - } - CloseHandle( dest_file ); - } while (FindNextFileW( find_handle, &find_data )); - - FindClose( find_handle ); - } - - CloseHandle( source_file ); - return FALSE; -} - -/*********************************************************************** - * SetupCopyOEMInfW (SETUPAPI.@) - */ -BOOL WINAPI SetupCopyOEMInfW( PCWSTR source, PCWSTR location, - DWORD media_type, DWORD style, PWSTR dest, - DWORD buffer_size, DWORD *required_size, WCHAR **filepart ) -{ - BOOL ret = FALSE; - WCHAR target[MAX_PATH], catalog_file[MAX_PATH], pnf_path[MAX_PATH], *p; - static const WCHAR inf[] = { '\','i','n','f','\',0 }; - static const WCHAR wszVersion[] = { 'V','e','r','s','i','o','n',0 }; - static const WCHAR wszCatalogFile[] = { 'C','a','t','a','l','o','g','F','i','l','e',0 }; - FILE *pnf_file; - unsigned int i; - DWORD size; - HINF hinf; - - TRACE("%s, %s, %ld, %ld, %p, %ld, %p, %p\n", debugstr_w(source), debugstr_w(location), - media_type, style, dest, buffer_size, required_size, filepart); - - if (!source) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - /* check for a relative path */ - if (!(*source == '\' || (*source && source[1] == ':'))) - { - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; - } - - if (find_existing_inf( source, target )) - { - TRACE("Found existing INF %s.\n", debugstr_w(target)); - if (style & SP_COPY_NOOVERWRITE) - { - SetLastError( ERROR_FILE_EXISTS ); - ret = FALSE; - } - else - ret = TRUE; - goto done; - } - - GetWindowsDirectoryW( target, ARRAY_SIZE(target) ); - lstrcatW( target, inf ); - lstrcatW( target, wcsrchr( source, '\' ) + 1 ); - if (GetFileAttributesW( target ) != INVALID_FILE_ATTRIBUTES) - { - for (i = 0; i < OEM_INDEX_LIMIT; i++) - { - static const WCHAR formatW[] = {'o','e','m','%','u','.','i','n','f',0}; - - GetWindowsDirectoryW( target, ARRAY_SIZE(target) ); - lstrcatW( target, inf ); - swprintf( target + lstrlenW(target), ARRAY_SIZE(target) - lstrlenW(target), formatW, i ); - - if (GetFileAttributesW( target ) == INVALID_FILE_ATTRIBUTES) - break; - } - if (i == OEM_INDEX_LIMIT) - { - SetLastError( ERROR_FILENAME_EXCED_RANGE ); - return FALSE; - } - } - - hinf = SetupOpenInfFileW( source, NULL, INF_STYLE_WIN4, NULL ); - if (hinf == INVALID_HANDLE_VALUE) return FALSE; - - if (SetupGetLineTextW( NULL, hinf, wszVersion, wszCatalogFile, catalog_file, - ARRAY_SIZE( catalog_file ), NULL )) - { - WCHAR source_cat[MAX_PATH]; - HCATADMIN handle; - HCATINFO cat; - GUID msguid = DRIVER_ACTION_VERIFY; - - SetupCloseInfFile( hinf ); - - lstrcpyW( source_cat, source ); - p = wcsrchr( source_cat, '\' ); - if (p) p++; - else p = source_cat; - lstrcpyW( p, catalog_file ); - - TRACE("installing catalog file %s\n", debugstr_w( source_cat )); - - if (!CryptCATAdminAcquireContext(&handle, &msguid, 0)) - { - ERR("Could not acquire security context\n"); - return FALSE; - } - - if (!(cat = CryptCATAdminAddCatalog(handle, source_cat, catalog_file, 0))) - { - ERR("Could not add catalog\n"); - CryptCATAdminReleaseContext(handle, 0); - return FALSE; - } - - CryptCATAdminReleaseCatalogContext(handle, cat, 0); - CryptCATAdminReleaseContext(handle, 0); - } - else - SetupCloseInfFile( hinf ); - - if (!(ret = CopyFileW( source, target, TRUE ))) - return ret; - - wcscpy(pnf_path, target); - PathRemoveExtensionW(pnf_path); - PathAddExtensionW(pnf_path, L".pnf"); - if ((pnf_file = _wfopen(pnf_path, L"w"))) - { - fputws(PNF_HEADER, pnf_file); - fputws(source, pnf_file); - fclose(pnf_file); - } - -done: - if (style & SP_COPY_DELETESOURCE) - DeleteFileW( source ); - - size = lstrlenW( target ) + 1; - if (dest) - { - if (buffer_size >= size) - { - lstrcpyW( dest, target ); - if (filepart) *filepart = wcsrchr( dest, '\' ) + 1; - } - else - { - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - ret = FALSE; - } - } - - if (required_size) *required_size = size; - if (ret) SetLastError(ERROR_SUCCESS); - - return ret; -} - -/*********************************************************************** - * SetupUninstallOEMInfA (SETUPAPI.@) - */ -BOOL WINAPI SetupUninstallOEMInfA( PCSTR inf_file, DWORD flags, PVOID reserved ) -{ - BOOL ret; - WCHAR *inf_fileW = NULL; - - TRACE("%s, 0x%08lx, %p\n", debugstr_a(inf_file), flags, reserved); - - if (inf_file && !(inf_fileW = strdupAtoW( inf_file ))) return FALSE; - ret = SetupUninstallOEMInfW( inf_fileW, flags, reserved ); - free( inf_fileW ); - return ret; -} - -/*********************************************************************** - * SetupUninstallOEMInfW (SETUPAPI.@) - */ -BOOL WINAPI SetupUninstallOEMInfW( PCWSTR inf_file, DWORD flags, PVOID reserved ) -{ - static const WCHAR infW[] = {'\','i','n','f','\',0}; - WCHAR target[MAX_PATH]; - - TRACE("%s, 0x%08lx, %p\n", debugstr_w(inf_file), flags, reserved); - - if (!inf_file) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - if (!GetWindowsDirectoryW( target, ARRAY_SIZE( target ))) return FALSE; - - lstrcatW( target, infW ); - lstrcatW( target, inf_file ); - - if (flags & SUOI_FORCEDELETE) - return DeleteFileW(target); - - FIXME("not deleting %s\n", debugstr_w(target)); - - return TRUE; -} - /*********************************************************************** * InstallCatalog (SETUPAPI.@) */
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/setupapi/devinst.c | 96 +++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 47 deletions(-)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 89e8bb7cf8c..74250347ff4 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -5471,46 +5471,22 @@ static BOOL find_existing_inf(const WCHAR *source, WCHAR *target) /* arbitrary limit not related to what native actually uses */ #define OEM_INDEX_LIMIT 999
-/*********************************************************************** - * SetupCopyOEMInfW (SETUPAPI.@) - */ -BOOL WINAPI SetupCopyOEMInfW(const WCHAR *source, const WCHAR *location, DWORD media_type, - DWORD style, WCHAR *dest, DWORD buffer_size, DWORD *required_size, WCHAR **filepart) +static DWORD copy_inf(const WCHAR *source, DWORD style, WCHAR *ret_path) { WCHAR target[MAX_PATH], catalog_file[MAX_PATH], pnf_path[MAX_PATH], *p; - BOOL ret = FALSE; FILE *pnf_file; unsigned int i; - DWORD size; HINF hinf;
- TRACE("source %s, location %s, media_type %lu, style %#lx, dest %p, buffer_size %lu, required_size %p, filepart %p.\n", - debugstr_w(source), debugstr_w(location), media_type, style, dest, buffer_size, required_size, filepart); - - if (!source) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - /* check for a relative path */ - if (!(*source == '\' || (*source && source[1] == ':'))) - { - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; - } - if (find_existing_inf(source, target)) { TRACE("Found existing INF %s.\n", debugstr_w(target)); + + wcscpy(ret_path, target); if (style & SP_COPY_NOOVERWRITE) - { - SetLastError(ERROR_FILE_EXISTS); - ret = FALSE; - } + return ERROR_FILE_EXISTS; else - ret = TRUE; - goto done; + return ERROR_SUCCESS; }
GetWindowsDirectoryW(target, ARRAY_SIZE(target)); @@ -5528,15 +5504,12 @@ BOOL WINAPI SetupCopyOEMInfW(const WCHAR *source, const WCHAR *location, DWORD m break; } if (i == OEM_INDEX_LIMIT) - { - SetLastError(ERROR_FILENAME_EXCED_RANGE); - return FALSE; - } + return ERROR_FILENAME_EXCED_RANGE; }
hinf = SetupOpenInfFileW(source, NULL, INF_STYLE_WIN4, NULL); if (hinf == INVALID_HANDLE_VALUE) - return FALSE; + return GetLastError();
if (SetupGetLineTextW(NULL, hinf, L"Version", L"CatalogFile", catalog_file, ARRAY_SIZE(catalog_file), NULL)) @@ -5561,14 +5534,14 @@ BOOL WINAPI SetupCopyOEMInfW(const WCHAR *source, const WCHAR *location, DWORD m if (!CryptCATAdminAcquireContext(&handle, &msguid, 0)) { ERR("Failed to acquire security context, error %lu.\n", GetLastError()); - return FALSE; + return GetLastError(); }
if (!(cat = CryptCATAdminAddCatalog(handle, source_cat, catalog_file, 0))) { ERR("Failed to add catalog, error %lu.\n", GetLastError()); CryptCATAdminReleaseContext(handle, 0); - return FALSE; + return GetLastError(); }
CryptCATAdminReleaseCatalogContext(handle, cat, 0); @@ -5579,8 +5552,8 @@ BOOL WINAPI SetupCopyOEMInfW(const WCHAR *source, const WCHAR *location, DWORD m SetupCloseInfFile(hinf); }
- if (!(ret = CopyFileW(source, target, TRUE))) - return ret; + if (!CopyFileW(source, target, TRUE)) + return GetLastError();
wcscpy(pnf_path, target); PathRemoveExtensionW(pnf_path); @@ -5592,12 +5565,45 @@ BOOL WINAPI SetupCopyOEMInfW(const WCHAR *source, const WCHAR *location, DWORD m fclose(pnf_file); }
-done: + wcscpy(ret_path, target); + return ERROR_SUCCESS; +} + +/*********************************************************************** + * SetupCopyOEMInfW (SETUPAPI.@) + */ +BOOL WINAPI SetupCopyOEMInfW(const WCHAR *source, const WCHAR *location, DWORD media_type, + DWORD style, WCHAR *dest, DWORD buffer_size, DWORD *required_size, WCHAR **filepart) +{ + WCHAR target[MAX_PATH]; + DWORD size, ret; + + TRACE("source %s, location %s, media_type %lu, style %#lx, dest %p, buffer_size %lu, required_size %p, filepart %p.\n", + debugstr_w(source), debugstr_w(location), media_type, style, dest, buffer_size, required_size, filepart); + + if (!source) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* check for a relative path */ + if (!(*source == '\' || (*source && source[1] == ':'))) + { + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } + + ret = copy_inf(source, style, target); + if (style & SP_COPY_DELETESOURCE) DeleteFileW(source);
size = wcslen(target) + 1; - if (dest) + if (required_size) + *required_size = size; + + if ((!ret || ret == ERROR_FILE_EXISTS) && dest) { if (buffer_size >= size) { @@ -5608,16 +5614,12 @@ done: else { SetLastError(ERROR_INSUFFICIENT_BUFFER); - ret = FALSE; + return FALSE; } }
- if (required_size) - *required_size = size; - if (ret) - SetLastError(ERROR_SUCCESS); - - return ret; + SetLastError(ret); + return !ret; }
/***********************************************************************
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/setupapi/devinst.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 74250347ff4..2c46c8c5fef 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -4694,10 +4694,27 @@ static BOOL version_is_compatible(const WCHAR *version) return !wcsnicmp(version, machine_ext, len); }
+static bool any_version_is_compatible(INFCONTEXT *ctx) +{ + WCHAR version[LINE_LEN]; + DWORD j; + + if (SetupGetFieldCount(ctx) < 2) + return true; + + for (j = 2; SetupGetStringFieldW(ctx, j, version, ARRAY_SIZE(version), NULL); ++j) + { + if (version_is_compatible(version)) + return true; + } + + return false; +} + static void enum_compat_drivers_from_file(struct device *device, const WCHAR *path) { static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0}; - WCHAR mfg_key[LINE_LEN], id[MAX_DEVICE_ID_LEN], version[MAX_DEVICE_ID_LEN]; + WCHAR mfg_key[LINE_LEN], id[MAX_DEVICE_ID_LEN]; DWORD i, j, k, driver_count = device->driver_count; struct driver driver, *drivers = device->drivers; INFCONTEXT ctx; @@ -4717,20 +4734,8 @@ static void enum_compat_drivers_from_file(struct device *device, const WCHAR *pa if (!SetupGetStringFieldW(&ctx, 1, mfg_key, ARRAY_SIZE(mfg_key), NULL)) lstrcpyW(mfg_key, driver.manufacturer);
- if (SetupGetFieldCount(&ctx) >= 2) - { - BOOL compatible = FALSE; - for (j = 2; SetupGetStringFieldW(&ctx, j, version, ARRAY_SIZE(version), NULL); ++j) - { - if (version_is_compatible(version)) - { - compatible = TRUE; - break; - } - } - if (!compatible) - continue; - } + if (!any_version_is_compatible(&ctx)) + continue;
if (!SetupDiGetActualSectionToInstallW(hinf, mfg_key, driver.mfg_key, ARRAY_SIZE(driver.mfg_key), NULL, NULL))
From: Elizabeth Figura zfigura@codeweavers.com
This patch introduces the bulk of the Driver Store logic.
For some unfathomable reason, Windows driver files are not installed to their "proper" place until the device is actually plugged in and used. Once that happens, the INF file in C:/windows/inf/ is used as an installation script.
However, Microsoft also wanted to make it possible for drivers to be installed before a device is plugged in and used, without putting the onus on the driver distributor to keep the source files somewhere that the INF will know where to find them.
Thus the Driver Store was introduced. When an INF is "preinstalled", a "package" containing the INF, catalog, and any file referenced by the INF is copied to a location in C:/windows/system32/DriverStore/. The INF itself is then copied again to C:/windows/inf/ so that it can be probed when a new device is enumerated, and a PNF is created referencing the driver store location.
The Driver Store attempts to avoid duplication, but also treats any difference in any file as creating a different driver package.
The Driver Store APIs introduced here are actually completely undocumented. The Driver Store is normally accessed through one of several apparently higher-level components, apparently introduced at different points in time, and all with apparently the same function:
* DriverPackageInstall() et al. from difxapi.dll
* DiInstallDriver() et al. from newdev.dll
* SetupCopyOEMInf() [this not only installs the INF but also implicitly also installs to the driver store]
* The DIFx MSI-based framework, including the DIFxApp.dll redistributable and dpinst.exe
The first three are Windows components, but the last is a redistributable. More pressingly, DIFxApp.dll is a custom action DLL, which means that MSI will invariably rename it, so we cannot even in practice substitute a builtin version.
We cannot easily substitute a builtin dpinst.exe, either, since our current load order logic always uses a native EXE if specified by path (which in practice is the case). It's not clear that changing this logic is worthwhile. --- dlls/setupapi/devinst.c | 573 +++++++++++++++++++++++++++++++++++- dlls/setupapi/setupapi.spec | 2 + 2 files changed, 573 insertions(+), 2 deletions(-)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 2c46c8c5fef..ee3b4bb2a34 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -18,7 +18,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include <assert.h> #include <stdarg.h> +#include <stdbool.h> #include <stdlib.h>
#include "windef.h" @@ -161,6 +163,56 @@ struct device_iface struct list entry; };
+static bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) +{ + unsigned int new_capacity, max_capacity; + void *new_elements; + + if (count <= *capacity) + return true; + + max_capacity = ~(size_t)0 / size; + if (count > max_capacity) + return false; + + new_capacity = max(4, *capacity); + while (new_capacity < count && new_capacity <= max_capacity / 2) + new_capacity *= 2; + if (new_capacity < count) + new_capacity = max_capacity; + + if (!(new_elements = realloc(*elements, new_capacity * size))) + return false; + + *elements = new_elements; + *capacity = new_capacity; + + return true; +} + +static WCHAR *sprintf_path(const WCHAR *format, ...) +{ + va_list args, args_copy; + WCHAR *buffer; + size_t len; + + va_start(args, format); + + va_copy(args_copy, args); + len = _vsnwprintf(NULL, 0, format, args_copy) + 1; + va_end(args_copy); + + buffer = malloc(len * sizeof(WCHAR)); + _vsnwprintf(buffer, len, format, args); + va_end(args); + return buffer; +} + +static WCHAR *concat_path(const WCHAR *root, const WCHAR *path) +{ + return sprintf_path(L"%s\%s", root, path); +} + static struct DeviceInfoSet *get_device_set(HDEVINFO devinfo) { struct DeviceInfoSet *set = devinfo; @@ -5420,6 +5472,351 @@ static int compare_files(HANDLE file1, HANDLE file2) return 0; }
+struct driver_package +{ + const WCHAR *inf_name; + HINF hinf; + WCHAR *src_root, *dst_root; + bool already_installed; + + struct file + { + WCHAR *desc, *tag, *subdir, *filename; + } *files; + size_t file_count, files_size; +}; + +static void driver_package_cleanup(struct driver_package *package) +{ + free(package->src_root); + free(package->dst_root); + for (size_t i = 0; i < package->file_count; ++i) + { + free(package->files[i].desc); + free(package->files[i].tag); + free(package->files[i].subdir); + free(package->files[i].filename); + } + free(package->files); + SetupCloseInfFile(package->hinf); +} + +static WCHAR *get_string_field(INFCONTEXT *ctx, DWORD index) +{ + WCHAR *ret; + DWORD len; + + if (!SetupGetStringFieldW(ctx, index, NULL, 0, &len) || len <= 1) + return NULL; + + ret = malloc(len * sizeof(WCHAR)); + SetupGetStringFieldW(ctx, index, ret, len, NULL); + return ret; +} + +static bool get_source_info(HINF hinf, const WCHAR *filename, WCHAR **desc, WCHAR **tag, WCHAR **subdir) +{ + WCHAR *file_subdir = NULL, *disk_subdir = NULL; + UINT diskid; + DWORD len; + + if (!SetupGetSourceFileLocationW(hinf, NULL, filename, &diskid, NULL, 0, &len)) + { + ERR("Failed to get location for %s, error %lu.\n", debugstr_w(filename), GetLastError()); + return false; + } + + if (len > 1) + { + if (!(file_subdir = malloc(len * sizeof(WCHAR)))) + return false; + SetupGetSourceFileLocationW(hinf, NULL, filename, &diskid, file_subdir, len, NULL); + } + + if (SetupGetSourceInfoW(hinf, diskid, SRCINFO_DESCRIPTION, NULL, 0, &len) && len > 1 + && (*desc = malloc(len * sizeof(WCHAR)))) + SetupGetSourceInfoW(hinf, diskid, SRCINFO_DESCRIPTION, *desc, len, NULL); + + if (SetupGetSourceInfoW(hinf, diskid, SRCINFO_TAGFILE, NULL, 0, &len) && len > 1 + && (*tag = malloc(len * sizeof(WCHAR)))) + SetupGetSourceInfoW(hinf, diskid, SRCINFO_TAGFILE, *tag, len, NULL); + + if (SetupGetSourceInfoW(hinf, diskid, SRCINFO_PATH, NULL, 0, &len) && len > 1 + && (disk_subdir = malloc(len * sizeof(WCHAR)))) + SetupGetSourceInfoW(hinf, diskid, SRCINFO_PATH, disk_subdir, len, NULL); + + if (disk_subdir) + { + if (file_subdir) + { + *subdir = concat_path(disk_subdir, file_subdir); + free(disk_subdir); + free(file_subdir); + } + else + { + *subdir = disk_subdir; + } + } + else + { + *subdir = file_subdir; + } + + return true; +} + +static void add_file(struct driver_package *package, + WCHAR *filename, WCHAR *desc, WCHAR *tag, WCHAR *subdir) +{ + struct file *file; + + array_reserve((void **)&package->files, &package->files_size, + package->file_count + 1, sizeof(*package->files)); + + file = &package->files[package->file_count++]; + file->filename = filename; + file->desc = desc; + file->tag = tag; + file->subdir = subdir; + + TRACE("Adding file %s, desc %s, tag %s, subdir %s.\n", + debugstr_w(filename), debugstr_w(desc), debugstr_w(tag), debugstr_w(subdir)); +} + +static void add_file_from_copy_section(struct driver_package *package, + const WCHAR *dst_filename, const WCHAR *src_filename) +{ + WCHAR *desc = NULL, *tag = NULL, *subdir = NULL; + + if (get_source_info(package->hinf, src_filename, &desc, &tag, &subdir)) + add_file(package, wcsdup(src_filename), desc, tag, subdir); +} + +static void add_copy_section(struct driver_package *package, const WCHAR *section) +{ + TRACE("Building file list from CopyFiles section %s.\n", debugstr_w(section)); + + if (section[0] == '@') + { + add_file_from_copy_section(package, section + 1, section + 1); + } + else + { + INFCONTEXT context; + + if (!SetupFindFirstLineW(package->hinf, section, NULL, &context)) + return; + do + { + WCHAR *dst_filename = get_string_field(&context, 1); + WCHAR *src_filename = get_string_field(&context, 2); + + add_file_from_copy_section(package, dst_filename, src_filename ? src_filename : dst_filename); + + free(dst_filename); + free(src_filename); + } while (SetupFindNextLine(&context, &context)); + } +} + +static void add_driver_files(struct driver_package *package, const WCHAR *driver_section) +{ + INFCONTEXT ctx; + BOOL found; + + TRACE("Building file list for driver section %s.\n", debugstr_w(driver_section)); + + found = SetupFindFirstLineW(package->hinf, driver_section, L"CopyFiles", &ctx); + while (found) + { + DWORD count = SetupGetFieldCount(&ctx); + + for (DWORD i = 1; i <= count; ++i) + { + WCHAR *section = get_string_field(&ctx, i); + + add_copy_section(package, section); + free(section); + } + + found = SetupFindNextMatchLineW(&ctx, L"CopyFiles", &ctx); + } +} + +static bool driver_store_files_are_equal(const WCHAR *src_path, const WCHAR *store_path) +{ + HANDLE src_file, store_file; + bool ret; + + src_file = CreateFileW(src_path, FILE_READ_DATA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); + if (src_file == INVALID_HANDLE_VALUE) + { + ERR("Source file %s doesn't exist.\n", debugstr_w(src_path)); + return false; + } + + store_file = CreateFileW(store_path, FILE_READ_DATA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); + if (store_file == INVALID_HANDLE_VALUE) + { + TRACE("File %s doesn't exist in driver store; this is the wrong package.\n", debugstr_w(store_path)); + CloseHandle(src_file); + return false; + } + + ret = !compare_files(src_file, store_file); + + CloseHandle(src_file); + CloseHandle(store_file); + return ret; +} + +static void find_driver_store_path(struct driver_package *package, const WCHAR *inf_path) +{ + static const WCHAR file_repository[] = L"C:\windows\system32\driverstore\filerepository"; + WCHAR *search_path = sprintf_path(L"%s\%s_*", file_repository, package->inf_name); + unsigned int index = 1; + WIN32_FIND_DATAW data; + HANDLE handle; + + /* Windows names directories using the inf name and what appears to be a + * hash, separated by an underscore. For simplicity we don't implement the + * hash; instead we just use an integer to discriminate different packages + * with the same name. */ + + handle = FindFirstFileW(search_path, &data); + free(search_path); + + if (handle != INVALID_HANDLE_VALUE) + { + do + { + const size_t prefix_len = wcslen(package->inf_name) + 1; + WCHAR *store_root, *end_ptr, *store_inf; + unsigned int dir_index; + + /* FindFirstFile() should have given us a name at least as long as + * the INF name followed by an underscore. */ + assert(wcslen(data.cFileName) >= prefix_len); + if (!(dir_index = wcstoul(data.cFileName + prefix_len, &end_ptr, 10))) + ERR("Malformed directory name %s.\n", debugstr_w(data.cFileName)); + index = max(index, dir_index + 1); + + store_root = concat_path(file_repository, data.cFileName); + store_inf = concat_path(store_root, package->inf_name); + + if (driver_store_files_are_equal(inf_path, store_inf)) + { + TRACE("Found matching driver package %s.\n", debugstr_w(store_root)); + free(store_inf); + FindClose(handle); + package->already_installed = true; + package->dst_root = store_root; + return; + } + + free(store_root); + } while (FindNextFileW(handle, &data)); + + FindClose(handle); + } + else + { + if (GetLastError() != ERROR_PATH_NOT_FOUND && GetLastError() != ERROR_FILE_NOT_FOUND) + { + ERR("Failed to enumerate file repository, error %lu.\n", GetLastError()); + return; + } + } + + package->dst_root = sprintf_path(L"%s\%s_%u", file_repository, package->inf_name, index); + TRACE("No matching driver package found; using new path %s.\n", debugstr_w(package->dst_root)); +} + +static DWORD parse_inf(struct driver_package *package, const WCHAR *filename) +{ + WCHAR mfg_key[LINE_LEN], manufacturer[LINE_LEN]; + WCHAR *filename_abs, *file_part, *catalog; + INFCONTEXT ctx; + DWORD len; + + memset(package, 0, sizeof(*package)); + + if (!*filename) + return ERROR_FILE_NOT_FOUND; + + len = GetFullPathNameW(filename, 0, NULL, NULL); + filename_abs = malloc(len * sizeof(WCHAR)); + GetFullPathNameW(filename, len, filename_abs, NULL); + + TRACE("Parsing %s.\n", debugstr_w(filename_abs)); + + if ((package->hinf = SetupOpenInfFileW(filename_abs, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE) + { + ERR("Failed to open %s, error %lu.\n", debugstr_w(filename_abs), GetLastError()); + driver_package_cleanup(package); + return GetLastError(); + } + + file_part = wcsrchr(filename_abs, '\'); + assert(file_part); + package->inf_name = file_part + 1; + + *file_part = 0; + package->src_root = filename_abs; + + add_file(package, wcsdup(package->inf_name), NULL, NULL, NULL); + + if (SetupFindFirstLineW(package->hinf, L"Version", L"CatalogFile", &ctx) + && (catalog = get_string_field(&ctx, 1))) + add_file(package, catalog, NULL, NULL, NULL); + + for (DWORD i = 0; SetupGetLineByIndexW(package->hinf, L"Manufacturer", i, &ctx); ++i) + { + SetupGetStringFieldW(&ctx, 0, manufacturer, ARRAY_SIZE(manufacturer), NULL); + if (!SetupGetStringFieldW(&ctx, 1, mfg_key, ARRAY_SIZE(mfg_key), NULL)) + wcscpy(mfg_key, manufacturer); + + if (!any_version_is_compatible(&ctx)) + continue; + + if (!SetupDiGetActualSectionToInstallW(package->hinf, mfg_key, mfg_key, ARRAY_SIZE(mfg_key), NULL, NULL)) + { + WARN("Failed to find section for %s, skipping.\n", debugstr_w(mfg_key)); + continue; + } + + for (DWORD j = 0; SetupGetLineByIndexW(package->hinf, mfg_key, j, &ctx); ++j) + { + WCHAR *driver_section = get_string_field(&ctx, 1); + WCHAR arch_driver_section[LINE_LEN]; + + if (SetupDiGetActualSectionToInstallW(package->hinf, driver_section, + arch_driver_section, ARRAY_SIZE(arch_driver_section), NULL, NULL)) + { + WCHAR coinst_section[LINE_LEN]; + + add_driver_files(package, arch_driver_section); + + swprintf(coinst_section, ARRAY_SIZE(coinst_section), L"%s.CoInstallers", arch_driver_section); + add_driver_files(package, coinst_section); + } + else + { + WARN("Failed to find driver section for %s, skipping.\n", debugstr_w(driver_section)); + } + + free(driver_section); + } + } + + find_driver_store_path(package, filename); + + return ERROR_SUCCESS; +} + static BOOL find_existing_inf(const WCHAR *source, WCHAR *target) { LARGE_INTEGER source_file_size, dest_file_size; @@ -5461,6 +5858,7 @@ static BOOL find_existing_inf(const WCHAR *source, WCHAR *target) CloseHandle(dest_file); CloseHandle(source_file); FindClose(find_handle); + TRACE("Found matching INF %s.\n", debugstr_w(target)); return TRUE; } CloseHandle(dest_file); @@ -5470,6 +5868,7 @@ static BOOL find_existing_inf(const WCHAR *source, WCHAR *target) }
CloseHandle(source_file); + TRACE("No matching INF found.\n"); return FALSE; }
@@ -5487,7 +5886,8 @@ static DWORD copy_inf(const WCHAR *source, DWORD style, WCHAR *ret_path) { TRACE("Found existing INF %s.\n", debugstr_w(target));
- wcscpy(ret_path, target); + if (ret_path) + wcscpy(ret_path, target); if (style & SP_COPY_NOOVERWRITE) return ERROR_FILE_EXISTS; else @@ -5570,10 +5970,78 @@ static DWORD copy_inf(const WCHAR *source, DWORD style, WCHAR *ret_path) fclose(pnf_file); }
- wcscpy(ret_path, target); + if (ret_path) + wcscpy(ret_path, target); return ERROR_SUCCESS; }
+static void queue_copy_file(const struct driver_package *package, HSPFILEQ queue, const struct file *file) +{ + SP_FILE_COPY_PARAMS_W params = + { + .cbSize = sizeof(params), + .QueueHandle = queue, + .SourceRootPath = package->src_root, + .CopyStyle = SP_COPY_NODECOMP, + .SourceFilename = file->filename, + .TargetFilename = file->filename, + }; + + params.SourceDescription = file->desc; + params.SourceTagfile = file->tag; + params.SourcePath = file->subdir; + + TRACE("Queueing copy from subdir %s, filename %s.\n", + debugstr_w(file->subdir), debugstr_w(file->filename)); + + if (file->subdir) + { + WCHAR *dst_dir = concat_path(package->dst_root, file->subdir); + + params.TargetDirectory = dst_dir; + if (!SetupQueueCopyIndirectW(¶ms)) + ERR("Failed to queue copy, error %lu.\n", GetLastError()); + free(dst_dir); + } + else + { + params.TargetDirectory = package->dst_root; + if (!SetupQueueCopyIndirectW(¶ms)) + ERR("Failed to queue copy, error %lu.\n", GetLastError()); + } +} + +static DWORD driver_package_install_to_store(const struct driver_package *package, DWORD style, WCHAR *infdir_path) +{ + HSPFILEQ queue = SetupOpenFileQueue(); + DWORD ret = ERROR_SUCCESS; + void *setupapi_ctx; + WCHAR *store_inf; + + for (size_t i = 0; i < package->file_count; ++i) + queue_copy_file(package, queue, &package->files[i]); + + setupapi_ctx = SetupInitDefaultQueueCallback(NULL); + if (!SetupCommitFileQueueW(NULL, queue, SetupDefaultQueueCallbackW, setupapi_ctx)) + { + ERR("Failed to commit queue, error %lu.\n", GetLastError()); + ret = GetLastError(); + } + + SetupTermDefaultQueueCallback(setupapi_ctx); + SetupCloseFileQueue(queue); + + if (!ret) + { + store_inf = concat_path(package->dst_root, package->inf_name); + if ((ret = copy_inf(store_inf, style, infdir_path))) + ERR("Failed to copy INF %s, error %lu.\n", debugstr_w(store_inf), GetLastError()); + free(store_inf); + } + + return ret; +} + /*********************************************************************** * SetupCopyOEMInfW (SETUPAPI.@) */ @@ -5672,3 +6140,104 @@ BOOL WINAPI SetupUninstallOEMInfW(const WCHAR *inf_file, DWORD flags, void *rese
return TRUE; } + +HRESULT WINAPI DriverStoreAddDriverPackageW(const WCHAR *inf_path, void *unk1, + void *unk2, WORD architecture, WCHAR *ret_path, DWORD *ret_len) +{ + struct driver_package package; + SYSTEM_INFO system_info; + DWORD ret, len; + HRESULT hr; + + TRACE("inf_path %s, unk1 %p, unk2 %p, architecture %#x, ret_path %p, ret_len %p.\n", + debugstr_w(inf_path), unk1, unk2, architecture, ret_path, ret_len); + + if (unk1) + FIXME("Ignoring unk1 %p.\n", unk1); + if (unk2) + FIXME("Ignoring unk2 %p.\n", unk2); + + if (*ret_len < MAX_PATH) + { + FIXME("Length %lu too short, returning E_INVALIDARG.\n", *ret_len); + return E_INVALIDARG; + } + + GetSystemInfo(&system_info); + if (architecture != system_info.wProcessorArchitecture) + { + FIXME("Wrong architecture %#x, expected %#x.\n", architecture, system_info.wProcessorArchitecture); + return E_INVALIDARG; + } + + if ((ret = parse_inf(&package, inf_path))) + return HRESULT_FROM_WIN32(ret); + + if (!package.already_installed) + { + if ((ret = driver_package_install_to_store(&package, 0, NULL))) + { + driver_package_cleanup(&package); + return HRESULT_FROM_WIN32(ret); + } + } + + len = wcslen(package.dst_root) + 1 + wcslen(package.inf_name) + 1; + + if (len > *ret_len) + { + FIXME("Buffer too small.\n"); + /* FIXME: What do we return here? */ + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else + { + swprintf(ret_path, len, L"%s\%s", package.dst_root, package.inf_name); + hr = S_OK; + } + *ret_len = len; + + driver_package_cleanup(&package); + return hr; +} + +HRESULT WINAPI DriverStoreAddDriverPackageA(const char *inf_path, void *unk1, + void *unk2, WORD architecture, char *ret_path, DWORD *ret_len) +{ + WCHAR ret_pathW[MAX_PATH]; + WCHAR *inf_pathW; + DWORD lenW, len; + HRESULT hr; + + TRACE("inf_path %s, unk1 %p, unk2 %p, architecture %#x, ret_path %p, ret_len %p.\n", + debugstr_a(inf_path), unk1, unk2, architecture, ret_path, ret_len); + + if (*ret_len < MAX_PATH) + { + FIXME("Length %lu too short, returning E_INVALIDARG.\n", *ret_len); + return E_INVALIDARG; + } + + if (!(inf_pathW = strdupAtoW(inf_path))) + return E_OUTOFMEMORY; + + lenW = ARRAY_SIZE(ret_pathW); + hr = DriverStoreAddDriverPackageW(inf_pathW, unk1, unk2, architecture, ret_pathW, &lenW); + if (!hr) + { + len = WideCharToMultiByte(CP_ACP, 0, ret_pathW, lenW, NULL, 0, NULL, NULL); + if (len > *ret_len) + { + FIXME("Buffer too small.\n"); + /* FIXME: What do we return here? */ + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else + { + WideCharToMultiByte(CP_ACP, 0, ret_pathW, lenW, ret_path, len, NULL, NULL); + } + *ret_len = len; + } + free(inf_pathW); + return hr; +} diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index 4d144fe739b..5dddbe4fb5e 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -208,6 +208,8 @@ @ stub DelimStringToMultiSz @ stub DestroyTextFileReadBuffer @ stdcall DoesUserHavePrivilege(wstr) +@ stdcall DriverStoreAddDriverPackageA(ptr ptr ptr long ptr ptr) +@ stdcall DriverStoreAddDriverPackageW(ptr ptr ptr long ptr ptr) @ stdcall DuplicateString(wstr) @ stdcall EnablePrivilege(wstr long) @ stub ExtensionPropSheetPageProc
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/setupapi/devinst.c | 101 ++++++++++++++++++++++++++++++++++++ dlls/setupapi/setupapi.spec | 2 + 2 files changed, 103 insertions(+)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index ee3b4bb2a34..6e06d3351b4 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -6042,6 +6042,68 @@ static DWORD driver_package_install_to_store(const struct driver_package *packag return ret; }
+static DWORD driver_package_delete(const struct driver_package *package) +{ + WCHAR infdir_path[MAX_PATH]; + WCHAR *inf_path; + + inf_path = concat_path(package->dst_root, package->inf_name); + + if (find_existing_inf(inf_path, infdir_path)) + { + if (!DeleteFileW(infdir_path)) + ERR("Failed to delete %s, error %lu.\n", debugstr_w(infdir_path), GetLastError()); + PathRemoveExtensionW(infdir_path); + PathAddExtensionW(infdir_path, L".pnf"); + if (!DeleteFileW(infdir_path)) + ERR("Failed to delete %s, error %lu.\n", debugstr_w(infdir_path), GetLastError()); + } + else + { + ERR("Driver package INF %s not found in INF directory!\n", debugstr_w(inf_path)); + } + + free(inf_path); + + for (size_t i = 0; i < package->file_count; ++i) + { + const struct file *file = &package->files[i]; + WCHAR *path; + + if (file->subdir) + path = sprintf_path(L"%s\%s\%s", package->dst_root, file->subdir, file->filename); + else + path = sprintf_path(L"%s\%s", package->dst_root, file->filename); + + if (DeleteFileW(path)) + { + for (;;) + { + *wcsrchr(path, '\') = 0; + if (wcslen(path) == wcslen(package->dst_root)) + break; + if (!RemoveDirectoryW(path)) + { + if (GetLastError() != ERROR_DIR_NOT_EMPTY) + ERR("Failed to remove %s, error %lu.\n", debugstr_w(path), GetLastError()); + break; + } + } + } + else + { + ERR("Failed to delete %s, error %lu.\n", debugstr_w(path), GetLastError()); + } + + free(path); + } + + if (!RemoveDirectoryW(package->dst_root)) + ERR("Failed to remove %s, error %lu.\n", debugstr_w(package->dst_root), GetLastError()); + + return ERROR_SUCCESS; +} + /*********************************************************************** * SetupCopyOEMInfW (SETUPAPI.@) */ @@ -6241,3 +6303,42 @@ HRESULT WINAPI DriverStoreAddDriverPackageA(const char *inf_path, void *unk1, free(inf_pathW); return hr; } + +HRESULT WINAPI DriverStoreDeleteDriverPackageW(const WCHAR *inf_path, void *unk1, void *unk2) +{ + struct driver_package package; + DWORD ret; + + TRACE("inf_path %s, unk1 %p, unk2 %p.\n", debugstr_w(inf_path), unk1, unk2); + + if (unk1) + FIXME("Ignoring unk1 %p.\n", unk1); + if (unk2) + FIXME("Ignoring unk2 %p.\n", unk2); + + if ((ret = parse_inf(&package, inf_path))) + return HRESULT_FROM_WIN32(ret); + + if (package.already_installed) + ret = driver_package_delete(&package); + else + ret = ERROR_FILE_NOT_FOUND; + + driver_package_cleanup(&package); + return HRESULT_FROM_WIN32(ret); +} + +HRESULT WINAPI DriverStoreDeleteDriverPackageA(const char *inf_path, void *unk1, void *unk2) +{ + WCHAR *inf_pathW; + HRESULT hr; + + TRACE("inf_path %s, unk1 %p, unk2 %p.\n", debugstr_a(inf_path), unk1, unk2); + + if (!(inf_pathW = strdupAtoW(inf_path))) + return E_OUTOFMEMORY; + + hr = DriverStoreDeleteDriverPackageW(inf_pathW, unk1, unk2); + free(inf_pathW); + return hr; +} diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index 5dddbe4fb5e..c1f87a40169 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -210,6 +210,8 @@ @ stdcall DoesUserHavePrivilege(wstr) @ stdcall DriverStoreAddDriverPackageA(ptr ptr ptr long ptr ptr) @ stdcall DriverStoreAddDriverPackageW(ptr ptr ptr long ptr ptr) +@ stdcall DriverStoreDeleteDriverPackageA(ptr ptr ptr) +@ stdcall DriverStoreDeleteDriverPackageW(ptr ptr ptr) @ stdcall DuplicateString(wstr) @ stdcall EnablePrivilege(wstr long) @ stub ExtensionPropSheetPageProc
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/setupapi/devinst.c | 108 ++++++++++++++++++++++++++++++++++++ dlls/setupapi/setupapi.spec | 2 + 2 files changed, 110 insertions(+)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 6e06d3351b4..3676a08c566 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -6203,6 +6203,114 @@ BOOL WINAPI SetupUninstallOEMInfW(const WCHAR *inf_file, DWORD flags, void *rese return TRUE; }
+HRESULT WINAPI DriverStoreFindDriverPackageW(const WCHAR *inf_path, void *unk1, + void *unk2, WORD architecture, void *unk4, WCHAR *ret_path, DWORD *ret_len) +{ + struct driver_package package; + SYSTEM_INFO system_info; + HRESULT hr; + DWORD ret; + + TRACE("inf_path %s, unk1 %p, unk2 %p, architecture %#x, unk4 %p, ret_path %p, ret_len %p.\n", + debugstr_w(inf_path), unk1, unk2, architecture, unk4, ret_path, ret_len); + + if (unk1) + FIXME("Ignoring unk1 %p.\n", unk1); + if (unk2) + FIXME("Ignoring unk2 %p.\n", unk2); + if (unk4) + FIXME("Ignoring unk4 %p.\n", unk4); + + if (*ret_len < MAX_PATH) + { + FIXME("Length %lu too short, returning E_INVALIDARG.\n", *ret_len); + return E_INVALIDARG; + } + + GetSystemInfo(&system_info); + if (architecture != system_info.wProcessorArchitecture) + { + FIXME("Wrong architecture %#x, expected %#x.\n", architecture, system_info.wProcessorArchitecture); + return E_INVALIDARG; + } + + if ((ret = parse_inf(&package, inf_path))) + return HRESULT_FROM_WIN32(ret); + + if (package.already_installed) + { + DWORD len = wcslen(package.dst_root) + 1 + wcslen(package.inf_name) + 1; + + if (len > *ret_len) + { + FIXME("Buffer too small.\n"); + /* FIXME: What do we return here? */ + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else + { + swprintf(ret_path, len, L"%s\%s", package.dst_root, package.inf_name); + hr = S_OK; + } + *ret_len = len; + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + *ret_path = 0; + *ret_len = 1; + } + + driver_package_cleanup(&package); + return hr; +} + +HRESULT WINAPI DriverStoreFindDriverPackageA(const char *inf_path, void *unk1, + void *unk2, WORD architecture, void *unk4, char *ret_path, DWORD *ret_len) +{ + WCHAR ret_pathW[MAX_PATH]; + WCHAR *inf_pathW; + DWORD lenW, len; + HRESULT hr; + + TRACE("inf_path %s, unk1 %p, unk2 %p, architecture %#x, unk4 %p, ret_path %p, ret_len %p.\n", + debugstr_a(inf_path), unk1, unk2, architecture, unk4, ret_path, ret_len); + + if (*ret_len < MAX_PATH) + { + FIXME("Length %lu too short, returning E_INVALIDARG.\n", *ret_len); + return E_INVALIDARG; + } + + if (!(inf_pathW = strdupAtoW(inf_path))) + return E_OUTOFMEMORY; + + lenW = ARRAY_SIZE(ret_pathW); + hr = DriverStoreFindDriverPackageW(inf_pathW, unk1, unk2, architecture, unk4, ret_pathW, &lenW); + if (!hr) + { + len = WideCharToMultiByte(CP_ACP, 0, ret_pathW, lenW, NULL, 0, NULL, NULL); + if (len > *ret_len) + { + FIXME("Buffer too small.\n"); + /* FIXME: What do we return here? */ + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else + { + WideCharToMultiByte(CP_ACP, 0, ret_pathW, lenW, ret_path, len, NULL, NULL); + } + *ret_len = len; + } + else + { + *ret_path = 0; + *ret_len = 1; + } + free(inf_pathW); + return hr; +} + HRESULT WINAPI DriverStoreAddDriverPackageW(const WCHAR *inf_path, void *unk1, void *unk2, WORD architecture, WCHAR *ret_path, DWORD *ret_len) { diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index c1f87a40169..d29ceea9572 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -212,6 +212,8 @@ @ stdcall DriverStoreAddDriverPackageW(ptr ptr ptr long ptr ptr) @ stdcall DriverStoreDeleteDriverPackageA(ptr ptr ptr) @ stdcall DriverStoreDeleteDriverPackageW(ptr ptr ptr) +@ stdcall DriverStoreFindDriverPackageA(ptr ptr ptr long ptr ptr ptr) +@ stdcall DriverStoreFindDriverPackageW(ptr ptr ptr long ptr ptr ptr) @ stdcall DuplicateString(wstr) @ stdcall EnablePrivilege(wstr long) @ stub ExtensionPropSheetPageProc
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/setupapi/devinst.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 3676a08c566..b22ab64a022 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -6110,6 +6110,7 @@ static DWORD driver_package_delete(const struct driver_package *package) BOOL WINAPI SetupCopyOEMInfW(const WCHAR *source, const WCHAR *location, DWORD media_type, DWORD style, WCHAR *dest, DWORD buffer_size, DWORD *required_size, WCHAR **filepart) { + struct driver_package package; WCHAR target[MAX_PATH]; DWORD size, ret;
@@ -6122,14 +6123,32 @@ BOOL WINAPI SetupCopyOEMInfW(const WCHAR *source, const WCHAR *location, DWORD m return FALSE; }
- /* check for a relative path */ - if (!(*source == '\' || (*source && source[1] == ':'))) + if ((ret = parse_inf(&package, source))) { - SetLastError(ERROR_FILE_NOT_FOUND); + SetLastError(ret); return FALSE; }
- ret = copy_inf(source, style, target); + if (package.already_installed) + { + if (find_existing_inf(source, target)) + { + if (style & SP_COPY_NOOVERWRITE) + ret = ERROR_FILE_EXISTS; + else + ret = ERROR_SUCCESS; + } + else + { + ERR("Inf %s is already installed to driver store, but not found in C:\windows\inf!\n", + debugstr_w(source)); + ret = ERROR_FILE_NOT_FOUND; + } + } + else + { + ret = driver_package_install_to_store(&package, style, target); + }
if (style & SP_COPY_DELETESOURCE) DeleteFileW(source);
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/setupapi/devinst.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index b22ab64a022..e70431e4ec9 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -6198,7 +6198,9 @@ BOOL WINAPI SetupUninstallOEMInfA(const char *inf_file, DWORD flags, void *reser */ BOOL WINAPI SetupUninstallOEMInfW(const WCHAR *inf_file, DWORD flags, void *reserved) { + struct driver_package package; WCHAR target[MAX_PATH]; + DWORD ret;
TRACE("inf_file %s, flags %#lx, reserved %p.\n", debugstr_w(inf_file), flags, reserved);
@@ -6214,12 +6216,21 @@ BOOL WINAPI SetupUninstallOEMInfW(const WCHAR *inf_file, DWORD flags, void *rese wcscat(target, L"\inf\"); wcscat(target, inf_file);
- if (flags & SUOI_FORCEDELETE) - return DeleteFileW(target); + if ((ret = parse_inf(&package, target))) + { + SetLastError(ret); + return FALSE; + }
- FIXME("not deleting %s\n", debugstr_w(target)); + if (package.already_installed) + ret = driver_package_delete(&package); + else + ret = ERROR_FILE_NOT_FOUND;
- return TRUE; + driver_package_cleanup(&package); + + SetLastError(ret); + return !ret; }
HRESULT WINAPI DriverStoreFindDriverPackageW(const WCHAR *inf_path, void *unk1,
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/setupapi/setupapi.spec | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index d29ceea9572..84d008fe4d7 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -212,6 +212,8 @@ @ stdcall DriverStoreAddDriverPackageW(ptr ptr ptr long ptr ptr) @ stdcall DriverStoreDeleteDriverPackageA(ptr ptr ptr) @ stdcall DriverStoreDeleteDriverPackageW(ptr ptr ptr) +@ stub DriverStoreEnumDriverPackageA +@ stub DriverStoreEnumDriverPackageW @ stdcall DriverStoreFindDriverPackageA(ptr ptr ptr long ptr ptr ptr) @ stdcall DriverStoreFindDriverPackageW(ptr ptr ptr long ptr ptr ptr) @ stdcall DuplicateString(wstr)
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/setupapi/tests/devinst.c | 596 +++++++++++++++++++++++++++++++++- 1 file changed, 595 insertions(+), 1 deletion(-)
diff --git a/dlls/setupapi/tests/devinst.c b/dlls/setupapi/tests/devinst.c index 194fa50f6d0..1f33f25005c 100644 --- a/dlls/setupapi/tests/devinst.c +++ b/dlls/setupapi/tests/devinst.c @@ -37,6 +37,7 @@ #include "setupapi.h" #include "cfgmgr32.h" #include "cguid.h" +#include "fci.h"
#include "wine/test.h" #include "wine/mssign.h" @@ -47,12 +48,23 @@ static GUID guid2 = {0x6a55b5a5, 0x3f65, 0x11db, {0xb7,0x04,0x00,0x11,0x95,0x5c, static GUID iface_guid = {0xdeadbeef, 0x3f65, 0x11db, {0xb7,0x04,0x00,0x11,0x95,0x5c,0x2b,0xdb}}; static GUID iface_guid2 = {0xdeadf00d, 0x3f65, 0x11db, {0xb7,0x04,0x00,0x11,0x95,0x5c,0x2b,0xdb}};
+static HRESULT (WINAPI *pDriverStoreAddDriverPackageA)(const char *inf_path, void *unk1, + void *unk2, WORD architecture, char *ret_path, DWORD *ret_len); +static HRESULT (WINAPI *pDriverStoreDeleteDriverPackageA)(const char *path, void *unk1, void *unk2); +static HRESULT (WINAPI *pDriverStoreFindDriverPackageA)(const char *inf_path, void *unk1, + void *unk2, WORD architecture, void *unk4, char *ret_path, DWORD *ret_len); static BOOL (WINAPI *pSetupDiSetDevicePropertyW)(HDEVINFO, SP_DEVINFO_DATA *, const DEVPROPKEY *, DEVPROPTYPE, const BYTE *, DWORD, DWORD); static BOOL (WINAPI *pSetupDiGetDevicePropertyW)(HDEVINFO, SP_DEVINFO_DATA *, const DEVPROPKEY *, DEVPROPTYPE *, BYTE *, DWORD, DWORD *, DWORD); static BOOL (WINAPI *pSetupQueryInfOriginalFileInformationA)(SP_INF_INFORMATION *, UINT, SP_ALTPLATFORM_INFO *, SP_ORIGINAL_FILE_INFO_A *);
static BOOL wow64;
+static void create_directory(const char *name) +{ + BOOL ret = CreateDirectoryA(name, NULL); + ok(ret, "Failed to create %s, error %lu.\n", name, GetLastError()); +} + static void create_file(const char *name, const char *data) { HANDLE file; @@ -66,6 +78,18 @@ static void create_file(const char *name, const char *data) CloseHandle(file); }
+static void delete_directory(const char *name) +{ + BOOL ret = RemoveDirectoryA(name); + ok(ret, "Failed to delete %s, error %lu.\n", name, GetLastError()); +} + +static void delete_file(const char *name) +{ + BOOL ret = DeleteFileA(name); + ok(ret, "Failed to delete %s, error %lu.\n", name, GetLastError()); +} + static void load_resource(const char *name, const char *filename) { DWORD written; @@ -395,6 +419,193 @@ static void get_temp_filename(LPSTR path) lstrcpyA(path, ptr + 1); }
+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 *ctx) +{ + sprintf(pccab->szCab, ctx, pccab->iCab); + return TRUE; +} + +static LONG CDECL progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *ctx) +{ + return 0; +} + +static int CDECL file_placed(PCCAB pccab, char *pszFile, LONG cbFile, + BOOL fContinuation, void *ctx) +{ + return 0; +} + +static INT_PTR CDECL fci_open(char *pszFile, int oflag, int pmode, int *err, void *ctx) +{ + 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 *ctx) +{ + 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 *ctx) +{ + 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 *ctx) +{ + 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 *ctx) +{ + 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 *ctx) +{ + 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 *ctx) +{ + LPSTR tempname; + + tempname = malloc(MAX_PATH); + GetTempFileNameA(".", "xx", 0, tempname); + + if (tempname && (strlen(tempname) < (unsigned)cbTempName)) + { + lstrcpyA(pszTempName, tempname); + free(tempname); + return TRUE; + } + + free(tempname); + + return FALSE; +} + +static INT_PTR CDECL get_open_info(char *name, USHORT *date, USHORT *time, USHORT *attribs, int *err, void *ctx) +{ + BY_HANDLE_FILE_INFORMATION finfo; + FILETIME filetime; + HANDLE handle; + DWORD attrs; + BOOL res; + + handle = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + + ok(handle != INVALID_HANDLE_VALUE, "Failed to create %s, error %lu.\n", debugstr_a(name), GetLastError()); + + res = GetFileInformationByHandle(handle, &finfo); + ok(res, "Expected GetFileInformationByHandle to succeed\n"); + + FileTimeToLocalFileTime(&finfo.ftLastWriteTime, &filetime); + FileTimeToDosDateTime(&filetime, date, time); + + attrs = GetFileAttributesA(name); + 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], filename[MAX_PATH]; + + GetCurrentDirectoryA(sizeof(path), path); + strcat(path, "\"); + strcat(path, file); + + strcpy(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 *source) +{ + CCAB cab_params = {0}; + HFCI hfci; + ERF erf; + BOOL res; + + cab_params.cb = INT_MAX; + cab_params.cbFolderThresh = 900000; + cab_params.setID = 0xbeef; + cab_params.iCab = 1; + GetCurrentDirectoryA(sizeof(cab_params.szCabPath), cab_params.szCabPath); + strcat(cab_params.szCabPath, "\"); + strcpy(cab_params.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, &cab_params, NULL); + + ok(hfci != NULL, "Failed to create an FCI context\n"); + + res = add_file(hfci, source, tcompTYPE_MSZIP); + ok(res, "Failed to add %s\n", source); + + 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"); +} + static void test_install_class(void) { static const WCHAR classKey[] = {'S','y','s','t','e','m','\', @@ -3711,7 +3922,7 @@ static void check_original_file_name(const char *dest_inf, const char *src_inf,
static void test_copy_oem_inf(struct testsign_context *ctx) { - char path[MAX_PATH * 2], dest[MAX_PATH], orig_dest[MAX_PATH]; + char path[MAX_PATH * 2], dest[MAX_PATH], orig_dest[MAX_PATH], orig_store[MAX_PATH]; char orig_cwd[MAX_PATH], *cwd, *filepart, pnf[MAX_PATH]; SYSTEM_INFO system_info; HANDLE catalog; @@ -3790,6 +4001,13 @@ static void test_copy_oem_inf(struct testsign_context *ctx)
testsign_sign(ctx, L"winetest.cat");
+ size = ARRAY_SIZE(dest); + memset(dest, 0xcc, sizeof(dest)); + ret = pDriverStoreFindDriverPackageA("winetest.inf", 0, 0, system_info.wProcessorArchitecture, 0, dest, &size); + ok(ret == HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Got %#x.\n", ret); + ok(!dest[0], "Got %s.\n", debugstr_a(dest)); + todo_wine ok(!size, "Got size %lu.\n", size); + /* Test with a relative path. */ SetLastError(0xdeadbeef); memset(dest, 0xcc, sizeof(dest)); @@ -3828,6 +4046,14 @@ static void test_copy_oem_inf(struct testsign_context *ctx) /* Test a successful call. */ GetCurrentDirectoryA(sizeof(path), path); strcat(path, "\winetest.inf"); + + size = ARRAY_SIZE(dest); + memset(dest, 0xcc, sizeof(dest)); + ret = pDriverStoreFindDriverPackageA(path, 0, 0, system_info.wProcessorArchitecture, 0, dest, &size); + ok(ret == HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Got %#x.\n", ret); + ok(!dest[0], "Got %s.\n", debugstr_a(dest)); + todo_wine ok(!size, "Got size %lu.\n", size); + SetLastError(0xdeadbeef); ret = SetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, dest, sizeof(dest), NULL, NULL); ok(ret == TRUE, "Got %d.\n", ret); @@ -3839,6 +4065,12 @@ static void test_copy_oem_inf(struct testsign_context *ctx)
check_original_file_name(dest, "winetest.inf", "winetest.cat");
+ size = ARRAY_SIZE(dest); + memset(dest, 0xcc, sizeof(dest)); + ret = pDriverStoreFindDriverPackageA(path, 0, 0, system_info.wProcessorArchitecture, 0, dest, &size); + ok(!ret, "Got %#x.\n", ret); + strcpy(orig_store, dest); + SetLastError(0xdeadbeef); ret = SetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, dest, sizeof(dest), NULL, NULL); ok(ret == TRUE, "Got %d.\n", ret); @@ -3917,6 +4149,13 @@ static void test_copy_oem_inf(struct testsign_context *ctx) DeleteFileA(dest); todo_wine ok(!file_exists(pnf), "Expected pnf '%s' not to exist.\n", pnf);
+ size = ARRAY_SIZE(dest); + memset(dest, 0xcc, sizeof(dest)); + ret = pDriverStoreFindDriverPackageA(path, 0, 0, system_info.wProcessorArchitecture, 0, dest, &size); + ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "Got %#x.\n", ret); + ok(!dest[0], "Got %s.\n", debugstr_a(dest)); + todo_wine ok(!size, "Got size %lu.\n", size); + create_file("winetest.inf", inf_data1); SetLastError(0xdeadbeef); ret = SetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, dest, sizeof(dest), NULL, NULL); @@ -3983,6 +4222,357 @@ static void test_copy_oem_inf(struct testsign_context *ctx)
}
+static void check_driver_store_file_exists(const char *driver_store, const char *file, BOOL exists) +{ + char path[MAX_PATH]; + + sprintf(path, "%s\%s", driver_store, file); + ok(file_exists(path) == exists, "Expected %s to %s.\n", debugstr_a(path), exists ? "exist" : "not exist"); +} + +static const char driver_store_hardware_id[] = "winetest_store_hardware_id\0"; + +static void create_driver_store_test_device(HDEVINFO set, const char *name, SP_DEVINFO_DATA *device) +{ + static const GUID guid = {0x77777777}; + BOOL ret; + + if (SetupDiOpenDeviceInfoA(set, name, NULL, 0, device)) + { + ret = SetupDiCallClassInstaller(DIF_REMOVE, set, device); + ok(ret, "Failed to remove device, error %#lx.\n", GetLastError()); + } + + ret = SetupDiCreateDeviceInfoA(set, name, &guid, NULL, NULL, 0, device); + ok(ret, "Failed to create device, error %#lx.\n", GetLastError()); + ret = SetupDiSetDeviceRegistryPropertyA(set, device, SPDRP_HARDWAREID, + (const BYTE *)driver_store_hardware_id, sizeof(driver_store_hardware_id)); + ok(ret, "Failed to set hardware ID, error %#lx.\n", GetLastError()); + ret = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, set, device); + ok(ret, "Failed to call class installer, error %#lx.\n", GetLastError()); +} + +static void test_driver_store(struct testsign_context *ctx) +{ + static const char repository_dir[] = "C:\windows\system32\DriverStore\FileRepository\"; + SP_DEVINFO_DATA device = {sizeof(device)}, device2 = {sizeof(device2)}; + char dest[MAX_PATH], orig_dest[MAX_PATH], inf_path[MAX_PATH]; + SP_DRVINFO_DATA_A driver = {sizeof(driver)}; + char orig_cwd[MAX_PATH], *cwd; + char driver_path[MAX_PATH]; + SYSTEM_INFO system_info; + HANDLE catalog; + HDEVINFO set; + DWORD size; + BOOL ret; + + static const char inf_data1[] = + "[Version]\n" + "Signature="$Chicago$"\n" + "CatalogFile=winetest.cat\n" + "Class=Bogus\n" + "ClassGUID={6a55b5a4-3f65-11db-b704-0011955c2bdb}\n" + + "[Manufacturer]\n" + "mfg1=mfg_section,NT" MYEXT "\n" + "mfg2=mfg_section_wrongarch,NT" WRONGEXT "\n" + + "[mfg_section.nt" MYEXT "]\n" + "desc1=device_section,winetest_store_hardware_id\n" + + "[mfg_section_wrongarch.nt" WRONGEXT "]\n" + "desc1=device_section2,winetest_store_hardware_id\n" + + "[device_section.nt" MYEXT "]\n" + "CopyFiles=file_section\n" + + "[device_section_wrongarch.nt" WRONGEXT "]\n" + "CopyFiles=file_section_wrongarch\n" + + "[device_section.nt" MYEXT ".CoInstallers]\n" + "CopyFiles=coinst_file_section\n" + + "[file_section]\n" + "winetest_dst.txt,winetest_src.txt\n" + "winetest_child.txt\n" + "winetest_niece.txt\n" + "winetest_cab.txt\n" + + "[file_section_wrongarch]\n" + "winetest_wrongarch.txt\n" + + "[coinst_file_section]\n" + "winetest_coinst.txt\n" + + "[SourceDisksFiles]\n" + "winetest_src.txt=1\n" + "winetest_child.txt=1,subdir\n" + "winetest_niece.txt=2\n" + "winetest_ignored.txt=1\n" + "winetest_ignored2.txt=1\n" + "winetest_wrongarch.txt=1\n" + "winetest_cab.txt=3\n" + "winetest_coinst.txt=1\n" + + "[SourceDisksNames]\n" + "1=,winetest_src.txt\n" + "2=,winetest_niece.txt,,sister\n" + "3=,winetest_cab.cab\n" + + "[DestinationDirs]\n" + "DefaultDestDir=11\n" + ; + + if (wow64) + return; + + GetSystemInfo(&system_info); + + set = SetupDiCreateDeviceInfoList(NULL, NULL); + ok(set != INVALID_HANDLE_VALUE, "Failed to create device list, error %#lx.\n", GetLastError()); + + create_driver_store_test_device(set, "Root\winetest_store\1", &device); + + GetCurrentDirectoryA(sizeof(orig_cwd), orig_cwd); + cwd = tempnam(NULL, "wine"); + ret = CreateDirectoryA(cwd, NULL); + ok(ret, "Failed to create %s, error %lu.\n", debugstr_a(cwd), GetLastError()); + ret = SetCurrentDirectoryA(cwd); + ok(ret, "Failed to cd to %s, error %lu.\n", debugstr_a(cwd), GetLastError()); + + create_file("winetest.inf", inf_data1); + create_file("winetest_src.txt", "data1"); + create_file("winetest_unused.txt", "unused"); + create_file("winetest_ignored2.txt", "ignored2"); + create_directory("subdir"); + create_directory("sister"); + create_file("subdir\winetest_child.txt", "child"); + create_file("sister\winetest_niece.txt", "niece"); + create_file("winetest_cab.txt", "cab"); + create_cab_file("winetest_cab.cab", "winetest_cab.txt"); + create_file("winetest_coinst.txt", "coinst"); + + /* If the catalog doesn't exist, or any files are missing from it, + * validation fails and we get a UI dialog. */ + + catalog = CryptCATOpen((WCHAR *)L"winetest.cat", CRYPTCAT_OPEN_CREATENEW, 0, CRYPTCAT_VERSION_1, 0); + ok(catalog != INVALID_HANDLE_VALUE, "Failed to create catalog, error %#lx\n", GetLastError()); + + add_file_to_catalog(catalog, L"winetest.inf"); + add_file_to_catalog(catalog, L"winetest_src.txt"); + add_file_to_catalog(catalog, L"subdir\winetest_child.txt"); + add_file_to_catalog(catalog, L"sister\winetest_niece.txt"); + add_file_to_catalog(catalog, L"winetest_cab.txt"); + add_file_to_catalog(catalog, L"winetest_coinst.txt"); + add_file_to_catalog(catalog, L"winetest_unused.txt"); + add_file_to_catalog(catalog, L"winetest_ignored2.txt"); + + ret = CryptCATPersistStore(catalog); + todo_wine ok(ret, "Failed to write catalog, error %lu\n", GetLastError()); + + ret = CryptCATClose(catalog); + ok(ret, "Failed to close catalog, error %lu\n", GetLastError()); + + testsign_sign(ctx, L"winetest.cat"); + + /* Delete one of the files referenced in the catalog, to show that files + * present in the catalog and not used in the INF don't need to be present. */ + delete_file("winetest_unused.txt"); + /* Also delete the cab source file. */ + delete_file("winetest_cab.txt"); + + size = ARRAY_SIZE(dest); + memset(dest, 0xcc, sizeof(dest)); + ret = pDriverStoreFindDriverPackageA("winetest.inf", 0, 0, system_info.wProcessorArchitecture, 0, dest, &size); + ok(ret == HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Got %#x.\n", ret); + ok(!dest[0], "Got %s.\n", debugstr_a(dest)); + todo_wine ok(!size, "Got size %lu.\n", size); + + /* Windows 7 allows relative paths. Windows 8+ do not. + * However, all versions seem to accept relative paths in + * DriverStoreFindDriverPackage(). */ + + sprintf(inf_path, "%s\winetest.inf", cwd); + + size = ARRAY_SIZE(dest); + memset(dest, 0xcc, sizeof(dest)); + ret = pDriverStoreAddDriverPackageA(inf_path, 0, 0, system_info.wProcessorArchitecture, dest, &size); + ok(!ret, "Got %#x.\n", ret); + ok(size > ARRAY_SIZE(repository_dir), "Got size %lu.\n", size); + ok(size == strlen(dest) + 1, "Expected size %Iu, got %lu.\n", strlen(dest) + 1, size); + ok(!memicmp(dest, repository_dir, strlen(repository_dir)), "Got path %s.\n", debugstr_a(dest)); + ok(!strcmp(dest + strlen(dest) - 13, "\winetest.inf"), "Got path %s.\n", debugstr_a(dest)); + + strcpy(orig_dest, dest); + + /* Add again. */ + size = ARRAY_SIZE(dest); + memset(dest, 0xcc, sizeof(dest)); + ret = pDriverStoreAddDriverPackageA(inf_path, 0, 0, system_info.wProcessorArchitecture, dest, &size); + ok(!ret, "Got %#x.\n", ret); + ok(!strcmp(dest, orig_dest), "Expected %s, got %s.\n", debugstr_a(orig_dest), debugstr_a(dest)); + ok(size == strlen(dest) + 1, "Expected size %Iu, got %lu.\n", strlen(dest) + 1, size); + + size = ARRAY_SIZE(dest); + memset(dest, 0xcc, sizeof(dest)); + ret = pDriverStoreFindDriverPackageA("winetest.inf", 0, 0, system_info.wProcessorArchitecture, 0, dest, &size); + ok(!ret, "Got %#x.\n", ret); + ok(!strcmp(dest, orig_dest), "Expected %s, got %s.\n", debugstr_a(orig_dest), debugstr_a(dest)); + ok(size == strlen(dest) + 1, "Expected size %Iu, got %lu.\n", strlen(dest) + 1, size); + + /* Test the length parameter. + * Anything less than MAX_PATH returns E_INVALIDARG. + * It's not clear what happens if the returned path is longer than MAX_PATH. */ + + size = MAX_PATH - 1; + memset(dest, 0xcc, sizeof(dest)); + ret = pDriverStoreFindDriverPackageA("winetest.inf", 0, 0, system_info.wProcessorArchitecture, 0, dest, &size); + ok(ret == E_INVALIDARG, "Got %#x.\n", ret); + ok(dest[0] == (char)0xcc, "Got %s.\n", debugstr_a(dest)); + ok(size == MAX_PATH - 1, "Expected size %Iu, got %lu.\n", strlen(orig_dest) + 1, size); + + size = 0; + ret = pDriverStoreFindDriverPackageA("winetest.inf", 0, 0, system_info.wProcessorArchitecture, 0, dest, &size); + ok(ret == E_INVALIDARG, "Got %#x.\n", ret); + ok(!size, "Got size %lu.\n", size); + + /* Adding to the store also copies to the C:\windows\inf dir. */ + ret = SetupCopyOEMInfA(orig_dest, NULL, 0, SP_COPY_REPLACEONLY, NULL, 0, NULL, NULL); + ok(ret == TRUE, "Got %#x.\n", ret); + + /* The catalog, and files referenced through a CopyFiles section, + * are also present. */ + strcpy(dest, orig_dest); + *strrchr(dest, '\') = 0; + check_driver_store_file_exists(dest, "winetest.cat", TRUE); + check_driver_store_file_exists(dest, "winetest_src.txt", TRUE); + check_driver_store_file_exists(dest, "subdir/winetest_child.txt", TRUE); + check_driver_store_file_exists(dest, "sister/winetest_niece.txt", TRUE); + check_driver_store_file_exists(dest, "winetest_cab.txt", TRUE); + check_driver_store_file_exists(dest, "winetest_coinst.txt", TRUE); + check_driver_store_file_exists(dest, "winetest_dst.txt", FALSE); + check_driver_store_file_exists(dest, "winetest_ignored2.txt", FALSE); + check_driver_store_file_exists(dest, "winetest_cab.cab", FALSE); + + /* The inf is installed to C:\windows\inf, but the driver isn't installed + * for existing devices that match, and hence files aren't installed to + * their final destination. */ + + ret = SetupDiBuildDriverInfoList(set, &device, SPDIT_COMPATDRIVER); + ok(ret, "Got error %#lx.\n", GetLastError()); + + ret = SetupDiSelectBestCompatDrv(set, &device); + ok(ret, "Got error %#lx.\n", GetLastError()); + + ret = SetupDiGetSelectedDriverA(set, &device, &driver); + ok(driver.DriverType == SPDIT_COMPATDRIVER, "Got wrong type %#lx.\n", driver.DriverType); + ok(!strcmp(driver.Description, "desc1"), "Got wrong description '%s'.\n", driver.Description); + ok(!strcmp(driver.MfgName, "mfg1"), "Got wrong manufacturer '%s'.\n", driver.MfgName); + ok(!strcmp(driver.ProviderName, ""), "Got wrong provider '%s'.\n", driver.ProviderName); + + ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_DRIVER, NULL, + (BYTE *)driver_path, sizeof(driver_path), NULL); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "Got unexpected error %#lx.\n", GetLastError()); + + ok(!file_exists("C:\windows\system32\winetest_dst.txt"), "Expected dst to not exist.\n"); + + /* The apparent point of the driver store is to provide a source directory + * for INF files that doesn't require the original install medium. + * Hence, test that we can move the original files out of place and then + * trigger device installation. + * + * (Of course, it would have been easier just to install the driver files + * directly, even if the corresponding device doesn't exist yet, but that's + * not the model that Microsoft chose, for some reason. */ + + ret = MoveFileExA("winetest.cat", "not_winetest.cat", 0); + ok(ret, "Got error %#lx.\n", GetLastError()); + ret = MoveFileExA("winetest_src.txt", "not_winetest_src.txt", 0); + ok(ret, "Got error %#lx.\n", GetLastError()); + ret = MoveFileExA("winetest_cab.cab", "not_winetest_cab.cab", 0); + ok(ret, "Got error %#lx.\n", GetLastError()); + ret = MoveFileExA("sister", "not_sister", 0); + ok(ret, "Got error %#lx.\n", GetLastError()); + + /* Also call DriverStoreFindDriverPackageA() again here, to prove that it + * only needs to compare the inf, not any of the other files. */ + size = ARRAY_SIZE(dest); + memset(dest, 0xcc, sizeof(dest)); + ret = pDriverStoreFindDriverPackageA("winetest.inf", 0, 0, system_info.wProcessorArchitecture, 0, dest, &size); + ok(!ret, "Got %#x.\n", ret); + ok(!strcmp(dest, orig_dest), "Expected %s, got %s.\n", debugstr_a(orig_dest), debugstr_a(dest)); + ok(size == strlen(dest) + 1, "Expected size %Iu, got %lu.\n", strlen(dest) + 1, size); + + ret = MoveFileExA("winetest.inf", "not_winetest.inf", 0); + ok(ret, "Got error %#lx.\n", GetLastError()); + + /* However, the inf name does need to match. */ + size = ARRAY_SIZE(dest); + memset(dest, 0xcc, sizeof(dest)); + ret = pDriverStoreFindDriverPackageA("not_winetest.inf", 0, 0, system_info.wProcessorArchitecture, 0, dest, &size); + ok(ret == HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Got %#x.\n", ret); + ok(!dest[0], "Got %s.\n", debugstr_a(dest)); + todo_wine ok(!size, "Got size %lu.\n", size); + + ret = SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES, set, &device); + ok(ret, "Got error %#lx.\n", GetLastError()); + + delete_file("C:\windows\system32\winetest_dst.txt"); + delete_file("C:\windows\system32\winetest_child.txt"); + delete_file("C:\windows\system32\winetest_niece.txt"); + delete_file("C:\windows\system32\winetest_cab.txt"); + todo_wine delete_file("C:\windows\system32\winetest_coinst.txt"); + + ret = MoveFileExA("not_winetest.inf", "winetest.inf", 0); + ok(ret, "Got error %#lx.\n", GetLastError()); + ret = MoveFileExA("not_winetest.cat", "winetest.cat", 0); + ok(ret, "Got error %#lx.\n", GetLastError()); + ret = MoveFileExA("not_winetest_src.txt", "winetest_src.txt", 0); + ok(ret, "Got error %#lx.\n", GetLastError()); + ret = MoveFileExA("not_winetest_cab.cab", "winetest_cab.cab", 0); + ok(ret, "Got error %#lx.\n", GetLastError()); + ret = MoveFileExA("not_sister", "sister", 0); + ok(ret, "Got error %#lx.\n", GetLastError()); + + ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device); + ok(ret, "Got error %#lx.\n", GetLastError()); + + ret = pDriverStoreDeleteDriverPackageA(orig_dest, 0, 0); + ok(!ret, "Got %#x.\n", ret); + + ret = SetupCopyOEMInfA(orig_dest, NULL, 0, SP_COPY_REPLACEONLY, NULL, 0, NULL, NULL); + ok(!ret, "Got %#x.\n", ret); + todo_wine ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Got error %lu.\n", GetLastError()); + + /* All files reachable through CopyFiles have to be present. If any are + * missing, DriverStoreAddDriverPackage() fails with + * HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND). + * + * On Windows 8, this also seems to result in an internal leak: attempting + * to delete the source directory afterward ("cwd") fails with + * ERROR_SHARING_VIOLATION, even though FindFirstFile() confirms that it's + * empty. */ + + delete_file("subdir\winetest_child.txt"); + delete_file("sister\winetest_niece.txt"); + delete_file("winetest_cab.cab"); + delete_file("winetest_coinst.txt"); + delete_file("winetest_ignored2.txt"); + delete_file("winetest_src.txt"); + delete_file("winetest.cat"); + delete_file("winetest.inf"); + delete_directory("subdir"); + delete_directory("sister"); + + SetCurrentDirectoryA(orig_cwd); + ret = RemoveDirectoryA(cwd); + ok(ret, "Failed to delete %s, error %lu.\n", cwd, GetLastError()); + + ret = SetupDiDestroyDeviceInfoList(set); + ok(ret, "Failed to destroy device list.\n"); +} + START_TEST(devinst) { static BOOL (WINAPI *pIsWow64Process)(HANDLE, BOOL *); @@ -3990,6 +4580,9 @@ START_TEST(devinst) struct testsign_context ctx; HKEY hkey;
+ pDriverStoreAddDriverPackageA = (void *)GetProcAddress(module, "DriverStoreAddDriverPackageA"); + pDriverStoreFindDriverPackageA = (void *)GetProcAddress(module, "DriverStoreFindDriverPackageA"); + pDriverStoreDeleteDriverPackageA = (void *)GetProcAddress(module, "DriverStoreDeleteDriverPackageA"); pSetupQueryInfOriginalFileInformationA = (void *)GetProcAddress(module, "SetupQueryInfOriginalFileInformationA");
test_get_actual_section(); @@ -4031,6 +4624,7 @@ START_TEST(devinst) return;
test_copy_oem_inf(&ctx); + test_driver_store(&ctx);
testsign_cleanup(&ctx); }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=147264
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
setupapi: devinst.c:4503: Test failed: Got 0x80070490. devinst.c:4504: Test failed: Expected "C:\Windows\System32\DriverStore\FileRepository\winetest.inf_x86_neutral_d9fb57589cec6293\winetest.inf", got "". devinst.c:4505: Test failed: Expected size 1, got 0.
=== w7u_el (32 bit report) ===
setupapi: devinst.c:4503: Test failed: Got 0x80070490. devinst.c:4504: Test failed: Expected "C:\Windows\System32\DriverStore\FileRepository\winetest.inf_x86_neutral_d9fb57589cec6293\winetest.inf", got "". devinst.c:4505: Test failed: Expected size 1, got 0.
=== w7pro64 (64 bit report) ===
setupapi: devinst.c:4503: Test failed: Got 0x80070490. devinst.c:4504: Test failed: Expected "C:\Windows\System32\DriverStore\FileRepository\winetest.inf_amd64_neutral_a73d996a8cf778c8\winetest.inf", got "". devinst.c:4505: Test failed: Expected size 1, got 0.
=== debian11 (32 bit report) ===
setupapi: devinst.c:4015: Test succeeded inside todo block: Got 1. devinst.c:4016: Test succeeded inside todo block: Got error 0. devinst.c:4148: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest.inf' not to exist. devinst.c:4150: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest.pnf' not to exist. devinst.c:4193: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4197: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist. devinst.c:4201: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4205: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist. misc.c:417: Test succeeded inside todo block: Expected failure misc.c:425: Test succeeded inside todo block: Expected failure misc.c:426: Test succeeded inside todo block: Expected ERROR_FILE_NOT_FOUND, got 00000002
=== debian11 (32 bit ar:MA report) ===
setupapi: devinst.c:4015: Test succeeded inside todo block: Got 1. devinst.c:4016: Test succeeded inside todo block: Got error 0. devinst.c:4148: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest.inf' not to exist. devinst.c:4150: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest.pnf' not to exist. devinst.c:4193: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4197: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist. devinst.c:4201: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4205: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist.
=== debian11 (32 bit de report) ===
setupapi: devinst.c:4015: Test succeeded inside todo block: Got 1. devinst.c:4016: Test succeeded inside todo block: Got error 0. devinst.c:4148: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest.inf' not to exist. devinst.c:4150: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest.pnf' not to exist. devinst.c:4193: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4197: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist. devinst.c:4201: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4205: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist.
=== debian11 (32 bit fr report) ===
setupapi: devinst.c:4015: Test succeeded inside todo block: Got 1. devinst.c:4016: Test succeeded inside todo block: Got error 0. devinst.c:4148: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest.inf' not to exist. devinst.c:4150: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest.pnf' not to exist. devinst.c:4193: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4197: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist. devinst.c:4201: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4205: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist.
=== debian11 (32 bit he:IL report) ===
setupapi: devinst.c:4015: Test succeeded inside todo block: Got 1. devinst.c:4016: Test succeeded inside todo block: Got error 0. devinst.c:4148: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest.inf' not to exist. devinst.c:4150: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest.pnf' not to exist. devinst.c:4193: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4197: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist. devinst.c:4201: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4205: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist.
=== debian11 (32 bit hi:IN report) ===
setupapi: devinst.c:4015: Test succeeded inside todo block: Got 1. devinst.c:4016: Test succeeded inside todo block: Got error 0. devinst.c:4148: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest.inf' not to exist. devinst.c:4150: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest.pnf' not to exist. devinst.c:4193: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4197: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist. devinst.c:4201: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4205: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist.
=== debian11 (32 bit ja:JP report) ===
setupapi: devinst.c:4015: Test succeeded inside todo block: Got 1. devinst.c:4016: Test succeeded inside todo block: Got error 0. devinst.c:4148: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest.inf' not to exist. devinst.c:4150: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest.pnf' not to exist. devinst.c:4193: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4197: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist. devinst.c:4201: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4205: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist.
=== debian11 (32 bit zh:CN report) ===
setupapi: devinst.c:4015: Test succeeded inside todo block: Got 1. devinst.c:4016: Test succeeded inside todo block: Got error 0. devinst.c:4148: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest.inf' not to exist. devinst.c:4150: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest.pnf' not to exist. devinst.c:4193: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4197: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist. devinst.c:4201: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4205: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist.
=== debian11b (64 bit WoW report) ===
setupapi: devinst.c:4015: Test succeeded inside todo block: Got 1. devinst.c:4016: Test succeeded inside todo block: Got error 0. devinst.c:4148: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest.inf' not to exist. devinst.c:4150: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest.pnf' not to exist. devinst.c:4193: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4197: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist. devinst.c:4201: Test succeeded inside todo block: Expected inf 'C:\windows\inf\winetest2.inf' not to exist. devinst.c:4205: Test succeeded inside todo block: Expected pnf 'C:\windows\inf\winetest2.pnf' not to exist. misc.c:417: Test succeeded inside todo block: Expected failure misc.c:425: Test succeeded inside todo block: Expected failure misc.c:426: Test succeeded inside todo block: Expected ERROR_FILE_NOT_FOUND, got 00000002
Impressive, thanks for taking this on! Can't have been easy...