[WINESYNC] setupapi: Rewrite DiskSpaceList logic using lists.

wine-staging patch by Michael Müller <michael@fds-team.de>

[WINESYNC] setupapi: Implement SetupAddToDiskSpaceList.

wine-staging patch by Michael Müller <michael@fds-team.de>

[WINESYNC] setupapi: Implement SetupQueryDrivesInDiskSpaceList.

wine-staging patch by Michael Müller <michael@fds-team.de>

+ Add the .spec exports.

Co-authored-by: Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>

[WINESYNC] setupapi: Ignore deletion of added files in SetupAddToDiskSpaceList.

wine-staging patch by Michael Müller <michael@fds-team.de>

[WINESYNC] setupapi: ImplementSetupAddSectionToDiskSpaceList.

wine-staging patch by Michael Müller <michael@fds-team.de>

[WINESYNC] setupapi: Implement SetupAddInstallSectionToDiskSpaceList.

wine-staging patch by Michael Müller <michael@fds-team.de>
This commit is contained in:
winesync 2023-09-17 15:36:58 +02:00 committed by Hermès Bélusca-Maïto
parent 205538a382
commit a1188a84d8
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
11 changed files with 2878 additions and 111 deletions

View file

@ -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 <stdlib.h>
#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,&sectors,&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;
}

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -19,6 +19,7 @@
*/
#include <stdarg.h>
#include <stdio.h>
#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 = &section_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 = &section_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 = &section_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 = &section_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();
}

View file

@ -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,&sectors,&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;
}

View file

@ -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 <stdarg.h>
+#include <stdio.h>
#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();
}

View file

@ -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();
}

View file

@ -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");
}

View file

@ -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 <stdlib.h>
#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 = &section_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 = &section_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();
}

View file

@ -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 = &section_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 = &section_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();
}