Merge remote-tracking branch 'remotes/mdroth/qga-pull-2014-02-24' into staging

* remotes/mdroth/qga-pull-2014-02-24:
  qemu-ga: isa-serial support on Windows
  qga: Fix memory allocation pasto
  qga: Don't require 'time' argument in guest-set-time command
  qga: vss-win32: Fix interference with snapshot deletion by other VSS request
  qga: vss-win32: Fix interference with snapshot creation by other VSS requesters
  qga: vss-win32: Use NULL as an invalid pointer for OpenEvent and CreateEvent

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/qga/channel-win32.c b/qga/channel-win32.c
index 8a303f3..0d5e5f5 100644
--- a/qga/channel-win32.c
+++ b/qga/channel-win32.c
@@ -287,12 +287,22 @@
 static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method,
                                 const gchar *path)
 {
-    if (method != GA_CHANNEL_VIRTIO_SERIAL) {
+    COMMTIMEOUTS comTimeOut = {0};
+    gchar newpath[MAXPATHLEN] = {0};
+    comTimeOut.ReadIntervalTimeout = 1;
+
+    if (method != GA_CHANNEL_VIRTIO_SERIAL && method != GA_CHANNEL_ISA_SERIAL) {
         g_critical("unsupported communication method");
         return false;
     }
 
-    c->handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+    if (method == GA_CHANNEL_ISA_SERIAL){
+        snprintf(newpath, sizeof(newpath), "\\\\.\\%s", path);
+    }else {
+        g_strlcpy(newpath, path, sizeof(newpath));
+    }
+
+    c->handle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
                            OPEN_EXISTING,
                            FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);
     if (c->handle == INVALID_HANDLE_VALUE) {
@@ -300,6 +310,12 @@
         return false;
     }
 
+    if (method == GA_CHANNEL_ISA_SERIAL && !SetCommTimeouts(c->handle,&comTimeOut)) {
+        g_critical("error setting timeout for com port: %lu",GetLastError());
+        CloseHandle(c->handle);
+        return false;
+    }
+
     return true;
 }
 
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index cae4171..6b5f11f 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -142,7 +142,7 @@
    return time_ns;
 }
 
-void qmp_guest_set_time(int64_t time_ns, Error **errp)
+void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
 {
     int ret;
     int status;
@@ -150,22 +150,28 @@
     Error *local_err = NULL;
     struct timeval tv;
 
-    /* year-2038 will overflow in case time_t is 32bit */
-    if (time_ns / 1000000000 != (time_t)(time_ns / 1000000000)) {
-        error_setg(errp, "Time %" PRId64 " is too large", time_ns);
-        return;
+    /* If user has passed a time, validate and set it. */
+    if (has_time) {
+        /* year-2038 will overflow in case time_t is 32bit */
+        if (time_ns / 1000000000 != (time_t)(time_ns / 1000000000)) {
+            error_setg(errp, "Time %" PRId64 " is too large", time_ns);
+            return;
+        }
+
+        tv.tv_sec = time_ns / 1000000000;
+        tv.tv_usec = (time_ns % 1000000000) / 1000;
+
+        ret = settimeofday(&tv, NULL);
+        if (ret < 0) {
+            error_setg_errno(errp, errno, "Failed to set time to guest");
+            return;
+        }
     }
 
-    tv.tv_sec = time_ns / 1000000000;
-    tv.tv_usec = (time_ns % 1000000000) / 1000;
-
-    ret = settimeofday(&tv, NULL);
-    if (ret < 0) {
-        error_setg_errno(errp, errno, "Failed to set time to guest");
-        return;
-    }
-
-    /* Set the Hardware Clock to the current System Time. */
+    /* Now, if user has passed a time to set and the system time is set, we
+     * just need to synchronize the hardware clock. However, if no time was
+     * passed, user is requesting the opposite: set the system time from the
+     * hardware clock. */
     pid = fork();
     if (pid == 0) {
         setsid();
@@ -173,7 +179,10 @@
         reopen_fd_to_null(1);
         reopen_fd_to_null(2);
 
-        execle("/sbin/hwclock", "hwclock", "-w", NULL, environ);
+        /* Use '/sbin/hwclock -w' to set RTC from the system time,
+         * or '/sbin/hwclock -s' to set the system time from RTC. */
+        execle("/sbin/hwclock", "hwclock", has_time ? "-w" : "-s",
+               NULL, environ);
         _exit(EXIT_FAILURE);
     } else if (pid < 0) {
         error_setg_errno(errp, errno, "failed to create child process");
@@ -525,7 +534,7 @@
     if (ret == -1) {
         error_setg_errno(err, errno, "failed to seek file");
     } else {
-        seek_data = g_malloc0(sizeof(GuestFileRead));
+        seek_data = g_new0(GuestFileSeek, 1);
         seek_data->position = ftell(fh);
         seek_data->eof = feof(fh);
     }
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 50094dd..0ee07b6 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -370,25 +370,37 @@
     return time_ns;
 }
 
-void qmp_guest_set_time(int64_t time_ns, Error **errp)
+void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
 {
     SYSTEMTIME ts;
     FILETIME tf;
     LONGLONG time;
 
-    if (time_ns < 0 || time_ns / 100 > INT64_MAX - W32_FT_OFFSET) {
-        error_setg(errp, "Time %" PRId64 "is invalid", time_ns);
-        return;
-    }
+    if (has_time) {
+        /* Okay, user passed a time to set. Validate it. */
+        if (time_ns < 0 || time_ns / 100 > INT64_MAX - W32_FT_OFFSET) {
+            error_setg(errp, "Time %" PRId64 "is invalid", time_ns);
+            return;
+        }
 
-    time = time_ns / 100 + W32_FT_OFFSET;
+        time = time_ns / 100 + W32_FT_OFFSET;
 
-    tf.dwLowDateTime = (DWORD) time;
-    tf.dwHighDateTime = (DWORD) (time >> 32);
+        tf.dwLowDateTime = (DWORD) time;
+        tf.dwHighDateTime = (DWORD) (time >> 32);
 
-    if (!FileTimeToSystemTime(&tf, &ts)) {
-        error_setg(errp, "Failed to convert system time %d", (int)GetLastError());
-        return;
+        if (!FileTimeToSystemTime(&tf, &ts)) {
+            error_setg(errp, "Failed to convert system time %d",
+                       (int)GetLastError());
+            return;
+        }
+    } else {
+        /* Otherwise read the time from RTC which contains the correct value.
+         * Hopefully. */
+        GetSystemTime(&ts);
+        if (ts.wYear < 1601 || ts.wYear > 30827) {
+            error_setg(errp, "Failed to get time");
+            return;
+        }
     }
 
     acquire_privilege(SE_SYSTEMTIME_NAME, errp);
diff --git a/qga/main.c b/qga/main.c
index c58b26a..cfca291 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -47,9 +47,11 @@
 #ifndef _WIN32
 #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0"
 #define QGA_STATE_RELATIVE_DIR  "run"
+#define QGA_SERIAL_PATH_DEFAULT "/dev/ttyS0"
 #else
 #define QGA_VIRTIO_PATH_DEFAULT "\\\\.\\Global\\org.qemu.guest_agent.0"
 #define QGA_STATE_RELATIVE_DIR  "qemu-ga"
+#define QGA_SERIAL_PATH_DEFAULT "COM1"
 #endif
 #ifdef CONFIG_FSFREEZE
 #define QGA_FSFREEZE_HOOK_DEFAULT CONFIG_QEMU_CONFDIR "/fsfreeze-hook"
@@ -189,6 +191,8 @@
 "  -m, --method      transport method: one of unix-listen, virtio-serial, or\n"
 "                    isa-serial (virtio-serial is the default)\n"
 "  -p, --path        device/socket path (the default for virtio-serial is:\n"
+"                    %s,\n"
+"                    the default for isa-serial is:\n"
 "                    %s)\n"
 "  -l, --logfile     set logfile path, logs to stderr by default\n"
 "  -f, --pidfile     specify pidfile (default is %s)\n"
@@ -215,7 +219,8 @@
 "  -h, --help        display this help and exit\n"
 "\n"
 "Report bugs to <mdroth@linux.vnet.ibm.com>\n"
-    , cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, dfl_pathnames.pidfile,
+    , cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_SERIAL_PATH_DEFAULT,
+    dfl_pathnames.pidfile,
 #ifdef CONFIG_FSFREEZE
     QGA_FSFREEZE_HOOK_DEFAULT,
 #endif
@@ -659,12 +664,16 @@
     }
 
     if (path == NULL) {
-        if (strcmp(method, "virtio-serial") != 0) {
+        if (strcmp(method, "virtio-serial") == 0 ) {
+            /* try the default path for the virtio-serial port */
+            path = QGA_VIRTIO_PATH_DEFAULT;
+        } else if (strcmp(method, "isa-serial") == 0){
+            /* try the default path for the serial port - COM1 */
+            path = QGA_SERIAL_PATH_DEFAULT;
+        } else {
             g_critical("must specify a path for this channel");
             return false;
         }
-        /* try the default path for the virtio-serial port */
-        path = QGA_VIRTIO_PATH_DEFAULT;
     }
 
     if (strcmp(method, "virtio-serial") == 0) {
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 245f968..80edca1 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -120,17 +120,18 @@
 # This command tries to set guest time to the given value,
 # then sets the Hardware Clock to the current System Time.
 # This will make it easier for a guest to resynchronize
-# without waiting for NTP.
+# without waiting for NTP. If no @time is specified, then
+# the time to set is read from RTC.
 #
-# @time: time of nanoseconds, relative to the Epoch of
-#        1970-01-01 in UTC.
+# @time: #optional time of nanoseconds, relative to the Epoch
+#        of 1970-01-01 in UTC.
 #
 # Returns: Nothing on success.
 #
 # Since: 1.5
 ##
 { 'command': 'guest-set-time',
-  'data': { 'time': 'int' } }
+  'data': { '*time': 'int' } }
 
 ##
 # @GuestAgentCommandInfo:
diff --git a/qga/vss-win32/provider.cpp b/qga/vss-win32/provider.cpp
index bf42b5e..d5129f8 100644
--- a/qga/vss-win32/provider.cpp
+++ b/qga/vss-win32/provider.cpp
@@ -278,7 +278,9 @@
     VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
     BOOL bForceDelete, LONG *plDeletedSnapshots, VSS_ID *pNondeletedSnapshotID)
 {
-    return E_NOTIMPL;
+    *plDeletedSnapshots = 0;
+    *pNondeletedSnapshotID = SourceObjectId;
+    return S_OK;
 }
 
 STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot(
@@ -291,8 +293,17 @@
 STDMETHODIMP CQGAVssProvider::IsVolumeSupported(
     VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider)
 {
-    *pbSupportedByThisProvider = TRUE;
+    HANDLE hEventFrozen;
 
+    /* Check if a requester is qemu-ga by whether an event is created */
+    hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
+    if (!hEventFrozen) {
+        *pbSupportedByThisProvider = FALSE;
+        return S_OK;
+    }
+    CloseHandle(hEventFrozen);
+
+    *pbSupportedByThisProvider = TRUE;
     return S_OK;
 }
 
@@ -342,18 +353,18 @@
     HANDLE hEventFrozen, hEventThaw, hEventTimeout;
 
     hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
-    if (hEventFrozen == INVALID_HANDLE_VALUE) {
+    if (!hEventFrozen) {
         return E_FAIL;
     }
 
     hEventThaw = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_THAW);
-    if (hEventThaw == INVALID_HANDLE_VALUE) {
+    if (!hEventThaw) {
         CloseHandle(hEventFrozen);
         return E_FAIL;
     }
 
     hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT);
-    if (hEventTimeout == INVALID_HANDLE_VALUE) {
+    if (!hEventTimeout) {
         CloseHandle(hEventFrozen);
         CloseHandle(hEventThaw);
         return E_FAIL;
diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp
index 1e8dd3d..922e74d 100644
--- a/qga/vss-win32/requester.cpp
+++ b/qga/vss-win32/requester.cpp
@@ -50,10 +50,6 @@
 
 STDAPI requester_init(void)
 {
-    vss_ctx.hEventFrozen =  INVALID_HANDLE_VALUE;
-    vss_ctx.hEventThaw = INVALID_HANDLE_VALUE;
-    vss_ctx.hEventTimeout = INVALID_HANDLE_VALUE;
-
     COMInitializer initializer; /* to call CoInitializeSecurity */
     HRESULT hr = CoInitializeSecurity(
         NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
@@ -94,17 +90,17 @@
 
 static void requester_cleanup(void)
 {
-    if (vss_ctx.hEventFrozen != INVALID_HANDLE_VALUE) {
+    if (vss_ctx.hEventFrozen) {
         CloseHandle(vss_ctx.hEventFrozen);
-        vss_ctx.hEventFrozen = INVALID_HANDLE_VALUE;
+        vss_ctx.hEventFrozen = NULL;
     }
-    if (vss_ctx.hEventThaw != INVALID_HANDLE_VALUE) {
+    if (vss_ctx.hEventThaw) {
         CloseHandle(vss_ctx.hEventThaw);
-        vss_ctx.hEventThaw = INVALID_HANDLE_VALUE;
+        vss_ctx.hEventThaw = NULL;
     }
-    if (vss_ctx.hEventTimeout != INVALID_HANDLE_VALUE) {
+    if (vss_ctx.hEventTimeout) {
         CloseHandle(vss_ctx.hEventTimeout);
-        vss_ctx.hEventTimeout = INVALID_HANDLE_VALUE;
+        vss_ctx.hEventTimeout = NULL;
     }
     if (vss_ctx.pAsyncSnapshot) {
         vss_ctx.pAsyncSnapshot->Release();
@@ -256,6 +252,32 @@
 
     CoInitialize(NULL);
 
+    /* Allow unrestricted access to events */
+    InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
+    SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
+    sa.nLength = sizeof(sa);
+    sa.lpSecurityDescriptor = &sd;
+    sa.bInheritHandle = FALSE;
+
+    vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN);
+    if (!vss_ctx.hEventFrozen) {
+        err_set(errset, GetLastError(), "failed to create event %s",
+                EVENT_NAME_FROZEN);
+        goto out;
+    }
+    vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW);
+    if (!vss_ctx.hEventThaw) {
+        err_set(errset, GetLastError(), "failed to create event %s",
+                EVENT_NAME_THAW);
+        goto out;
+    }
+    vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT);
+    if (!vss_ctx.hEventTimeout) {
+        err_set(errset, GetLastError(), "failed to create event %s",
+                EVENT_NAME_TIMEOUT);
+        goto out;
+    }
+
     assert(pCreateVssBackupComponents != NULL);
     hr = pCreateVssBackupComponents(&vss_ctx.pVssbc);
     if (FAILED(hr)) {
@@ -366,32 +388,6 @@
         goto out;
     }
 
-    /* Allow unrestricted access to events */
-    InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
-    SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
-    sa.nLength = sizeof(sa);
-    sa.lpSecurityDescriptor = &sd;
-    sa.bInheritHandle = FALSE;
-
-    vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN);
-    if (vss_ctx.hEventFrozen == INVALID_HANDLE_VALUE) {
-        err_set(errset, GetLastError(), "failed to create event %s",
-                EVENT_NAME_FROZEN);
-        goto out;
-    }
-    vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW);
-    if (vss_ctx.hEventThaw == INVALID_HANDLE_VALUE) {
-        err_set(errset, GetLastError(), "failed to create event %s",
-                EVENT_NAME_THAW);
-        goto out;
-    }
-    vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT);
-    if (vss_ctx.hEventTimeout == INVALID_HANDLE_VALUE) {
-        err_set(errset, GetLastError(), "failed to create event %s",
-                EVENT_NAME_TIMEOUT);
-        goto out;
-    }
-
     /*
      * Start VSS quiescing operations.
      * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
@@ -443,7 +439,7 @@
 {
     COMPointer<IVssAsync> pAsync;
 
-    if (vss_ctx.hEventThaw == INVALID_HANDLE_VALUE) {
+    if (!vss_ctx.hEventThaw) {
         /*
          * In this case, DoSnapshotSet is aborted or not started,
          * and no volumes must be frozen. We return without an error.