Statistics
| Branch: | Revision:

root / qga / vss-win32.c @ f311f2c2

History | View | Annotate | Download (4.4 kB)

1
/*
2
 * QEMU Guest Agent VSS utility functions
3
 *
4
 * Copyright Hitachi Data Systems Corp. 2013
5
 *
6
 * Authors:
7
 *  Tomoki Sekiyama   <tomoki.sekiyama@hds.com>
8
 *
9
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10
 * See the COPYING file in the top-level directory.
11
 */
12

    
13
#include <stdio.h>
14
#include <windows.h>
15
#include "qga/guest-agent-core.h"
16
#include "qga/vss-win32.h"
17
#include "qga/vss-win32/requester.h"
18

    
19
#define QGA_VSS_DLL "qga-vss.dll"
20

    
21
static HMODULE provider_lib;
22

    
23
/* Call a function in qga-vss.dll with the specified name */
24
static HRESULT call_vss_provider_func(const char *func_name)
25
{
26
    FARPROC WINAPI func;
27

    
28
    g_assert(provider_lib);
29

    
30
    func = GetProcAddress(provider_lib, func_name);
31
    if (!func) {
32
        char *msg;
33
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
34
                      FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
35
                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
36
                      (char *)&msg, 0, NULL);
37
        fprintf(stderr, "failed to load %s from %s: %s",
38
                func_name, QGA_VSS_DLL, msg);
39
        LocalFree(msg);
40
        return E_FAIL;
41
    }
42

    
43
    return func();
44
}
45

    
46
/* Check whether this OS version supports VSS providers */
47
static bool vss_check_os_version(void)
48
{
49
    OSVERSIONINFO OSver;
50

    
51
    OSver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
52
    GetVersionEx(&OSver);
53
    if ((OSver.dwMajorVersion == 5 && OSver.dwMinorVersion >= 2) ||
54
       OSver.dwMajorVersion > 5) {
55
        BOOL wow64 = false;
56
#ifndef _WIN64
57
        /* Provider doesn't work under WOW64 (32bit agent on 64bit OS) */
58
        if (!IsWow64Process(GetCurrentProcess(), &wow64)) {
59
            fprintf(stderr, "failed to IsWow64Process (Error: %lx\n)\n",
60
                    GetLastError());
61
            return false;
62
        }
63
        if (wow64) {
64
            fprintf(stderr, "Warning: Running under WOW64\n");
65
        }
66
#endif
67
        return !wow64;
68
    }
69
    return false;
70
}
71

    
72
/* Load qga-vss.dll */
73
bool vss_init(bool init_requester)
74
{
75
    if (!vss_check_os_version()) {
76
        /* Do nothing if OS doesn't support providers. */
77
        fprintf(stderr, "VSS provider is not supported in this OS version: "
78
                "fsfreeze is disabled.\n");
79
        return false;
80
    }
81

    
82
    provider_lib = LoadLibraryA(QGA_VSS_DLL);
83
    if (!provider_lib) {
84
        char *msg;
85
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
86
                      FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
87
                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
88
                      (char *)&msg, 0, NULL);
89
        fprintf(stderr, "failed to load %s: %sfsfreeze is disabled\n",
90
                QGA_VSS_DLL, msg);
91
        LocalFree(msg);
92
        return false;
93
    }
94

    
95
    if (init_requester) {
96
        HRESULT hr = call_vss_provider_func("requester_init");
97
        if (FAILED(hr)) {
98
            fprintf(stderr, "fsfreeze is disabled.\n");
99
            vss_deinit(false);
100
            return false;
101
        }
102
    }
103

    
104
    return true;
105
}
106

    
107
/* Unload qga-provider.dll */
108
void vss_deinit(bool deinit_requester)
109
{
110
    if (deinit_requester) {
111
        call_vss_provider_func("requester_deinit");
112
    }
113
    FreeLibrary(provider_lib);
114
    provider_lib = NULL;
115
}
116

    
117
bool vss_initialized(void)
118
{
119
    return !!provider_lib;
120
}
121

    
122
int ga_install_vss_provider(void)
123
{
124
    HRESULT hr;
125

    
126
    if (!vss_init(false)) {
127
        fprintf(stderr, "Installation of VSS provider is skipped. "
128
                "fsfreeze will be disabled.\n");
129
        return 0;
130
    }
131
    hr = call_vss_provider_func("COMRegister");
132
    vss_deinit(false);
133

    
134
    return SUCCEEDED(hr) ? 0 : EXIT_FAILURE;
135
}
136

    
137
void ga_uninstall_vss_provider(void)
138
{
139
    if (!vss_init(false)) {
140
        fprintf(stderr, "Removal of VSS provider is skipped.\n");
141
        return;
142
    }
143
    call_vss_provider_func("COMUnregister");
144
    vss_deinit(false);
145
}
146

    
147
/* Call VSS requester and freeze/thaw filesystems and applications */
148
void qga_vss_fsfreeze(int *nr_volume, Error **err, bool freeze)
149
{
150
    const char *func_name = freeze ? "requester_freeze" : "requester_thaw";
151
    QGAVSSRequesterFunc func;
152
    ErrorSet errset = {
153
        .error_set = (ErrorSetFunc)error_set_win32,
154
        .errp = (void **)err,
155
        .err_class = ERROR_CLASS_GENERIC_ERROR
156
    };
157

    
158
    func = (QGAVSSRequesterFunc)GetProcAddress(provider_lib, func_name);
159
    if (!func) {
160
        error_setg_win32(err, GetLastError(), "failed to load %s from %s",
161
                         func_name, QGA_VSS_DLL);
162
        return;
163
    }
164

    
165
    func(nr_volume, &errset);
166
}