From a1188a84d802129c63bd342e782c09cd8bbf738f Mon Sep 17 00:00:00 2001 From: winesync Date: Sun, 17 Sep 2023 15:36:58 +0200 Subject: [PATCH] [WINESYNC] setupapi: Rewrite DiskSpaceList logic using lists. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wine-staging patch by Michael Müller [WINESYNC] setupapi: Implement SetupAddToDiskSpaceList. wine-staging patch by Michael Müller [WINESYNC] setupapi: Implement SetupQueryDrivesInDiskSpaceList. wine-staging patch by Michael Müller + Add the .spec exports. Co-authored-by: Hermès Bélusca-Maïto [WINESYNC] setupapi: Ignore deletion of added files in SetupAddToDiskSpaceList. wine-staging patch by Michael Müller [WINESYNC] setupapi: ImplementSetupAddSectionToDiskSpaceList. wine-staging patch by Michael Müller [WINESYNC] setupapi: Implement SetupAddInstallSectionToDiskSpaceList. wine-staging patch by Michael Müller --- dll/win32/setupapi/diskspace.c | 640 ++++++++++++++--- dll/win32/setupapi/queue.c | 2 +- dll/win32/setupapi/setupapi.spec | 12 +- dll/win32/setupapi/setupapi_private.h | 2 + .../rostests/winetests/setupapi/diskspace.c | 650 +++++++++++++++++- ...write_DiskSpaceList_logic_using_lists.diff | 276 ++++++++ ...pi__Implement_SetupAddToDiskSpaceList.diff | 380 ++++++++++ ...ement_SetupQueryDrivesInDiskSpaceList.diff | 194 ++++++ ...dded_files_in_SetupAddToDiskSpaceList.diff | 109 +++ ...plementSetupAddSectionToDiskSpaceList.diff | 418 +++++++++++ ...SetupAddInstallSectionToDiskSpaceList.diff | 306 +++++++++ 11 files changed, 2878 insertions(+), 111 deletions(-) create mode 100644 sdk/tools/winesync/setupapi_staging/0001-setupapi__Rewrite_DiskSpaceList_logic_using_lists.diff create mode 100644 sdk/tools/winesync/setupapi_staging/0002-setupapi__Implement_SetupAddToDiskSpaceList.diff create mode 100644 sdk/tools/winesync/setupapi_staging/0003-setupapi__Implement_SetupQueryDrivesInDiskSpaceList.diff create mode 100644 sdk/tools/winesync/setupapi_staging/0004-setupapi__Ignore_deletion_of_added_files_in_SetupAddToDiskSpaceList.diff create mode 100644 sdk/tools/winesync/setupapi_staging/0005-setupapi__ImplementSetupAddSectionToDiskSpaceList.diff create mode 100644 sdk/tools/winesync/setupapi_staging/0006-setupapi__Implement_SetupAddInstallSectionToDiskSpaceList.diff diff --git a/dll/win32/setupapi/diskspace.c b/dll/win32/setupapi/diskspace.c index 5fc3f6a2319..dd1383ee31b 100644 --- a/dll/win32/setupapi/diskspace.c +++ b/dll/win32/setupapi/diskspace.c @@ -1,6 +1,7 @@ /* * SetupAPI DiskSpace functions * + * Copyright 2016 Michael Müller * Copyright 2004 CodeWeavers (Aric Stewart) * * This library is free software; you can redistribute it and/or @@ -18,67 +19,79 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include "setupapi_private.h" +#include "wine/list.h" -typedef struct { - WCHAR lpzName[20]; - LONGLONG dwFreeSpace; - LONGLONG dwWantedSpace; -} DRIVE_ENTRY, *LPDRIVE_ENTRY; +struct file_entry +{ + struct list entry; + WCHAR *path; + UINT operation; + LONGLONG size; +}; -typedef struct { - DWORD dwDriveCount; - DRIVE_ENTRY Drives[26]; -} DISKSPACELIST, *LPDISKSPACELIST; +struct space_list +{ + struct list files; + UINT flags; +}; +static LONGLONG get_file_size(WCHAR *path) +{ + HANDLE file; + LARGE_INTEGER size; + + file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) return 0; + + if (!GetFileSizeEx(file, &size)) + size.QuadPart = 0; + + CloseHandle(file); + return size.QuadPart; +} + +static BOOL get_size_from_inf(HINF layoutinf, WCHAR *filename, LONGLONG *size) +{ + static const WCHAR SourceDisksFiles[] = {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0}; + INFCONTEXT context; + WCHAR buffer[20]; + + if (!SetupFindFirstLineW(layoutinf, SourceDisksFiles, filename, &context)) + return FALSE; + + if (!SetupGetStringFieldW(&context, 3, buffer, sizeof(buffer), NULL)) + return FALSE; + + /* FIXME: is there a atollW ? */ + *size = wcstol(buffer, NULL, 10); + return TRUE; +} /*********************************************************************** * SetupCreateDiskSpaceListW (SETUPAPI.@) */ -HDSKSPC WINAPI SetupCreateDiskSpaceListW(PVOID Reserved1, DWORD Reserved2, UINT Flags) +HDSKSPC WINAPI SetupCreateDiskSpaceListW(PVOID reserved1, DWORD reserved2, UINT flags) { - WCHAR drives[255]; - DWORD rc; - WCHAR *ptr; - LPDISKSPACELIST list=NULL; + struct space_list *list; - TRACE("(%p, %lu, 0x%08x)\n", Reserved1, Reserved2, Flags); + TRACE("(%p, %lu, 0x%08x)\n", reserved1, reserved2, flags); - if (Reserved1 || Reserved2 || Flags & ~SPDSL_IGNORE_DISK) + if (reserved1 || reserved2 || flags & ~SPDSL_IGNORE_DISK) { SetLastError(ERROR_INVALID_PARAMETER); return NULL; } - rc = GetLogicalDriveStringsW(255,drives); - - if (rc == 0) - return NULL; - - list = malloc(sizeof(DISKSPACELIST)); - - list->dwDriveCount = 0; - - ptr = drives; - - while (*ptr) + list = malloc(sizeof(*list)); + if (list) { - DWORD type = GetDriveTypeW(ptr); - if (type == DRIVE_FIXED) - { - DWORD clusters; - DWORD sectors; - DWORD bytes; - DWORD total; - lstrcpyW(list->Drives[list->dwDriveCount].lpzName,ptr); - GetDiskFreeSpaceW(ptr,§ors,&bytes,&clusters,&total); - list->Drives[list->dwDriveCount].dwFreeSpace = clusters * sectors * - bytes; - list->Drives[list->dwDriveCount].dwWantedSpace = 0; - list->dwDriveCount++; - } - ptr += lstrlenW(ptr) + 1; + list->flags = flags; + list_init(&list->files); } + return list; } @@ -94,32 +107,58 @@ HDSKSPC WINAPI SetupCreateDiskSpaceListA(PVOID Reserved1, DWORD Reserved2, UINT /*********************************************************************** * SetupDuplicateDiskSpaceListW (SETUPAPI.@) */ -HDSKSPC WINAPI SetupDuplicateDiskSpaceListW(HDSKSPC DiskSpace, PVOID Reserved1, DWORD Reserved2, UINT Flags) +HDSKSPC WINAPI SetupDuplicateDiskSpaceListW(HDSKSPC diskspace, PVOID reserved1, DWORD reserved2, UINT flags) { - DISKSPACELIST *list_copy, *list_original = DiskSpace; + struct space_list *list_copy, *list = diskspace; + struct file_entry *file, *file_copy; - if (Reserved1 || Reserved2 || Flags) + TRACE("(%p, %p, %lu, %u)\n", diskspace, reserved1, reserved2, flags); + + if (reserved1 || reserved2 || flags) { SetLastError(ERROR_INVALID_PARAMETER); return NULL; } - if (!DiskSpace) + if (!diskspace) { SetLastError(ERROR_INVALID_HANDLE); return NULL; } - list_copy = malloc(sizeof(DISKSPACELIST)); + list_copy = malloc(sizeof(*list_copy)); if (!list_copy) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } - *list_copy = *list_original; + list_copy->flags = list->flags; + list_init(&list_copy->files); + + LIST_FOR_EACH_ENTRY(file, &list->files, struct file_entry, entry) + { + file_copy = malloc(sizeof(*file_copy)); + if (!file_copy) goto error; + + file_copy->path = wcsdup(file->path); + if (!file_copy->path) + { + free(file_copy); + goto error; + } + + file_copy->operation = file->operation; + file_copy->size = file->size; + list_add_head(&list_copy->files, &file->entry); + } return list_copy; + +error: + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + SetupDestroyDiskSpaceList(list_copy); + return NULL; } /*********************************************************************** @@ -131,68 +170,254 @@ HDSKSPC WINAPI SetupDuplicateDiskSpaceListA(HDSKSPC DiskSpace, PVOID Reserved1, } /*********************************************************************** - * SetupAddInstallSectionToDiskSpaceListA (SETUPAPI.@) + * SetupAddSectionToDiskSpaceListW (SETUPAPI.@) */ -BOOL WINAPI SetupAddInstallSectionToDiskSpaceListA(HDSKSPC DiskSpace, - HINF InfHandle, HINF LayoutInfHandle, - LPCSTR SectionName, PVOID Reserved1, UINT Reserved2) +BOOL WINAPI SetupAddSectionToDiskSpaceListW(HDSKSPC diskspace, HINF hinf, HINF hlist, + PCWSTR section, UINT operation, PVOID reserved1, + UINT reserved2) { - FIXME ("Stub\n"); - return TRUE; -} + static const WCHAR sepW[] = {'\\',0}; + WCHAR dest[MAX_PATH], src[MAX_PATH], *dest_dir, *full_path; + INFCONTEXT context; + BOOL ret = FALSE; -/*********************************************************************** -* SetupQuerySpaceRequiredOnDriveW (SETUPAPI.@) -*/ -BOOL WINAPI SetupQuerySpaceRequiredOnDriveW(HDSKSPC DiskSpace, - LPCWSTR DriveSpec, LONGLONG *SpaceRequired, - PVOID Reserved1, UINT Reserved2) -{ - WCHAR *driveW; - unsigned int i; - LPDISKSPACELIST list = DiskSpace; - BOOL rc = FALSE; - static const WCHAR bkslsh[]= {'\\',0}; + TRACE("(%p, %p, %p, %s, %u, %p, %u)\n", diskspace, hinf, hlist, debugstr_w(section), + operation, reserved1, reserved2); - if (!DiskSpace) + if (!diskspace) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } - if (!DriveSpec) + if (!section) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - driveW = malloc((wcslen(DriveSpec) + 2) * sizeof(WCHAR)); - if (!driveW) + if (!hlist) hlist = hinf; + + if (!SetupFindFirstLineW(hlist, section, NULL, &context)) + { + SetLastError(ERROR_SECTION_NOT_FOUND); + return FALSE; + } + + dest_dir = get_destination_dir(hinf, section); + if (!dest_dir) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } - lstrcpyW(driveW,DriveSpec); - lstrcatW(driveW,bkslsh); - - TRACE("Looking for drive %s\n",debugstr_w(driveW)); - - for (i = 0; i < list->dwDriveCount; i++) + do { - TRACE("checking drive %s\n",debugstr_w(list->Drives[i].lpzName)); - if (wcscmp(driveW,list->Drives[i].lpzName)==0) + LONGLONG filesize; + int path_size; + BOOL tmp_ret; + + if (!SetupGetStringFieldW(&context, 1, dest, sizeof(dest) / sizeof(WCHAR), NULL)) + goto end; + if (!SetupGetStringFieldW(&context, 2, src, sizeof(src) / sizeof(WCHAR), NULL)) + *src = 0; + if (!get_size_from_inf(hinf, src[0] ? src : dest, &filesize)) + goto end; + + path_size = lstrlenW(dest_dir) + lstrlenW(dest) + 2; + full_path = HeapAlloc(GetProcessHeap(), 0, path_size * sizeof(WCHAR)); + if (!full_path) { - rc = TRUE; - *SpaceRequired = list->Drives[i].dwWantedSpace; - break; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto end; } + + lstrcpyW(full_path, dest_dir); + lstrcatW(full_path, sepW); + lstrcatW(full_path, dest); + + tmp_ret = SetupAddToDiskSpaceListW(diskspace, full_path, filesize, operation, 0, 0); + HeapFree(GetProcessHeap(), 0, full_path); + if (!tmp_ret) goto end; + } + while (SetupFindNextLine(&context, &context)); + + ret = TRUE; + +end: + HeapFree(GetProcessHeap(), 0, dest_dir); + return ret; +} + +/*********************************************************************** + * SetupAddSectionToDiskSpaceListA (SETUPAPI.@) + */ +BOOL WINAPI SetupAddSectionToDiskSpaceListA(HDSKSPC diskspace, HINF hinf, HINF hlist, + PCSTR section, UINT operation, PVOID reserved1, + UINT reserved2) +{ + LPWSTR sectionW = NULL; + DWORD len; + BOOL ret; + + if (section) + { + len = MultiByteToWideChar(CP_ACP, 0, section, -1, NULL, 0); + + sectionW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!sectionW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + MultiByteToWideChar(CP_ACP, 0, section, -1, sectionW, len); } - free(driveW); + ret = SetupAddSectionToDiskSpaceListW(diskspace, hinf, hlist, sectionW, operation, + reserved1, reserved2); + if (sectionW) HeapFree(GetProcessHeap(), 0, sectionW); + return ret; +} - if (!rc) SetLastError(ERROR_INVALID_DRIVE); - return rc; +/*********************************************************************** + * SetupAddInstallSectionToDiskSpaceListW (SETUPAPI.@) + */ +BOOL WINAPI SetupAddInstallSectionToDiskSpaceListW(HDSKSPC diskspace, + HINF inf, HINF layoutinf, LPCWSTR section, + PVOID reserved1, UINT reserved2) +{ + static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0}; + static const WCHAR DelFiles[] = {'D','e','l','F','i','l','e','s',0}; + WCHAR section_name[MAX_PATH]; + INFCONTEXT context; + BOOL ret; + int i; + + TRACE("(%p, %p, %p, %s, %p, %u)\n", diskspace, inf, layoutinf, debugstr_w(section), + reserved1, reserved2); + + if (!diskspace) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!section) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!inf) return TRUE; + if (!layoutinf) layoutinf = inf; + + ret = SetupFindFirstLineW(inf, section, CopyFiles, &context); + while (ret) + { + for (i = 1;; i++) + { + if (!SetupGetStringFieldW(&context, i, section_name, sizeof(section_name) / sizeof(WCHAR), NULL)) + break; + SetupAddSectionToDiskSpaceListW(diskspace, layoutinf, inf, section_name, FILEOP_COPY, 0, 0); + } + ret = SetupFindNextLine(&context, &context); + } + + ret = SetupFindFirstLineW(inf, section, DelFiles, &context); + while (ret) + { + for (i = 1;; i++) + { + if (!SetupGetStringFieldW(&context, i, section_name, sizeof(section_name) / sizeof(WCHAR), NULL)) + break; + SetupAddSectionToDiskSpaceListW(diskspace, layoutinf, inf, section_name, FILEOP_DELETE, 0, 0); + } + ret = SetupFindNextLine(&context, &context); + } + + return TRUE; +} + +/*********************************************************************** + * SetupAddInstallSectionToDiskSpaceListA (SETUPAPI.@) + */ +BOOL WINAPI SetupAddInstallSectionToDiskSpaceListA(HDSKSPC diskspace, + HINF inf, HINF layoutinf, LPCSTR section, + PVOID reserved1, UINT reserved2) +{ + LPWSTR sectionW = NULL; + DWORD len; + BOOL ret; + + if (section) + { + len = MultiByteToWideChar(CP_ACP, 0, section, -1, NULL, 0); + + sectionW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!sectionW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + MultiByteToWideChar(CP_ACP, 0, section, -1, sectionW, len); + } + + ret = SetupAddInstallSectionToDiskSpaceListW(diskspace, inf, layoutinf, + sectionW, reserved1, reserved2); + if (sectionW) HeapFree(GetProcessHeap(), 0, sectionW); + return ret; +} + +/*********************************************************************** +* SetupQuerySpaceRequiredOnDriveW (SETUPAPI.@) +*/ +BOOL WINAPI SetupQuerySpaceRequiredOnDriveW(HDSKSPC diskspace, + LPCWSTR drivespec, LONGLONG *required, + PVOID reserved1, UINT reserved2) +{ + struct space_list *list = diskspace; + struct file_entry *file; + LONGLONG sum = 0; + + TRACE("(%p, %s, %p, %p, %u)\n", diskspace, debugstr_w(drivespec), required, reserved1, reserved2); + + if (!diskspace) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!drivespec || !drivespec[0]) + { + SetLastError(drivespec ? ERROR_INVALID_DRIVE : ERROR_INVALID_DRIVE); + return FALSE; + } + + if (!required) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (towlower(drivespec[0]) < 'a' || towlower(drivespec[0]) > 'z' || + drivespec[1] != ':' || drivespec[2] != 0) + { + FIXME("UNC paths not yet supported (%s)\n", debugstr_w(drivespec)); + SetLastError((GetVersion() & 0x80000000) ? ERROR_INVALID_DRIVE : ERROR_INVALID_PARAMETER); + return FALSE; + } + + LIST_FOR_EACH_ENTRY(file, &list->files, struct file_entry, entry) + { + if (towlower(file->path[0]) == towlower(drivespec[0]) && + file->path[1] == ':' && file->path[2] == '\\') + sum += file->size; + } + + *required = sum; + return TRUE; } /*********************************************************************** @@ -242,25 +467,28 @@ BOOL WINAPI SetupQuerySpaceRequiredOnDriveA(HDSKSPC DiskSpace, /*********************************************************************** * SetupDestroyDiskSpaceList (SETUPAPI.@) */ -BOOL WINAPI SetupDestroyDiskSpaceList(HDSKSPC DiskSpace) +BOOL WINAPI SetupDestroyDiskSpaceList(HDSKSPC diskspace) { - LPDISKSPACELIST list = (LPDISKSPACELIST)DiskSpace; + struct space_list *list = diskspace; + struct file_entry *file, *file2; + + if (!diskspace) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + LIST_FOR_EACH_ENTRY_SAFE(file, file2, &list->files, struct file_entry, entry) + { + free(file->path); + list_remove(&file->entry); + free(file); + } + free(list); return TRUE; } -/*********************************************************************** -* SetupAddToDiskSpaceListA (SETUPAPI.@) -*/ -BOOL WINAPI SetupAddToDiskSpaceListA(HDSKSPC diskspace, PCSTR targetfile, - LONGLONG filesize, UINT operation, - PVOID reserved1, UINT reserved2) -{ - FIXME(": stub\n"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - /*********************************************************************** * SetupAddToDiskSpaceListW (SETUPAPI.@) */ @@ -268,7 +496,213 @@ BOOL WINAPI SetupAddToDiskSpaceListW(HDSKSPC diskspace, PCWSTR targetfile, LONGLONG filesize, UINT operation, PVOID reserved1, UINT reserved2) { - FIXME(": stub\n"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + struct space_list *list = diskspace; + struct file_entry *file; + WCHAR *fullpathW; + BOOL ret = FALSE; + DWORD size; + + TRACE("(%p, %s, %s, %u, %p, %u)\n", diskspace, debugstr_w(targetfile), + wine_dbgstr_longlong(filesize), operation, reserved1, reserved2); + + if (!targetfile) + return TRUE; + + if (!diskspace) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (operation != FILEOP_COPY && operation != FILEOP_DELETE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + size = GetFullPathNameW(targetfile, 0, NULL, NULL); + if (!size) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + size = (size+1) * sizeof(WCHAR); + fullpathW = HeapAlloc(GetProcessHeap(), 0, size); + + if (!GetFullPathNameW(targetfile, size, fullpathW, NULL)) + { + SetLastError(ERROR_INVALID_PARAMETER); + goto done; + } + + if (fullpathW[1] != ':' && fullpathW[2] != '\\') + { + FIXME("UNC paths not yet supported\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + goto done; + } + + LIST_FOR_EACH_ENTRY(file, &list->files, struct file_entry, entry) + { + if (!lstrcmpiW(file->path, fullpathW)) + break; + } + + if (&file->entry == &list->files) + { + file = HeapAlloc(GetProcessHeap(), 0, sizeof(*file)); + if (!file) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto done; + } + + file->path = wcsdup(fullpathW); + if (!file->path) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + HeapFree(GetProcessHeap(), 0, file); + goto done; + } + + list_add_tail(&list->files, &file->entry); + } + else if (operation == FILEOP_DELETE) + { + /* delete operations for added files are ignored */ + ret = TRUE; + goto done; + } + + file->operation = operation; + if (operation == FILEOP_COPY) + file->size = filesize; + else + file->size = 0; + + if (!(list->flags & SPDSL_IGNORE_DISK)) + file->size -= get_file_size(fullpathW); + + ret = TRUE; + +done: + HeapFree(GetProcessHeap(), 0, fullpathW); + return ret; +} + +/*********************************************************************** +* SetupAddToDiskSpaceListA (SETUPAPI.@) +*/ +BOOL WINAPI SetupAddToDiskSpaceListA(HDSKSPC diskspace, PCSTR targetfile, + LONGLONG filesize, UINT operation, + PVOID reserved1, UINT reserved2) +{ + LPWSTR targetfileW = NULL; + DWORD len; + BOOL ret; + + if (targetfile) + { + len = MultiByteToWideChar(CP_ACP, 0, targetfile, -1, NULL, 0); + + targetfileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!targetfileW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + MultiByteToWideChar(CP_ACP, 0, targetfile, -1, targetfileW, len); + } + + ret = SetupAddToDiskSpaceListW(diskspace, targetfileW, filesize, + operation, reserved1, reserved2); + if (targetfileW) HeapFree(GetProcessHeap(), 0, targetfileW); + return ret; +} + +/*********************************************************************** + * SetupQueryDrivesInDiskSpaceListW (SETUPAPI.@) + */ +BOOL WINAPI SetupQueryDrivesInDiskSpaceListW(HDSKSPC diskspace, PWSTR buffer, DWORD size, PDWORD required_size) +{ + struct space_list *list = diskspace; + struct file_entry *file; + DWORD cur_size = 1; + BOOL used[26]; + + TRACE("(%p, %p, %ld, %p)\n", diskspace, buffer, size, required_size); + + if (!diskspace) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + memset(&used, 0, sizeof(used)); + LIST_FOR_EACH_ENTRY(file, &list->files, struct file_entry, entry) + { + int device; + + /* UNC paths are not yet supported by this function */ + if (towlower(file->path[0]) < 'a' || towlower(file->path[0]) > 'z' || file->path[1] != ':') + continue; + + device = towlower(file->path[0]) - 'a'; + if (used[device]) continue; + + cur_size += 3; + + if (buffer) + { + if (cur_size > size) + { + if (required_size) *required_size = cur_size; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + *buffer++ = towlower(file->path[0]); + *buffer++ = ':'; + *buffer++ = 0; + } + + used[device] = TRUE; + } + + if (buffer && size) *buffer = 0; + if (required_size) *required_size = cur_size; + return TRUE; +} + +/*********************************************************************** + * SetupQueryDrivesInDiskSpaceListA (SETUPAPI.@) + */ +BOOL WINAPI SetupQueryDrivesInDiskSpaceListA(HDSKSPC diskspace, PSTR buffer, DWORD size, PDWORD required_size) +{ + WCHAR *bufferW = NULL; + BOOL ret; + int i; + + if (buffer && size) + { + bufferW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); + if (!bufferW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + } + + ret = SetupQueryDrivesInDiskSpaceListW(diskspace, bufferW ? bufferW : (WCHAR *)buffer, + size, required_size); + + if (bufferW) + { + for (i = 0; i < size; i++) + buffer[i] = bufferW[i]; + HeapFree(GetProcessHeap(), 0, bufferW); + } + + return ret; } diff --git a/dll/win32/setupapi/queue.c b/dll/win32/setupapi/queue.c index c9f2d72431c..d908c92a0ef 100644 --- a/dll/win32/setupapi/queue.c +++ b/dll/win32/setupapi/queue.c @@ -418,7 +418,7 @@ static void get_source_info( HINF hinf, const WCHAR *src_file, SP_FILE_COPY_PARA * * Retrieve the destination dir for a given section. */ -static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section ) +WCHAR *get_destination_dir( HINF hinf, const WCHAR *section ) { INFCONTEXT context; WCHAR systemdir[MAX_PATH], *dir; diff --git a/dll/win32/setupapi/setupapi.spec b/dll/win32/setupapi/setupapi.spec index 5da201b5579..9dc6cafdb20 100644 --- a/dll/win32/setupapi/setupapi.spec +++ b/dll/win32/setupapi/setupapi.spec @@ -216,10 +216,10 @@ @ stdcall MyFree(ptr) @ stdcall MyMalloc(long) @ stdcall MyRealloc(ptr long) -@ stdcall SetupAddInstallSectionToDiskSpaceListA(long long long str ptr long) -@ stub SetupAddInstallSectionToDiskSpaceListW -@ stdcall -stub SetupAddSectionToDiskSpaceListA(long long long str long ptr long) -@ stub SetupAddSectionToDiskSpaceListW +@ stdcall SetupAddInstallSectionToDiskSpaceListA(ptr ptr ptr str ptr long) +@ stdcall SetupAddInstallSectionToDiskSpaceListW(ptr ptr ptr wstr ptr long) +@ stdcall SetupAddSectionToDiskSpaceListA(ptr ptr ptr str long ptr long) +@ stdcall SetupAddSectionToDiskSpaceListW(ptr ptr ptr wstr long ptr long) @ stdcall SetupAddToDiskSpaceListA(long str int64 long ptr long) @ stdcall SetupAddToDiskSpaceListW(long wstr int64 long ptr long) @ stdcall SetupAddToSourceListA(long str) @@ -469,8 +469,8 @@ @ stdcall SetupPromptForDiskA(ptr str str str str str long ptr long ptr) @ stdcall SetupPromptForDiskW(ptr wstr wstr wstr wstr wstr long ptr long ptr) @ stdcall SetupPromptReboot(ptr ptr long) -@ stdcall -stub SetupQueryDrivesInDiskSpaceListA(ptr ptr long ptr) -@ stub SetupQueryDrivesInDiskSpaceListW +@ stdcall SetupQueryDrivesInDiskSpaceListA(ptr ptr long ptr) +@ stdcall SetupQueryDrivesInDiskSpaceListW(ptr ptr long ptr) @ stub SetupQueryFileLogA @ stub SetupQueryFileLogW @ stdcall SetupQueryInfFileInformationA(ptr long str long ptr) diff --git a/dll/win32/setupapi/setupapi_private.h b/dll/win32/setupapi/setupapi_private.h index 3a6839abf99..a41d167954f 100644 --- a/dll/win32/setupapi/setupapi_private.h +++ b/dll/win32/setupapi/setupapi_private.h @@ -327,6 +327,8 @@ extern const WCHAR *PARSER_get_inf_filename( HINF hinf ) DECLSPEC_HIDDEN; extern WCHAR *PARSER_get_src_root( HINF hinf ) DECLSPEC_HIDDEN; extern WCHAR *PARSER_get_dest_dir( INFCONTEXT *context ) DECLSPEC_HIDDEN; +extern WCHAR *get_destination_dir( HINF hinf, const WCHAR *section ); + /* support for Ascii queue callback functions */ struct callback_WtoA_context diff --git a/modules/rostests/winetests/setupapi/diskspace.c b/modules/rostests/winetests/setupapi/diskspace.c index 577b1f84a2a..5643f930d9d 100644 --- a/modules/rostests/winetests/setupapi/diskspace.c +++ b/modules/rostests/winetests/setupapi/diskspace.c @@ -19,6 +19,7 @@ */ #include +#include #include "windef.h" #include "winbase.h" @@ -29,6 +30,30 @@ #include "wine/test.h" +#define STD_HEADER "[Version]\r\nSignature=\"$CHICAGO$\"\r\n" + +static inline const char* debugstr_longlong(ULONGLONG ll) +{ + static char string[17]; + if (sizeof(ll) > sizeof(unsigned long) && ll >> 32) + sprintf(string, "%lx%08lx", (unsigned long)(ll >> 32), (unsigned long)ll); + else + sprintf(string, "%lx", (unsigned long)ll); + return string; +} + +/* create a new file with specified contents and open it */ +static HINF inf_open_file_content(const char * tmpfilename, const char *data, UINT *err_line) +{ + DWORD res; + HANDLE handle = CreateFileA(tmpfilename, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0); + if (handle == INVALID_HANDLE_VALUE) return 0; + if (!WriteFile( handle, data, strlen(data), &res, NULL )) trace( "write error\n" ); + CloseHandle( handle ); + return SetupOpenInfFileA( tmpfilename, 0, INF_STYLE_WIN4, err_line ); +} + static void test_SetupCreateDiskSpaceListA(void) { HDSKSPC ret; @@ -293,11 +318,31 @@ static void test_SetupDuplicateDiskSpaceListW(void) ok(SetupDestroyDiskSpaceList(handle), "Expected SetupDestroyDiskSpaceList to succeed\n"); } +static LONGLONG get_file_size(char *path) +{ + HANDLE file; + LARGE_INTEGER size; + + file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) return 0; + + if (!GetFileSizeEx(file, &size)) + size.QuadPart = 0; + + CloseHandle(file); + return size.QuadPart; +} + static void test_SetupQuerySpaceRequiredOnDriveA(void) { BOOL ret; HDSKSPC handle; LONGLONG space; + char windir[MAX_PATH]; + char drive[3]; + char tmp[MAX_PATH]; + LONGLONG size; SetLastError(0xdeadbeef); ret = SetupQuerySpaceRequiredOnDriveA(NULL, NULL, NULL, NULL, 0); @@ -357,7 +402,7 @@ static void test_SetupQuerySpaceRequiredOnDriveA(void) ret = SetupQuerySpaceRequiredOnDriveA(handle, "", NULL, NULL, 0); ok(!ret, "Expected SetupQuerySpaceRequiredOnDriveA to return FALSE, got %d\n", ret); ok(GetLastError() == ERROR_INVALID_DRIVE, - "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", + "Expected GetLastError() to return ERROR_INVALID_DRIVE, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); @@ -369,6 +414,155 @@ static void test_SetupQuerySpaceRequiredOnDriveA(void) "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); + GetWindowsDirectoryA(windir, MAX_PATH); + drive[0] = windir[0]; drive[1] = windir[1]; drive[2] = 0; + + snprintf(tmp, MAX_PATH, "%c:\\wine-test-should-not-exist.txt", drive[0]); + ret = SetupAddToDiskSpaceListA(handle, tmp, 0x100000, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + space = 0; + ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space == 0x100000, "Expected 0x100000 as required space, got %s\n", debugstr_longlong(space)); + + /* adding the same file again doesn't sum up the size */ + ret = SetupAddToDiskSpaceListA(handle, tmp, 0x200000, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + space = 0; + ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space == 0x200000, "Expected 0x200000 as required space, got %s\n", debugstr_longlong(space)); + + /* the device doesn't need to exist */ + snprintf(tmp, MAX_PATH, "F:\\wine-test-should-not-exist.txt"); + ret = SetupAddToDiskSpaceListA(handle, tmp, 0x200000, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + ret = SetupQuerySpaceRequiredOnDriveA(handle, "F:", &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space == 0x200000, "Expected 0x200000 as required space, got %s\n", debugstr_longlong(space)); + + snprintf(tmp, MAX_PATH, "F:\\wine-test-should-not-exist.txt"); + ret = SetupAddToDiskSpaceListA(handle, tmp, 0x200000, FILEOP_DELETE, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + ret = SetupQuerySpaceRequiredOnDriveA(handle, "F:", &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space == 0x200000, "Expected 0x200000 as required space, got %s\n", debugstr_longlong(space)); + + ok(SetupDestroyDiskSpaceList(handle), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + + handle = SetupCreateDiskSpaceListA(NULL, 0, 0); + ok(handle != NULL, + "Expected SetupCreateDiskSpaceListA to return a valid handle, got NULL\n"); + + /* the real size is subtracted unless SPDSL_IGNORE_DISK is specified */ + snprintf(tmp, MAX_PATH, "%s\\regedit.exe", windir); + + size = get_file_size(tmp); + ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + space = 0; + ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space == 0 || broken(space == -0x5000) || broken(space == -0x7000), + "Expected 0x0 as required space, got %s\n", debugstr_longlong(space)); + + ret = SetupAddToDiskSpaceListA(handle, tmp, size + 0x100000, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space == 0x100000 || broken(space == 0xf9000) || broken(space == 0xfb000), + "Expected 0x100000 as required space, got %s\n", debugstr_longlong(space)); + + ret = SetupAddToDiskSpaceListA(handle, tmp, size - 0x1000, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space == -0x1000 || broken(space == -0x6000) || broken(space == -0x8000), + "Expected -0x1000 as required space, got %s\n", debugstr_longlong(space)); + + ok(SetupDestroyDiskSpaceList(handle), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + + /* test FILEOP_DELETE, then FILEOP_COPY */ + handle = SetupCreateDiskSpaceListA(NULL, 0, 0); + ok(handle != NULL, + "Expected SetupCreateDiskSpaceListA to return a valid handle, got NULL\n"); + + ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_DELETE, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + space = 0; + ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space == 0 || broken(space == -0x5000) || broken(space == -0x7000), + "Expected 0x0 as required space, got %s\n", debugstr_longlong(space)); + + ok(SetupDestroyDiskSpaceList(handle), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + + /* test FILEOP_COPY, then FILEOP_DELETE */ + handle = SetupCreateDiskSpaceListA(NULL, 0, 0); + ok(handle != NULL, + "Expected SetupCreateDiskSpaceListA to return a valid handle, got NULL\n"); + + ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_DELETE, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + space = 0; + ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space == 0 || broken(space == -0x5000) || broken(space == -0x7000), + "Expected 0x0 as required space, got %s\n", debugstr_longlong(space)); + + ok(SetupDestroyDiskSpaceList(handle), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + + /* test FILEOP_DELETE without SPDSL_IGNORE_DISK */ + handle = SetupCreateDiskSpaceListA(NULL, 0, 0); + ok(handle != NULL, + "Expected SetupCreateDiskSpaceListA to return a valid handle, got NULL\n"); + + ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_DELETE, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + space = 0; + ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space <= -size, "Expected space <= -size, got %s\n", debugstr_longlong(space)); + + ok(SetupDestroyDiskSpaceList(handle), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + + /* test FILEOP_COPY and FILEOP_DELETE with SPDSL_IGNORE_DISK */ + handle = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); + ok(handle != NULL, + "Expected SetupCreateDiskSpaceListA to return a valid handle, got NULL\n"); + + ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_DELETE, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + space = 0; + ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space == 0, "Expected size = 0, got %s\n", debugstr_longlong(space)); + + ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_DELETE, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + space = 0; + ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space >= size, "Expected size >= %s\n", debugstr_longlong(space)); + ok(SetupDestroyDiskSpaceList(handle), "Expected SetupDestroyDiskSpaceList to succeed\n"); } @@ -460,6 +654,456 @@ static void test_SetupQuerySpaceRequiredOnDriveW(void) "Expected SetupDestroyDiskSpaceList to succeed\n"); } +static void test_SetupAddToDiskSpaceListA(void) +{ + HDSKSPC handle; + BOOL ret; + + ret = SetupAddToDiskSpaceListA(NULL, "C:\\some-file.dat", 0, FILEOP_COPY, 0, 0); + ok(!ret, "Expected SetupAddToDiskSpaceListA to return FALSE, got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "Expected GetLastError() to return ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); + + handle = SetupCreateDiskSpaceListA(NULL, 0, 0); + ok(handle != NULL,"Expected SetupCreateDiskSpaceListA to return a valid handle\n"); + + ret = SetupAddToDiskSpaceListA(handle, NULL, 0, FILEOP_COPY, 0, 0); + ok(ret || broken(!ret) /* >= Vista */, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + ret = SetupAddToDiskSpaceListA(handle, "C:\\some-file.dat", -20, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + ret = SetupAddToDiskSpaceListA(handle, "C:\\some-file.dat", 0, FILEOP_RENAME, 0, 0); + ok(!ret, "Expected SetupAddToDiskSpaceListA to return FALSE\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); + + ret = SetupAddToDiskSpaceListA(handle, NULL, 0, FILEOP_RENAME, 0, 0); + ok(ret || broken(!ret) /* >= Vista */, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + ret = SetupAddToDiskSpaceListA(NULL, NULL, 0, FILEOP_RENAME, 0, 0); + ok(ret || broken(!ret) /* >= Vista */, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + ok(SetupDestroyDiskSpaceList(handle), + "Expected SetupDestroyDiskSpaceList to succeed\n"); +} + +static void test_SetupQueryDrivesInDiskSpaceListA(void) +{ + char buffer[MAX_PATH]; + HDSKSPC handle; + DWORD size; + BOOL ret; + + handle = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); + ok(handle != NULL,"Expected SetupCreateDiskSpaceListA to return a valid handle\n"); + + ret = SetupQueryDrivesInDiskSpaceListA(handle, NULL, 0, NULL); + ok(ret, "Expected SetupQueryDrivesInDiskSpaceListA to succeed\n"); + + size = 0; + ret = SetupQueryDrivesInDiskSpaceListA(handle, NULL, 0, &size); + ok(ret, "Expected SetupQueryDrivesInDiskSpaceListA to succeed\n"); + ok(size == 1, "Expected size 1, got %lu\n", size); + + ret = SetupAddToDiskSpaceListA(handle, "F:\\random-file.dat", 0, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + ret = SetupAddToDiskSpaceListA(handle, "G:\\random-file.dat", 0, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + ret = SetupAddToDiskSpaceListA(handle, "G:\\random-file2.dat", 0, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + ret = SetupAddToDiskSpaceListA(handle, "X:\\random-file.dat", 0, FILEOP_COPY, 0, 0); + ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); + + size = 0; + ret = SetupQueryDrivesInDiskSpaceListA(handle, NULL, 0, &size); + ok(ret, "Expected SetupQueryDrivesInDiskSpaceListA to succeed\n"); + ok(size == 10, "Expected size 10, got %lu\n", size); + + size = 0; + ret = SetupQueryDrivesInDiskSpaceListA(handle, buffer, 0, &size); + ok(!ret, "Expected SetupQueryDrivesInDiskSpaceListA to fail\n"); + ok(size == 4, "Expected size 4, got %lu\n", size); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); + + size = 0; + ret = SetupQueryDrivesInDiskSpaceListA(handle, buffer, 4, &size); + ok(!ret, "Expected SetupQueryDrivesInDiskSpaceListA to fail\n"); + ok(size == 7, "Expected size 7, got %lu\n", size); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); + + size = 0; + ret = SetupQueryDrivesInDiskSpaceListA(handle, buffer, 7, &size); + ok(!ret, "Expected SetupQueryDrivesInDiskSpaceListA to fail\n"); + ok(size == 10, "Expected size 10, got %lu\n", size); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); + + size = 0; + memset(buffer, 0xff, sizeof(buffer)); + ret = SetupQueryDrivesInDiskSpaceListA(handle, buffer, sizeof(buffer), &size); + ok(ret, "Expected SetupQueryDrivesInDiskSpaceListA to succeed\n"); + ok(size == 10, "Expected size 10, got %lu\n", size); + ok(!memcmp("f:\0g:\0x:\0\0", buffer, 10), "Device list does not match\n"); + + memset(buffer, 0xff, sizeof(buffer)); + ret = SetupQueryDrivesInDiskSpaceListA(handle, buffer, sizeof(buffer), NULL); + ok(ret, "Expected SetupQueryDrivesInDiskSpaceListA to succeed\n"); + ok(!memcmp("f:\0g:\0x:\0\0", buffer, 10), "Device list does not match\n"); + + ok(SetupDestroyDiskSpaceList(handle), + "Expected SetupDestroyDiskSpaceList to succeed\n"); +} + +struct device_usage +{ + const char *dev; + LONGLONG usage; +}; + +struct section +{ + const char *name; + UINT fileop; + BOOL result; + DWORD error_code; +}; + +static const struct +{ + const char *data; + struct section sections[2]; + const char *devices; + int device_length; + struct device_usage usage[2]; +} +section_test[] = +{ + /* 0 */ + {STD_HEADER "[a]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", + {{"a", FILEOP_COPY, TRUE, 0}, {NULL, 0, TRUE, 0}}, + "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, + /* 1 */ + {STD_HEADER "[a]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", + {{"a", FILEOP_DELETE, TRUE, 0}, {NULL, 0, TRUE, 0}}, + "c:\00", sizeof("c:\00"), {{"c:", 0}, {NULL, 0}}}, + /* 2 */ + {STD_HEADER "[a]\ntest,,,\n\r\n", + {{"a", FILEOP_COPY, FALSE, ERROR_LINE_NOT_FOUND}, {NULL, 0, TRUE, 0}}, + "", sizeof(""), {{NULL, 0}, {NULL, 0}}}, + /* 3 */ + {STD_HEADER "[a]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\n[DestinationDirs]\nDefaultDestDir=-1,F:\\test\r\n", + {{"a", FILEOP_COPY, TRUE, 0}, {NULL, 0, TRUE, 0}}, + "f:\00", sizeof("f:\00"), {{"f:", 4096}, {NULL, 0}}}, + /* 4 */ + {STD_HEADER "[a]\ntest,test2,,\n[SourceDisksFiles]\ntest2=1,,4096\r\n", + {{"a", FILEOP_COPY, TRUE, 0}, {NULL, 0, TRUE, 0}}, + "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, + /* 5 */ + {STD_HEADER "[a]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", + {{"b", FILEOP_COPY, FALSE, ERROR_SECTION_NOT_FOUND}, {NULL, 0, TRUE, 0}}, + "", sizeof(""), {{NULL, 0}, {NULL, 0}}}, + /* 6 */ + {STD_HEADER "[a]\ntest,,,\n[b]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", + {{"a", FILEOP_COPY, TRUE, 0}, {"b", FILEOP_COPY, TRUE, 0}}, + "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, + /* 7 */ + {STD_HEADER "[a]\ntest,,,\n[b]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\n[DestinationDirs]\nb=-1,F:\\test\r\n", + {{"a", FILEOP_COPY, TRUE, 0}, {"b", FILEOP_COPY, TRUE, 0}}, + "c:\00f:\00", sizeof("c:\00f:\00"), {{"c:", 4096}, {"f:", 4096}}}, + /* 8 */ + {STD_HEADER "[a]\ntest,test1,,\n[b]\ntest,test2,,\n[SourceDisksFiles]\ntest1=1,,4096\ntest2=1,,8192\r\n", + {{"a", FILEOP_COPY, TRUE, 0}, {"b", FILEOP_COPY, TRUE, 0}}, + "c:\00", sizeof("c:\00"), {{"c:", 8192}, {NULL, 0}}}, + /* 9 */ + {STD_HEADER "[a]\ntest1,test,,\n[b]\ntest2,test,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", + {{"a", FILEOP_COPY, TRUE, 0}, {"b", FILEOP_COPY, TRUE, 0}}, + "c:\00", sizeof("c:\00"), {{"c:", 8192}, {NULL, 0}}}, +}; + +static void test_SetupAddSectionToDiskSpaceListA(void) +{ + char tmp[MAX_PATH]; + char tmpfilename[MAX_PATH]; + char buffer[MAX_PATH]; + HDSKSPC diskspace; + UINT err_line; + LONGLONG space; + BOOL ret; + int i, j; + HINF inf; + + if (!GetTempPathA(MAX_PATH, tmp)) + { + win_skip("GetTempPath failed with error %lu\n", GetLastError()); + return; + } + + if (!GetTempFileNameA(tmp, "inftest", 0, tmpfilename)) + { + win_skip("GetTempFileNameA failed with error %lu\n", GetLastError()); + return; + } + + inf = inf_open_file_content(tmpfilename, STD_HEADER "[a]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", &err_line); + ok(!!inf, "Failed to open inf file (%lu, line %d)\n", GetLastError(), err_line); + + diskspace = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); + ok(diskspace != NULL,"Expected SetupCreateDiskSpaceListA to return a valid handle\n"); + + ret = SetupAddSectionToDiskSpaceListA(diskspace, NULL, NULL, "a", FILEOP_COPY, 0, 0); + ok(!ret, "Expected SetupAddSectionToDiskSpaceListA to fail\n"); + ok(GetLastError() == ERROR_SECTION_NOT_FOUND, "Expected ERROR_SECTION_NOT_FOUND as error, got %lu\n", + GetLastError()); + + ret = SetupAddSectionToDiskSpaceListA(NULL, inf, NULL, "a", FILEOP_COPY, 0, 0); + ok(!ret, "Expected SetupAddSectionToDiskSpaceListA to fail\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE as error, got %lu\n", + GetLastError()); + + ret = SetupAddSectionToDiskSpaceListA(NULL, inf, NULL, "b", FILEOP_COPY, 0, 0); + ok(!ret, "Expected SetupAddSectionToDiskSpaceListA to fail\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE as error, got %lu\n", + GetLastError()); + + ret = SetupAddSectionToDiskSpaceListA(diskspace, inf, NULL, "a", 0, 0, 0); + ok(ret, "Expected SetupAddSectionToDiskSpaceListA to succeed (%lu)\n", GetLastError()); + + ok(SetupDestroyDiskSpaceList(diskspace), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + + for (i = 0; i < sizeof(section_test) / sizeof(section_test[0]); i++) + { + err_line = 0; + + inf = inf_open_file_content(tmpfilename, section_test[i].data, &err_line); + ok(!!inf, "test %d: Failed to open inf file (%lu, line %d)\n", i, GetLastError(), err_line); + if (!inf) continue; + + diskspace = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); + ok(diskspace != NULL, "Expected SetupCreateDiskSpaceListA to return a valid handle\n"); + + for (j = 0; j < 2; j++) + { + const struct section *section = §ion_test[i].sections[j]; + if (!section->name) + continue; + + SetLastError(0xdeadbeef); + ret = SetupAddSectionToDiskSpaceListA(diskspace, inf, NULL, section->name, section->fileop, 0, 0); + if (section->result) + ok(ret, "test %d: Expected adding section %d to succeed (%lu)\n", i, j, GetLastError()); + else + { + ok(!ret, "test %d: Expected adding section %d to fail\n", i, j); + ok(GetLastError() == section->error_code, "test %d: Expected %lu as error, got %lu\n", + i, section->error_code, GetLastError()); + } + } + + memset(buffer, 0x0, sizeof(buffer)); + ret = SetupQueryDrivesInDiskSpaceListA(diskspace, buffer, sizeof(buffer), NULL); + ok(ret, "test %d: Expected SetupQueryDrivesInDiskSpaceListA to succeed (%lu)\n", i, GetLastError()); + ok(!memcmp(section_test[i].devices, buffer, section_test[i].device_length), + "test %d: Device list (%s) does not match\n", i, buffer); + + for (j = 0; j < 2; j++) + { + const struct device_usage *usage = §ion_test[i].usage[j]; + if (!usage->dev) + continue; + + space = 0; + ret = SetupQuerySpaceRequiredOnDriveA(diskspace, usage->dev, &space, NULL, 0); + ok(ret, "test %d: Expected SetupQuerySpaceRequiredOnDriveA to succeed for device %s (%lu)\n", + i, usage->dev, GetLastError()); + ok(space == usage->usage, "test %d: Expected size %lu for device %s, got %lu\n", + i, (DWORD)usage->usage, usage->dev, (DWORD)space); + } + + ok(SetupDestroyDiskSpaceList(diskspace), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + + SetupCloseInfFile(inf); + } + + DeleteFileA(tmpfilename); +} + +struct section_i +{ + const char *name; + BOOL result; + DWORD error_code; +}; + +static const struct +{ + const char *data; + struct section_i sections[2]; + const char *devices; + int device_length; + struct device_usage usage[2]; +} +section_test_i[] = +{ + /* 0 */ + {STD_HEADER "[a.Install]\nCopyFiles=a.CopyFiles\n" + "[a.CopyFiles]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", + {{"a.Install", TRUE, 0}, {NULL, TRUE, 0}}, "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, + /* 1 */ + {STD_HEADER "[a]\nCopyFiles=a.CopyFiles\n" + "[a.CopyFiles]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", + {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, + /* 2 */ + {STD_HEADER "[a]\nCopyFiles=a.CopyFiles\nCopyFiles=a.CopyFiles2\n" + "[a.CopyFiles]\ntest,,,\n[a.CopyFiles2]\ntest2,,,\n" + "[SourceDisksFiles]\ntest=1,,4096\ntest2=1,,4096\r\n", + {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "c:\00", sizeof("c:\00"), {{"c:", 8192}, {NULL, 0}}}, + /* 3 */ + {STD_HEADER "[a]\nCopyFiles=a.CopyFiles,a.CopyFiles2\n" + "[a.CopyFiles]\ntest,,,\n[a.CopyFiles2]\ntest2,,,\n" + "[SourceDisksFiles]\ntest=1,,4096\ntest2=1,,4096\r\n", + {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "c:\00", sizeof("c:\00"), {{"c:", 8192}, {NULL, 0}}}, + /* 4 */ + {STD_HEADER "[a]\r\n", + {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "", sizeof(""), {{NULL, 0}, {NULL, 0}}}, + /* 5 */ + {STD_HEADER "[a]\nDelFiles=a.DelFiles\n" + "[a.nDelFiles]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", + {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "", sizeof(""), {{NULL, 0}, {NULL, 0}}}, + /* 6 */ + {STD_HEADER "[a]\nCopyFiles=a.CopyFiles\nDelFiles=a.DelFiles\n" + "[a.CopyFiles]\ntest,,,\n[a.DelFiles]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", + {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, + /* 7 */ + {STD_HEADER "[a]\nCopyFiles=a.CopyFiles\n[b]\nDelFiles=b.DelFiles\n" + "[a.CopyFiles]\ntest,,,\n[b.DelFiles]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", + {{"a", TRUE, 0}, {"b", TRUE, 0}}, "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, + /* 7 */ + {STD_HEADER "[a]\nCopyFiles=\r\n", + {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "", sizeof(""), {{NULL, 0}, {NULL, 0}}}, + /* 8 */ + {STD_HEADER "[a]\nCopyFiles=something\r\n", + {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "", sizeof(""), {{NULL, 0}, {NULL, 0}}}, + /* 9 */ + {STD_HEADER "[a]\nCopyFiles=a.CopyFiles,b.CopyFiles\n[a.CopyFiles]\ntest,,,\n[b.CopyFiles]\ntest,,,\n" + "[SourceDisksFiles]\ntest=1,,4096\n[DestinationDirs]\nb.CopyFiles=-1,F:\\test\r\n", + {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "c:\00f:\00", sizeof("c:\00f:\00"), {{"c:", 4096}, {"f:", 4096}}}, +}; + +static void test_SetupAddInstallSectionToDiskSpaceListA(void) +{ + char tmp[MAX_PATH]; + char tmpfilename[MAX_PATH]; + char buffer[MAX_PATH]; + HDSKSPC diskspace; + LONGLONG space; + UINT err_line; + BOOL ret; + int i, j; + HINF inf; + + if (!GetTempPathA(MAX_PATH, tmp)) + { + win_skip("GetTempPath failed with error %ld\n", GetLastError()); + return; + } + + if (!GetTempFileNameA(tmp, "inftest", 0, tmpfilename)) + { + win_skip("GetTempFileNameA failed with error %ld\n", GetLastError()); + return; + } + + inf = inf_open_file_content(tmpfilename, STD_HEADER "[a]\nCopyFiles=b\n[b]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", &err_line); + ok(!!inf, "Failed to open inf file (%ld, line %u)\n", GetLastError(), err_line); + + diskspace = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); + ok(diskspace != NULL,"Expected SetupCreateDiskSpaceListA to return a valid handle\n"); + + ret = SetupAddInstallSectionToDiskSpaceListA(diskspace, NULL, NULL, "a", 0, 0); + ok(ret, "Expected SetupAddInstallSectionToDiskSpaceListA to succeed\n"); + + ret = SetupAddInstallSectionToDiskSpaceListA(NULL, inf, NULL, "a", 0, 0); + ok(!ret, "Expected SetupAddInstallSectionToDiskSpaceListA to fail\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE as error, got %lu\n", + GetLastError()); + + ret = SetupAddInstallSectionToDiskSpaceListA(diskspace, inf, NULL, NULL, 0, 0); + ok(!ret || broken(ret), "Expected SetupAddSectionToDiskSpaceListA to fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(ret), + "Expected ERROR_INVALID_PARAMETER as error, got %lu\n", GetLastError()); + + ret = SetupAddInstallSectionToDiskSpaceListA(diskspace, inf, NULL, "", 0, 0); + ok(ret, "Expected SetupAddInstallSectionToDiskSpaceListA to succeed (%lu)\n", GetLastError()); + + ok(SetupDestroyDiskSpaceList(diskspace), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + + for (i = 0; i < sizeof(section_test_i) / sizeof(section_test_i[0]); i++) + { + err_line = 0; + + inf = inf_open_file_content(tmpfilename, section_test_i[i].data, &err_line); + ok(!!inf, "test %u: Failed to open inf file (%lu, line %u)\n", i, GetLastError(), err_line); + if (!inf) continue; + + diskspace = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); + ok(diskspace != NULL,"Expected SetupCreateDiskSpaceListA to return a valid handle\n"); + + for (j = 0; j < 2; j++) + { + const struct section_i *section = §ion_test_i[i].sections[j]; + if (!section->name) + continue; + + SetLastError(0xdeadbeef); + ret = SetupAddInstallSectionToDiskSpaceListA(diskspace, inf, NULL, section->name, 0, 0); + if (section->result) + ok(ret, "test %d: Expected adding section %d to succeed (%lu)\n", i, j, GetLastError()); + else + { + ok(!ret, "test %d: Expected adding section %d to fail\n", i, j); + ok(GetLastError() == section->error_code, "test %d: Expected %lu as error, got %lu\n", + i, section->error_code, GetLastError()); + } + } + + memset(buffer, 0x0, sizeof(buffer)); + ret = SetupQueryDrivesInDiskSpaceListA(diskspace, buffer, sizeof(buffer), NULL); + ok(ret, "test %d: Expected SetupQueryDrivesInDiskSpaceListA to succeed (%lu)\n", i, GetLastError()); + ok(!memcmp(section_test_i[i].devices, buffer, section_test_i[i].device_length), + "test %d: Device list (%s) does not match\n", i, buffer); + + for (j = 0; j < 2; j++) + { + const struct device_usage *usage = §ion_test_i[i].usage[j]; + if (!usage->dev) + continue; + + space = 0; + ret = SetupQuerySpaceRequiredOnDriveA(diskspace, usage->dev, &space, NULL, 0); + ok(ret, "test %d: Expected SetupQuerySpaceRequiredOnDriveA to succeed for device %s (%lu)\n", + i, usage->dev, GetLastError()); + ok(space == usage->usage, "test %d: Expected size %lu for device %s, got %lu\n", + i, (DWORD)usage->usage, usage->dev, (DWORD)space); + } + + ok(SetupDestroyDiskSpaceList(diskspace), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + + SetupCloseInfFile(inf); + } + + DeleteFileA(tmpfilename); +} + START_TEST(diskspace) { test_SetupCreateDiskSpaceListA(); @@ -468,4 +1112,8 @@ START_TEST(diskspace) test_SetupDuplicateDiskSpaceListW(); test_SetupQuerySpaceRequiredOnDriveA(); test_SetupQuerySpaceRequiredOnDriveW(); + test_SetupAddToDiskSpaceListA(); + test_SetupQueryDrivesInDiskSpaceListA(); + test_SetupAddSectionToDiskSpaceListA(); + test_SetupAddInstallSectionToDiskSpaceListA(); } diff --git a/sdk/tools/winesync/setupapi_staging/0001-setupapi__Rewrite_DiskSpaceList_logic_using_lists.diff b/sdk/tools/winesync/setupapi_staging/0001-setupapi__Rewrite_DiskSpaceList_logic_using_lists.diff new file mode 100644 index 00000000000..6788abbf52f --- /dev/null +++ b/sdk/tools/winesync/setupapi_staging/0001-setupapi__Rewrite_DiskSpaceList_logic_using_lists.diff @@ -0,0 +1,276 @@ +diff --git a/dll/win32/setupapi/diskspace.c b/dll/win32/setupapi/diskspace.c +index 5fc3f6a2319..b900f8a84ee 100644 +--- a/dll/win32/setupapi/diskspace.c ++++ b/dll/win32/setupapi/diskspace.c +@@ -1,6 +1,7 @@ + /* + * SetupAPI DiskSpace functions + * ++ * Copyright 2016 Michael Müller + * Copyright 2004 CodeWeavers (Aric Stewart) + * + * This library is free software; you can redistribute it and/or +@@ -19,66 +20,46 @@ + */ + + #include "setupapi_private.h" ++#include "wine/list.h" + +-typedef struct { +- WCHAR lpzName[20]; +- LONGLONG dwFreeSpace; +- LONGLONG dwWantedSpace; +-} DRIVE_ENTRY, *LPDRIVE_ENTRY; ++struct file_entry ++{ ++ struct list entry; ++ WCHAR *path; ++ UINT operation; ++ LONGLONG size; ++}; ++ ++struct space_list ++{ ++ struct list files; ++ UINT flags; ++}; + +-typedef struct { +- DWORD dwDriveCount; +- DRIVE_ENTRY Drives[26]; +-} DISKSPACELIST, *LPDISKSPACELIST; + + + /*********************************************************************** + * SetupCreateDiskSpaceListW (SETUPAPI.@) + */ +-HDSKSPC WINAPI SetupCreateDiskSpaceListW(PVOID Reserved1, DWORD Reserved2, UINT Flags) ++HDSKSPC WINAPI SetupCreateDiskSpaceListW(PVOID reserved1, DWORD reserved2, UINT flags) + { +- WCHAR drives[255]; +- DWORD rc; +- WCHAR *ptr; +- LPDISKSPACELIST list=NULL; ++ struct space_list *list; + +- TRACE("(%p, %lu, 0x%08x)\n", Reserved1, Reserved2, Flags); ++ TRACE("(%p, %lu, 0x%08x)\n", reserved1, reserved2, flags); + +- if (Reserved1 || Reserved2 || Flags & ~SPDSL_IGNORE_DISK) ++ if (reserved1 || reserved2 || flags & ~SPDSL_IGNORE_DISK) + { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + +- rc = GetLogicalDriveStringsW(255,drives); +- +- if (rc == 0) +- return NULL; +- +- list = malloc(sizeof(DISKSPACELIST)); +- +- list->dwDriveCount = 0; +- +- ptr = drives; +- +- while (*ptr) ++ list = malloc(sizeof(*list)); ++ if (list) + { +- DWORD type = GetDriveTypeW(ptr); +- if (type == DRIVE_FIXED) +- { +- DWORD clusters; +- DWORD sectors; +- DWORD bytes; +- DWORD total; +- lstrcpyW(list->Drives[list->dwDriveCount].lpzName,ptr); +- GetDiskFreeSpaceW(ptr,§ors,&bytes,&clusters,&total); +- list->Drives[list->dwDriveCount].dwFreeSpace = clusters * sectors * +- bytes; +- list->Drives[list->dwDriveCount].dwWantedSpace = 0; +- list->dwDriveCount++; +- } +- ptr += lstrlenW(ptr) + 1; ++ list->flags = flags; ++ list_init(&list->files); + } ++ + return list; + } + +@@ -94,32 +75,58 @@ HDSKSPC WINAPI SetupCreateDiskSpaceListA(PVOID Reserved1, DWORD Reserved2, UINT + /*********************************************************************** + * SetupDuplicateDiskSpaceListW (SETUPAPI.@) + */ +-HDSKSPC WINAPI SetupDuplicateDiskSpaceListW(HDSKSPC DiskSpace, PVOID Reserved1, DWORD Reserved2, UINT Flags) ++HDSKSPC WINAPI SetupDuplicateDiskSpaceListW(HDSKSPC diskspace, PVOID reserved1, DWORD reserved2, UINT flags) + { +- DISKSPACELIST *list_copy, *list_original = DiskSpace; ++ struct space_list *list_copy, *list = diskspace; ++ struct file_entry *file, *file_copy; + +- if (Reserved1 || Reserved2 || Flags) ++ TRACE("(%p, %p, %lu, %u)\n", diskspace, reserved1, reserved2, flags); ++ ++ if (reserved1 || reserved2 || flags) + { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + +- if (!DiskSpace) ++ if (!diskspace) + { + SetLastError(ERROR_INVALID_HANDLE); + return NULL; + } + +- list_copy = malloc(sizeof(DISKSPACELIST)); ++ list_copy = malloc(sizeof(*list_copy)); + if (!list_copy) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + +- *list_copy = *list_original; ++ list_copy->flags = list->flags; ++ list_init(&list_copy->files); ++ ++ LIST_FOR_EACH_ENTRY(file, &list->files, struct file_entry, entry) ++ { ++ file_copy = malloc(sizeof(*file_copy)); ++ if (!file_copy) goto error; ++ ++ file_copy->path = wcsdup(file->path); ++ if (!file_copy->path) ++ { ++ free(file_copy); ++ goto error; ++ } ++ ++ file_copy->operation = file->operation; ++ file_copy->size = file->size; ++ list_add_head(&list_copy->files, &file->entry); ++ } + + return list_copy; ++ ++error: ++ SetLastError(ERROR_NOT_ENOUGH_MEMORY); ++ SetupDestroyDiskSpaceList(list_copy); ++ return NULL; + } + + /*********************************************************************** +@@ -144,55 +151,51 @@ BOOL WINAPI SetupAddInstallSectionToDiskSpaceListA(HDSKSPC DiskSpace, + /*********************************************************************** + * SetupQuerySpaceRequiredOnDriveW (SETUPAPI.@) + */ +-BOOL WINAPI SetupQuerySpaceRequiredOnDriveW(HDSKSPC DiskSpace, +- LPCWSTR DriveSpec, LONGLONG *SpaceRequired, +- PVOID Reserved1, UINT Reserved2) ++BOOL WINAPI SetupQuerySpaceRequiredOnDriveW(HDSKSPC diskspace, ++ LPCWSTR drivespec, LONGLONG *required, ++ PVOID reserved1, UINT reserved2) + { +- WCHAR *driveW; +- unsigned int i; +- LPDISKSPACELIST list = DiskSpace; +- BOOL rc = FALSE; +- static const WCHAR bkslsh[]= {'\\',0}; ++ struct space_list *list = diskspace; ++ struct file_entry *file; ++ LONGLONG sum = 0; + +- if (!DiskSpace) ++ TRACE("(%p, %s, %p, %p, %u)\n", diskspace, debugstr_w(drivespec), required, reserved1, reserved2); ++ ++ if (!diskspace) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + +- if (!DriveSpec) ++ if (!drivespec || !drivespec[0]) + { +- SetLastError(ERROR_INVALID_PARAMETER); ++ SetLastError(drivespec ? ERROR_INVALID_DRIVE : ERROR_INVALID_DRIVE); + return FALSE; + } + +- driveW = malloc((wcslen(DriveSpec) + 2) * sizeof(WCHAR)); +- if (!driveW) ++ if (!required) + { +- SetLastError(ERROR_NOT_ENOUGH_MEMORY); ++ SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + +- lstrcpyW(driveW,DriveSpec); +- lstrcatW(driveW,bkslsh); +- +- TRACE("Looking for drive %s\n",debugstr_w(driveW)); +- +- for (i = 0; i < list->dwDriveCount; i++) ++ if (towlower(drivespec[0]) < 'a' || towlower(drivespec[0]) > 'z' || ++ drivespec[1] != ':' || drivespec[2] != 0) + { +- TRACE("checking drive %s\n",debugstr_w(list->Drives[i].lpzName)); +- if (wcscmp(driveW,list->Drives[i].lpzName)==0) +- { +- rc = TRUE; +- *SpaceRequired = list->Drives[i].dwWantedSpace; +- break; +- } ++ FIXME("UNC paths not yet supported (%s)\n", debugstr_w(drivespec)); ++ SetLastError((GetVersion() & 0x80000000) ? ERROR_INVALID_DRIVE : ERROR_INVALID_PARAMETER); ++ return FALSE; + } + +- free(driveW); ++ LIST_FOR_EACH_ENTRY(file, &list->files, struct file_entry, entry) ++ { ++ if (towlower(file->path[0]) == towlower(drivespec[0]) && ++ file->path[1] == ':' && file->path[2] == '\\') ++ sum += file->size; ++ } + +- if (!rc) SetLastError(ERROR_INVALID_DRIVE); +- return rc; ++ *required = sum; ++ return TRUE; + } + + /*********************************************************************** +@@ -242,9 +245,24 @@ BOOL WINAPI SetupQuerySpaceRequiredOnDriveA(HDSKSPC DiskSpace, + /*********************************************************************** + * SetupDestroyDiskSpaceList (SETUPAPI.@) + */ +-BOOL WINAPI SetupDestroyDiskSpaceList(HDSKSPC DiskSpace) ++BOOL WINAPI SetupDestroyDiskSpaceList(HDSKSPC diskspace) + { +- LPDISKSPACELIST list = (LPDISKSPACELIST)DiskSpace; ++ struct space_list *list = diskspace; ++ struct file_entry *file, *file2; ++ ++ if (!diskspace) ++ { ++ SetLastError(ERROR_INVALID_PARAMETER); ++ return FALSE; ++ } ++ ++ LIST_FOR_EACH_ENTRY_SAFE(file, file2, &list->files, struct file_entry, entry) ++ { ++ free(file->path); ++ list_remove(&file->entry); ++ free(file); ++ } ++ + free(list); + return TRUE; + } diff --git a/sdk/tools/winesync/setupapi_staging/0002-setupapi__Implement_SetupAddToDiskSpaceList.diff b/sdk/tools/winesync/setupapi_staging/0002-setupapi__Implement_SetupAddToDiskSpaceList.diff new file mode 100644 index 00000000000..64f494fbdf2 --- /dev/null +++ b/sdk/tools/winesync/setupapi_staging/0002-setupapi__Implement_SetupAddToDiskSpaceList.diff @@ -0,0 +1,380 @@ +diff --git a/dll/win32/setupapi/diskspace.c b/dll/win32/setupapi/diskspace.c +index b900f8a84ee..962764cf279 100644 +--- a/dll/win32/setupapi/diskspace.c ++++ b/dll/win32/setupapi/diskspace.c +@@ -36,7 +36,21 @@ struct space_list + UINT flags; + }; + ++static LONGLONG get_file_size(WCHAR *path) ++{ ++ HANDLE file; ++ LARGE_INTEGER size; ++ ++ file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, ++ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ++ if (file == INVALID_HANDLE_VALUE) return 0; + ++ if (!GetFileSizeEx(file, &size)) ++ size.QuadPart = 0; ++ ++ CloseHandle(file); ++ return size.QuadPart; ++} + + /*********************************************************************** + * SetupCreateDiskSpaceListW (SETUPAPI.@) +@@ -268,25 +282,128 @@ BOOL WINAPI SetupDestroyDiskSpaceList(HDSKSPC diskspace) + } + + /*********************************************************************** +-* SetupAddToDiskSpaceListA (SETUPAPI.@) ++* SetupAddToDiskSpaceListW (SETUPAPI.@) + */ +-BOOL WINAPI SetupAddToDiskSpaceListA(HDSKSPC diskspace, PCSTR targetfile, ++BOOL WINAPI SetupAddToDiskSpaceListW(HDSKSPC diskspace, PCWSTR targetfile, + LONGLONG filesize, UINT operation, + PVOID reserved1, UINT reserved2) + { +- FIXME(": stub\n"); +- SetLastError(ERROR_CALL_NOT_IMPLEMENTED); +- return FALSE; ++ struct space_list *list = diskspace; ++ struct file_entry *file; ++ WCHAR *fullpathW; ++ BOOL ret = FALSE; ++ DWORD size; ++ ++ TRACE("(%p, %s, %s, %u, %p, %u)\n", diskspace, debugstr_w(targetfile), ++ wine_dbgstr_longlong(filesize), operation, reserved1, reserved2); ++ ++ if (!targetfile) ++ return TRUE; ++ ++ if (!diskspace) ++ { ++ SetLastError(ERROR_INVALID_HANDLE); ++ return FALSE; ++ } ++ ++ if (operation != FILEOP_COPY && operation != FILEOP_DELETE) ++ { ++ SetLastError(ERROR_INVALID_PARAMETER); ++ return FALSE; ++ } ++ ++ size = GetFullPathNameW(targetfile, 0, NULL, NULL); ++ if (!size) ++ { ++ SetLastError(ERROR_INVALID_PARAMETER); ++ return FALSE; ++ } ++ ++ size = (size+1) * sizeof(WCHAR); ++ fullpathW = HeapAlloc(GetProcessHeap(), 0, size); ++ ++ if (!GetFullPathNameW(targetfile, size, fullpathW, NULL)) ++ { ++ SetLastError(ERROR_INVALID_PARAMETER); ++ goto done; ++ } ++ ++ if (fullpathW[1] != ':' && fullpathW[2] != '\\') ++ { ++ FIXME("UNC paths not yet supported\n"); ++ SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ++ goto done; ++ } ++ ++ LIST_FOR_EACH_ENTRY(file, &list->files, struct file_entry, entry) ++ { ++ if (!lstrcmpiW(file->path, fullpathW)) ++ break; ++ } ++ ++ if (&file->entry == &list->files) ++ { ++ file = HeapAlloc(GetProcessHeap(), 0, sizeof(*file)); ++ if (!file) ++ { ++ SetLastError(ERROR_NOT_ENOUGH_MEMORY); ++ goto done; ++ } ++ ++ file->path = wcsdup(fullpathW); ++ if (!file->path) ++ { ++ SetLastError(ERROR_NOT_ENOUGH_MEMORY); ++ HeapFree(GetProcessHeap(), 0, file); ++ goto done; ++ } ++ ++ list_add_tail(&list->files, &file->entry); ++ } ++ ++ file->operation = operation; ++ if (operation == FILEOP_COPY) ++ file->size = filesize; ++ else ++ file->size = 0; ++ ++ if (!(list->flags & SPDSL_IGNORE_DISK)) ++ file->size -= get_file_size(fullpathW); ++ ++ ret = TRUE; ++ ++done: ++ HeapFree(GetProcessHeap(), 0, fullpathW); ++ return ret; + } + + /*********************************************************************** +-* SetupAddToDiskSpaceListW (SETUPAPI.@) ++* SetupAddToDiskSpaceListA (SETUPAPI.@) + */ +-BOOL WINAPI SetupAddToDiskSpaceListW(HDSKSPC diskspace, PCWSTR targetfile, ++BOOL WINAPI SetupAddToDiskSpaceListA(HDSKSPC diskspace, PCSTR targetfile, + LONGLONG filesize, UINT operation, + PVOID reserved1, UINT reserved2) + { +- FIXME(": stub\n"); +- SetLastError(ERROR_CALL_NOT_IMPLEMENTED); +- return FALSE; ++ LPWSTR targetfileW = NULL; ++ DWORD len; ++ BOOL ret; ++ ++ if (targetfile) ++ { ++ len = MultiByteToWideChar(CP_ACP, 0, targetfile, -1, NULL, 0); ++ ++ targetfileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); ++ if (!targetfileW) ++ { ++ SetLastError(ERROR_NOT_ENOUGH_MEMORY); ++ return FALSE; ++ } ++ ++ MultiByteToWideChar(CP_ACP, 0, targetfile, -1, targetfileW, len); ++ } ++ ++ ret = SetupAddToDiskSpaceListW(diskspace, targetfileW, filesize, ++ operation, reserved1, reserved2); ++ if (targetfileW) HeapFree(GetProcessHeap(), 0, targetfileW); ++ return ret; + } +diff --git a/modules/rostests/winetests/setupapi/diskspace.c b/modules/rostests/winetests/setupapi/diskspace.c +index 577b1f84a2a..3cd83c8471f 100644 +--- a/modules/rostests/winetests/setupapi/diskspace.c ++++ b/modules/rostests/winetests/setupapi/diskspace.c +@@ -19,6 +19,7 @@ + */ + + #include ++#include + + #include "windef.h" + #include "winbase.h" +@@ -29,6 +30,16 @@ + + #include "wine/test.h" + ++static inline const char* debugstr_longlong(ULONGLONG ll) ++{ ++ static char string[17]; ++ if (sizeof(ll) > sizeof(unsigned long) && ll >> 32) ++ sprintf(string, "%lx%08lx", (unsigned long)(ll >> 32), (unsigned long)ll); ++ else ++ sprintf(string, "%lx", (unsigned long)ll); ++ return string; ++} ++ + static void test_SetupCreateDiskSpaceListA(void) + { + HDSKSPC ret; +@@ -293,11 +304,31 @@ static void test_SetupDuplicateDiskSpaceListW(void) + ok(SetupDestroyDiskSpaceList(handle), "Expected SetupDestroyDiskSpaceList to succeed\n"); + } + ++static LONGLONG get_file_size(char *path) ++{ ++ HANDLE file; ++ LARGE_INTEGER size; ++ ++ file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, ++ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ++ if (file == INVALID_HANDLE_VALUE) return 0; ++ ++ if (!GetFileSizeEx(file, &size)) ++ size.QuadPart = 0; ++ ++ CloseHandle(file); ++ return size.QuadPart; ++} ++ + static void test_SetupQuerySpaceRequiredOnDriveA(void) + { + BOOL ret; + HDSKSPC handle; + LONGLONG space; ++ char windir[MAX_PATH]; ++ char drive[3]; ++ char tmp[MAX_PATH]; ++ LONGLONG size; + + SetLastError(0xdeadbeef); + ret = SetupQuerySpaceRequiredOnDriveA(NULL, NULL, NULL, NULL, 0); +@@ -357,7 +388,7 @@ static void test_SetupQuerySpaceRequiredOnDriveA(void) + ret = SetupQuerySpaceRequiredOnDriveA(handle, "", NULL, NULL, 0); + ok(!ret, "Expected SetupQuerySpaceRequiredOnDriveA to return FALSE, got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_DRIVE, +- "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", ++ "Expected GetLastError() to return ERROR_INVALID_DRIVE, got %lu\n", + GetLastError()); + + SetLastError(0xdeadbeef); +@@ -369,6 +400,97 @@ static void test_SetupQuerySpaceRequiredOnDriveA(void) + "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", + GetLastError()); + ++ GetWindowsDirectoryA(windir, MAX_PATH); ++ drive[0] = windir[0]; drive[1] = windir[1]; drive[2] = 0; ++ ++ snprintf(tmp, MAX_PATH, "%c:\\wine-test-should-not-exist.txt", drive[0]); ++ ret = SetupAddToDiskSpaceListA(handle, tmp, 0x100000, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ space = 0; ++ ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); ++ ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); ++ ok(space == 0x100000, "Expected 0x100000 as required space, got %s\n", debugstr_longlong(space)); ++ ++ /* adding the same file again doesn't sum up the size */ ++ ret = SetupAddToDiskSpaceListA(handle, tmp, 0x200000, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ space = 0; ++ ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); ++ ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); ++ ok(space == 0x200000, "Expected 0x200000 as required space, got %s\n", debugstr_longlong(space)); ++ ++ /* the device doesn't need to exist */ ++ snprintf(tmp, MAX_PATH, "F:\\wine-test-should-not-exist.txt"); ++ ret = SetupAddToDiskSpaceListA(handle, tmp, 0x200000, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ ret = SetupQuerySpaceRequiredOnDriveA(handle, "F:", &space, NULL, 0); ++ ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); ++ ok(space == 0x200000, "Expected 0x100000 as required space, got %s\n", debugstr_longlong(space)); ++ ++ ok(SetupDestroyDiskSpaceList(handle), ++ "Expected SetupDestroyDiskSpaceList to succeed\n"); ++ ++ handle = SetupCreateDiskSpaceListA(NULL, 0, 0); ++ ok(handle != NULL, ++ "Expected SetupCreateDiskSpaceListA to return a valid handle, got NULL\n"); ++ ++ /* the real size is subtracted unless SPDSL_IGNORE_DISK is specified */ ++ snprintf(tmp, MAX_PATH, "%s\\regedit.exe", windir); ++ ++ size = get_file_size(tmp); ++ ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ space = 0; ++ ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); ++ ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); ++ ok(space == 0 || broken(space == -0x5000) || broken(space == -0x7000), ++ "Expected 0x0 as required space, got %s\n", debugstr_longlong(space)); ++ ++ ret = SetupAddToDiskSpaceListA(handle, tmp, size + 0x100000, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); ++ ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); ++ ok(space == 0x100000 || broken(space == 0xf9000) || broken(space == 0xfb000), ++ "Expected 0x100000 as required space, got %s\n", debugstr_longlong(space)); ++ ++ ret = SetupAddToDiskSpaceListA(handle, tmp, size - 0x1000, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); ++ ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); ++ ok(space == -0x1000 || broken(space == -0x6000) || broken(space == -0x8000), ++ "Expected -0x1000 as required space, got %s\n", debugstr_longlong(space)); ++ ++ ok(SetupDestroyDiskSpaceList(handle), ++ "Expected SetupDestroyDiskSpaceList to succeed\n"); ++ ++ handle = SetupCreateDiskSpaceListA(NULL, 0, 0); ++ ok(handle != NULL, ++ "Expected SetupCreateDiskSpaceListA to return a valid handle, got NULL\n"); ++ ++ ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_DELETE, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ space = 0; ++ ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); ++ ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); ++ ok(space <= -size, "Expected space <= -size, got %s\n", debugstr_longlong(space)); ++ ++ ok(SetupDestroyDiskSpaceList(handle), ++ "Expected SetupDestroyDiskSpaceList to succeed\n"); ++ ++ handle = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); ++ ok(handle != NULL, ++ "Expected SetupCreateDiskSpaceListA to return a valid handle, got NULL\n"); ++ ++ ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_DELETE, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ space = 0; ++ ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); ++ ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); ++ ok(space == 0, "Expected size = 0, got %s\n", debugstr_longlong(space)); ++ + ok(SetupDestroyDiskSpaceList(handle), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + } +@@ -460,6 +582,40 @@ static void test_SetupQuerySpaceRequiredOnDriveW(void) + "Expected SetupDestroyDiskSpaceList to succeed\n"); + } + ++static void test_SetupAddToDiskSpaceListA(void) ++{ ++ HDSKSPC handle; ++ BOOL ret; ++ ++ ret = SetupAddToDiskSpaceListA(NULL, "C:\\some-file.dat", 0, FILEOP_COPY, 0, 0); ++ ok(!ret, "Expected SetupAddToDiskSpaceListA to return FALSE, got %d\n", ret); ++ ok(GetLastError() == ERROR_INVALID_HANDLE, ++ "Expected GetLastError() to return ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); ++ ++ handle = SetupCreateDiskSpaceListA(NULL, 0, 0); ++ ok(handle != NULL,"Expected SetupCreateDiskSpaceListA to return a valid handle\n"); ++ ++ ret = SetupAddToDiskSpaceListA(handle, NULL, 0, FILEOP_COPY, 0, 0); ++ ok(ret || broken(!ret) /* >= Vista */, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ ret = SetupAddToDiskSpaceListA(handle, "C:\\some-file.dat", -20, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ ret = SetupAddToDiskSpaceListA(handle, "C:\\some-file.dat", 0, FILEOP_RENAME, 0, 0); ++ ok(!ret, "Expected SetupAddToDiskSpaceListA to return FALSE\n"); ++ ok(GetLastError() == ERROR_INVALID_PARAMETER, ++ "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); ++ ++ ret = SetupAddToDiskSpaceListA(handle, NULL, 0, FILEOP_RENAME, 0, 0); ++ ok(ret || broken(!ret) /* >= Vista */, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ ret = SetupAddToDiskSpaceListA(NULL, NULL, 0, FILEOP_RENAME, 0, 0); ++ ok(ret || broken(!ret) /* >= Vista */, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ ok(SetupDestroyDiskSpaceList(handle), ++ "Expected SetupDestroyDiskSpaceList to succeed\n"); ++} ++ + START_TEST(diskspace) + { + test_SetupCreateDiskSpaceListA(); +@@ -468,4 +624,5 @@ START_TEST(diskspace) + test_SetupDuplicateDiskSpaceListW(); + test_SetupQuerySpaceRequiredOnDriveA(); + test_SetupQuerySpaceRequiredOnDriveW(); ++ test_SetupAddToDiskSpaceListA(); + } diff --git a/sdk/tools/winesync/setupapi_staging/0003-setupapi__Implement_SetupQueryDrivesInDiskSpaceList.diff b/sdk/tools/winesync/setupapi_staging/0003-setupapi__Implement_SetupQueryDrivesInDiskSpaceList.diff new file mode 100644 index 00000000000..1397e7da22b --- /dev/null +++ b/sdk/tools/winesync/setupapi_staging/0003-setupapi__Implement_SetupQueryDrivesInDiskSpaceList.diff @@ -0,0 +1,194 @@ +diff --git a/dll/win32/setupapi/diskspace.c b/dll/win32/setupapi/diskspace.c +index 962764cf279..1fa4486ce1e 100644 +--- a/dll/win32/setupapi/diskspace.c ++++ b/dll/win32/setupapi/diskspace.c +@@ -407,3 +407,88 @@ BOOL WINAPI SetupAddToDiskSpaceListA(HDSKSPC diskspace, PCSTR targetfile, + if (targetfileW) HeapFree(GetProcessHeap(), 0, targetfileW); + return ret; + } ++ ++/*********************************************************************** ++ * SetupQueryDrivesInDiskSpaceListW (SETUPAPI.@) ++ */ ++BOOL WINAPI SetupQueryDrivesInDiskSpaceListW(HDSKSPC diskspace, PWSTR buffer, DWORD size, PDWORD required_size) ++{ ++ struct space_list *list = diskspace; ++ struct file_entry *file; ++ DWORD cur_size = 1; ++ BOOL used[26]; ++ ++ TRACE("(%p, %p, %ld, %p)\n", diskspace, buffer, size, required_size); ++ ++ if (!diskspace) ++ { ++ SetLastError(ERROR_INVALID_PARAMETER); ++ return FALSE; ++ } ++ ++ memset(&used, 0, sizeof(used)); ++ LIST_FOR_EACH_ENTRY(file, &list->files, struct file_entry, entry) ++ { ++ int device; ++ ++ /* UNC paths are not yet supported by this function */ ++ if (towlower(file->path[0]) < 'a' || towlower(file->path[0]) > 'z' || file->path[1] != ':') ++ continue; ++ ++ device = towlower(file->path[0]) - 'a'; ++ if (used[device]) continue; ++ ++ cur_size += 3; ++ ++ if (buffer) ++ { ++ if (cur_size > size) ++ { ++ if (required_size) *required_size = cur_size; ++ SetLastError(ERROR_INSUFFICIENT_BUFFER); ++ return FALSE; ++ } ++ *buffer++ = towlower(file->path[0]); ++ *buffer++ = ':'; ++ *buffer++ = 0; ++ } ++ ++ used[device] = TRUE; ++ } ++ ++ if (buffer && size) *buffer = 0; ++ if (required_size) *required_size = cur_size; ++ return TRUE; ++} ++ ++/*********************************************************************** ++ * SetupQueryDrivesInDiskSpaceListA (SETUPAPI.@) ++ */ ++BOOL WINAPI SetupQueryDrivesInDiskSpaceListA(HDSKSPC diskspace, PSTR buffer, DWORD size, PDWORD required_size) ++{ ++ WCHAR *bufferW = NULL; ++ BOOL ret; ++ int i; ++ ++ if (buffer && size) ++ { ++ bufferW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); ++ if (!bufferW) ++ { ++ SetLastError(ERROR_NOT_ENOUGH_MEMORY); ++ return FALSE; ++ } ++ } ++ ++ ret = SetupQueryDrivesInDiskSpaceListW(diskspace, bufferW ? bufferW : (WCHAR *)buffer, ++ size, required_size); ++ ++ if (bufferW) ++ { ++ for (i = 0; i < size; i++) ++ buffer[i] = bufferW[i]; ++ HeapFree(GetProcessHeap(), 0, bufferW); ++ } ++ ++ return ret; ++} +diff --git a/dll/win32/setupapi/setupapi.spec b/dll/win32/setupapi/setupapi.spec +index 04296dbf9c4..4a87ac167da 100644 +--- a/dll/win32/setupapi/setupapi.spec ++++ b/dll/win32/setupapi/setupapi.spec +@@ -469,8 +469,8 @@ + @ stdcall SetupPromptForDiskA(ptr str str str str str long ptr long ptr) + @ stdcall SetupPromptForDiskW(ptr wstr wstr wstr wstr wstr long ptr long ptr) + @ stdcall SetupPromptReboot(ptr ptr long) +-@ stdcall -stub SetupQueryDrivesInDiskSpaceListA(ptr ptr long ptr) +-@ stub SetupQueryDrivesInDiskSpaceListW ++@ stdcall SetupQueryDrivesInDiskSpaceListA(ptr ptr long ptr) ++@ stdcall SetupQueryDrivesInDiskSpaceListW(ptr ptr long ptr) + @ stub SetupQueryFileLogA + @ stub SetupQueryFileLogW + @ stdcall SetupQueryInfFileInformationA(ptr long str long ptr) +diff --git a/modules/rostests/winetests/setupapi/diskspace.c b/modules/rostests/winetests/setupapi/diskspace.c +index 3cd83c8471f..930b957e913 100644 +--- a/modules/rostests/winetests/setupapi/diskspace.c ++++ b/modules/rostests/winetests/setupapi/diskspace.c +@@ -616,6 +616,75 @@ static void test_SetupAddToDiskSpaceListA(void) + "Expected SetupDestroyDiskSpaceList to succeed\n"); + } + ++static void test_SetupQueryDrivesInDiskSpaceListA(void) ++{ ++ char buffer[MAX_PATH]; ++ HDSKSPC handle; ++ DWORD size; ++ BOOL ret; ++ ++ handle = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); ++ ok(handle != NULL,"Expected SetupCreateDiskSpaceListA to return a valid handle\n"); ++ ++ ret = SetupQueryDrivesInDiskSpaceListA(handle, NULL, 0, NULL); ++ ok(ret, "Expected SetupQueryDrivesInDiskSpaceListA to succeed\n"); ++ ++ size = 0; ++ ret = SetupQueryDrivesInDiskSpaceListA(handle, NULL, 0, &size); ++ ok(ret, "Expected SetupQueryDrivesInDiskSpaceListA to succeed\n"); ++ ok(size == 1, "Expected size 1, got %lu\n", size); ++ ++ ret = SetupAddToDiskSpaceListA(handle, "F:\\random-file.dat", 0, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ ret = SetupAddToDiskSpaceListA(handle, "G:\\random-file.dat", 0, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ ret = SetupAddToDiskSpaceListA(handle, "G:\\random-file2.dat", 0, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ ret = SetupAddToDiskSpaceListA(handle, "X:\\random-file.dat", 0, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ size = 0; ++ ret = SetupQueryDrivesInDiskSpaceListA(handle, NULL, 0, &size); ++ ok(ret, "Expected SetupQueryDrivesInDiskSpaceListA to succeed\n"); ++ ok(size == 10, "Expected size 10, got %lu\n", size); ++ ++ size = 0; ++ ret = SetupQueryDrivesInDiskSpaceListA(handle, buffer, 0, &size); ++ ok(!ret, "Expected SetupQueryDrivesInDiskSpaceListA to fail\n"); ++ ok(size == 4, "Expected size 4, got %lu\n", size); ++ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); ++ ++ size = 0; ++ ret = SetupQueryDrivesInDiskSpaceListA(handle, buffer, 4, &size); ++ ok(!ret, "Expected SetupQueryDrivesInDiskSpaceListA to fail\n"); ++ ok(size == 7, "Expected size 7, got %lu\n", size); ++ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); ++ ++ size = 0; ++ ret = SetupQueryDrivesInDiskSpaceListA(handle, buffer, 7, &size); ++ ok(!ret, "Expected SetupQueryDrivesInDiskSpaceListA to fail\n"); ++ ok(size == 10, "Expected size 10, got %lu\n", size); ++ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); ++ ++ size = 0; ++ memset(buffer, 0xff, sizeof(buffer)); ++ ret = SetupQueryDrivesInDiskSpaceListA(handle, buffer, sizeof(buffer), &size); ++ ok(ret, "Expected SetupQueryDrivesInDiskSpaceListA to succeed\n"); ++ ok(size == 10, "Expected size 10, got %lu\n", size); ++ ok(!memcmp("f:\0g:\0x:\0\0", buffer, 10), "Device list does not match\n"); ++ ++ memset(buffer, 0xff, sizeof(buffer)); ++ ret = SetupQueryDrivesInDiskSpaceListA(handle, buffer, sizeof(buffer), NULL); ++ ok(ret, "Expected SetupQueryDrivesInDiskSpaceListA to succeed\n"); ++ ok(!memcmp("f:\0g:\0x:\0\0", buffer, 10), "Device list does not match\n"); ++} ++ + START_TEST(diskspace) + { + test_SetupCreateDiskSpaceListA(); +@@ -625,4 +694,5 @@ START_TEST(diskspace) + test_SetupQuerySpaceRequiredOnDriveA(); + test_SetupQuerySpaceRequiredOnDriveW(); + test_SetupAddToDiskSpaceListA(); ++ test_SetupQueryDrivesInDiskSpaceListA(); + } diff --git a/sdk/tools/winesync/setupapi_staging/0004-setupapi__Ignore_deletion_of_added_files_in_SetupAddToDiskSpaceList.diff b/sdk/tools/winesync/setupapi_staging/0004-setupapi__Ignore_deletion_of_added_files_in_SetupAddToDiskSpaceList.diff new file mode 100644 index 00000000000..5ea42f4694e --- /dev/null +++ b/sdk/tools/winesync/setupapi_staging/0004-setupapi__Ignore_deletion_of_added_files_in_SetupAddToDiskSpaceList.diff @@ -0,0 +1,109 @@ +diff --git a/dll/win32/setupapi/diskspace.c b/dll/win32/setupapi/diskspace.c +index 1fa4486ce1e..474f2b2c48b 100644 +--- a/dll/win32/setupapi/diskspace.c ++++ b/dll/win32/setupapi/diskspace.c +@@ -360,6 +360,12 @@ BOOL WINAPI SetupAddToDiskSpaceListW(HDSKSPC diskspace, PCWSTR targetfile, + + list_add_tail(&list->files, &file->entry); + } ++ else if (operation == FILEOP_DELETE) ++ { ++ /* delete operations for added files are ignored */ ++ ret = TRUE; ++ goto done; ++ } + + file->operation = operation; + if (operation == FILEOP_COPY) +diff --git a/modules/rostests/winetests/setupapi/diskspace.c b/modules/rostests/winetests/setupapi/diskspace.c +index 930b957e913..0cacf9a75aa 100644 +--- a/modules/rostests/winetests/setupapi/diskspace.c ++++ b/modules/rostests/winetests/setupapi/diskspace.c +@@ -428,7 +428,15 @@ static void test_SetupQuerySpaceRequiredOnDriveA(void) + + ret = SetupQuerySpaceRequiredOnDriveA(handle, "F:", &space, NULL, 0); + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); +- ok(space == 0x200000, "Expected 0x100000 as required space, got %s\n", debugstr_longlong(space)); ++ ok(space == 0x200000, "Expected 0x200000 as required space, got %s\n", debugstr_longlong(space)); ++ ++ snprintf(tmp, MAX_PATH, "F:\\wine-test-should-not-exist.txt"); ++ ret = SetupAddToDiskSpaceListA(handle, tmp, 0x200000, FILEOP_DELETE, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ ret = SetupQuerySpaceRequiredOnDriveA(handle, "F:", &space, NULL, 0); ++ ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); ++ ok(space == 0x200000, "Expected 0x200000 as required space, got %s\n", debugstr_longlong(space)); + + ok(SetupDestroyDiskSpaceList(handle), + "Expected SetupDestroyDiskSpaceList to succeed\n"); +@@ -466,6 +474,45 @@ static void test_SetupQuerySpaceRequiredOnDriveA(void) + ok(SetupDestroyDiskSpaceList(handle), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + ++ /* test FILEOP_DELETE, then FILEOP_COPY */ ++ handle = SetupCreateDiskSpaceListA(NULL, 0, 0); ++ ok(handle != NULL, ++ "Expected SetupCreateDiskSpaceListA to return a valid handle, got NULL\n"); ++ ++ ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_DELETE, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ space = 0; ++ ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); ++ ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); ++ ok(space == 0 || broken(space == -0x5000) || broken(space == -0x7000), ++ "Expected 0x0 as required space, got %s\n", debugstr_longlong(space)); ++ ++ ok(SetupDestroyDiskSpaceList(handle), ++ "Expected SetupDestroyDiskSpaceList to succeed\n"); ++ ++ /* test FILEOP_COPY, then FILEOP_DELETE */ ++ handle = SetupCreateDiskSpaceListA(NULL, 0, 0); ++ ok(handle != NULL, ++ "Expected SetupCreateDiskSpaceListA to return a valid handle, got NULL\n"); ++ ++ ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_DELETE, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ space = 0; ++ ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); ++ ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); ++ ok(space == 0 || broken(space == -0x5000) || broken(space == -0x7000), ++ "Expected 0x0 as required space, got %s\n", debugstr_longlong(space)); ++ ++ ok(SetupDestroyDiskSpaceList(handle), ++ "Expected SetupDestroyDiskSpaceList to succeed\n"); ++ ++ /* test FILEOP_DELETE without SPDSL_IGNORE_DISK */ + handle = SetupCreateDiskSpaceListA(NULL, 0, 0); + ok(handle != NULL, + "Expected SetupCreateDiskSpaceListA to return a valid handle, got NULL\n"); +@@ -480,6 +527,7 @@ static void test_SetupQuerySpaceRequiredOnDriveA(void) + ok(SetupDestroyDiskSpaceList(handle), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + ++ /* test FILEOP_COPY and FILEOP_DELETE with SPDSL_IGNORE_DISK */ + handle = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); + ok(handle != NULL, + "Expected SetupCreateDiskSpaceListA to return a valid handle, got NULL\n"); +@@ -491,6 +539,16 @@ static void test_SetupQuerySpaceRequiredOnDriveA(void) + ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); + ok(space == 0, "Expected size = 0, got %s\n", debugstr_longlong(space)); + ++ ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_COPY, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ret = SetupAddToDiskSpaceListA(handle, tmp, size, FILEOP_DELETE, 0, 0); ++ ok(ret, "Expected SetupAddToDiskSpaceListA to succeed\n"); ++ ++ space = 0; ++ ret = SetupQuerySpaceRequiredOnDriveA(handle, drive, &space, NULL, 0); ++ ok(ret, "Expected SetupQuerySpaceRequiredOnDriveA to succeed\n"); ++ ok(space >= size, "Expected size >= %s\n", debugstr_longlong(space)); ++ + ok(SetupDestroyDiskSpaceList(handle), + "Expected SetupDestroyDiskSpaceList to succeed\n"); + } diff --git a/sdk/tools/winesync/setupapi_staging/0005-setupapi__ImplementSetupAddSectionToDiskSpaceList.diff b/sdk/tools/winesync/setupapi_staging/0005-setupapi__ImplementSetupAddSectionToDiskSpaceList.diff new file mode 100644 index 00000000000..b905aeb7f42 --- /dev/null +++ b/sdk/tools/winesync/setupapi_staging/0005-setupapi__ImplementSetupAddSectionToDiskSpaceList.diff @@ -0,0 +1,418 @@ +diff --git a/dll/win32/setupapi/diskspace.c b/dll/win32/setupapi/diskspace.c +index 474f2b2c48b..c789fcd5958 100644 +--- a/dll/win32/setupapi/diskspace.c ++++ b/dll/win32/setupapi/diskspace.c +@@ -19,6 +19,7 @@ + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + ++#include + #include "setupapi_private.h" + #include "wine/list.h" + +@@ -52,6 +53,23 @@ static LONGLONG get_file_size(WCHAR *path) + return size.QuadPart; + } + ++static BOOL get_size_from_inf(HINF layoutinf, WCHAR *filename, LONGLONG *size) ++{ ++ static const WCHAR SourceDisksFiles[] = {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0}; ++ INFCONTEXT context; ++ WCHAR buffer[20]; ++ ++ if (!SetupFindFirstLineW(layoutinf, SourceDisksFiles, filename, &context)) ++ return FALSE; ++ ++ if (!SetupGetStringFieldW(&context, 3, buffer, sizeof(buffer), NULL)) ++ return FALSE; ++ ++ /* FIXME: is there a atollW ? */ ++ *size = wcstol(buffer, NULL, 10); ++ return TRUE; ++} ++ + /*********************************************************************** + * SetupCreateDiskSpaceListW (SETUPAPI.@) + */ +@@ -151,6 +169,117 @@ HDSKSPC WINAPI SetupDuplicateDiskSpaceListA(HDSKSPC DiskSpace, PVOID Reserved1, + return SetupDuplicateDiskSpaceListW(DiskSpace, Reserved1, Reserved2, Flags); + } + ++/*********************************************************************** ++ * SetupAddSectionToDiskSpaceListW (SETUPAPI.@) ++ */ ++BOOL WINAPI SetupAddSectionToDiskSpaceListW(HDSKSPC diskspace, HINF hinf, HINF hlist, ++ PCWSTR section, UINT operation, PVOID reserved1, ++ UINT reserved2) ++{ ++ static const WCHAR sepW[] = {'\\',0}; ++ WCHAR dest[MAX_PATH], src[MAX_PATH], *dest_dir, *full_path; ++ INFCONTEXT context; ++ BOOL ret = FALSE; ++ ++ TRACE("(%p, %p, %p, %s, %u, %p, %u)\n", diskspace, hinf, hlist, debugstr_w(section), ++ operation, reserved1, reserved2); ++ ++ if (!diskspace) ++ { ++ SetLastError(ERROR_INVALID_HANDLE); ++ return FALSE; ++ } ++ ++ if (!section) ++ { ++ SetLastError(ERROR_INVALID_PARAMETER); ++ return FALSE; ++ } ++ ++ if (!hlist) hlist = hinf; ++ ++ if (!SetupFindFirstLineW(hlist, section, NULL, &context)) ++ { ++ SetLastError(ERROR_SECTION_NOT_FOUND); ++ return FALSE; ++ } ++ ++ dest_dir = get_destination_dir(hinf, section); ++ if (!dest_dir) ++ { ++ SetLastError(ERROR_NOT_ENOUGH_MEMORY); ++ return FALSE; ++ } ++ ++ do ++ { ++ LONGLONG filesize; ++ int path_size; ++ BOOL tmp_ret; ++ ++ if (!SetupGetStringFieldW(&context, 1, dest, sizeof(dest) / sizeof(WCHAR), NULL)) ++ goto end; ++ if (!SetupGetStringFieldW(&context, 2, src, sizeof(src) / sizeof(WCHAR), NULL)) ++ *src = 0; ++ if (!get_size_from_inf(hinf, src[0] ? src : dest, &filesize)) ++ goto end; ++ ++ path_size = lstrlenW(dest_dir) + lstrlenW(dest) + 2; ++ full_path = HeapAlloc(GetProcessHeap(), 0, path_size * sizeof(WCHAR)); ++ if (!full_path) ++ { ++ SetLastError(ERROR_NOT_ENOUGH_MEMORY); ++ goto end; ++ } ++ ++ lstrcpyW(full_path, dest_dir); ++ lstrcatW(full_path, sepW); ++ lstrcatW(full_path, dest); ++ ++ tmp_ret = SetupAddToDiskSpaceListW(diskspace, full_path, filesize, operation, 0, 0); ++ HeapFree(GetProcessHeap(), 0, full_path); ++ if (!tmp_ret) goto end; ++ } ++ while (SetupFindNextLine(&context, &context)); ++ ++ ret = TRUE; ++ ++end: ++ HeapFree(GetProcessHeap(), 0, dest_dir); ++ return ret; ++} ++ ++/*********************************************************************** ++ * SetupAddSectionToDiskSpaceListA (SETUPAPI.@) ++ */ ++BOOL WINAPI SetupAddSectionToDiskSpaceListA(HDSKSPC diskspace, HINF hinf, HINF hlist, ++ PCSTR section, UINT operation, PVOID reserved1, ++ UINT reserved2) ++{ ++ LPWSTR sectionW = NULL; ++ DWORD len; ++ BOOL ret; ++ ++ if (section) ++ { ++ len = MultiByteToWideChar(CP_ACP, 0, section, -1, NULL, 0); ++ ++ sectionW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); ++ if (!sectionW) ++ { ++ SetLastError(ERROR_NOT_ENOUGH_MEMORY); ++ return FALSE; ++ } ++ ++ MultiByteToWideChar(CP_ACP, 0, section, -1, sectionW, len); ++ } ++ ++ ret = SetupAddSectionToDiskSpaceListW(diskspace, hinf, hlist, sectionW, operation, ++ reserved1, reserved2); ++ if (sectionW) HeapFree(GetProcessHeap(), 0, sectionW); ++ return ret; ++} ++ + /*********************************************************************** + * SetupAddInstallSectionToDiskSpaceListA (SETUPAPI.@) + */ +diff --git a/dll/win32/setupapi/queue.c b/dll/win32/setupapi/queue.c +index c9f2d72431c..d908c92a0ef 100644 +--- a/dll/win32/setupapi/queue.c ++++ b/dll/win32/setupapi/queue.c +@@ -418,7 +418,7 @@ static void get_source_info( HINF hinf, const WCHAR *src_file, SP_FILE_COPY_PARA + * + * Retrieve the destination dir for a given section. + */ +-static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section ) ++WCHAR *get_destination_dir( HINF hinf, const WCHAR *section ) + { + INFCONTEXT context; + WCHAR systemdir[MAX_PATH], *dir; +diff --git a/dll/win32/setupapi/setupapi.spec b/dll/win32/setupapi/setupapi.spec +index 4a87ac167da..4bc3c552de5 100644 +--- a/dll/win32/setupapi/setupapi.spec ++++ b/dll/win32/setupapi/setupapi.spec +@@ -218,8 +218,8 @@ + @ stdcall MyRealloc(ptr long) + @ stdcall SetupAddInstallSectionToDiskSpaceListA(long long long str ptr long) + @ stub SetupAddInstallSectionToDiskSpaceListW +-@ stdcall -stub SetupAddSectionToDiskSpaceListA(long long long str long ptr long) +-@ stub SetupAddSectionToDiskSpaceListW ++@ stdcall SetupAddSectionToDiskSpaceListA(ptr ptr ptr str long ptr long) ++@ stdcall SetupAddSectionToDiskSpaceListW(ptr ptr ptr wstr long ptr long) + @ stdcall SetupAddToDiskSpaceListA(long str int64 long ptr long) + @ stdcall SetupAddToDiskSpaceListW(long wstr int64 long ptr long) + @ stdcall SetupAddToSourceListA(long str) +diff --git a/dll/win32/setupapi/setupapi_private.h b/dll/win32/setupapi/setupapi_private.h +index af248ce8e73..970e197b401 100644 +--- a/dll/win32/setupapi/setupapi_private.h ++++ b/dll/win32/setupapi/setupapi_private.h +@@ -327,6 +327,8 @@ extern const WCHAR *PARSER_get_inf_filename( HINF hinf ) DECLSPEC_HIDDEN; + extern WCHAR *PARSER_get_src_root( HINF hinf ) DECLSPEC_HIDDEN; + extern WCHAR *PARSER_get_dest_dir( INFCONTEXT *context ) DECLSPEC_HIDDEN; + ++extern WCHAR *get_destination_dir( HINF hinf, const WCHAR *section ); ++ + /* support for Ascii queue callback functions */ + + struct callback_WtoA_context +diff --git a/modules/rostests/winetests/setupapi/diskspace.c b/modules/rostests/winetests/setupapi/diskspace.c +index 0cacf9a75aa..8e2eb88bf93 100644 +--- a/modules/rostests/winetests/setupapi/diskspace.c ++++ b/modules/rostests/winetests/setupapi/diskspace.c +@@ -30,6 +30,8 @@ + + #include "wine/test.h" + ++#define STD_HEADER "[Version]\r\nSignature=\"$CHICAGO$\"\r\n" ++ + static inline const char* debugstr_longlong(ULONGLONG ll) + { + static char string[17]; +@@ -40,6 +42,18 @@ static inline const char* debugstr_longlong(ULONGLONG ll) + return string; + } + ++/* create a new file with specified contents and open it */ ++static HINF inf_open_file_content(const char * tmpfilename, const char *data, UINT *err_line) ++{ ++ DWORD res; ++ HANDLE handle = CreateFileA(tmpfilename, GENERIC_READ|GENERIC_WRITE, ++ FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0); ++ if (handle == INVALID_HANDLE_VALUE) return 0; ++ if (!WriteFile( handle, data, strlen(data), &res, NULL )) trace( "write error\n" ); ++ CloseHandle( handle ); ++ return SetupOpenInfFileA( tmpfilename, 0, INF_STYLE_WIN4, err_line ); ++} ++ + static void test_SetupCreateDiskSpaceListA(void) + { + HDSKSPC ret; +@@ -741,6 +755,184 @@ static void test_SetupQueryDrivesInDiskSpaceListA(void) + ret = SetupQueryDrivesInDiskSpaceListA(handle, buffer, sizeof(buffer), NULL); + ok(ret, "Expected SetupQueryDrivesInDiskSpaceListA to succeed\n"); + ok(!memcmp("f:\0g:\0x:\0\0", buffer, 10), "Device list does not match\n"); ++ ++ ok(SetupDestroyDiskSpaceList(handle), ++ "Expected SetupDestroyDiskSpaceList to succeed\n"); ++} ++ ++struct device_usage ++{ ++ const char *dev; ++ LONGLONG usage; ++}; ++ ++struct section ++{ ++ const char *name; ++ UINT fileop; ++ BOOL result; ++ DWORD error_code; ++}; ++ ++static const struct ++{ ++ const char *data; ++ struct section sections[2]; ++ const char *devices; ++ int device_length; ++ struct device_usage usage[2]; ++} ++section_test[] = ++{ ++ /* 0 */ ++ {STD_HEADER "[a]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", ++ {{"a", FILEOP_COPY, TRUE, 0}, {NULL, 0, TRUE, 0}}, ++ "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, ++ /* 1 */ ++ {STD_HEADER "[a]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", ++ {{"a", FILEOP_DELETE, TRUE, 0}, {NULL, 0, TRUE, 0}}, ++ "c:\00", sizeof("c:\00"), {{"c:", 0}, {NULL, 0}}}, ++ /* 2 */ ++ {STD_HEADER "[a]\ntest,,,\n\r\n", ++ {{"a", FILEOP_COPY, FALSE, ERROR_LINE_NOT_FOUND}, {NULL, 0, TRUE, 0}}, ++ "", sizeof(""), {{NULL, 0}, {NULL, 0}}}, ++ /* 3 */ ++ {STD_HEADER "[a]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\n[DestinationDirs]\nDefaultDestDir=-1,F:\\test\r\n", ++ {{"a", FILEOP_COPY, TRUE, 0}, {NULL, 0, TRUE, 0}}, ++ "f:\00", sizeof("f:\00"), {{"f:", 4096}, {NULL, 0}}}, ++ /* 4 */ ++ {STD_HEADER "[a]\ntest,test2,,\n[SourceDisksFiles]\ntest2=1,,4096\r\n", ++ {{"a", FILEOP_COPY, TRUE, 0}, {NULL, 0, TRUE, 0}}, ++ "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, ++ /* 5 */ ++ {STD_HEADER "[a]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", ++ {{"b", FILEOP_COPY, FALSE, ERROR_SECTION_NOT_FOUND}, {NULL, 0, TRUE, 0}}, ++ "", sizeof(""), {{NULL, 0}, {NULL, 0}}}, ++ /* 6 */ ++ {STD_HEADER "[a]\ntest,,,\n[b]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", ++ {{"a", FILEOP_COPY, TRUE, 0}, {"b", FILEOP_COPY, TRUE, 0}}, ++ "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, ++ /* 7 */ ++ {STD_HEADER "[a]\ntest,,,\n[b]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\n[DestinationDirs]\nb=-1,F:\\test\r\n", ++ {{"a", FILEOP_COPY, TRUE, 0}, {"b", FILEOP_COPY, TRUE, 0}}, ++ "c:\00f:\00", sizeof("c:\00f:\00"), {{"c:", 4096}, {"f:", 4096}}}, ++ /* 8 */ ++ {STD_HEADER "[a]\ntest,test1,,\n[b]\ntest,test2,,\n[SourceDisksFiles]\ntest1=1,,4096\ntest2=1,,8192\r\n", ++ {{"a", FILEOP_COPY, TRUE, 0}, {"b", FILEOP_COPY, TRUE, 0}}, ++ "c:\00", sizeof("c:\00"), {{"c:", 8192}, {NULL, 0}}}, ++ /* 9 */ ++ {STD_HEADER "[a]\ntest1,test,,\n[b]\ntest2,test,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", ++ {{"a", FILEOP_COPY, TRUE, 0}, {"b", FILEOP_COPY, TRUE, 0}}, ++ "c:\00", sizeof("c:\00"), {{"c:", 8192}, {NULL, 0}}}, ++}; ++ ++static void test_SetupAddSectionToDiskSpaceListA(void) ++{ ++ char tmp[MAX_PATH]; ++ char tmpfilename[MAX_PATH]; ++ char buffer[MAX_PATH]; ++ HDSKSPC diskspace; ++ UINT err_line; ++ LONGLONG space; ++ BOOL ret; ++ int i, j; ++ HINF inf; ++ ++ if (!GetTempPathA(MAX_PATH, tmp)) ++ { ++ win_skip("GetTempPath failed with error %lu\n", GetLastError()); ++ return; ++ } ++ ++ if (!GetTempFileNameA(tmp, "inftest", 0, tmpfilename)) ++ { ++ win_skip("GetTempFileNameA failed with error %lu\n", GetLastError()); ++ return; ++ } ++ ++ inf = inf_open_file_content(tmpfilename, STD_HEADER "[a]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", &err_line); ++ ok(!!inf, "Failed to open inf file (%lu, line %d)\n", GetLastError(), err_line); ++ ++ diskspace = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); ++ ok(diskspace != NULL,"Expected SetupCreateDiskSpaceListA to return a valid handle\n"); ++ ++ ret = SetupAddSectionToDiskSpaceListA(diskspace, NULL, NULL, "a", FILEOP_COPY, 0, 0); ++ ok(!ret, "Expected SetupAddSectionToDiskSpaceListA to fail\n"); ++ ok(GetLastError() == ERROR_SECTION_NOT_FOUND, "Expected ERROR_SECTION_NOT_FOUND as error, got %lu\n", ++ GetLastError()); ++ ++ ret = SetupAddSectionToDiskSpaceListA(NULL, inf, NULL, "a", FILEOP_COPY, 0, 0); ++ ok(!ret, "Expected SetupAddSectionToDiskSpaceListA to fail\n"); ++ ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE as error, got %lu\n", ++ GetLastError()); ++ ++ ret = SetupAddSectionToDiskSpaceListA(NULL, inf, NULL, "b", FILEOP_COPY, 0, 0); ++ ok(!ret, "Expected SetupAddSectionToDiskSpaceListA to fail\n"); ++ ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE as error, got %lu\n", ++ GetLastError()); ++ ++ ret = SetupAddSectionToDiskSpaceListA(diskspace, inf, NULL, "a", 0, 0, 0); ++ ok(ret, "Expected SetupAddSectionToDiskSpaceListA to succeed (%lu)\n", GetLastError()); ++ ++ ok(SetupDestroyDiskSpaceList(diskspace), ++ "Expected SetupDestroyDiskSpaceList to succeed\n"); ++ ++ for (i = 0; i < sizeof(section_test) / sizeof(section_test[0]); i++) ++ { ++ err_line = 0; ++ ++ inf = inf_open_file_content(tmpfilename, section_test[i].data, &err_line); ++ ok(!!inf, "test %d: Failed to open inf file (%lu, line %d)\n", i, GetLastError(), err_line); ++ if (!inf) continue; ++ ++ diskspace = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); ++ ok(diskspace != NULL, "Expected SetupCreateDiskSpaceListA to return a valid handle\n"); ++ ++ for (j = 0; j < 2; j++) ++ { ++ const struct section *section = §ion_test[i].sections[j]; ++ if (!section->name) ++ continue; ++ ++ SetLastError(0xdeadbeef); ++ ret = SetupAddSectionToDiskSpaceListA(diskspace, inf, NULL, section->name, section->fileop, 0, 0); ++ if (section->result) ++ ok(ret, "test %d: Expected adding section %d to succeed (%lu)\n", i, j, GetLastError()); ++ else ++ { ++ ok(!ret, "test %d: Expected adding section %d to fail\n", i, j); ++ ok(GetLastError() == section->error_code, "test %d: Expected %lu as error, got %lu\n", ++ i, section->error_code, GetLastError()); ++ } ++ } ++ ++ memset(buffer, 0x0, sizeof(buffer)); ++ ret = SetupQueryDrivesInDiskSpaceListA(diskspace, buffer, sizeof(buffer), NULL); ++ ok(ret, "test %d: Expected SetupQueryDrivesInDiskSpaceListA to succeed (%lu)\n", i, GetLastError()); ++ ok(!memcmp(section_test[i].devices, buffer, section_test[i].device_length), ++ "test %d: Device list (%s) does not match\n", i, buffer); ++ ++ for (j = 0; j < 2; j++) ++ { ++ const struct device_usage *usage = §ion_test[i].usage[j]; ++ if (!usage->dev) ++ continue; ++ ++ space = 0; ++ ret = SetupQuerySpaceRequiredOnDriveA(diskspace, usage->dev, &space, NULL, 0); ++ ok(ret, "test %d: Expected SetupQuerySpaceRequiredOnDriveA to succeed for device %s (%lu)\n", ++ i, usage->dev, GetLastError()); ++ ok(space == usage->usage, "test %d: Expected size %lu for device %s, got %lu\n", ++ i, (DWORD)usage->usage, usage->dev, (DWORD)space); ++ } ++ ++ ok(SetupDestroyDiskSpaceList(diskspace), ++ "Expected SetupDestroyDiskSpaceList to succeed\n"); ++ ++ SetupCloseInfFile(inf); ++ } ++ ++ DeleteFileA(tmpfilename); + } + + START_TEST(diskspace) +@@ -753,4 +945,5 @@ START_TEST(diskspace) + test_SetupQuerySpaceRequiredOnDriveW(); + test_SetupAddToDiskSpaceListA(); + test_SetupQueryDrivesInDiskSpaceListA(); ++ test_SetupAddSectionToDiskSpaceListA(); + } diff --git a/sdk/tools/winesync/setupapi_staging/0006-setupapi__Implement_SetupAddInstallSectionToDiskSpaceList.diff b/sdk/tools/winesync/setupapi_staging/0006-setupapi__Implement_SetupAddInstallSectionToDiskSpaceList.diff new file mode 100644 index 00000000000..97896aa52e8 --- /dev/null +++ b/sdk/tools/winesync/setupapi_staging/0006-setupapi__Implement_SetupAddInstallSectionToDiskSpaceList.diff @@ -0,0 +1,306 @@ +diff --git a/dll/win32/setupapi/diskspace.c b/dll/win32/setupapi/diskspace.c +index c789fcd5958..dd1383ee31b 100644 +--- a/dll/win32/setupapi/diskspace.c ++++ b/dll/win32/setupapi/diskspace.c +@@ -281,16 +281,95 @@ BOOL WINAPI SetupAddSectionToDiskSpaceListA(HDSKSPC diskspace, HINF hinf, HINF h + } + + /*********************************************************************** +- * SetupAddInstallSectionToDiskSpaceListA (SETUPAPI.@) ++ * SetupAddInstallSectionToDiskSpaceListW (SETUPAPI.@) + */ +-BOOL WINAPI SetupAddInstallSectionToDiskSpaceListA(HDSKSPC DiskSpace, +- HINF InfHandle, HINF LayoutInfHandle, +- LPCSTR SectionName, PVOID Reserved1, UINT Reserved2) ++BOOL WINAPI SetupAddInstallSectionToDiskSpaceListW(HDSKSPC diskspace, ++ HINF inf, HINF layoutinf, LPCWSTR section, ++ PVOID reserved1, UINT reserved2) + { +- FIXME ("Stub\n"); ++ static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0}; ++ static const WCHAR DelFiles[] = {'D','e','l','F','i','l','e','s',0}; ++ WCHAR section_name[MAX_PATH]; ++ INFCONTEXT context; ++ BOOL ret; ++ int i; ++ ++ TRACE("(%p, %p, %p, %s, %p, %u)\n", diskspace, inf, layoutinf, debugstr_w(section), ++ reserved1, reserved2); ++ ++ if (!diskspace) ++ { ++ SetLastError(ERROR_INVALID_HANDLE); ++ return FALSE; ++ } ++ ++ if (!section) ++ { ++ SetLastError(ERROR_INVALID_PARAMETER); ++ return FALSE; ++ } ++ ++ if (!inf) return TRUE; ++ if (!layoutinf) layoutinf = inf; ++ ++ ret = SetupFindFirstLineW(inf, section, CopyFiles, &context); ++ while (ret) ++ { ++ for (i = 1;; i++) ++ { ++ if (!SetupGetStringFieldW(&context, i, section_name, sizeof(section_name) / sizeof(WCHAR), NULL)) ++ break; ++ SetupAddSectionToDiskSpaceListW(diskspace, layoutinf, inf, section_name, FILEOP_COPY, 0, 0); ++ } ++ ret = SetupFindNextLine(&context, &context); ++ } ++ ++ ret = SetupFindFirstLineW(inf, section, DelFiles, &context); ++ while (ret) ++ { ++ for (i = 1;; i++) ++ { ++ if (!SetupGetStringFieldW(&context, i, section_name, sizeof(section_name) / sizeof(WCHAR), NULL)) ++ break; ++ SetupAddSectionToDiskSpaceListW(diskspace, layoutinf, inf, section_name, FILEOP_DELETE, 0, 0); ++ } ++ ret = SetupFindNextLine(&context, &context); ++ } ++ + return TRUE; + } + ++/*********************************************************************** ++ * SetupAddInstallSectionToDiskSpaceListA (SETUPAPI.@) ++ */ ++BOOL WINAPI SetupAddInstallSectionToDiskSpaceListA(HDSKSPC diskspace, ++ HINF inf, HINF layoutinf, LPCSTR section, ++ PVOID reserved1, UINT reserved2) ++{ ++ LPWSTR sectionW = NULL; ++ DWORD len; ++ BOOL ret; ++ ++ if (section) ++ { ++ len = MultiByteToWideChar(CP_ACP, 0, section, -1, NULL, 0); ++ ++ sectionW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); ++ if (!sectionW) ++ { ++ SetLastError(ERROR_NOT_ENOUGH_MEMORY); ++ return FALSE; ++ } ++ ++ MultiByteToWideChar(CP_ACP, 0, section, -1, sectionW, len); ++ } ++ ++ ret = SetupAddInstallSectionToDiskSpaceListW(diskspace, inf, layoutinf, ++ sectionW, reserved1, reserved2); ++ if (sectionW) HeapFree(GetProcessHeap(), 0, sectionW); ++ return ret; ++} ++ + /*********************************************************************** + * SetupQuerySpaceRequiredOnDriveW (SETUPAPI.@) + */ +diff --git a/dll/win32/setupapi/setupapi.spec b/dll/win32/setupapi/setupapi.spec +index 4bc3c552de5..5326e201886 100644 +--- a/dll/win32/setupapi/setupapi.spec ++++ b/dll/win32/setupapi/setupapi.spec +@@ -216,8 +216,8 @@ + @ stdcall MyFree(ptr) + @ stdcall MyMalloc(long) + @ stdcall MyRealloc(ptr long) +-@ stdcall SetupAddInstallSectionToDiskSpaceListA(long long long str ptr long) +-@ stub SetupAddInstallSectionToDiskSpaceListW ++@ stdcall SetupAddInstallSectionToDiskSpaceListA(ptr ptr ptr str ptr long) ++@ stdcall SetupAddInstallSectionToDiskSpaceListW(ptr ptr ptr wstr ptr long) + @ stdcall SetupAddSectionToDiskSpaceListA(ptr ptr ptr str long ptr long) + @ stdcall SetupAddSectionToDiskSpaceListW(ptr ptr ptr wstr long ptr long) + @ stdcall SetupAddToDiskSpaceListA(long str int64 long ptr long) +diff --git a/modules/rostests/winetests/setupapi/diskspace.c b/modules/rostests/winetests/setupapi/diskspace.c +index 8e2eb88bf93..5643f930d9d 100644 +--- a/modules/rostests/winetests/setupapi/diskspace.c ++++ b/modules/rostests/winetests/setupapi/diskspace.c +@@ -935,6 +935,175 @@ static void test_SetupAddSectionToDiskSpaceListA(void) + DeleteFileA(tmpfilename); + } + ++struct section_i ++{ ++ const char *name; ++ BOOL result; ++ DWORD error_code; ++}; ++ ++static const struct ++{ ++ const char *data; ++ struct section_i sections[2]; ++ const char *devices; ++ int device_length; ++ struct device_usage usage[2]; ++} ++section_test_i[] = ++{ ++ /* 0 */ ++ {STD_HEADER "[a.Install]\nCopyFiles=a.CopyFiles\n" ++ "[a.CopyFiles]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", ++ {{"a.Install", TRUE, 0}, {NULL, TRUE, 0}}, "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, ++ /* 1 */ ++ {STD_HEADER "[a]\nCopyFiles=a.CopyFiles\n" ++ "[a.CopyFiles]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", ++ {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, ++ /* 2 */ ++ {STD_HEADER "[a]\nCopyFiles=a.CopyFiles\nCopyFiles=a.CopyFiles2\n" ++ "[a.CopyFiles]\ntest,,,\n[a.CopyFiles2]\ntest2,,,\n" ++ "[SourceDisksFiles]\ntest=1,,4096\ntest2=1,,4096\r\n", ++ {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "c:\00", sizeof("c:\00"), {{"c:", 8192}, {NULL, 0}}}, ++ /* 3 */ ++ {STD_HEADER "[a]\nCopyFiles=a.CopyFiles,a.CopyFiles2\n" ++ "[a.CopyFiles]\ntest,,,\n[a.CopyFiles2]\ntest2,,,\n" ++ "[SourceDisksFiles]\ntest=1,,4096\ntest2=1,,4096\r\n", ++ {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "c:\00", sizeof("c:\00"), {{"c:", 8192}, {NULL, 0}}}, ++ /* 4 */ ++ {STD_HEADER "[a]\r\n", ++ {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "", sizeof(""), {{NULL, 0}, {NULL, 0}}}, ++ /* 5 */ ++ {STD_HEADER "[a]\nDelFiles=a.DelFiles\n" ++ "[a.nDelFiles]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", ++ {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "", sizeof(""), {{NULL, 0}, {NULL, 0}}}, ++ /* 6 */ ++ {STD_HEADER "[a]\nCopyFiles=a.CopyFiles\nDelFiles=a.DelFiles\n" ++ "[a.CopyFiles]\ntest,,,\n[a.DelFiles]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", ++ {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, ++ /* 7 */ ++ {STD_HEADER "[a]\nCopyFiles=a.CopyFiles\n[b]\nDelFiles=b.DelFiles\n" ++ "[a.CopyFiles]\ntest,,,\n[b.DelFiles]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", ++ {{"a", TRUE, 0}, {"b", TRUE, 0}}, "c:\00", sizeof("c:\00"), {{"c:", 4096}, {NULL, 0}}}, ++ /* 7 */ ++ {STD_HEADER "[a]\nCopyFiles=\r\n", ++ {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "", sizeof(""), {{NULL, 0}, {NULL, 0}}}, ++ /* 8 */ ++ {STD_HEADER "[a]\nCopyFiles=something\r\n", ++ {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "", sizeof(""), {{NULL, 0}, {NULL, 0}}}, ++ /* 9 */ ++ {STD_HEADER "[a]\nCopyFiles=a.CopyFiles,b.CopyFiles\n[a.CopyFiles]\ntest,,,\n[b.CopyFiles]\ntest,,,\n" ++ "[SourceDisksFiles]\ntest=1,,4096\n[DestinationDirs]\nb.CopyFiles=-1,F:\\test\r\n", ++ {{"a", TRUE, 0}, {NULL, TRUE, 0}}, "c:\00f:\00", sizeof("c:\00f:\00"), {{"c:", 4096}, {"f:", 4096}}}, ++}; ++ ++static void test_SetupAddInstallSectionToDiskSpaceListA(void) ++{ ++ char tmp[MAX_PATH]; ++ char tmpfilename[MAX_PATH]; ++ char buffer[MAX_PATH]; ++ HDSKSPC diskspace; ++ LONGLONG space; ++ UINT err_line; ++ BOOL ret; ++ int i, j; ++ HINF inf; ++ ++ if (!GetTempPathA(MAX_PATH, tmp)) ++ { ++ win_skip("GetTempPath failed with error %ld\n", GetLastError()); ++ return; ++ } ++ ++ if (!GetTempFileNameA(tmp, "inftest", 0, tmpfilename)) ++ { ++ win_skip("GetTempFileNameA failed with error %ld\n", GetLastError()); ++ return; ++ } ++ ++ inf = inf_open_file_content(tmpfilename, STD_HEADER "[a]\nCopyFiles=b\n[b]\ntest,,,\n[SourceDisksFiles]\ntest=1,,4096\r\n", &err_line); ++ ok(!!inf, "Failed to open inf file (%ld, line %u)\n", GetLastError(), err_line); ++ ++ diskspace = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); ++ ok(diskspace != NULL,"Expected SetupCreateDiskSpaceListA to return a valid handle\n"); ++ ++ ret = SetupAddInstallSectionToDiskSpaceListA(diskspace, NULL, NULL, "a", 0, 0); ++ ok(ret, "Expected SetupAddInstallSectionToDiskSpaceListA to succeed\n"); ++ ++ ret = SetupAddInstallSectionToDiskSpaceListA(NULL, inf, NULL, "a", 0, 0); ++ ok(!ret, "Expected SetupAddInstallSectionToDiskSpaceListA to fail\n"); ++ ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE as error, got %lu\n", ++ GetLastError()); ++ ++ ret = SetupAddInstallSectionToDiskSpaceListA(diskspace, inf, NULL, NULL, 0, 0); ++ ok(!ret || broken(ret), "Expected SetupAddSectionToDiskSpaceListA to fail\n"); ++ ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(ret), ++ "Expected ERROR_INVALID_PARAMETER as error, got %lu\n", GetLastError()); ++ ++ ret = SetupAddInstallSectionToDiskSpaceListA(diskspace, inf, NULL, "", 0, 0); ++ ok(ret, "Expected SetupAddInstallSectionToDiskSpaceListA to succeed (%lu)\n", GetLastError()); ++ ++ ok(SetupDestroyDiskSpaceList(diskspace), ++ "Expected SetupDestroyDiskSpaceList to succeed\n"); ++ ++ for (i = 0; i < sizeof(section_test_i) / sizeof(section_test_i[0]); i++) ++ { ++ err_line = 0; ++ ++ inf = inf_open_file_content(tmpfilename, section_test_i[i].data, &err_line); ++ ok(!!inf, "test %u: Failed to open inf file (%lu, line %u)\n", i, GetLastError(), err_line); ++ if (!inf) continue; ++ ++ diskspace = SetupCreateDiskSpaceListA(NULL, 0, SPDSL_IGNORE_DISK); ++ ok(diskspace != NULL,"Expected SetupCreateDiskSpaceListA to return a valid handle\n"); ++ ++ for (j = 0; j < 2; j++) ++ { ++ const struct section_i *section = §ion_test_i[i].sections[j]; ++ if (!section->name) ++ continue; ++ ++ SetLastError(0xdeadbeef); ++ ret = SetupAddInstallSectionToDiskSpaceListA(diskspace, inf, NULL, section->name, 0, 0); ++ if (section->result) ++ ok(ret, "test %d: Expected adding section %d to succeed (%lu)\n", i, j, GetLastError()); ++ else ++ { ++ ok(!ret, "test %d: Expected adding section %d to fail\n", i, j); ++ ok(GetLastError() == section->error_code, "test %d: Expected %lu as error, got %lu\n", ++ i, section->error_code, GetLastError()); ++ } ++ } ++ ++ memset(buffer, 0x0, sizeof(buffer)); ++ ret = SetupQueryDrivesInDiskSpaceListA(diskspace, buffer, sizeof(buffer), NULL); ++ ok(ret, "test %d: Expected SetupQueryDrivesInDiskSpaceListA to succeed (%lu)\n", i, GetLastError()); ++ ok(!memcmp(section_test_i[i].devices, buffer, section_test_i[i].device_length), ++ "test %d: Device list (%s) does not match\n", i, buffer); ++ ++ for (j = 0; j < 2; j++) ++ { ++ const struct device_usage *usage = §ion_test_i[i].usage[j]; ++ if (!usage->dev) ++ continue; ++ ++ space = 0; ++ ret = SetupQuerySpaceRequiredOnDriveA(diskspace, usage->dev, &space, NULL, 0); ++ ok(ret, "test %d: Expected SetupQuerySpaceRequiredOnDriveA to succeed for device %s (%lu)\n", ++ i, usage->dev, GetLastError()); ++ ok(space == usage->usage, "test %d: Expected size %lu for device %s, got %lu\n", ++ i, (DWORD)usage->usage, usage->dev, (DWORD)space); ++ } ++ ++ ok(SetupDestroyDiskSpaceList(diskspace), ++ "Expected SetupDestroyDiskSpaceList to succeed\n"); ++ ++ SetupCloseInfFile(inf); ++ } ++ ++ DeleteFileA(tmpfilename); ++} ++ + START_TEST(diskspace) + { + test_SetupCreateDiskSpaceListA(); +@@ -946,4 +1115,5 @@ START_TEST(diskspace) + test_SetupAddToDiskSpaceListA(); + test_SetupQueryDrivesInDiskSpaceListA(); + test_SetupAddSectionToDiskSpaceListA(); ++ test_SetupAddInstallSectionToDiskSpaceListA(); + }