[libvirt] [PATCH 5/7] src: remove use of g_date_time_new_from_iso8601 function

Daniel P. Berrangé berrange at redhat.com
Mon Jan 6 17:26:53 UTC 2020


The g_date_time_new_from_iso8601() function was introduced as
a replacement for strptime in

  commit 810613a60efe3924c536b3663246900bc08910a5
  Author: Daniel P. Berrangé <berrange at redhat.com>
  Date:   Mon Dec 23 15:37:26 2019 +0000

    src: replace strptime()/timegm()/mktime() with GDateTime APIs set

Unfortunately g_date_time_new_from_iso8601 isn't available until
glib 2.56, and backporting it requires alot of code copying and
poking at private glib structs.

This reverts domain_conf.c back to its original parsing logic prior
to 810613a60efe3924c536b3663246900bc08910a5, but using g_date_time_new()
instead of gmtime(). The other files are then adapted to follow a
similar approach.
---
 src/conf/domain_conf.c | 28 ++++++++++++++++-----
 src/esx/esx_vi_types.c | 56 +++++++++++++++++++++++++++++++++++++-----
 src/vz/vz_sdk.c        | 24 ++++++++++++++----
 3 files changed, 91 insertions(+), 17 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index ee33b7caf0..69967d4cb7 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -13675,15 +13675,31 @@ virDomainGraphicsAuthDefParseXML(xmlNodePtr node,
     if (validTo) {
         g_autoptr(GDateTime) then = NULL;
         g_autoptr(GTimeZone) tz = g_time_zone_new_utc();
-
-        then = g_date_time_new_from_iso8601(validTo, tz);
-        if (!then) {
-            virReportError(VIR_ERR_INVALID_ARG,
-                           _("password validity time '%s' values out of range"), validTo);
+        char *tmp;
+        int year, mon, mday, hour, min, sec;
+
+        /* Expect: YYYY-MM-DDTHH:MM:SS (%d-%d-%dT%d:%d:%d)  eg 2010-11-28T14:29:01 */
+        if (/* year */
+            virStrToLong_i(validTo, &tmp, 10, &year) < 0 || *tmp != '-' ||
+            /* month */
+            virStrToLong_i(tmp+1, &tmp, 10, &mon) < 0 || *tmp != '-' ||
+            /* day */
+            virStrToLong_i(tmp+1, &tmp, 10, &mday) < 0 || *tmp != 'T' ||
+            /* hour */
+            virStrToLong_i(tmp+1, &tmp, 10, &hour) < 0 || *tmp != ':' ||
+            /* minute */
+            virStrToLong_i(tmp+1, &tmp, 10, &min) < 0 || *tmp != ':' ||
+            /* second */
+            virStrToLong_i(tmp+1, &tmp, 10, &sec) < 0 || *tmp != '\0') {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("cannot parse password validity time '%s', expect YYYY-MM-DDTHH:MM:SS"),
+                           validTo);
+            VIR_FREE(def->passwd);
             return -1;
         }
 
-        def->validTo = (int)g_date_time_to_unix(then);
+        then = g_date_time_new(tz, year, mon, mday, hour, min, sec);
+        def->validTo = (time_t)g_date_time_to_unix(then);
         def->expires = true;
     }
 
diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c
index 434313dfa4..ad40ddf54b 100644
--- a/src/esx/esx_vi_types.c
+++ b/src/esx/esx_vi_types.c
@@ -1473,8 +1473,10 @@ int
 esxVI_DateTime_ConvertToCalendarTime(esxVI_DateTime *dateTime,
                                      long long *secondsSinceEpoch)
 {
+    char *tmp;
     g_autoptr(GDateTime) then = NULL;
     g_autoptr(GTimeZone) tz = NULL;
+    int year, mon, mday, hour, min, sec, milliseconds;
 
     if (!dateTime || !secondsSinceEpoch) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
@@ -1489,22 +1491,64 @@ esxVI_DateTime_ConvertToCalendarTime(esxVI_DateTime *dateTime,
      *
      * map negative years to 0, since the base for time_t is the year 1970.
      */
-    if (*(dateTime->value) == '-') {
+    if (dateTime->value[0] == '-') {
         *secondsSinceEpoch = 0;
         return 0;
     }
 
-    tz = g_time_zone_new_utc();
-    then = g_date_time_new_from_iso8601(dateTime->value, tz);
-
-    if (!then) {
+    if (/* year */
+        virStrToLong_i(dateTime->value, &tmp, 10, &year) < 0 || *tmp != '-' ||
+        /* month */
+        virStrToLong_i(tmp+1, &tmp, 10, &mon) < 0 || *tmp != '-' ||
+        /* day */
+        virStrToLong_i(tmp+1, &tmp, 10, &mday) < 0 || *tmp != 'T' ||
+        /* hour */
+        virStrToLong_i(tmp+1, &tmp, 10, &hour) < 0 || *tmp != ':' ||
+        /* minute */
+        virStrToLong_i(tmp+1, &tmp, 10, &min) < 0 || *tmp != ':' ||
+        /* second */
+        virStrToLong_i(tmp+1, &tmp, 10, &sec) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("xsd:dateTime value '%s' has unexpected format"),
                        dateTime->value);
         return -1;
     }
 
-    *secondsSinceEpoch = g_date_time_to_unix(then);
+    if (*tmp != '\0') {
+        /* skip .ssssss part if present */
+        if (*tmp == '.' &&
+            virStrToLong_i(tmp + 1, &tmp, 10, &milliseconds) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("xsd:dateTime value '%s' has unexpected format"),
+                           dateTime->value);
+            return -1;
+        }
+
+        /* parse timezone offset if present. if missing assume UTC */
+        if (*tmp == '+' || *tmp == '-') {
+            tz = g_time_zone_new(tmp);
+        } else if (STREQ(tmp, "Z")) {
+            tz = g_time_zone_new_utc();
+        } else {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("xsd:dateTime value '%s' has unexpected format"),
+                           dateTime->value);
+            return -1;
+        }
+    } else {
+        tz = g_time_zone_new_utc();
+    }
+
+    /*
+     * xsd:dateTime represents local time relative to the optional timezone
+     * given as offset. pretend the local time is in UTC and use timegm in
+     * order to avoid interference with the timezone to this computer.
+     * apply timezone correction afterwards, because it's simpler than
+     * handling all the possible over- and underflows when trying to apply
+     * it to the tm struct.
+     */
+    then = g_date_time_new(tz, year, mon, mday, hour, min, sec);
+    *secondsSinceEpoch = (long long)g_date_time_to_unix(then);
 
     return 0;
 }
diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c
index c98542c244..26e9e38729 100644
--- a/src/vz/vz_sdk.c
+++ b/src/vz/vz_sdk.c
@@ -4608,16 +4608,30 @@ static long long
 prlsdkParseDateTime(const char *str)
 {
     g_autoptr(GDateTime) then = NULL;
-    g_autoptr(GTimeZone) tz = g_time_zone_new_local();
-
-    then = g_date_time_new_from_iso8601(str, tz);
-    if (!then) {
+    g_autoptr(GTimeZone) tz = g_time_zone_new_utc();
+    char *tmp;
+    int year, mon, mday, hour, min, sec;
+
+    /* Expect: YYYY-MM-DD HH:MM:SS (%d-%d-%dT%d:%d:%d)  eg 2010-11-28 14:29:01 */
+    if (/* year */
+        virStrToLong_i(str, &tmp, 10, &year) < 0 || *tmp != '-' ||
+        /* month */
+        virStrToLong_i(tmp+1, &tmp, 10, &mon) < 0 || *tmp != '-' ||
+        /* day */
+        virStrToLong_i(tmp+1, &tmp, 10, &mday) < 0 || *tmp != ' ' ||
+        /* hour */
+        virStrToLong_i(tmp+1, &tmp, 10, &hour) < 0 || *tmp != ':' ||
+        /* minute */
+        virStrToLong_i(tmp+1, &tmp, 10, &min) < 0 || *tmp != ':' ||
+        /* second */
+        virStrToLong_i(tmp+1, &tmp, 10, &sec) < 0 || *tmp != '\0') {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unexpected DateTime format: '%s'"), str);
         return -1;
     }
 
-    return g_date_time_to_unix(then);
+    then = g_date_time_new(tz, year, mon, mday, hour, min, sec);
+    return (long long)g_date_time_to_unix(then);
 }
 
 static virDomainSnapshotObjListPtr
-- 
2.24.1




More information about the libvir-list mailing list