mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 07:43:54 -06:00

qga_vss_fsfreeze() casts error_set_win32() from void (*)(Error **, int, ErrorClass, const char *, ...) to void (*)(void **, int, int, const char *, ...) The result is later called. Since the two types are not compatible, the call is undefined behavior. It works in practice anyway. However, there's no real need for trickery here. Clean it up as follows: * Declare struct Error, and fix the first parameter. * Switch to error_setg_win32(). This gets rid of the troublesome ErrorClass parameter. Requires converting error_setg_win32() from macro to function, but that's trivially easy, because this is the only user of error_set_win32(). Signed-off-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
165 lines
4.4 KiB
C
165 lines
4.4 KiB
C
/*
|
|
* QEMU Guest Agent VSS utility functions
|
|
*
|
|
* Copyright Hitachi Data Systems Corp. 2013
|
|
*
|
|
* Authors:
|
|
* Tomoki Sekiyama <tomoki.sekiyama@hds.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
|
* See the COPYING file in the top-level directory.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include "qga/guest-agent-core.h"
|
|
#include "qga/vss-win32.h"
|
|
#include "qga/vss-win32/requester.h"
|
|
|
|
#define QGA_VSS_DLL "qga-vss.dll"
|
|
|
|
static HMODULE provider_lib;
|
|
|
|
/* Call a function in qga-vss.dll with the specified name */
|
|
static HRESULT call_vss_provider_func(const char *func_name)
|
|
{
|
|
FARPROC WINAPI func;
|
|
|
|
g_assert(provider_lib);
|
|
|
|
func = GetProcAddress(provider_lib, func_name);
|
|
if (!func) {
|
|
char *msg;
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(char *)&msg, 0, NULL);
|
|
fprintf(stderr, "failed to load %s from %s: %s",
|
|
func_name, QGA_VSS_DLL, msg);
|
|
LocalFree(msg);
|
|
return E_FAIL;
|
|
}
|
|
|
|
return func();
|
|
}
|
|
|
|
/* Check whether this OS version supports VSS providers */
|
|
static bool vss_check_os_version(void)
|
|
{
|
|
OSVERSIONINFO OSver;
|
|
|
|
OSver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionEx(&OSver);
|
|
if ((OSver.dwMajorVersion == 5 && OSver.dwMinorVersion >= 2) ||
|
|
OSver.dwMajorVersion > 5) {
|
|
BOOL wow64 = false;
|
|
#ifndef _WIN64
|
|
/* Provider doesn't work under WOW64 (32bit agent on 64bit OS) */
|
|
if (!IsWow64Process(GetCurrentProcess(), &wow64)) {
|
|
fprintf(stderr, "failed to IsWow64Process (Error: %lx\n)\n",
|
|
GetLastError());
|
|
return false;
|
|
}
|
|
if (wow64) {
|
|
fprintf(stderr, "Warning: Running under WOW64\n");
|
|
}
|
|
#endif
|
|
return !wow64;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Load qga-vss.dll */
|
|
bool vss_init(bool init_requester)
|
|
{
|
|
if (!vss_check_os_version()) {
|
|
/* Do nothing if OS doesn't support providers. */
|
|
fprintf(stderr, "VSS provider is not supported in this OS version: "
|
|
"fsfreeze is disabled.\n");
|
|
return false;
|
|
}
|
|
|
|
provider_lib = LoadLibraryA(QGA_VSS_DLL);
|
|
if (!provider_lib) {
|
|
char *msg;
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(char *)&msg, 0, NULL);
|
|
fprintf(stderr, "failed to load %s: %sfsfreeze is disabled\n",
|
|
QGA_VSS_DLL, msg);
|
|
LocalFree(msg);
|
|
return false;
|
|
}
|
|
|
|
if (init_requester) {
|
|
HRESULT hr = call_vss_provider_func("requester_init");
|
|
if (FAILED(hr)) {
|
|
fprintf(stderr, "fsfreeze is disabled.\n");
|
|
vss_deinit(false);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Unload qga-provider.dll */
|
|
void vss_deinit(bool deinit_requester)
|
|
{
|
|
if (deinit_requester) {
|
|
call_vss_provider_func("requester_deinit");
|
|
}
|
|
FreeLibrary(provider_lib);
|
|
provider_lib = NULL;
|
|
}
|
|
|
|
bool vss_initialized(void)
|
|
{
|
|
return !!provider_lib;
|
|
}
|
|
|
|
int ga_install_vss_provider(void)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (!vss_init(false)) {
|
|
fprintf(stderr, "Installation of VSS provider is skipped. "
|
|
"fsfreeze will be disabled.\n");
|
|
return 0;
|
|
}
|
|
hr = call_vss_provider_func("COMRegister");
|
|
vss_deinit(false);
|
|
|
|
return SUCCEEDED(hr) ? 0 : EXIT_FAILURE;
|
|
}
|
|
|
|
void ga_uninstall_vss_provider(void)
|
|
{
|
|
if (!vss_init(false)) {
|
|
fprintf(stderr, "Removal of VSS provider is skipped.\n");
|
|
return;
|
|
}
|
|
call_vss_provider_func("COMUnregister");
|
|
vss_deinit(false);
|
|
}
|
|
|
|
/* Call VSS requester and freeze/thaw filesystems and applications */
|
|
void qga_vss_fsfreeze(int *nr_volume, Error **errp, bool freeze)
|
|
{
|
|
const char *func_name = freeze ? "requester_freeze" : "requester_thaw";
|
|
QGAVSSRequesterFunc func;
|
|
ErrorSet errset = {
|
|
.error_setg_win32 = error_setg_win32,
|
|
.errp = errp,
|
|
};
|
|
|
|
func = (QGAVSSRequesterFunc)GetProcAddress(provider_lib, func_name);
|
|
if (!func) {
|
|
error_setg_win32(errp, GetLastError(), "failed to load %s from %s",
|
|
func_name, QGA_VSS_DLL);
|
|
return;
|
|
}
|
|
|
|
func(nr_volume, &errset);
|
|
}
|