From fcea025d0e0c037348a1530cf82dfbb64a1995fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 6 Jan 2020 14:20:09 +0000 Subject: [PATCH] src: remove use of g_date_time_new_from_iso8601 function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The g_date_time_new_from_iso8601() function was introduced as a replacement for strptime in commit 810613a60efe3924c536b3663246900bc08910a5 Author: Daniel P. Berrangé 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. Reviewed-by: Pavel Hrdina Reviewed-by: Daniel Henrique Barboza Signed-off-by: Daniel P. Berrangé --- src/conf/domain_conf.c | 26 ++++++++++++++++---- src/esx/esx_vi_types.c | 56 +++++++++++++++++++++++++++++++++++++----- src/vz/vz_sdk.c | 22 ++++++++++++++--- 3 files changed, 89 insertions(+), 15 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(); + char *tmp; + int year, mon, mday, hour, min, sec; - 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); + /* 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(); + g_autoptr(GTimeZone) tz = g_time_zone_new_utc(); + char *tmp; + int year, mon, mday, hour, min, sec; - then = g_date_time_new_from_iso8601(str, tz); - if (!then) { + /* 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