The g_date_time_new_from_iso8601() function was introduced as
a replacement for strptime in
commit 810613a60efe3924c536b3663246900bc08910a5
Author: Daniel P. Berrangé <berrange(a)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