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