qemu/qga/commands-win32.c
<<
>>
Prefs
   1/*
   2 * QEMU Guest Agent win32-specific command implementations
   3 *
   4 * Copyright IBM Corp. 2012
   5 *
   6 * Authors:
   7 *  Michael Roth      <mdroth@linux.vnet.ibm.com>
   8 *  Gal Hammer        <ghammer@redhat.com>
   9 *
  10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  11 * See the COPYING file in the top-level directory.
  12 */
  13#include "qemu/osdep.h"
  14
  15#include <wtypes.h>
  16#include <powrprof.h>
  17#include <winsock2.h>
  18#include <ws2tcpip.h>
  19#include <iptypes.h>
  20#include <iphlpapi.h>
  21#include <winioctl.h>
  22#include <ntddscsi.h>
  23#include <setupapi.h>
  24#include <cfgmgr32.h>
  25#include <initguid.h>
  26#include <devpropdef.h>
  27#include <lm.h>
  28#include <wtsapi32.h>
  29#include <wininet.h>
  30
  31#include "guest-agent-core.h"
  32#include "vss-win32.h"
  33#include "qga-qapi-commands.h"
  34#include "qapi/error.h"
  35#include "qapi/qmp/qerror.h"
  36#include "qemu/queue.h"
  37#include "qemu/host-utils.h"
  38#include "qemu/base64.h"
  39#include "commands-common.h"
  40
  41/*
  42 * The following should be in devpkey.h, but it isn't. The key names were
  43 * prefixed to avoid (future) name clashes. Once the definitions get into
  44 * mingw the following lines can be removed.
  45 */
  46DEFINE_DEVPROPKEY(qga_DEVPKEY_NAME, 0xb725f130, 0x47ef, 0x101a, 0xa5,
  47    0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac, 10);
  48    /* DEVPROP_TYPE_STRING */
  49DEFINE_DEVPROPKEY(qga_DEVPKEY_Device_HardwareIds, 0xa45c254e, 0xdf1c,
  50    0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 3);
  51    /* DEVPROP_TYPE_STRING_LIST */
  52DEFINE_DEVPROPKEY(qga_DEVPKEY_Device_DriverDate, 0xa8b865dd, 0x2e3d,
  53    0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 2);
  54    /* DEVPROP_TYPE_FILETIME */
  55DEFINE_DEVPROPKEY(qga_DEVPKEY_Device_DriverVersion, 0xa8b865dd, 0x2e3d,
  56    0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 3);
  57    /* DEVPROP_TYPE_STRING */
  58/* The CM_Get_DevNode_PropertyW prototype is only sometimes in cfgmgr32.h */
  59#ifndef CM_Get_DevNode_Property
  60#pragma GCC diagnostic push
  61#pragma GCC diagnostic ignored "-Wredundant-decls"
  62CMAPI CONFIGRET WINAPI CM_Get_DevNode_PropertyW(
  63    DEVINST          dnDevInst,
  64    CONST DEVPROPKEY * PropertyKey,
  65    DEVPROPTYPE      * PropertyType,
  66    PBYTE            PropertyBuffer,
  67    PULONG           PropertyBufferSize,
  68    ULONG            ulFlags
  69);
  70#define CM_Get_DevNode_Property CM_Get_DevNode_PropertyW
  71#pragma GCC diagnostic pop
  72#endif
  73
  74#ifndef SHTDN_REASON_FLAG_PLANNED
  75#define SHTDN_REASON_FLAG_PLANNED 0x80000000
  76#endif
  77
  78/* multiple of 100 nanoseconds elapsed between windows baseline
  79 *    (1/1/1601) and Unix Epoch (1/1/1970), accounting for leap years */
  80#define W32_FT_OFFSET (10000000ULL * 60 * 60 * 24 * \
  81                       (365 * (1970 - 1601) +       \
  82                        (1970 - 1601) / 4 - 3))
  83
  84#define INVALID_SET_FILE_POINTER ((DWORD)-1)
  85
  86struct GuestFileHandle {
  87    int64_t id;
  88    HANDLE fh;
  89    QTAILQ_ENTRY(GuestFileHandle) next;
  90};
  91
  92static struct {
  93    QTAILQ_HEAD(, GuestFileHandle) filehandles;
  94} guest_file_state = {
  95    .filehandles = QTAILQ_HEAD_INITIALIZER(guest_file_state.filehandles),
  96};
  97
  98#define FILE_GENERIC_APPEND (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA)
  99
 100typedef struct OpenFlags {
 101    const char *forms;
 102    DWORD desired_access;
 103    DWORD creation_disposition;
 104} OpenFlags;
 105static OpenFlags guest_file_open_modes[] = {
 106    {"r",   GENERIC_READ,                     OPEN_EXISTING},
 107    {"rb",  GENERIC_READ,                     OPEN_EXISTING},
 108    {"w",   GENERIC_WRITE,                    CREATE_ALWAYS},
 109    {"wb",  GENERIC_WRITE,                    CREATE_ALWAYS},
 110    {"a",   FILE_GENERIC_APPEND,              OPEN_ALWAYS  },
 111    {"r+",  GENERIC_WRITE | GENERIC_READ,       OPEN_EXISTING},
 112    {"rb+", GENERIC_WRITE | GENERIC_READ,       OPEN_EXISTING},
 113    {"r+b", GENERIC_WRITE | GENERIC_READ,       OPEN_EXISTING},
 114    {"w+",  GENERIC_WRITE | GENERIC_READ,       CREATE_ALWAYS},
 115    {"wb+", GENERIC_WRITE | GENERIC_READ,       CREATE_ALWAYS},
 116    {"w+b", GENERIC_WRITE | GENERIC_READ,       CREATE_ALWAYS},
 117    {"a+",  FILE_GENERIC_APPEND | GENERIC_READ, OPEN_ALWAYS  },
 118    {"ab+", FILE_GENERIC_APPEND | GENERIC_READ, OPEN_ALWAYS  },
 119    {"a+b", FILE_GENERIC_APPEND | GENERIC_READ, OPEN_ALWAYS  }
 120};
 121
 122#define debug_error(msg) do { \
 123    char *suffix = g_win32_error_message(GetLastError()); \
 124    g_debug("%s: %s", (msg), suffix); \
 125    g_free(suffix); \
 126} while (0)
 127
 128static OpenFlags *find_open_flag(const char *mode_str)
 129{
 130    int mode;
 131    Error **errp = NULL;
 132
 133    for (mode = 0; mode < ARRAY_SIZE(guest_file_open_modes); ++mode) {
 134        OpenFlags *flags = guest_file_open_modes + mode;
 135
 136        if (strcmp(flags->forms, mode_str) == 0) {
 137            return flags;
 138        }
 139    }
 140
 141    error_setg(errp, "invalid file open mode '%s'", mode_str);
 142    return NULL;
 143}
 144
 145static int64_t guest_file_handle_add(HANDLE fh, Error **errp)
 146{
 147    GuestFileHandle *gfh;
 148    int64_t handle;
 149
 150    handle = ga_get_fd_handle(ga_state, errp);
 151    if (handle < 0) {
 152        return -1;
 153    }
 154    gfh = g_new0(GuestFileHandle, 1);
 155    gfh->id = handle;
 156    gfh->fh = fh;
 157    QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
 158
 159    return handle;
 160}
 161
 162GuestFileHandle *guest_file_handle_find(int64_t id, Error **errp)
 163{
 164    GuestFileHandle *gfh;
 165    QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next) {
 166        if (gfh->id == id) {
 167            return gfh;
 168        }
 169    }
 170    error_setg(errp, "handle '%" PRId64 "' has not been found", id);
 171    return NULL;
 172}
 173
 174static void handle_set_nonblocking(HANDLE fh)
 175{
 176    DWORD file_type, pipe_state;
 177    file_type = GetFileType(fh);
 178    if (file_type != FILE_TYPE_PIPE) {
 179        return;
 180    }
 181    /* If file_type == FILE_TYPE_PIPE, according to MSDN
 182     * the specified file is socket or named pipe */
 183    if (!GetNamedPipeHandleState(fh, &pipe_state, NULL,
 184                                 NULL, NULL, NULL, 0)) {
 185        return;
 186    }
 187    /* The fd is named pipe fd */
 188    if (pipe_state & PIPE_NOWAIT) {
 189        return;
 190    }
 191
 192    pipe_state |= PIPE_NOWAIT;
 193    SetNamedPipeHandleState(fh, &pipe_state, NULL, NULL);
 194}
 195
 196int64_t qmp_guest_file_open(const char *path, const char *mode, Error **errp)
 197{
 198    int64_t fd = -1;
 199    HANDLE fh;
 200    HANDLE templ_file = NULL;
 201    DWORD share_mode = FILE_SHARE_READ;
 202    DWORD flags_and_attr = FILE_ATTRIBUTE_NORMAL;
 203    LPSECURITY_ATTRIBUTES sa_attr = NULL;
 204    OpenFlags *guest_flags;
 205    GError *gerr = NULL;
 206    wchar_t *w_path = NULL;
 207
 208    if (!mode) {
 209        mode = "r";
 210    }
 211    slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
 212    guest_flags = find_open_flag(mode);
 213    if (guest_flags == NULL) {
 214        error_setg(errp, "invalid file open mode");
 215        goto done;
 216    }
 217
 218    w_path = g_utf8_to_utf16(path, -1, NULL, NULL, &gerr);
 219    if (!w_path) {
 220        goto done;
 221    }
 222
 223    fh = CreateFileW(w_path, guest_flags->desired_access, share_mode, sa_attr,
 224                    guest_flags->creation_disposition, flags_and_attr,
 225                    templ_file);
 226    if (fh == INVALID_HANDLE_VALUE) {
 227        error_setg_win32(errp, GetLastError(), "failed to open file '%s'",
 228                         path);
 229        goto done;
 230    }
 231
 232    /* set fd non-blocking to avoid common use cases (like reading from a
 233     * named pipe) from hanging the agent
 234     */
 235    handle_set_nonblocking(fh);
 236
 237    fd = guest_file_handle_add(fh, errp);
 238    if (fd < 0) {
 239        CloseHandle(fh);
 240        error_setg(errp, "failed to add handle to qmp handle table");
 241        goto done;
 242    }
 243
 244    slog("guest-file-open, handle: % " PRId64, fd);
 245
 246done:
 247    if (gerr) {
 248        error_setg(errp, QERR_QGA_COMMAND_FAILED, gerr->message);
 249        g_error_free(gerr);
 250    }
 251    g_free(w_path);
 252    return fd;
 253}
 254
 255void qmp_guest_file_close(int64_t handle, Error **errp)
 256{
 257    bool ret;
 258    GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
 259    slog("guest-file-close called, handle: %" PRId64, handle);
 260    if (gfh == NULL) {
 261        return;
 262    }
 263    ret = CloseHandle(gfh->fh);
 264    if (!ret) {
 265        error_setg_win32(errp, GetLastError(), "failed close handle");
 266        return;
 267    }
 268
 269    QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
 270    g_free(gfh);
 271}
 272
 273static void acquire_privilege(const char *name, Error **errp)
 274{
 275    HANDLE token = NULL;
 276    TOKEN_PRIVILEGES priv;
 277
 278    if (OpenProcessToken(GetCurrentProcess(),
 279        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
 280    {
 281        if (!LookupPrivilegeValue(NULL, name, &priv.Privileges[0].Luid)) {
 282            error_setg(errp, QERR_QGA_COMMAND_FAILED,
 283                       "no luid for requested privilege");
 284            goto out;
 285        }
 286
 287        priv.PrivilegeCount = 1;
 288        priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 289
 290        if (!AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, 0)) {
 291            error_setg(errp, QERR_QGA_COMMAND_FAILED,
 292                       "unable to acquire requested privilege");
 293            goto out;
 294        }
 295
 296    } else {
 297        error_setg(errp, QERR_QGA_COMMAND_FAILED,
 298                   "failed to open privilege token");
 299    }
 300
 301out:
 302    if (token) {
 303        CloseHandle(token);
 304    }
 305}
 306
 307static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque,
 308                          Error **errp)
 309{
 310    HANDLE thread = CreateThread(NULL, 0, func, opaque, 0, NULL);
 311    if (!thread) {
 312        error_setg(errp, QERR_QGA_COMMAND_FAILED,
 313                   "failed to dispatch asynchronous command");
 314    }
 315}
 316
 317void qmp_guest_shutdown(const char *mode, Error **errp)
 318{
 319    Error *local_err = NULL;
 320    UINT shutdown_flag = EWX_FORCE;
 321
 322    slog("guest-shutdown called, mode: %s", mode);
 323
 324    if (!mode || strcmp(mode, "powerdown") == 0) {
 325        shutdown_flag |= EWX_POWEROFF;
 326    } else if (strcmp(mode, "halt") == 0) {
 327        shutdown_flag |= EWX_SHUTDOWN;
 328    } else if (strcmp(mode, "reboot") == 0) {
 329        shutdown_flag |= EWX_REBOOT;
 330    } else {
 331        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "mode",
 332                   "'halt', 'powerdown', or 'reboot'");
 333        return;
 334    }
 335
 336    /* Request a shutdown privilege, but try to shut down the system
 337       anyway. */
 338    acquire_privilege(SE_SHUTDOWN_NAME, &local_err);
 339    if (local_err) {
 340        error_propagate(errp, local_err);
 341        return;
 342    }
 343
 344    if (!ExitWindowsEx(shutdown_flag, SHTDN_REASON_FLAG_PLANNED)) {
 345        g_autofree gchar *emsg = g_win32_error_message(GetLastError());
 346        slog("guest-shutdown failed: %s", emsg);
 347        error_setg_win32(errp, GetLastError(), "guest-shutdown failed");
 348    }
 349}
 350
 351GuestFileRead *guest_file_read_unsafe(GuestFileHandle *gfh,
 352                                      int64_t count, Error **errp)
 353{
 354    GuestFileRead *read_data = NULL;
 355    guchar *buf;
 356    HANDLE fh = gfh->fh;
 357    bool is_ok;
 358    DWORD read_count;
 359
 360    buf = g_malloc0(count + 1);
 361    is_ok = ReadFile(fh, buf, count, &read_count, NULL);
 362    if (!is_ok) {
 363        error_setg_win32(errp, GetLastError(), "failed to read file");
 364    } else {
 365        buf[read_count] = 0;
 366        read_data = g_new0(GuestFileRead, 1);
 367        read_data->count = (size_t)read_count;
 368        read_data->eof = read_count == 0;
 369
 370        if (read_count != 0) {
 371            read_data->buf_b64 = g_base64_encode(buf, read_count);
 372        }
 373    }
 374    g_free(buf);
 375
 376    return read_data;
 377}
 378
 379GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
 380                                     bool has_count, int64_t count,
 381                                     Error **errp)
 382{
 383    GuestFileWrite *write_data = NULL;
 384    guchar *buf;
 385    gsize buf_len;
 386    bool is_ok;
 387    DWORD write_count;
 388    GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
 389    HANDLE fh;
 390
 391    if (!gfh) {
 392        return NULL;
 393    }
 394    fh = gfh->fh;
 395    buf = qbase64_decode(buf_b64, -1, &buf_len, errp);
 396    if (!buf) {
 397        return NULL;
 398    }
 399
 400    if (!has_count) {
 401        count = buf_len;
 402    } else if (count < 0 || count > buf_len) {
 403        error_setg(errp, "value '%" PRId64
 404                   "' is invalid for argument count", count);
 405        goto done;
 406    }
 407
 408    is_ok = WriteFile(fh, buf, count, &write_count, NULL);
 409    if (!is_ok) {
 410        error_setg_win32(errp, GetLastError(), "failed to write to file");
 411        slog("guest-file-write-failed, handle: %" PRId64, handle);
 412    } else {
 413        write_data = g_new0(GuestFileWrite, 1);
 414        write_data->count = (size_t) write_count;
 415    }
 416
 417done:
 418    g_free(buf);
 419    return write_data;
 420}
 421
 422GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
 423                                   GuestFileWhence *whence_code,
 424                                   Error **errp)
 425{
 426    GuestFileHandle *gfh;
 427    GuestFileSeek *seek_data;
 428    HANDLE fh;
 429    LARGE_INTEGER new_pos, off_pos;
 430    off_pos.QuadPart = offset;
 431    BOOL res;
 432    int whence;
 433    Error *err = NULL;
 434
 435    gfh = guest_file_handle_find(handle, errp);
 436    if (!gfh) {
 437        return NULL;
 438    }
 439
 440    /* We stupidly exposed 'whence':'int' in our qapi */
 441    whence = ga_parse_whence(whence_code, &err);
 442    if (err) {
 443        error_propagate(errp, err);
 444        return NULL;
 445    }
 446
 447    fh = gfh->fh;
 448    res = SetFilePointerEx(fh, off_pos, &new_pos, whence);
 449    if (!res) {
 450        error_setg_win32(errp, GetLastError(), "failed to seek file");
 451        return NULL;
 452    }
 453    seek_data = g_new0(GuestFileSeek, 1);
 454    seek_data->position = new_pos.QuadPart;
 455    return seek_data;
 456}
 457
 458void qmp_guest_file_flush(int64_t handle, Error **errp)
 459{
 460    HANDLE fh;
 461    GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
 462    if (!gfh) {
 463        return;
 464    }
 465
 466    fh = gfh->fh;
 467    if (!FlushFileBuffers(fh)) {
 468        error_setg_win32(errp, GetLastError(), "failed to flush file");
 469    }
 470}
 471
 472static GuestDiskBusType win2qemu[] = {
 473    [BusTypeUnknown] = GUEST_DISK_BUS_TYPE_UNKNOWN,
 474    [BusTypeScsi] = GUEST_DISK_BUS_TYPE_SCSI,
 475    [BusTypeAtapi] = GUEST_DISK_BUS_TYPE_IDE,
 476    [BusTypeAta] = GUEST_DISK_BUS_TYPE_IDE,
 477    [BusType1394] = GUEST_DISK_BUS_TYPE_IEEE1394,
 478    [BusTypeSsa] = GUEST_DISK_BUS_TYPE_SSA,
 479    [BusTypeFibre] = GUEST_DISK_BUS_TYPE_SSA,
 480    [BusTypeUsb] = GUEST_DISK_BUS_TYPE_USB,
 481    [BusTypeRAID] = GUEST_DISK_BUS_TYPE_RAID,
 482    [BusTypeiScsi] = GUEST_DISK_BUS_TYPE_ISCSI,
 483    [BusTypeSas] = GUEST_DISK_BUS_TYPE_SAS,
 484    [BusTypeSata] = GUEST_DISK_BUS_TYPE_SATA,
 485    [BusTypeSd] =  GUEST_DISK_BUS_TYPE_SD,
 486    [BusTypeMmc] = GUEST_DISK_BUS_TYPE_MMC,
 487#if (_WIN32_WINNT >= 0x0601)
 488    [BusTypeVirtual] = GUEST_DISK_BUS_TYPE_VIRTUAL,
 489    [BusTypeFileBackedVirtual] = GUEST_DISK_BUS_TYPE_FILE_BACKED_VIRTUAL,
 490    /*
 491     * BusTypeSpaces currently is not suported
 492     */
 493    [BusTypeSpaces] = GUEST_DISK_BUS_TYPE_UNKNOWN,
 494    [BusTypeNvme] = GUEST_DISK_BUS_TYPE_NVME,
 495#endif
 496};
 497
 498static GuestDiskBusType find_bus_type(STORAGE_BUS_TYPE bus)
 499{
 500    if (bus >= ARRAY_SIZE(win2qemu) || (int)bus < 0) {
 501        return GUEST_DISK_BUS_TYPE_UNKNOWN;
 502    }
 503    return win2qemu[(int)bus];
 504}
 505
 506DEFINE_GUID(GUID_DEVINTERFACE_DISK,
 507        0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2,
 508        0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
 509DEFINE_GUID(GUID_DEVINTERFACE_STORAGEPORT,
 510        0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82,
 511        0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
 512
 513static void get_pci_address_for_device(GuestPCIAddress *pci,
 514                                       HDEVINFO dev_info)
 515{
 516    SP_DEVINFO_DATA dev_info_data;
 517    DWORD j;
 518    DWORD size;
 519    bool partial_pci = false;
 520
 521    dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
 522
 523    for (j = 0;
 524         SetupDiEnumDeviceInfo(dev_info, j, &dev_info_data);
 525         j++) {
 526        DWORD addr, bus, ui_slot, type;
 527        int func, slot;
 528        size = sizeof(DWORD);
 529
 530        /*
 531        * There is no need to allocate buffer in the next functions. The
 532        * size is known and ULONG according to
 533        * https://msdn.microsoft.com/en-us/library/windows/hardware/ff543095(v=vs.85).aspx
 534        */
 535        if (!SetupDiGetDeviceRegistryProperty(
 536                dev_info, &dev_info_data, SPDRP_BUSNUMBER,
 537                &type, (PBYTE)&bus, size, NULL)) {
 538            debug_error("failed to get PCI bus");
 539            bus = -1;
 540            partial_pci = true;
 541        }
 542
 543        /*
 544        * The function retrieves the device's address. This value will be
 545        * transformed into device function and number
 546        */
 547        if (!SetupDiGetDeviceRegistryProperty(
 548                dev_info, &dev_info_data, SPDRP_ADDRESS,
 549                &type, (PBYTE)&addr, size, NULL)) {
 550            debug_error("failed to get PCI address");
 551            addr = -1;
 552            partial_pci = true;
 553        }
 554
 555        /*
 556        * This call returns UINumber of DEVICE_CAPABILITIES structure.
 557        * This number is typically a user-perceived slot number.
 558        */
 559        if (!SetupDiGetDeviceRegistryProperty(
 560                dev_info, &dev_info_data, SPDRP_UI_NUMBER,
 561                &type, (PBYTE)&ui_slot, size, NULL)) {
 562            debug_error("failed to get PCI slot");
 563            ui_slot = -1;
 564            partial_pci = true;
 565        }
 566
 567        /*
 568        * SetupApi gives us the same information as driver with
 569        * IoGetDeviceProperty. According to Microsoft:
 570        *
 571        *   FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF)
 572        *   DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF)
 573        *   SPDRP_ADDRESS is propertyAddress, so we do the same.
 574        *
 575        * https://docs.microsoft.com/en-us/windows/desktop/api/setupapi/nf-setupapi-setupdigetdeviceregistrypropertya
 576        */
 577        if (partial_pci) {
 578            pci->domain = -1;
 579            pci->slot = -1;
 580            pci->function = -1;
 581            pci->bus = -1;
 582            continue;
 583        } else {
 584            func = ((int)addr == -1) ? -1 : addr & 0x0000FFFF;
 585            slot = ((int)addr == -1) ? -1 : (addr >> 16) & 0x0000FFFF;
 586            if ((int)ui_slot != slot) {
 587                g_debug("mismatch with reported slot values: %d vs %d",
 588                        (int)ui_slot, slot);
 589            }
 590            pci->domain = 0;
 591            pci->slot = (int)ui_slot;
 592            pci->function = func;
 593            pci->bus = (int)bus;
 594            return;
 595        }
 596    }
 597}
 598
 599static GuestPCIAddress *get_empty_pci_address(void)
 600{
 601    GuestPCIAddress *pci = NULL;
 602
 603    pci = g_malloc0(sizeof(*pci));
 604    pci->domain = -1;
 605    pci->slot = -1;
 606    pci->function = -1;
 607    pci->bus = -1;
 608    return pci;
 609}
 610
 611static GuestPCIAddress *get_pci_info(int number, Error **errp)
 612{
 613    HDEVINFO dev_info = INVALID_HANDLE_VALUE;
 614    HDEVINFO parent_dev_info = INVALID_HANDLE_VALUE;
 615
 616    SP_DEVINFO_DATA dev_info_data;
 617    SP_DEVICE_INTERFACE_DATA dev_iface_data;
 618    HANDLE dev_file;
 619    int i;
 620    GuestPCIAddress *pci = get_empty_pci_address();
 621
 622    dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0,
 623                                   DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
 624    if (dev_info == INVALID_HANDLE_VALUE) {
 625        error_setg_win32(errp, GetLastError(), "failed to get devices tree");
 626        goto end;
 627    }
 628
 629    g_debug("enumerating devices");
 630    dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
 631    dev_iface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
 632    for (i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
 633        g_autofree PSP_DEVICE_INTERFACE_DETAIL_DATA pdev_iface_detail_data = NULL;
 634        STORAGE_DEVICE_NUMBER sdn;
 635        g_autofree char *parent_dev_id = NULL;
 636        SP_DEVINFO_DATA parent_dev_info_data;
 637        DWORD size = 0;
 638
 639        g_debug("getting device path");
 640        if (SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data,
 641                                        &GUID_DEVINTERFACE_DISK, 0,
 642                                        &dev_iface_data)) {
 643            if (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_iface_data,
 644                                                 pdev_iface_detail_data,
 645                                                 size, &size,
 646                                                 &dev_info_data)) {
 647                if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
 648                    pdev_iface_detail_data = g_malloc(size);
 649                    pdev_iface_detail_data->cbSize =
 650                        sizeof(*pdev_iface_detail_data);
 651                } else {
 652                    error_setg_win32(errp, GetLastError(),
 653                                     "failed to get device interfaces");
 654                    goto end;
 655                }
 656            }
 657
 658            if (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_iface_data,
 659                                                 pdev_iface_detail_data,
 660                                                 size, &size,
 661                                                 &dev_info_data)) {
 662                // pdev_iface_detail_data already is allocated
 663                error_setg_win32(errp, GetLastError(),
 664                                    "failed to get device interfaces");
 665                goto end;
 666            }
 667
 668            dev_file = CreateFile(pdev_iface_detail_data->DevicePath, 0,
 669                                  FILE_SHARE_READ, NULL, OPEN_EXISTING, 0,
 670                                  NULL);
 671
 672            if (!DeviceIoControl(dev_file, IOCTL_STORAGE_GET_DEVICE_NUMBER,
 673                                 NULL, 0, &sdn, sizeof(sdn), &size, NULL)) {
 674                CloseHandle(dev_file);
 675                error_setg_win32(errp, GetLastError(),
 676                                 "failed to get device slot number");
 677                goto end;
 678            }
 679
 680            CloseHandle(dev_file);
 681            if (sdn.DeviceNumber != number) {
 682                continue;
 683            }
 684        } else {
 685            error_setg_win32(errp, GetLastError(),
 686                             "failed to get device interfaces");
 687            goto end;
 688        }
 689
 690        g_debug("found device slot %d. Getting storage controller", number);
 691        {
 692            CONFIGRET cr;
 693            DEVINST dev_inst, parent_dev_inst;
 694            ULONG dev_id_size = 0;
 695
 696            size = 0;
 697            if (!SetupDiGetDeviceInstanceId(dev_info, &dev_info_data,
 698                                            parent_dev_id, size, &size)) {
 699                if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
 700                    parent_dev_id = g_malloc(size);
 701                } else {
 702                    error_setg_win32(errp, GetLastError(),
 703                                     "failed to get device instance ID");
 704                    goto end;
 705                }
 706            }
 707
 708            if (!SetupDiGetDeviceInstanceId(dev_info, &dev_info_data,
 709                                            parent_dev_id, size, &size)) {
 710                // parent_dev_id already is allocated
 711                error_setg_win32(errp, GetLastError(),
 712                                    "failed to get device instance ID");
 713                goto end;
 714            }
 715
 716            /*
 717             * CM API used here as opposed to
 718             * SetupDiGetDeviceProperty(..., DEVPKEY_Device_Parent, ...)
 719             * which exports are only available in mingw-w64 6+
 720             */
 721            cr = CM_Locate_DevInst(&dev_inst, parent_dev_id, 0);
 722            if (cr != CR_SUCCESS) {
 723                g_error("CM_Locate_DevInst failed with code %lx", cr);
 724                error_setg_win32(errp, GetLastError(),
 725                                 "failed to get device instance");
 726                goto end;
 727            }
 728            cr = CM_Get_Parent(&parent_dev_inst, dev_inst, 0);
 729            if (cr != CR_SUCCESS) {
 730                g_error("CM_Get_Parent failed with code %lx", cr);
 731                error_setg_win32(errp, GetLastError(),
 732                                 "failed to get parent device instance");
 733                goto end;
 734            }
 735
 736            cr = CM_Get_Device_ID_Size(&dev_id_size, parent_dev_inst, 0);
 737            if (cr != CR_SUCCESS) {
 738                g_error("CM_Get_Device_ID_Size failed with code %lx", cr);
 739                error_setg_win32(errp, GetLastError(),
 740                                 "failed to get parent device ID length");
 741                goto end;
 742            }
 743
 744            ++dev_id_size;
 745            if (dev_id_size > size) {
 746                g_free(parent_dev_id);
 747                parent_dev_id = g_malloc(dev_id_size);
 748            }
 749
 750            cr = CM_Get_Device_ID(parent_dev_inst, parent_dev_id, dev_id_size,
 751                                  0);
 752            if (cr != CR_SUCCESS) {
 753                g_error("CM_Get_Device_ID failed with code %lx", cr);
 754                error_setg_win32(errp, GetLastError(),
 755                                 "failed to get parent device ID");
 756                goto end;
 757            }
 758        }
 759
 760        g_debug("querying storage controller %s for PCI information",
 761                parent_dev_id);
 762        parent_dev_info =
 763            SetupDiGetClassDevs(&GUID_DEVINTERFACE_STORAGEPORT, parent_dev_id,
 764                                NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
 765
 766        if (parent_dev_info == INVALID_HANDLE_VALUE) {
 767            error_setg_win32(errp, GetLastError(),
 768                             "failed to get parent device");
 769            goto end;
 770        }
 771
 772        parent_dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
 773        if (!SetupDiEnumDeviceInfo(parent_dev_info, 0, &parent_dev_info_data)) {
 774            error_setg_win32(errp, GetLastError(),
 775                           "failed to get parent device data");
 776            goto end;
 777        }
 778
 779        get_pci_address_for_device(pci, parent_dev_info);
 780
 781        break;
 782    }
 783
 784end:
 785    if (parent_dev_info != INVALID_HANDLE_VALUE) {
 786        SetupDiDestroyDeviceInfoList(parent_dev_info);
 787    }
 788    if (dev_info != INVALID_HANDLE_VALUE) {
 789        SetupDiDestroyDeviceInfoList(dev_info);
 790    }
 791    return pci;
 792}
 793
 794static void get_disk_properties(HANDLE vol_h, GuestDiskAddress *disk,
 795    Error **errp)
 796{
 797    STORAGE_PROPERTY_QUERY query;
 798    STORAGE_DEVICE_DESCRIPTOR *dev_desc, buf;
 799    DWORD received;
 800    ULONG size = sizeof(buf);
 801
 802    dev_desc = &buf;
 803    query.PropertyId = StorageDeviceProperty;
 804    query.QueryType = PropertyStandardQuery;
 805
 806    if (!DeviceIoControl(vol_h, IOCTL_STORAGE_QUERY_PROPERTY, &query,
 807                         sizeof(STORAGE_PROPERTY_QUERY), dev_desc,
 808                         size, &received, NULL)) {
 809        error_setg_win32(errp, GetLastError(), "failed to get bus type");
 810        return;
 811    }
 812    disk->bus_type = find_bus_type(dev_desc->BusType);
 813    g_debug("bus type %d", disk->bus_type);
 814
 815    /* Query once more. Now with long enough buffer. */
 816    size = dev_desc->Size;
 817    dev_desc = g_malloc0(size);
 818    if (!DeviceIoControl(vol_h, IOCTL_STORAGE_QUERY_PROPERTY, &query,
 819                         sizeof(STORAGE_PROPERTY_QUERY), dev_desc,
 820                         size, &received, NULL)) {
 821        error_setg_win32(errp, GetLastError(), "failed to get serial number");
 822        g_debug("failed to get serial number");
 823        goto out_free;
 824    }
 825    if (dev_desc->SerialNumberOffset > 0) {
 826        const char *serial;
 827        size_t len;
 828
 829        if (dev_desc->SerialNumberOffset >= received) {
 830            error_setg(errp, "failed to get serial number: offset outside the buffer");
 831            g_debug("serial number offset outside the buffer");
 832            goto out_free;
 833        }
 834        serial = (char *)dev_desc + dev_desc->SerialNumberOffset;
 835        len = received - dev_desc->SerialNumberOffset;
 836        g_debug("serial number \"%s\"", serial);
 837        if (*serial != 0) {
 838            disk->serial = g_strndup(serial, len);
 839        }
 840    }
 841out_free:
 842    g_free(dev_desc);
 843
 844    return;
 845}
 846
 847static void get_single_disk_info(int disk_number,
 848                                 GuestDiskAddress *disk, Error **errp)
 849{
 850    SCSI_ADDRESS addr, *scsi_ad;
 851    DWORD len;
 852    HANDLE disk_h;
 853    Error *local_err = NULL;
 854
 855    scsi_ad = &addr;
 856
 857    g_debug("getting disk info for: %s", disk->dev);
 858    disk_h = CreateFile(disk->dev, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
 859                       0, NULL);
 860    if (disk_h == INVALID_HANDLE_VALUE) {
 861        error_setg_win32(errp, GetLastError(), "failed to open disk");
 862        return;
 863    }
 864
 865    get_disk_properties(disk_h, disk, &local_err);
 866    if (local_err) {
 867        error_propagate(errp, local_err);
 868        goto err_close;
 869    }
 870
 871    g_debug("bus type %d", disk->bus_type);
 872    /* always set pci_controller as required by schema. get_pci_info() should
 873     * report -1 values for non-PCI buses rather than fail. fail the command
 874     * if that doesn't hold since that suggests some other unexpected
 875     * breakage
 876     */
 877    if (disk->bus_type == GUEST_DISK_BUS_TYPE_USB) {
 878        disk->pci_controller = get_empty_pci_address();
 879    } else {
 880        disk->pci_controller = get_pci_info(disk_number, &local_err);
 881        if (local_err) {
 882            error_propagate(errp, local_err);
 883            goto err_close;
 884        }
 885    }
 886    if (disk->bus_type == GUEST_DISK_BUS_TYPE_SCSI
 887            || disk->bus_type == GUEST_DISK_BUS_TYPE_IDE
 888            || disk->bus_type == GUEST_DISK_BUS_TYPE_RAID
 889            /* This bus type is not supported before Windows Server 2003 SP1 */
 890            || disk->bus_type == GUEST_DISK_BUS_TYPE_SAS
 891        ) {
 892        /* We are able to use the same ioctls for different bus types
 893         * according to Microsoft docs
 894         * https://technet.microsoft.com/en-us/library/ee851589(v=ws.10).aspx */
 895        g_debug("getting SCSI info");
 896        if (DeviceIoControl(disk_h, IOCTL_SCSI_GET_ADDRESS, NULL, 0, scsi_ad,
 897                            sizeof(SCSI_ADDRESS), &len, NULL)) {
 898            disk->unit = addr.Lun;
 899            disk->target = addr.TargetId;
 900            disk->bus = addr.PathId;
 901        }
 902        /* We do not set error in this case, because we still have enough
 903         * information about volume. */
 904    }
 905
 906err_close:
 907    CloseHandle(disk_h);
 908    return;
 909}
 910
 911/* VSS provider works with volumes, thus there is no difference if
 912 * the volume consist of spanned disks. Info about the first disk in the
 913 * volume is returned for the spanned disk group (LVM) */
 914static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
 915{
 916    Error *local_err = NULL;
 917    GuestDiskAddressList *list = NULL;
 918    GuestDiskAddress *disk = NULL;
 919    int i;
 920    HANDLE vol_h;
 921    DWORD size;
 922    PVOLUME_DISK_EXTENTS extents = NULL;
 923
 924    /* strip final backslash */
 925    char *name = g_strdup(guid);
 926    if (g_str_has_suffix(name, "\\")) {
 927        name[strlen(name) - 1] = 0;
 928    }
 929
 930    g_debug("opening %s", name);
 931    vol_h = CreateFile(name, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
 932                       0, NULL);
 933    if (vol_h == INVALID_HANDLE_VALUE) {
 934        error_setg_win32(errp, GetLastError(), "failed to open volume");
 935        goto out;
 936    }
 937
 938    /* Get list of extents */
 939    g_debug("getting disk extents");
 940    size = sizeof(VOLUME_DISK_EXTENTS);
 941    extents = g_malloc0(size);
 942    if (!DeviceIoControl(vol_h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL,
 943                         0, extents, size, &size, NULL)) {
 944        DWORD last_err = GetLastError();
 945        if (last_err == ERROR_MORE_DATA) {
 946            /* Try once more with big enough buffer */
 947            g_free(extents);
 948            extents = g_malloc0(size);
 949            if (!DeviceIoControl(
 950                    vol_h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL,
 951                    0, extents, size, NULL, NULL)) {
 952                error_setg_win32(errp, GetLastError(),
 953                    "failed to get disk extents");
 954                goto out;
 955            }
 956        } else if (last_err == ERROR_INVALID_FUNCTION) {
 957            /* Possibly CD-ROM or a shared drive. Try to pass the volume */
 958            g_debug("volume not on disk");
 959            disk = g_new0(GuestDiskAddress, 1);
 960            disk->dev = g_strdup(name);
 961            get_single_disk_info(0xffffffff, disk, &local_err);
 962            if (local_err) {
 963                g_debug("failed to get disk info, ignoring error: %s",
 964                    error_get_pretty(local_err));
 965                error_free(local_err);
 966                goto out;
 967            }
 968            QAPI_LIST_PREPEND(list, disk);
 969            disk = NULL;
 970            goto out;
 971        } else {
 972            error_setg_win32(errp, GetLastError(),
 973                "failed to get disk extents");
 974            goto out;
 975        }
 976    }
 977    g_debug("Number of extents: %lu", extents->NumberOfDiskExtents);
 978
 979    /* Go through each extent */
 980    for (i = 0; i < extents->NumberOfDiskExtents; i++) {
 981        disk = g_new0(GuestDiskAddress, 1);
 982
 983        /* Disk numbers directly correspond to numbers used in UNCs
 984         *
 985         * See documentation for DISK_EXTENT:
 986         * https://docs.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_disk_extent
 987         *
 988         * See also Naming Files, Paths and Namespaces:
 989         * https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#win32-device-namespaces
 990         */
 991        disk->dev = g_strdup_printf("\\\\.\\PhysicalDrive%lu",
 992                                    extents->Extents[i].DiskNumber);
 993
 994        get_single_disk_info(extents->Extents[i].DiskNumber, disk, &local_err);
 995        if (local_err) {
 996            error_propagate(errp, local_err);
 997            goto out;
 998        }
 999        QAPI_LIST_PREPEND(list, disk);
1000        disk = NULL;
1001    }
1002
1003
1004out:
1005    if (vol_h != INVALID_HANDLE_VALUE) {
1006        CloseHandle(vol_h);
1007    }
1008    qapi_free_GuestDiskAddress(disk);
1009    g_free(extents);
1010    g_free(name);
1011
1012    return list;
1013}
1014
1015GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
1016{
1017    GuestDiskInfoList *ret = NULL;
1018    HDEVINFO dev_info;
1019    SP_DEVICE_INTERFACE_DATA dev_iface_data;
1020    int i;
1021
1022    dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0,
1023        DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
1024    if (dev_info == INVALID_HANDLE_VALUE) {
1025        error_setg_win32(errp, GetLastError(), "failed to get device tree");
1026        return NULL;
1027    }
1028
1029    g_debug("enumerating devices");
1030    dev_iface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
1031    for (i = 0;
1032        SetupDiEnumDeviceInterfaces(dev_info, NULL, &GUID_DEVINTERFACE_DISK,
1033            i, &dev_iface_data);
1034        i++) {
1035        GuestDiskAddress *address = NULL;
1036        GuestDiskInfo *disk = NULL;
1037        Error *local_err = NULL;
1038        g_autofree PSP_DEVICE_INTERFACE_DETAIL_DATA
1039            pdev_iface_detail_data = NULL;
1040        STORAGE_DEVICE_NUMBER sdn;
1041        HANDLE dev_file;
1042        DWORD size = 0;
1043        BOOL result;
1044        int attempt;
1045
1046        g_debug("  getting device path");
1047        for (attempt = 0, result = FALSE; attempt < 2 && !result; attempt++) {
1048            result = SetupDiGetDeviceInterfaceDetail(dev_info,
1049                &dev_iface_data, pdev_iface_detail_data, size, &size, NULL);
1050            if (result) {
1051                break;
1052            }
1053            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
1054                pdev_iface_detail_data = g_realloc(pdev_iface_detail_data,
1055                    size);
1056                pdev_iface_detail_data->cbSize =
1057                    sizeof(*pdev_iface_detail_data);
1058            } else {
1059                g_debug("failed to get device interface details");
1060                break;
1061            }
1062        }
1063        if (!result) {
1064            g_debug("skipping device");
1065            continue;
1066        }
1067
1068        g_debug("  device: %s", pdev_iface_detail_data->DevicePath);
1069        dev_file = CreateFile(pdev_iface_detail_data->DevicePath, 0,
1070            FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
1071        if (!DeviceIoControl(dev_file, IOCTL_STORAGE_GET_DEVICE_NUMBER,
1072                NULL, 0, &sdn, sizeof(sdn), &size, NULL)) {
1073            CloseHandle(dev_file);
1074            debug_error("failed to get storage device number");
1075            continue;
1076        }
1077        CloseHandle(dev_file);
1078
1079        disk = g_new0(GuestDiskInfo, 1);
1080        disk->name = g_strdup_printf("\\\\.\\PhysicalDrive%lu",
1081            sdn.DeviceNumber);
1082
1083        g_debug("  number: %lu", sdn.DeviceNumber);
1084        address = g_new0(GuestDiskAddress, 1);
1085        address->dev = g_strdup(disk->name);
1086        get_single_disk_info(sdn.DeviceNumber, address, &local_err);
1087        if (local_err) {
1088            g_debug("failed to get disk info: %s",
1089                error_get_pretty(local_err));
1090            error_free(local_err);
1091            qapi_free_GuestDiskAddress(address);
1092            address = NULL;
1093        } else {
1094            disk->address = address;
1095        }
1096
1097        QAPI_LIST_PREPEND(ret, disk);
1098    }
1099
1100    SetupDiDestroyDeviceInfoList(dev_info);
1101    return ret;
1102}
1103
1104static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp)
1105{
1106    DWORD info_size;
1107    char mnt, *mnt_point;
1108    wchar_t wfs_name[32];
1109    char fs_name[32];
1110    wchar_t vol_info[MAX_PATH + 1];
1111    size_t len;
1112    uint64_t i64FreeBytesToCaller, i64TotalBytes, i64FreeBytes;
1113    GuestFilesystemInfo *fs = NULL;
1114    HANDLE hLocalDiskHandle = INVALID_HANDLE_VALUE;
1115
1116    GetVolumePathNamesForVolumeName(guid, (LPCH)&mnt, 0, &info_size);
1117    if (GetLastError() != ERROR_MORE_DATA) {
1118        error_setg_win32(errp, GetLastError(), "failed to get volume name");
1119        return NULL;
1120    }
1121
1122    mnt_point = g_malloc(info_size + 1);
1123    if (!GetVolumePathNamesForVolumeName(guid, mnt_point, info_size,
1124                                         &info_size)) {
1125        error_setg_win32(errp, GetLastError(), "failed to get volume name");
1126        goto free;
1127    }
1128
1129    hLocalDiskHandle = CreateFile(guid, 0 , 0, NULL, OPEN_EXISTING,
1130                                  FILE_ATTRIBUTE_NORMAL |
1131                                  FILE_FLAG_BACKUP_SEMANTICS, NULL);
1132    if (INVALID_HANDLE_VALUE == hLocalDiskHandle) {
1133        error_setg_win32(errp, GetLastError(), "failed to get handle for volume");
1134        goto free;
1135    }
1136
1137    len = strlen(mnt_point);
1138    mnt_point[len] = '\\';
1139    mnt_point[len + 1] = 0;
1140
1141    if (!GetVolumeInformationByHandleW(hLocalDiskHandle, vol_info,
1142                                       sizeof(vol_info), NULL, NULL, NULL,
1143                                       (LPWSTR) & wfs_name, sizeof(wfs_name))) {
1144        if (GetLastError() != ERROR_NOT_READY) {
1145            error_setg_win32(errp, GetLastError(), "failed to get volume info");
1146        }
1147        goto free;
1148    }
1149
1150    fs = g_malloc(sizeof(*fs));
1151    fs->name = g_strdup(guid);
1152    fs->has_total_bytes = false;
1153    fs->has_used_bytes = false;
1154    if (len == 0) {
1155        fs->mountpoint = g_strdup("System Reserved");
1156    } else {
1157        fs->mountpoint = g_strndup(mnt_point, len);
1158        if (GetDiskFreeSpaceEx(fs->mountpoint,
1159                               (PULARGE_INTEGER) & i64FreeBytesToCaller,
1160                               (PULARGE_INTEGER) & i64TotalBytes,
1161                               (PULARGE_INTEGER) & i64FreeBytes)) {
1162            fs->used_bytes = i64TotalBytes - i64FreeBytes;
1163            fs->total_bytes = i64TotalBytes;
1164            fs->has_total_bytes = true;
1165            fs->has_used_bytes = true;
1166        }
1167    }
1168    wcstombs(fs_name, wfs_name, sizeof(wfs_name));
1169    fs->type = g_strdup(fs_name);
1170    fs->disk = build_guest_disk_info(guid, errp);
1171free:
1172    if (hLocalDiskHandle != INVALID_HANDLE_VALUE) {
1173        CloseHandle(hLocalDiskHandle);
1174    }
1175    g_free(mnt_point);
1176    return fs;
1177}
1178
1179GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
1180{
1181    HANDLE vol_h;
1182    GuestFilesystemInfoList *ret = NULL;
1183    char guid[256];
1184
1185    vol_h = FindFirstVolume(guid, sizeof(guid));
1186    if (vol_h == INVALID_HANDLE_VALUE) {
1187        error_setg_win32(errp, GetLastError(), "failed to find any volume");
1188        return NULL;
1189    }
1190
1191    do {
1192        Error *local_err = NULL;
1193        GuestFilesystemInfo *info = build_guest_fsinfo(guid, &local_err);
1194        if (local_err) {
1195            g_debug("failed to get filesystem info, ignoring error: %s",
1196                    error_get_pretty(local_err));
1197            error_free(local_err);
1198            continue;
1199        }
1200        QAPI_LIST_PREPEND(ret, info);
1201    } while (FindNextVolume(vol_h, guid, sizeof(guid)));
1202
1203    if (GetLastError() != ERROR_NO_MORE_FILES) {
1204        error_setg_win32(errp, GetLastError(), "failed to find next volume");
1205    }
1206
1207    FindVolumeClose(vol_h);
1208    return ret;
1209}
1210
1211/*
1212 * Return status of freeze/thaw
1213 */
1214GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
1215{
1216    if (!vss_initialized()) {
1217        error_setg(errp, QERR_UNSUPPORTED);
1218        return 0;
1219    }
1220
1221    if (ga_is_frozen(ga_state)) {
1222        return GUEST_FSFREEZE_STATUS_FROZEN;
1223    }
1224
1225    return GUEST_FSFREEZE_STATUS_THAWED;
1226}
1227
1228/*
1229 * Freeze local file systems using Volume Shadow-copy Service.
1230 * The frozen state is limited for up to 10 seconds by VSS.
1231 */
1232int64_t qmp_guest_fsfreeze_freeze(Error **errp)
1233{
1234    return qmp_guest_fsfreeze_freeze_list(false, NULL, errp);
1235}
1236
1237int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
1238                                       strList *mountpoints,
1239                                       Error **errp)
1240{
1241    int i;
1242    Error *local_err = NULL;
1243
1244    if (!vss_initialized()) {
1245        error_setg(errp, QERR_UNSUPPORTED);
1246        return 0;
1247    }
1248
1249    slog("guest-fsfreeze called");
1250
1251    /* cannot risk guest agent blocking itself on a write in this state */
1252    ga_set_frozen(ga_state);
1253
1254    qga_vss_fsfreeze(&i, true, mountpoints, &local_err);
1255    if (local_err) {
1256        error_propagate(errp, local_err);
1257        goto error;
1258    }
1259
1260    return i;
1261
1262error:
1263    local_err = NULL;
1264    qmp_guest_fsfreeze_thaw(&local_err);
1265    if (local_err) {
1266        g_debug("cleanup thaw: %s", error_get_pretty(local_err));
1267        error_free(local_err);
1268    }
1269    return 0;
1270}
1271
1272/*
1273 * Thaw local file systems using Volume Shadow-copy Service.
1274 */
1275int64_t qmp_guest_fsfreeze_thaw(Error **errp)
1276{
1277    int i;
1278
1279    if (!vss_initialized()) {
1280        error_setg(errp, QERR_UNSUPPORTED);
1281        return 0;
1282    }
1283
1284    qga_vss_fsfreeze(&i, false, NULL, errp);
1285
1286    ga_unset_frozen(ga_state);
1287    return i;
1288}
1289
1290static void guest_fsfreeze_cleanup(void)
1291{
1292    Error *err = NULL;
1293
1294    if (!vss_initialized()) {
1295        return;
1296    }
1297
1298    if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
1299        qmp_guest_fsfreeze_thaw(&err);
1300        if (err) {
1301            slog("failed to clean up frozen filesystems: %s",
1302                 error_get_pretty(err));
1303            error_free(err);
1304        }
1305    }
1306
1307    vss_deinit(true);
1308}
1309
1310/*
1311 * Walk list of mounted file systems in the guest, and discard unused
1312 * areas.
1313 */
1314GuestFilesystemTrimResponse *
1315qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
1316{
1317    GuestFilesystemTrimResponse *resp;
1318    HANDLE handle;
1319    WCHAR guid[MAX_PATH] = L"";
1320    OSVERSIONINFO osvi;
1321    BOOL win8_or_later;
1322
1323    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
1324    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1325    GetVersionEx(&osvi);
1326    win8_or_later = (osvi.dwMajorVersion > 6 ||
1327                          ((osvi.dwMajorVersion == 6) &&
1328                           (osvi.dwMinorVersion >= 2)));
1329    if (!win8_or_later) {
1330        error_setg(errp, "fstrim is only supported for Win8+");
1331        return NULL;
1332    }
1333
1334    handle = FindFirstVolumeW(guid, ARRAYSIZE(guid));
1335    if (handle == INVALID_HANDLE_VALUE) {
1336        error_setg_win32(errp, GetLastError(), "failed to find any volume");
1337        return NULL;
1338    }
1339
1340    resp = g_new0(GuestFilesystemTrimResponse, 1);
1341
1342    do {
1343        GuestFilesystemTrimResult *res;
1344        PWCHAR uc_path;
1345        DWORD char_count = 0;
1346        char *path, *out;
1347        GError *gerr = NULL;
1348        gchar *argv[4];
1349
1350        GetVolumePathNamesForVolumeNameW(guid, NULL, 0, &char_count);
1351
1352        if (GetLastError() != ERROR_MORE_DATA) {
1353            continue;
1354        }
1355        if (GetDriveTypeW(guid) != DRIVE_FIXED) {
1356            continue;
1357        }
1358
1359        uc_path = g_new(WCHAR, char_count);
1360        if (!GetVolumePathNamesForVolumeNameW(guid, uc_path, char_count,
1361                                              &char_count) || !*uc_path) {
1362            /* strange, but this condition could be faced even with size == 2 */
1363            g_free(uc_path);
1364            continue;
1365        }
1366
1367        res = g_new0(GuestFilesystemTrimResult, 1);
1368
1369        path = g_utf16_to_utf8(uc_path, char_count, NULL, NULL, &gerr);
1370
1371        g_free(uc_path);
1372
1373        if (!path) {
1374            res->error = g_strdup(gerr->message);
1375            g_error_free(gerr);
1376            break;
1377        }
1378
1379        res->path = path;
1380
1381        QAPI_LIST_PREPEND(resp->paths, res);
1382
1383        memset(argv, 0, sizeof(argv));
1384        argv[0] = (gchar *)"defrag.exe";
1385        argv[1] = (gchar *)"/L";
1386        argv[2] = path;
1387
1388        if (!g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
1389                          &out /* stdout */, NULL /* stdin */,
1390                          NULL, &gerr)) {
1391            res->error = g_strdup(gerr->message);
1392            g_error_free(gerr);
1393        } else {
1394            /* defrag.exe is UGLY. Exit code is ALWAYS zero.
1395               Error is reported in the output with something like
1396               (x89000020) etc code in the stdout */
1397
1398            int i;
1399            gchar **lines = g_strsplit(out, "\r\n", 0);
1400            g_free(out);
1401
1402            for (i = 0; lines[i] != NULL; i++) {
1403                if (g_strstr_len(lines[i], -1, "(0x") == NULL) {
1404                    continue;
1405                }
1406                res->error = g_strdup(lines[i]);
1407                break;
1408            }
1409            g_strfreev(lines);
1410        }
1411    } while (FindNextVolumeW(handle, guid, ARRAYSIZE(guid)));
1412
1413    FindVolumeClose(handle);
1414    return resp;
1415}
1416
1417typedef enum {
1418    GUEST_SUSPEND_MODE_DISK,
1419    GUEST_SUSPEND_MODE_RAM
1420} GuestSuspendMode;
1421
1422static void check_suspend_mode(GuestSuspendMode mode, Error **errp)
1423{
1424    SYSTEM_POWER_CAPABILITIES sys_pwr_caps;
1425
1426    ZeroMemory(&sys_pwr_caps, sizeof(sys_pwr_caps));
1427    if (!GetPwrCapabilities(&sys_pwr_caps)) {
1428        error_setg(errp, QERR_QGA_COMMAND_FAILED,
1429                   "failed to determine guest suspend capabilities");
1430        return;
1431    }
1432
1433    switch (mode) {
1434    case GUEST_SUSPEND_MODE_DISK:
1435        if (!sys_pwr_caps.SystemS4) {
1436            error_setg(errp, QERR_QGA_COMMAND_FAILED,
1437                       "suspend-to-disk not supported by OS");
1438        }
1439        break;
1440    case GUEST_SUSPEND_MODE_RAM:
1441        if (!sys_pwr_caps.SystemS3) {
1442            error_setg(errp, QERR_QGA_COMMAND_FAILED,
1443                       "suspend-to-ram not supported by OS");
1444        }
1445        break;
1446    default:
1447        abort();
1448    }
1449}
1450
1451static DWORD WINAPI do_suspend(LPVOID opaque)
1452{
1453    GuestSuspendMode *mode = opaque;
1454    DWORD ret = 0;
1455
1456    if (!SetSuspendState(*mode == GUEST_SUSPEND_MODE_DISK, TRUE, TRUE)) {
1457        g_autofree gchar *emsg = g_win32_error_message(GetLastError());
1458        slog("failed to suspend guest: %s", emsg);
1459        ret = -1;
1460    }
1461    g_free(mode);
1462    return ret;
1463}
1464
1465void qmp_guest_suspend_disk(Error **errp)
1466{
1467    Error *local_err = NULL;
1468    GuestSuspendMode *mode = g_new(GuestSuspendMode, 1);
1469
1470    *mode = GUEST_SUSPEND_MODE_DISK;
1471    check_suspend_mode(*mode, &local_err);
1472    if (local_err) {
1473        goto out;
1474    }
1475    acquire_privilege(SE_SHUTDOWN_NAME, &local_err);
1476    if (local_err) {
1477        goto out;
1478    }
1479    execute_async(do_suspend, mode, &local_err);
1480
1481out:
1482    if (local_err) {
1483        error_propagate(errp, local_err);
1484        g_free(mode);
1485    }
1486}
1487
1488void qmp_guest_suspend_ram(Error **errp)
1489{
1490    Error *local_err = NULL;
1491    GuestSuspendMode *mode = g_new(GuestSuspendMode, 1);
1492
1493    *mode = GUEST_SUSPEND_MODE_RAM;
1494    check_suspend_mode(*mode, &local_err);
1495    if (local_err) {
1496        goto out;
1497    }
1498    acquire_privilege(SE_SHUTDOWN_NAME, &local_err);
1499    if (local_err) {
1500        goto out;
1501    }
1502    execute_async(do_suspend, mode, &local_err);
1503
1504out:
1505    if (local_err) {
1506        error_propagate(errp, local_err);
1507        g_free(mode);
1508    }
1509}
1510
1511void qmp_guest_suspend_hybrid(Error **errp)
1512{
1513    error_setg(errp, QERR_UNSUPPORTED);
1514}
1515
1516static IP_ADAPTER_ADDRESSES *guest_get_adapters_addresses(Error **errp)
1517{
1518    IP_ADAPTER_ADDRESSES *adptr_addrs = NULL;
1519    ULONG adptr_addrs_len = 0;
1520    DWORD ret;
1521
1522    /* Call the first time to get the adptr_addrs_len. */
1523    GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
1524                         NULL, adptr_addrs, &adptr_addrs_len);
1525
1526    adptr_addrs = g_malloc(adptr_addrs_len);
1527    ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
1528                               NULL, adptr_addrs, &adptr_addrs_len);
1529    if (ret != ERROR_SUCCESS) {
1530        error_setg_win32(errp, ret, "failed to get adapters addresses");
1531        g_free(adptr_addrs);
1532        adptr_addrs = NULL;
1533    }
1534    return adptr_addrs;
1535}
1536
1537static char *guest_wctomb_dup(WCHAR *wstr)
1538{
1539    char *str;
1540    size_t str_size;
1541
1542    str_size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
1543    /* add 1 to str_size for NULL terminator */
1544    str = g_malloc(str_size + 1);
1545    WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, str_size, NULL, NULL);
1546    return str;
1547}
1548
1549static char *guest_addr_to_str(IP_ADAPTER_UNICAST_ADDRESS *ip_addr,
1550                               Error **errp)
1551{
1552    char addr_str[INET6_ADDRSTRLEN + INET_ADDRSTRLEN];
1553    DWORD len;
1554    int ret;
1555
1556    if (ip_addr->Address.lpSockaddr->sa_family == AF_INET ||
1557            ip_addr->Address.lpSockaddr->sa_family == AF_INET6) {
1558        len = sizeof(addr_str);
1559        ret = WSAAddressToString(ip_addr->Address.lpSockaddr,
1560                                 ip_addr->Address.iSockaddrLength,
1561                                 NULL,
1562                                 addr_str,
1563                                 &len);
1564        if (ret != 0) {
1565            error_setg_win32(errp, WSAGetLastError(),
1566                "failed address presentation form conversion");
1567            return NULL;
1568        }
1569        return g_strdup(addr_str);
1570    }
1571    return NULL;
1572}
1573
1574static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS *ip_addr)
1575{
1576    /* For Windows Vista/2008 and newer, use the OnLinkPrefixLength
1577     * field to obtain the prefix.
1578     */
1579    return ip_addr->OnLinkPrefixLength;
1580}
1581
1582#define INTERFACE_PATH_BUF_SZ 512
1583
1584static DWORD get_interface_index(const char *guid)
1585{
1586    ULONG index;
1587    DWORD status;
1588    wchar_t wbuf[INTERFACE_PATH_BUF_SZ];
1589    snwprintf(wbuf, INTERFACE_PATH_BUF_SZ, L"\\device\\tcpip_%s", guid);
1590    wbuf[INTERFACE_PATH_BUF_SZ - 1] = 0;
1591    status = GetAdapterIndex (wbuf, &index);
1592    if (status != NO_ERROR) {
1593        return (DWORD)~0;
1594    } else {
1595        return index;
1596    }
1597}
1598
1599typedef NETIOAPI_API (WINAPI *GetIfEntry2Func)(PMIB_IF_ROW2 Row);
1600
1601static int guest_get_network_stats(const char *name,
1602                                   GuestNetworkInterfaceStat *stats)
1603{
1604    OSVERSIONINFO os_ver;
1605
1606    os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1607    GetVersionEx(&os_ver);
1608    if (os_ver.dwMajorVersion >= 6) {
1609        MIB_IF_ROW2 a_mid_ifrow;
1610        GetIfEntry2Func getifentry2_ex;
1611        DWORD if_index = 0;
1612        HMODULE module = GetModuleHandle("iphlpapi");
1613        PVOID func = GetProcAddress(module, "GetIfEntry2");
1614
1615        if (func == NULL) {
1616            return -1;
1617        }
1618
1619        getifentry2_ex = (GetIfEntry2Func)func;
1620        if_index = get_interface_index(name);
1621        if (if_index == (DWORD)~0) {
1622            return -1;
1623        }
1624
1625        memset(&a_mid_ifrow, 0, sizeof(a_mid_ifrow));
1626        a_mid_ifrow.InterfaceIndex = if_index;
1627        if (NO_ERROR == getifentry2_ex(&a_mid_ifrow)) {
1628            stats->rx_bytes = a_mid_ifrow.InOctets;
1629            stats->rx_packets = a_mid_ifrow.InUcastPkts;
1630            stats->rx_errs = a_mid_ifrow.InErrors;
1631            stats->rx_dropped = a_mid_ifrow.InDiscards;
1632            stats->tx_bytes = a_mid_ifrow.OutOctets;
1633            stats->tx_packets = a_mid_ifrow.OutUcastPkts;
1634            stats->tx_errs = a_mid_ifrow.OutErrors;
1635            stats->tx_dropped = a_mid_ifrow.OutDiscards;
1636            return 0;
1637        }
1638    }
1639    return -1;
1640}
1641
1642GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
1643{
1644    IP_ADAPTER_ADDRESSES *adptr_addrs, *addr;
1645    IP_ADAPTER_UNICAST_ADDRESS *ip_addr = NULL;
1646    GuestNetworkInterfaceList *head = NULL, **tail = &head;
1647    GuestIpAddressList *head_addr, **tail_addr;
1648    GuestNetworkInterface *info;
1649    GuestNetworkInterfaceStat *interface_stat = NULL;
1650    GuestIpAddress *address_item = NULL;
1651    unsigned char *mac_addr;
1652    char *addr_str;
1653    WORD wsa_version;
1654    WSADATA wsa_data;
1655    int ret;
1656
1657    adptr_addrs = guest_get_adapters_addresses(errp);
1658    if (adptr_addrs == NULL) {
1659        return NULL;
1660    }
1661
1662    /* Make WSA APIs available. */
1663    wsa_version = MAKEWORD(2, 2);
1664    ret = WSAStartup(wsa_version, &wsa_data);
1665    if (ret != 0) {
1666        error_setg_win32(errp, ret, "failed socket startup");
1667        goto out;
1668    }
1669
1670    for (addr = adptr_addrs; addr; addr = addr->Next) {
1671        info = g_malloc0(sizeof(*info));
1672
1673        QAPI_LIST_APPEND(tail, info);
1674
1675        info->name = guest_wctomb_dup(addr->FriendlyName);
1676
1677        if (addr->PhysicalAddressLength != 0) {
1678            mac_addr = addr->PhysicalAddress;
1679
1680            info->hardware_address =
1681                g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
1682                                (int) mac_addr[0], (int) mac_addr[1],
1683                                (int) mac_addr[2], (int) mac_addr[3],
1684                                (int) mac_addr[4], (int) mac_addr[5]);
1685        }
1686
1687        head_addr = NULL;
1688        tail_addr = &head_addr;
1689        for (ip_addr = addr->FirstUnicastAddress;
1690                ip_addr;
1691                ip_addr = ip_addr->Next) {
1692            addr_str = guest_addr_to_str(ip_addr, errp);
1693            if (addr_str == NULL) {
1694                continue;
1695            }
1696
1697            address_item = g_malloc0(sizeof(*address_item));
1698
1699            QAPI_LIST_APPEND(tail_addr, address_item);
1700
1701            address_item->ip_address = addr_str;
1702            address_item->prefix = guest_ip_prefix(ip_addr);
1703            if (ip_addr->Address.lpSockaddr->sa_family == AF_INET) {
1704                address_item->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
1705            } else if (ip_addr->Address.lpSockaddr->sa_family == AF_INET6) {
1706                address_item->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
1707            }
1708        }
1709        if (head_addr) {
1710            info->has_ip_addresses = true;
1711            info->ip_addresses = head_addr;
1712        }
1713        if (!info->statistics) {
1714            interface_stat = g_malloc0(sizeof(*interface_stat));
1715            if (guest_get_network_stats(addr->AdapterName, interface_stat)
1716                == -1) {
1717                g_free(interface_stat);
1718            } else {
1719                info->statistics = interface_stat;
1720            }
1721        }
1722    }
1723    WSACleanup();
1724out:
1725    g_free(adptr_addrs);
1726    return head;
1727}
1728
1729static int64_t filetime_to_ns(const FILETIME *tf)
1730{
1731    return ((((int64_t)tf->dwHighDateTime << 32) | tf->dwLowDateTime)
1732            - W32_FT_OFFSET) * 100;
1733}
1734
1735void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
1736{
1737    Error *local_err = NULL;
1738    SYSTEMTIME ts;
1739    FILETIME tf;
1740    LONGLONG time;
1741
1742    if (!has_time) {
1743        /* Unfortunately, Windows libraries don't provide an easy way to access
1744         * RTC yet:
1745         *
1746         * https://msdn.microsoft.com/en-us/library/aa908981.aspx
1747         *
1748         * Instead, a workaround is to use the Windows win32tm command to
1749         * resync the time using the Windows Time service.
1750         */
1751        LPVOID msg_buffer;
1752        DWORD ret_flags;
1753
1754        HRESULT hr = system("w32tm /resync /nowait");
1755
1756        if (GetLastError() != 0) {
1757            strerror_s((LPTSTR) & msg_buffer, 0, errno);
1758            error_setg(errp, "system(...) failed: %s", (LPCTSTR)msg_buffer);
1759        } else if (hr != 0) {
1760            if (hr == HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE)) {
1761                error_setg(errp, "Windows Time service not running on the "
1762                                 "guest");
1763            } else {
1764                if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1765                                   FORMAT_MESSAGE_FROM_SYSTEM |
1766                                   FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
1767                                   (DWORD)hr, MAKELANGID(LANG_NEUTRAL,
1768                                   SUBLANG_DEFAULT), (LPTSTR) & msg_buffer, 0,
1769                                   NULL)) {
1770                    error_setg(errp, "w32tm failed with error (0x%lx), couldn'"
1771                                     "t retrieve error message", hr);
1772                } else {
1773                    error_setg(errp, "w32tm failed with error (0x%lx): %s", hr,
1774                               (LPCTSTR)msg_buffer);
1775                    LocalFree(msg_buffer);
1776                }
1777            }
1778        } else if (!InternetGetConnectedState(&ret_flags, 0)) {
1779            error_setg(errp, "No internet connection on guest, sync not "
1780                             "accurate");
1781        }
1782        return;
1783    }
1784
1785    /* Validate time passed by user. */
1786    if (time_ns < 0 || time_ns / 100 > INT64_MAX - W32_FT_OFFSET) {
1787        error_setg(errp, "Time %" PRId64 "is invalid", time_ns);
1788        return;
1789    }
1790
1791    time = time_ns / 100 + W32_FT_OFFSET;
1792
1793    tf.dwLowDateTime = (DWORD) time;
1794    tf.dwHighDateTime = (DWORD) (time >> 32);
1795
1796    if (!FileTimeToSystemTime(&tf, &ts)) {
1797        error_setg(errp, "Failed to convert system time %d",
1798                   (int)GetLastError());
1799        return;
1800    }
1801
1802    acquire_privilege(SE_SYSTEMTIME_NAME, &local_err);
1803    if (local_err) {
1804        error_propagate(errp, local_err);
1805        return;
1806    }
1807
1808    if (!SetSystemTime(&ts)) {
1809        error_setg(errp, "Failed to set time to guest: %d", (int)GetLastError());
1810        return;
1811    }
1812}
1813
1814GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
1815{
1816    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pslpi, ptr;
1817    DWORD length;
1818    GuestLogicalProcessorList *head, **tail;
1819    Error *local_err = NULL;
1820    int64_t current;
1821
1822    ptr = pslpi = NULL;
1823    length = 0;
1824    current = 0;
1825    head = NULL;
1826    tail = &head;
1827
1828    if ((GetLogicalProcessorInformation(pslpi, &length) == FALSE) &&
1829        (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
1830        (length > sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION))) {
1831        ptr = pslpi = g_malloc0(length);
1832        if (GetLogicalProcessorInformation(pslpi, &length) == FALSE) {
1833            error_setg(&local_err, "Failed to get processor information: %d",
1834                       (int)GetLastError());
1835        }
1836    } else {
1837        error_setg(&local_err,
1838                   "Failed to get processor information buffer length: %d",
1839                   (int)GetLastError());
1840    }
1841
1842    while ((local_err == NULL) && (length > 0)) {
1843        if (pslpi->Relationship == RelationProcessorCore) {
1844            ULONG_PTR cpu_bits = pslpi->ProcessorMask;
1845
1846            while (cpu_bits > 0) {
1847                if (!!(cpu_bits & 1)) {
1848                    GuestLogicalProcessor *vcpu;
1849
1850                    vcpu = g_malloc0(sizeof *vcpu);
1851                    vcpu->logical_id = current++;
1852                    vcpu->online = true;
1853                    vcpu->has_can_offline = true;
1854
1855                    QAPI_LIST_APPEND(tail, vcpu);
1856                }
1857                cpu_bits >>= 1;
1858            }
1859        }
1860        length -= sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
1861        pslpi++; /* next entry */
1862    }
1863
1864    g_free(ptr);
1865
1866    if (local_err == NULL) {
1867        if (head != NULL) {
1868            return head;
1869        }
1870        /* there's no guest with zero VCPUs */
1871        error_setg(&local_err, "Guest reported zero VCPUs");
1872    }
1873
1874    qapi_free_GuestLogicalProcessorList(head);
1875    error_propagate(errp, local_err);
1876    return NULL;
1877}
1878
1879int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
1880{
1881    error_setg(errp, QERR_UNSUPPORTED);
1882    return -1;
1883}
1884
1885static gchar *
1886get_net_error_message(gint error)
1887{
1888    HMODULE module = NULL;
1889    gchar *retval = NULL;
1890    wchar_t *msg = NULL;
1891    int flags;
1892    size_t nchars;
1893
1894    flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
1895        FORMAT_MESSAGE_IGNORE_INSERTS |
1896        FORMAT_MESSAGE_FROM_SYSTEM;
1897
1898    if (error >= NERR_BASE && error <= MAX_NERR) {
1899        module = LoadLibraryExW(L"netmsg.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
1900
1901        if (module != NULL) {
1902            flags |= FORMAT_MESSAGE_FROM_HMODULE;
1903        }
1904    }
1905
1906    FormatMessageW(flags, module, error, 0, (LPWSTR)&msg, 0, NULL);
1907
1908    if (msg != NULL) {
1909        nchars = wcslen(msg);
1910
1911        if (nchars >= 2 &&
1912            msg[nchars - 1] == L'\n' &&
1913            msg[nchars - 2] == L'\r') {
1914            msg[nchars - 2] = L'\0';
1915        }
1916
1917        retval = g_utf16_to_utf8(msg, -1, NULL, NULL, NULL);
1918
1919        LocalFree(msg);
1920    }
1921
1922    if (module != NULL) {
1923        FreeLibrary(module);
1924    }
1925
1926    return retval;
1927}
1928
1929void qmp_guest_set_user_password(const char *username,
1930                                 const char *password,
1931                                 bool crypted,
1932                                 Error **errp)
1933{
1934    NET_API_STATUS nas;
1935    char *rawpasswddata = NULL;
1936    size_t rawpasswdlen;
1937    wchar_t *user = NULL, *wpass = NULL;
1938    USER_INFO_1003 pi1003 = { 0, };
1939    GError *gerr = NULL;
1940
1941    if (crypted) {
1942        error_setg(errp, QERR_UNSUPPORTED);
1943        return;
1944    }
1945
1946    rawpasswddata = (char *)qbase64_decode(password, -1, &rawpasswdlen, errp);
1947    if (!rawpasswddata) {
1948        return;
1949    }
1950    rawpasswddata = g_renew(char, rawpasswddata, rawpasswdlen + 1);
1951    rawpasswddata[rawpasswdlen] = '\0';
1952
1953    user = g_utf8_to_utf16(username, -1, NULL, NULL, &gerr);
1954    if (!user) {
1955        goto done;
1956    }
1957
1958    wpass = g_utf8_to_utf16(rawpasswddata, -1, NULL, NULL, &gerr);
1959    if (!wpass) {
1960        goto done;
1961    }
1962
1963    pi1003.usri1003_password = wpass;
1964    nas = NetUserSetInfo(NULL, user,
1965                         1003, (LPBYTE)&pi1003,
1966                         NULL);
1967
1968    if (nas != NERR_Success) {
1969        gchar *msg = get_net_error_message(nas);
1970        error_setg(errp, "failed to set password: %s", msg);
1971        g_free(msg);
1972    }
1973
1974done:
1975    if (gerr) {
1976        error_setg(errp, QERR_QGA_COMMAND_FAILED, gerr->message);
1977        g_error_free(gerr);
1978    }
1979    g_free(user);
1980    g_free(wpass);
1981    g_free(rawpasswddata);
1982}
1983
1984GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
1985{
1986    error_setg(errp, QERR_UNSUPPORTED);
1987    return NULL;
1988}
1989
1990GuestMemoryBlockResponseList *
1991qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
1992{
1993    error_setg(errp, QERR_UNSUPPORTED);
1994    return NULL;
1995}
1996
1997GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
1998{
1999    error_setg(errp, QERR_UNSUPPORTED);
2000    return NULL;
2001}
2002
2003/* add unsupported commands to the list of blocked RPCs */
2004GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
2005{
2006    const char *list_unsupported[] = {
2007        "guest-suspend-hybrid",
2008        "guest-set-vcpus",
2009        "guest-get-memory-blocks", "guest-set-memory-blocks",
2010        "guest-get-memory-block-size", "guest-get-memory-block-info",
2011        NULL};
2012    char **p = (char **)list_unsupported;
2013
2014    while (*p) {
2015        blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
2016    }
2017
2018    if (!vss_init(true)) {
2019        g_debug("vss_init failed, vss commands are going to be disabled");
2020        const char *list[] = {
2021            "guest-get-fsinfo", "guest-fsfreeze-status",
2022            "guest-fsfreeze-freeze", "guest-fsfreeze-thaw", NULL};
2023        p = (char **)list;
2024
2025        while (*p) {
2026            blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
2027        }
2028    }
2029
2030    return blockedrpcs;
2031}
2032
2033/* register init/cleanup routines for stateful command groups */
2034void ga_command_state_init(GAState *s, GACommandState *cs)
2035{
2036    if (!vss_initialized()) {
2037        ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
2038    }
2039}
2040
2041/* MINGW is missing two fields: IncomingFrames & OutgoingFrames */
2042typedef struct _GA_WTSINFOA {
2043    WTS_CONNECTSTATE_CLASS State;
2044    DWORD SessionId;
2045    DWORD IncomingBytes;
2046    DWORD OutgoingBytes;
2047    DWORD IncomingFrames;
2048    DWORD OutgoingFrames;
2049    DWORD IncomingCompressedBytes;
2050    DWORD OutgoingCompressedBy;
2051    CHAR WinStationName[WINSTATIONNAME_LENGTH];
2052    CHAR Domain[DOMAIN_LENGTH];
2053    CHAR UserName[USERNAME_LENGTH + 1];
2054    LARGE_INTEGER ConnectTime;
2055    LARGE_INTEGER DisconnectTime;
2056    LARGE_INTEGER LastInputTime;
2057    LARGE_INTEGER LogonTime;
2058    LARGE_INTEGER CurrentTime;
2059
2060} GA_WTSINFOA;
2061
2062GuestUserList *qmp_guest_get_users(Error **errp)
2063{
2064#define QGA_NANOSECONDS 10000000
2065
2066    GHashTable *cache = NULL;
2067    GuestUserList *head = NULL, **tail = &head;
2068
2069    DWORD buffer_size = 0, count = 0, i = 0;
2070    GA_WTSINFOA *info = NULL;
2071    WTS_SESSION_INFOA *entries = NULL;
2072    GuestUser *user = NULL;
2073    gpointer value = NULL;
2074    INT64 login = 0;
2075    double login_time = 0;
2076
2077    cache = g_hash_table_new(g_str_hash, g_str_equal);
2078
2079    if (WTSEnumerateSessionsA(NULL, 0, 1, &entries, &count)) {
2080        for (i = 0; i < count; ++i) {
2081            buffer_size = 0;
2082            info = NULL;
2083            if (WTSQuerySessionInformationA(
2084                NULL,
2085                entries[i].SessionId,
2086                WTSSessionInfo,
2087                (LPSTR *)&info,
2088                &buffer_size
2089            )) {
2090
2091                if (strlen(info->UserName) == 0) {
2092                    WTSFreeMemory(info);
2093                    continue;
2094                }
2095
2096                login = info->LogonTime.QuadPart;
2097                login -= W32_FT_OFFSET;
2098                login_time = ((double)login) / QGA_NANOSECONDS;
2099
2100                if (g_hash_table_contains(cache, info->UserName)) {
2101                    value = g_hash_table_lookup(cache, info->UserName);
2102                    user = (GuestUser *)value;
2103                    if (user->login_time > login_time) {
2104                        user->login_time = login_time;
2105                    }
2106                } else {
2107                    user = g_new0(GuestUser, 1);
2108
2109                    user->user = g_strdup(info->UserName);
2110                    user->domain = g_strdup(info->Domain);
2111
2112                    user->login_time = login_time;
2113
2114                    g_hash_table_add(cache, user->user);
2115
2116                    QAPI_LIST_APPEND(tail, user);
2117                }
2118            }
2119            WTSFreeMemory(info);
2120        }
2121        WTSFreeMemory(entries);
2122    }
2123    g_hash_table_destroy(cache);
2124    return head;
2125}
2126
2127typedef struct _ga_matrix_lookup_t {
2128    int major;
2129    int minor;
2130    char const *version;
2131    char const *version_id;
2132} ga_matrix_lookup_t;
2133
2134static ga_matrix_lookup_t const WIN_VERSION_MATRIX[2][7] = {
2135    {
2136        /* Desktop editions */
2137        { 5, 0, "Microsoft Windows 2000",   "2000"},
2138        { 5, 1, "Microsoft Windows XP",     "xp"},
2139        { 6, 0, "Microsoft Windows Vista",  "vista"},
2140        { 6, 1, "Microsoft Windows 7"       "7"},
2141        { 6, 2, "Microsoft Windows 8",      "8"},
2142        { 6, 3, "Microsoft Windows 8.1",    "8.1"},
2143        { 0, 0, 0}
2144    },{
2145        /* Server editions */
2146        { 5, 2, "Microsoft Windows Server 2003",        "2003"},
2147        { 6, 0, "Microsoft Windows Server 2008",        "2008"},
2148        { 6, 1, "Microsoft Windows Server 2008 R2",     "2008r2"},
2149        { 6, 2, "Microsoft Windows Server 2012",        "2012"},
2150        { 6, 3, "Microsoft Windows Server 2012 R2",     "2012r2"},
2151        { 0, 0, 0},
2152        { 0, 0, 0}
2153    }
2154};
2155
2156typedef struct _ga_win_10_0_t {
2157    int first_build;
2158    char const *version;
2159    char const *version_id;
2160} ga_win_10_0_t;
2161
2162static ga_win_10_0_t const WIN_10_0_SERVER_VERSION_MATRIX[4] = {
2163    {14393, "Microsoft Windows Server 2016",    "2016"},
2164    {17763, "Microsoft Windows Server 2019",    "2019"},
2165    {20344, "Microsoft Windows Server 2022",    "2022"},
2166    {0, 0}
2167};
2168
2169static ga_win_10_0_t const WIN_10_0_CLIENT_VERSION_MATRIX[3] = {
2170    {10240, "Microsoft Windows 10",    "10"},
2171    {22000, "Microsoft Windows 11",    "11"},
2172    {0, 0}
2173};
2174
2175static void ga_get_win_version(RTL_OSVERSIONINFOEXW *info, Error **errp)
2176{
2177    typedef NTSTATUS(WINAPI *rtl_get_version_t)(
2178        RTL_OSVERSIONINFOEXW *os_version_info_ex);
2179
2180    info->dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
2181
2182    HMODULE module = GetModuleHandle("ntdll");
2183    PVOID fun = GetProcAddress(module, "RtlGetVersion");
2184    if (fun == NULL) {
2185        error_setg(errp, QERR_QGA_COMMAND_FAILED,
2186            "Failed to get address of RtlGetVersion");
2187        return;
2188    }
2189
2190    rtl_get_version_t rtl_get_version = (rtl_get_version_t)fun;
2191    rtl_get_version(info);
2192    return;
2193}
2194
2195static char *ga_get_win_name(OSVERSIONINFOEXW const *os_version, bool id)
2196{
2197    DWORD major = os_version->dwMajorVersion;
2198    DWORD minor = os_version->dwMinorVersion;
2199    DWORD build = os_version->dwBuildNumber;
2200    int tbl_idx = (os_version->wProductType != VER_NT_WORKSTATION);
2201    ga_matrix_lookup_t const *table = WIN_VERSION_MATRIX[tbl_idx];
2202    ga_win_10_0_t const *win_10_0_table = tbl_idx ?
2203        WIN_10_0_SERVER_VERSION_MATRIX : WIN_10_0_CLIENT_VERSION_MATRIX;
2204    ga_win_10_0_t const *win_10_0_version = NULL;
2205    while (table->version != NULL) {
2206        if (major == 10 && minor == 0) {
2207            while (win_10_0_table->version != NULL) {
2208                if (build >= win_10_0_table->first_build) {
2209                    win_10_0_version = win_10_0_table;
2210                }
2211                win_10_0_table++;
2212            }
2213            if (win_10_0_table) {
2214                if (id) {
2215                    return g_strdup(win_10_0_version->version_id);
2216                } else {
2217                    return g_strdup(win_10_0_version->version);
2218                }
2219            }
2220        } else if (major == table->major && minor == table->minor) {
2221            if (id) {
2222                return g_strdup(table->version_id);
2223            } else {
2224                return g_strdup(table->version);
2225            }
2226        }
2227        ++table;
2228    }
2229    slog("failed to lookup Windows version: major=%lu, minor=%lu",
2230        major, minor);
2231    return g_strdup("N/A");
2232}
2233
2234static char *ga_get_win_product_name(Error **errp)
2235{
2236    HKEY key = INVALID_HANDLE_VALUE;
2237    DWORD size = 128;
2238    char *result = g_malloc0(size);
2239    LONG err = ERROR_SUCCESS;
2240
2241    err = RegOpenKeyA(HKEY_LOCAL_MACHINE,
2242                      "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
2243                      &key);
2244    if (err != ERROR_SUCCESS) {
2245        error_setg_win32(errp, err, "failed to open registry key");
2246        g_free(result);
2247        return NULL;
2248    }
2249
2250    err = RegQueryValueExA(key, "ProductName", NULL, NULL,
2251                            (LPBYTE)result, &size);
2252    if (err == ERROR_MORE_DATA) {
2253        slog("ProductName longer than expected (%lu bytes), retrying",
2254                size);
2255        g_free(result);
2256        result = NULL;
2257        if (size > 0) {
2258            result = g_malloc0(size);
2259            err = RegQueryValueExA(key, "ProductName", NULL, NULL,
2260                                    (LPBYTE)result, &size);
2261        }
2262    }
2263    if (err != ERROR_SUCCESS) {
2264        error_setg_win32(errp, err, "failed to retrive ProductName");
2265        goto fail;
2266    }
2267
2268    RegCloseKey(key);
2269    return result;
2270
2271fail:
2272    if (key != INVALID_HANDLE_VALUE) {
2273        RegCloseKey(key);
2274    }
2275    g_free(result);
2276    return NULL;
2277}
2278
2279static char *ga_get_current_arch(void)
2280{
2281    SYSTEM_INFO info;
2282    GetNativeSystemInfo(&info);
2283    char *result = NULL;
2284    switch (info.wProcessorArchitecture) {
2285    case PROCESSOR_ARCHITECTURE_AMD64:
2286        result = g_strdup("x86_64");
2287        break;
2288    case PROCESSOR_ARCHITECTURE_ARM:
2289        result = g_strdup("arm");
2290        break;
2291    case PROCESSOR_ARCHITECTURE_IA64:
2292        result = g_strdup("ia64");
2293        break;
2294    case PROCESSOR_ARCHITECTURE_INTEL:
2295        result = g_strdup("x86");
2296        break;
2297    case PROCESSOR_ARCHITECTURE_UNKNOWN:
2298    default:
2299        slog("unknown processor architecture 0x%0x",
2300            info.wProcessorArchitecture);
2301        result = g_strdup("unknown");
2302        break;
2303    }
2304    return result;
2305}
2306
2307GuestOSInfo *qmp_guest_get_osinfo(Error **errp)
2308{
2309    Error *local_err = NULL;
2310    OSVERSIONINFOEXW os_version = {0};
2311    bool server;
2312    char *product_name;
2313    GuestOSInfo *info;
2314
2315    ga_get_win_version(&os_version, &local_err);
2316    if (local_err) {
2317        error_propagate(errp, local_err);
2318        return NULL;
2319    }
2320
2321    server = os_version.wProductType != VER_NT_WORKSTATION;
2322    product_name = ga_get_win_product_name(errp);
2323    if (product_name == NULL) {
2324        return NULL;
2325    }
2326
2327    info = g_new0(GuestOSInfo, 1);
2328
2329    info->kernel_version = g_strdup_printf("%lu.%lu",
2330        os_version.dwMajorVersion,
2331        os_version.dwMinorVersion);
2332    info->kernel_release = g_strdup_printf("%lu",
2333        os_version.dwBuildNumber);
2334    info->machine = ga_get_current_arch();
2335
2336    info->id = g_strdup("mswindows");
2337    info->name = g_strdup("Microsoft Windows");
2338    info->pretty_name = product_name;
2339    info->version = ga_get_win_name(&os_version, false);
2340    info->version_id = ga_get_win_name(&os_version, true);
2341    info->variant = g_strdup(server ? "server" : "client");
2342    info->variant_id = g_strdup(server ? "server" : "client");
2343
2344    return info;
2345}
2346
2347/*
2348 * Safely get device property. Returned strings are using wide characters.
2349 * Caller is responsible for freeing the buffer.
2350 */
2351static LPBYTE cm_get_property(DEVINST devInst, const DEVPROPKEY *propName,
2352    PDEVPROPTYPE propType)
2353{
2354    CONFIGRET cr;
2355    g_autofree LPBYTE buffer = NULL;
2356    ULONG buffer_len = 0;
2357
2358    /* First query for needed space */
2359    cr = CM_Get_DevNode_PropertyW(devInst, propName, propType,
2360        buffer, &buffer_len, 0);
2361    if (cr != CR_SUCCESS && cr != CR_BUFFER_SMALL) {
2362
2363        slog("failed to get property size, error=0x%lx", cr);
2364        return NULL;
2365    }
2366    buffer = g_new0(BYTE, buffer_len + 1);
2367    cr = CM_Get_DevNode_PropertyW(devInst, propName, propType,
2368        buffer, &buffer_len, 0);
2369    if (cr != CR_SUCCESS) {
2370        slog("failed to get device property, error=0x%lx", cr);
2371        return NULL;
2372    }
2373    return g_steal_pointer(&buffer);
2374}
2375
2376static GStrv ga_get_hardware_ids(DEVINST devInstance)
2377{
2378    GArray *values = NULL;
2379    DEVPROPTYPE cm_type;
2380    LPWSTR id;
2381    g_autofree LPWSTR property = (LPWSTR)cm_get_property(devInstance,
2382        &qga_DEVPKEY_Device_HardwareIds, &cm_type);
2383    if (property == NULL) {
2384        slog("failed to get hardware IDs");
2385        return NULL;
2386    }
2387    if (*property == '\0') {
2388        /* empty list */
2389        return NULL;
2390    }
2391    values = g_array_new(TRUE, TRUE, sizeof(gchar *));
2392    for (id = property; '\0' != *id; id += lstrlenW(id) + 1) {
2393        gchar *id8 = g_utf16_to_utf8(id, -1, NULL, NULL, NULL);
2394        g_array_append_val(values, id8);
2395    }
2396    return (GStrv)g_array_free(values, FALSE);
2397}
2398
2399/*
2400 * https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-pci-devices
2401 */
2402#define DEVICE_PCI_RE "PCI\\\\VEN_(1AF4|1B36)&DEV_([0-9A-B]{4})(&|$)"
2403
2404GuestDeviceInfoList *qmp_guest_get_devices(Error **errp)
2405{
2406    GuestDeviceInfoList *head = NULL, **tail = &head;
2407    HDEVINFO dev_info = INVALID_HANDLE_VALUE;
2408    SP_DEVINFO_DATA dev_info_data;
2409    int i, j;
2410    GError *gerr = NULL;
2411    g_autoptr(GRegex) device_pci_re = NULL;
2412    DEVPROPTYPE cm_type;
2413
2414    device_pci_re = g_regex_new(DEVICE_PCI_RE,
2415        G_REGEX_ANCHORED | G_REGEX_OPTIMIZE, 0,
2416        &gerr);
2417    g_assert(device_pci_re != NULL);
2418
2419    dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
2420    dev_info = SetupDiGetClassDevs(0, 0, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES);
2421    if (dev_info == INVALID_HANDLE_VALUE) {
2422        error_setg(errp, "failed to get device tree");
2423        return NULL;
2424    }
2425
2426    slog("enumerating devices");
2427    for (i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
2428        bool skip = true;
2429        g_autofree LPWSTR name = NULL;
2430        g_autofree LPFILETIME date = NULL;
2431        g_autofree LPWSTR version = NULL;
2432        g_auto(GStrv) hw_ids = NULL;
2433        g_autoptr(GuestDeviceInfo) device = g_new0(GuestDeviceInfo, 1);
2434        g_autofree char *vendor_id = NULL;
2435        g_autofree char *device_id = NULL;
2436
2437        name = (LPWSTR)cm_get_property(dev_info_data.DevInst,
2438            &qga_DEVPKEY_NAME, &cm_type);
2439        if (name == NULL) {
2440            slog("failed to get device description");
2441            continue;
2442        }
2443        device->driver_name = g_utf16_to_utf8(name, -1, NULL, NULL, NULL);
2444        if (device->driver_name == NULL) {
2445            error_setg(errp, "conversion to utf8 failed (driver name)");
2446            return NULL;
2447        }
2448        slog("querying device: %s", device->driver_name);
2449        hw_ids = ga_get_hardware_ids(dev_info_data.DevInst);
2450        if (hw_ids == NULL) {
2451            continue;
2452        }
2453        for (j = 0; hw_ids[j] != NULL; j++) {
2454            g_autoptr(GMatchInfo) match_info;
2455            GuestDeviceIdPCI *id;
2456            if (!g_regex_match(device_pci_re, hw_ids[j], 0, &match_info)) {
2457                continue;
2458            }
2459            skip = false;
2460
2461            vendor_id = g_match_info_fetch(match_info, 1);
2462            device_id = g_match_info_fetch(match_info, 2);
2463
2464            device->id = g_new0(GuestDeviceId, 1);
2465            device->id->type = GUEST_DEVICE_TYPE_PCI;
2466            id = &device->id->u.pci;
2467            id->vendor_id = g_ascii_strtoull(vendor_id, NULL, 16);
2468            id->device_id = g_ascii_strtoull(device_id, NULL, 16);
2469
2470            break;
2471        }
2472        if (skip) {
2473            continue;
2474        }
2475
2476        version = (LPWSTR)cm_get_property(dev_info_data.DevInst,
2477            &qga_DEVPKEY_Device_DriverVersion, &cm_type);
2478        if (version == NULL) {
2479            slog("failed to get driver version");
2480            continue;
2481        }
2482        device->driver_version = g_utf16_to_utf8(version, -1, NULL,
2483            NULL, NULL);
2484        if (device->driver_version == NULL) {
2485            error_setg(errp, "conversion to utf8 failed (driver version)");
2486            return NULL;
2487        }
2488
2489        date = (LPFILETIME)cm_get_property(dev_info_data.DevInst,
2490            &qga_DEVPKEY_Device_DriverDate, &cm_type);
2491        if (date == NULL) {
2492            slog("failed to get driver date");
2493            continue;
2494        }
2495        device->driver_date = filetime_to_ns(date);
2496        device->has_driver_date = true;
2497
2498        slog("driver: %s\ndriver version: %" PRId64 ",%s\n",
2499             device->driver_name, device->driver_date,
2500             device->driver_version);
2501        QAPI_LIST_APPEND(tail, g_steal_pointer(&device));
2502    }
2503
2504    if (dev_info != INVALID_HANDLE_VALUE) {
2505        SetupDiDestroyDeviceInfoList(dev_info);
2506    }
2507    return head;
2508}
2509
2510char *qga_get_host_name(Error **errp)
2511{
2512    wchar_t tmp[MAX_COMPUTERNAME_LENGTH + 1];
2513    DWORD size = G_N_ELEMENTS(tmp);
2514
2515    if (GetComputerNameW(tmp, &size) == 0) {
2516        error_setg_win32(errp, GetLastError(), "failed close handle");
2517        return NULL;
2518    }
2519
2520    return g_utf16_to_utf8(tmp, size, NULL, NULL, NULL);
2521}
2522
2523GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
2524{
2525    error_setg(errp, QERR_UNSUPPORTED);
2526    return NULL;
2527}
2528
2529GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
2530{
2531    error_setg(errp, QERR_UNSUPPORTED);
2532    return NULL;
2533}
2534