File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c |
Location: | line 162, column 17 |
Description: | Potential buffer overflow. Replace with 'sizeof(dtString) - strlen(dtString) - 1' or use a safer 'strlcat' API |
1 | #include "xmlrpc_config.h" |
2 | |
3 | #define _XOPEN_SOURCE700 600 /* Make sure strdup() is in <string.h> */ |
4 | |
5 | #include <time.h> |
6 | #include <stdlib.h> |
7 | #include <string.h> |
8 | #include <ctype.h> |
9 | #include <assert.h> |
10 | #include <stdio.h> |
11 | #if MSVCRT0 |
12 | #include <windows.h> |
13 | #endif |
14 | |
15 | #include "bool.h" |
16 | #include "mallocvar.h" |
17 | |
18 | #include "xmlrpc-c/c_util.h" |
19 | #include "xmlrpc-c/base.h" |
20 | #include "xmlrpc-c/base_int.h" |
21 | #include "xmlrpc-c/string_int.h" |
22 | #include "xmlrpc-c/time_int.h" |
23 | |
24 | |
25 | #if HAVE_REGEX1 |
26 | #include <regex.h> |
27 | #endif |
28 | |
29 | #if MSVCRT0 |
30 | |
31 | static const __int64 SECS_BETWEEN_EPOCHS = 11644473600; |
32 | static const __int64 SECS_TO_100NS = 10000000; /* 10^7 */ |
33 | |
34 | |
35 | void |
36 | UnixTimeToFileTime(time_t const t, |
37 | LPFILETIME const pft) { |
38 | |
39 | int64_t const ll = |
40 | Int32x32To64(t, SECS_TO_100NS) + SECS_BETWEEN_EPOCHS * SECS_TO_100NS; |
41 | |
42 | pft->dwLowDateTime = (DWORD)ll; |
43 | pft->dwHighDateTime = (DWORD)(ll >> 32); |
44 | } |
45 | |
46 | |
47 | |
48 | void |
49 | UnixTimeToSystemTime(time_t const t, |
50 | LPSYSTEMTIME const pst) { |
51 | FILETIME ft; |
52 | |
53 | UnixTimeToFileTime(t, &ft); |
54 | FileTimeToSystemTime(&ft, pst); |
55 | } |
56 | |
57 | |
58 | |
59 | static void |
60 | UnixTimeFromFileTime(xmlrpc_env * const envP, |
61 | LPFILETIME const pft, |
62 | time_t * const timeValueP) { |
63 | |
64 | int64_t const WinEpoch100Ns = |
65 | ((int64_t)pft->dwHighDateTime << 32) + pft->dwLowDateTime; |
66 | int64_t const unixEpoch100Ns = |
67 | WinEpoch100Ns - (SECS_BETWEEN_EPOCHS * SECS_TO_100NS); |
68 | int64_t const unixEpochSeconds = |
69 | unixEpoch100Ns / SECS_TO_100NS; |
70 | |
71 | if ((time_t)unixEpochSeconds != unixEpochSeconds) { |
72 | /* Value is too big for a time_t; fail. */ |
73 | xmlrpc_faultf(envP, "Does not indicate a valid date"); |
74 | *timeValueP = (time_t)(-1); |
75 | } else |
76 | *timeValueP = (time_t)unixEpochSeconds; |
77 | } |
78 | |
79 | |
80 | |
81 | static void |
82 | UnixTimeFromSystemTime(xmlrpc_env * const envP, |
83 | LPSYSTEMTIME const pst, |
84 | time_t * const timeValueP) { |
85 | FILETIME filetime; |
86 | |
87 | SystemTimeToFileTime(pst, &filetime); |
88 | UnixTimeFromFileTime(envP, &filetime, timeValueP); |
89 | } |
90 | |
91 | #endif /* MSVCRT */ |
92 | |
93 | |
94 | |
95 | static void |
96 | validateDatetimeType(xmlrpc_env * const envP, |
97 | const xmlrpc_value * const valueP) { |
98 | |
99 | if (valueP->_type != XMLRPC_TYPE_DATETIME) { |
100 | xmlrpc_env_set_fault_formatted( |
101 | envP, XMLRPC_TYPE_ERROR(-501), "Value of type %s supplied where " |
102 | "type %s was expected.", |
103 | xmlrpc_type_name(valueP->_type), |
104 | xmlrpc_type_name(XMLRPC_TYPE_DATETIME)); |
105 | } |
106 | } |
107 | |
108 | |
109 | |
110 | void |
111 | xmlrpc_read_datetime(xmlrpc_env * const envP, |
112 | const xmlrpc_value * const valueP, |
113 | xmlrpc_datetime * const dtP) { |
114 | |
115 | validateDatetimeType(envP, valueP); |
116 | if (!envP->fault_occurred) { |
117 | *dtP = valueP->_value.dt; |
118 | } |
119 | } |
120 | |
121 | |
122 | |
123 | void |
124 | xmlrpc_read_datetime_str(xmlrpc_env * const envP, |
125 | const xmlrpc_value * const valueP, |
126 | const char ** const stringValueP) { |
127 | /*---------------------------------------------------------------------------- |
128 | This exists for backward compatibility. No normal modern program would |
129 | want to see a datetime value in this format. Note that the format isn't |
130 | even ISO 8601 -- it's a bizarre hybrid of two ISO 8601 formats. |
131 | |
132 | Do not extend this. |
133 | |
134 | This exists because Xmlrpc-c was at one time lazy and this was the only way |
135 | to extract the value. An xmlrpc_value in those days represented a datetime |
136 | with the actual XML-RPC wire format of a datetime, and this function simply |
137 | returned a copy of it. |
138 | -----------------------------------------------------------------------------*/ |
139 | validateDatetimeType(envP, valueP); |
140 | if (!envP->fault_occurred) { |
141 | time_t secs; |
142 | unsigned int usecs; |
143 | |
144 | xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs); |
145 | |
146 | if (!envP->fault_occurred) { |
147 | struct tm brokenTime; |
148 | char dtString[64]; |
149 | |
150 | xmlrpc_gmtime(secs, &brokenTime); |
151 | |
152 | /* Note that this format is NOT ISO 8601 -- it's a bizarre |
153 | hybrid of two ISO 8601 formats. |
154 | */ |
155 | strftime(dtString, sizeof(dtString), "%Y%m%dT%H:%M:%S", |
156 | &brokenTime); |
157 | |
158 | if (usecs != 0) { |
159 | char usecString[64]; |
160 | assert(usecs < 1000000)((usecs < 1000000) ? (void) (0) : __assert_fail ("usecs < 1000000" , "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 160, __PRETTY_FUNCTION__ )); |
161 | snprintf(usecString, sizeof(usecString), ".%06u", usecs); |
162 | STRSCAT(dtString, usecString)(__builtin_strncat ((dtString), (usecString), sizeof(dtString )-strlen(dtString)), *((dtString)+sizeof(dtString)-1) = '\0'); |
Potential buffer overflow. Replace with 'sizeof(dtString) - strlen(dtString) - 1' or use a safer 'strlcat' API | |
163 | } |
164 | |
165 | *stringValueP = strdup(dtString)(__extension__ (__builtin_constant_p (dtString) && (( size_t)(const void *)((dtString) + 1) - (size_t)(const void * )(dtString) == 1) ? (((const char *) (dtString))[0] == '\0' ? (char *) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len = strlen (dtString) + 1; char *__retval = (char *) malloc (__len ); if (__retval != ((void*)0)) __retval = (char *) memcpy (__retval , dtString, __len); __retval; })) : __strdup (dtString))); |
166 | if (*stringValueP == NULL((void*)0)) |
167 | xmlrpc_faultf(envP, |
168 | "Unable to allocate memory for datetime string"); |
169 | } |
170 | } |
171 | } |
172 | |
173 | |
174 | |
175 | void |
176 | xmlrpc_read_datetime_str_old(xmlrpc_env * const envP, |
177 | const xmlrpc_value * const valueP, |
178 | const char ** const stringValueP) { |
179 | |
180 | assert(valueP->_cache)((valueP->_cache) ? (void) (0) : __assert_fail ("valueP->_cache" , "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 180, __PRETTY_FUNCTION__ )); |
181 | |
182 | validateDatetimeType(envP, valueP); |
183 | if (!envP->fault_occurred) { |
184 | const char ** const readBufferP = valueP->_cache; |
185 | |
186 | if (!*readBufferP) |
187 | /* Nobody's asked for the internal buffer before. Set it up. */ |
188 | xmlrpc_read_datetime_str(envP, valueP, readBufferP); |
189 | |
190 | *stringValueP = *readBufferP; |
191 | } |
192 | } |
193 | |
194 | |
195 | |
196 | void |
197 | xmlrpc_read_datetime_usec(xmlrpc_env * const envP, |
198 | const xmlrpc_value * const valueP, |
199 | time_t * const secsP, |
200 | unsigned int * const usecsP) { |
201 | |
202 | validateDatetimeType(envP, valueP); |
203 | |
204 | if (!envP->fault_occurred) { |
205 | if (valueP->_value.dt.Y < 1970) |
206 | xmlrpc_faultf(envP, "Year (%u) is too early to represent as " |
207 | "a standard Unix time", |
208 | valueP->_value.dt.Y); |
209 | else { |
210 | struct tm brokenTime; |
211 | const char * error; |
212 | |
213 | brokenTime.tm_sec = valueP->_value.dt.s; |
214 | brokenTime.tm_min = valueP->_value.dt.m; |
215 | brokenTime.tm_hour = valueP->_value.dt.h; |
216 | brokenTime.tm_mday = valueP->_value.dt.D; |
217 | brokenTime.tm_mon = valueP->_value.dt.M - 1; |
218 | brokenTime.tm_year = valueP->_value.dt.Y - 1900; |
219 | |
220 | xmlrpc_timegm(&brokenTime, secsP, &error); |
221 | |
222 | if (error) { |
223 | /* Ideally, this wouldn't be possible - it wouldn't be |
224 | possible to create an xmlrpc_value that doesn't actually |
225 | represent a real datetime. But today, we're lazy and |
226 | don't fully validate incoming XML-RPC <dateTime.iso8601> |
227 | elements, and we also have the legacy |
228 | xmlrpc_datetime_new_str() constructor to which the user |
229 | may feed garbage. |
230 | |
231 | We should tighten that up and then simply assert here that |
232 | xmlrpc_timegm() succeeded. |
233 | */ |
234 | xmlrpc_env_set_fault_formatted(envP, XMLRPC_PARSE_ERROR(-503), |
235 | "A datetime received in an XML-RPC message " |
236 | "or generated with legacy Xmlrpc-c facilities " |
237 | "does not validly describe a datetime. %s", |
238 | error); |
239 | xmlrpc_strfree(error); |
240 | } else |
241 | *usecsP = valueP->_value.dt.u; |
242 | } |
243 | } |
244 | } |
245 | |
246 | |
247 | |
248 | void |
249 | xmlrpc_read_datetime_sec(xmlrpc_env * const envP, |
250 | const xmlrpc_value * const valueP, |
251 | time_t * const timeValueP) { |
252 | |
253 | unsigned int usecs; |
254 | |
255 | xmlrpc_read_datetime_usec(envP, valueP, timeValueP, &usecs); |
256 | } |
257 | |
258 | |
259 | |
260 | #if XMLRPC_HAVE_TIMEVAL1 |
261 | |
262 | void |
263 | xmlrpc_read_datetime_timeval(xmlrpc_env * const envP, |
264 | const xmlrpc_value * const valueP, |
265 | struct timeval * const timeValueP) { |
266 | |
267 | time_t secs; |
268 | unsigned int usecs; |
269 | |
270 | xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs); |
271 | |
272 | timeValueP->tv_sec = secs; |
273 | timeValueP->tv_usec = usecs; |
274 | } |
275 | #endif |
276 | |
277 | |
278 | |
279 | #if XMLRPC_HAVE_TIMESPEC1 |
280 | |
281 | void |
282 | xmlrpc_read_datetime_timespec(xmlrpc_env * const envP, |
283 | const xmlrpc_value * const valueP, |
284 | struct timespec * const timeValueP) { |
285 | |
286 | time_t secs; |
287 | unsigned int usecs; |
288 | |
289 | xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs); |
290 | |
291 | timeValueP->tv_sec = secs; |
292 | timeValueP->tv_nsec = usecs * 1000; |
293 | } |
294 | #endif |
295 | |
296 | |
297 | |
298 | xmlrpc_value * |
299 | xmlrpc_datetime_new(xmlrpc_env * const envP, |
300 | xmlrpc_datetime const dt) { |
301 | |
302 | xmlrpc_value * valP; |
303 | |
304 | const char ** readBufferP; |
305 | |
306 | MALLOCVAR(readBufferP)readBufferP = malloc(sizeof(*readBufferP)); |
307 | |
308 | if (!readBufferP) |
309 | xmlrpc_faultf(envP, "Couldn't get memory for the cache part of the " |
310 | "XML-RPC datetime value object"); |
311 | |
312 | else { |
313 | *readBufferP = NULL((void*)0); |
314 | |
315 | xmlrpc_createXmlrpcValue(envP, &valP); |
316 | |
317 | if (!envP->fault_occurred) { |
318 | valP->_type = XMLRPC_TYPE_DATETIME; |
319 | |
320 | valP->_value.dt = dt; |
321 | |
322 | valP->_cache = readBufferP; |
323 | } |
324 | if (envP->fault_occurred) |
325 | free(readBufferP); |
326 | } |
327 | return valP; |
328 | } |
329 | |
330 | |
331 | |
332 | static void |
333 | parseDatetimeString(const char * const datetimeString, |
334 | xmlrpc_datetime * const dtP) { |
335 | |
336 | size_t const dtStrlen = strlen(datetimeString); |
337 | |
338 | char year[4+1]; |
339 | char month[2+1]; |
340 | char day[2+1]; |
341 | char hour[2+1]; |
342 | char minute[2+1]; |
343 | char second[2+1]; |
344 | |
345 | /* Because we require input to be valid: */ |
346 | assert(dtStrlen >= 17 && dtStrlen != 18 && dtStrlen <= 24)((dtStrlen >= 17 && dtStrlen != 18 && dtStrlen <= 24) ? (void) (0) : __assert_fail ("dtStrlen >= 17 && dtStrlen != 18 && dtStrlen <= 24" , "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 346, __PRETTY_FUNCTION__ )); |
347 | |
348 | year[0] = datetimeString[ 0]; |
349 | year[1] = datetimeString[ 1]; |
350 | year[2] = datetimeString[ 2]; |
351 | year[3] = datetimeString[ 3]; |
352 | year[4] = '\0'; |
353 | |
354 | month[0] = datetimeString[ 4]; |
355 | month[1] = datetimeString[ 5]; |
356 | month[2] = '\0'; |
357 | |
358 | day[0] = datetimeString[ 6]; |
359 | day[1] = datetimeString[ 7]; |
360 | day[2] = '\0'; |
361 | |
362 | assert(datetimeString[ 8] == 'T')((datetimeString[ 8] == 'T') ? (void) (0) : __assert_fail ("datetimeString[ 8] == 'T'" , "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 362, __PRETTY_FUNCTION__ )); |
363 | |
364 | hour[0] = datetimeString[ 9]; |
365 | hour[1] = datetimeString[10]; |
366 | hour[2] = '\0'; |
367 | |
368 | assert(datetimeString[11] == ':')((datetimeString[11] == ':') ? (void) (0) : __assert_fail ("datetimeString[11] == ':'" , "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 368, __PRETTY_FUNCTION__ )); |
369 | |
370 | minute[0] = datetimeString[12]; |
371 | minute[1] = datetimeString[13]; |
372 | minute[2] = '\0'; |
373 | |
374 | assert(datetimeString[14] == ':')((datetimeString[14] == ':') ? (void) (0) : __assert_fail ("datetimeString[14] == ':'" , "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 374, __PRETTY_FUNCTION__ )); |
375 | |
376 | second[0] = datetimeString[15]; |
377 | second[1] = datetimeString[16]; |
378 | second[2] = '\0'; |
379 | |
380 | if (dtStrlen > 17) { |
381 | size_t const pad = 24 - dtStrlen; |
382 | size_t i; |
383 | |
384 | dtP->u = atoi(&datetimeString[18]); |
385 | for (i = 0; i < pad; ++i) |
386 | dtP->u *= 10; |
387 | } else |
388 | dtP->u = 0; |
389 | |
390 | dtP->Y = atoi(year); |
391 | dtP->M = atoi(month); |
392 | dtP->D = atoi(day); |
393 | dtP->h = atoi(hour); |
394 | dtP->m = atoi(minute); |
395 | dtP->s = atoi(second); |
396 | } |
397 | |
398 | |
399 | |
400 | static void |
401 | validateFirst17(xmlrpc_env * const envP, |
402 | const char * const dt) { |
403 | /*---------------------------------------------------------------------------- |
404 | Assuming 'dt' is at least 17 characters long, validate that the first |
405 | 17 characters are a valid XML-RPC datetime, e.g. |
406 | "20080628T16:35:02" |
407 | -----------------------------------------------------------------------------*/ |
408 | unsigned int i; |
409 | |
410 | for (i = 0; i < 8 && !envP->fault_occurred; ++i) |
411 | if (!isdigit(dt[i])((*__ctype_b_loc ())[(int) ((dt[i]))] & (unsigned short int ) _ISdigit)) |
412 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[i]); |
413 | |
414 | if (dt[8] != 'T') |
415 | xmlrpc_faultf(envP, "9th character is '%c', not 'T'", dt[8]); |
416 | if (!isdigit(dt[9])((*__ctype_b_loc ())[(int) ((dt[9]))] & (unsigned short int ) _ISdigit)) |
417 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[9]); |
418 | if (!isdigit(dt[10])((*__ctype_b_loc ())[(int) ((dt[10]))] & (unsigned short int ) _ISdigit)) |
419 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[10]); |
420 | if (dt[11] != ':') |
421 | xmlrpc_faultf(envP, "Not a colon: '%c'", dt[11]); |
422 | if (!isdigit(dt[12])((*__ctype_b_loc ())[(int) ((dt[12]))] & (unsigned short int ) _ISdigit)) |
423 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[12]); |
424 | if (!isdigit(dt[13])((*__ctype_b_loc ())[(int) ((dt[13]))] & (unsigned short int ) _ISdigit)) |
425 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[13]); |
426 | if (dt[14] != ':') |
427 | xmlrpc_faultf(envP, "Not a colon: '%c'", dt[14]); |
428 | if (!isdigit(dt[15])((*__ctype_b_loc ())[(int) ((dt[15]))] & (unsigned short int ) _ISdigit)) |
429 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[15]); |
430 | if (!isdigit(dt[16])((*__ctype_b_loc ())[(int) ((dt[16]))] & (unsigned short int ) _ISdigit)) |
431 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[16]); |
432 | } |
433 | |
434 | |
435 | |
436 | static void |
437 | validateFractionalSeconds(xmlrpc_env * const envP, |
438 | const char * const dt) { |
439 | /*---------------------------------------------------------------------------- |
440 | Validate the fractional seconds part of the XML-RPC datetime string |
441 | 'dt', if any. That's the decimal point and everything following |
442 | it. |
443 | -----------------------------------------------------------------------------*/ |
444 | if (strlen(dt) > 17) { |
445 | if (dt[17] != '.') { |
446 | xmlrpc_faultf(envP, "'%c' where only a period is valid", dt[17]); |
447 | } else { |
448 | if (dt[18] == '\0') |
449 | xmlrpc_faultf(envP, "Nothing after decimal point"); |
450 | else { |
451 | unsigned int i; |
452 | for (i = 18; dt[i] != '\0' && !envP->fault_occurred; ++i) { |
453 | if (!isdigit(dt[i])((*__ctype_b_loc ())[(int) ((dt[i]))] & (unsigned short int ) _ISdigit)) |
454 | xmlrpc_faultf(envP, |
455 | "Non-digit in fractional seconds: '%c'", |
456 | dt[i]); |
457 | } |
458 | } |
459 | } |
460 | } |
461 | } |
462 | |
463 | |
464 | |
465 | static void |
466 | validateFormat(xmlrpc_env * const envP, |
467 | const char * const dt) { |
468 | |
469 | if (strlen(dt) < 17) |
470 | xmlrpc_faultf(envP, |
471 | "Invalid length of %u of datetime string. " |
472 | "Must be at least 17 characters", |
473 | (unsigned)strlen(dt)); |
474 | else { |
475 | validateFirst17(envP, dt); |
476 | |
477 | if (!envP->fault_occurred) |
478 | validateFractionalSeconds(envP, dt); |
479 | } |
480 | } |
481 | |
482 | |
483 | |
484 | /* Microsoft Visual C in debug mode produces code that complains about |
485 | returning an undefined value from xmlrpc_datetime_new_str(). It's a bogus |
486 | complaint, because this function is defined to return nothing meaningful |
487 | those cases. So we disable the check. |
488 | */ |
489 | #pragma runtime_checks("u", off) |
490 | |
491 | |
492 | |
493 | xmlrpc_value * |
494 | xmlrpc_datetime_new_str(xmlrpc_env * const envP, |
495 | const char * const datetimeString) { |
496 | /*---------------------------------------------------------------------------- |
497 | This exists only for backward compatibility. Originally, this was the |
498 | only way to create a datetime XML-RPC value, because we had a really |
499 | lazy implementation of XML-RPC serialization and parsing (basically, the |
500 | user did it!). |
501 | |
502 | Do not extend this. The user should use more normal C representations |
503 | of datetimes. |
504 | -----------------------------------------------------------------------------*/ |
505 | xmlrpc_value * retval; |
506 | |
507 | validateFormat(envP, datetimeString); |
508 | if (!envP->fault_occurred) { |
509 | xmlrpc_datetime dt; |
510 | |
511 | parseDatetimeString(datetimeString, &dt); |
512 | |
513 | /* Note that parseDatetimeString() can generate an invalid datetime |
514 | value, e.g. Hour 25 or February 30. Ideally, we would catch that |
515 | here, but due to laziness, we simply accept the possibility of |
516 | invalid xmlrpc_datetime in xmlrpc_value and whoever uses the the |
517 | xmlrpc_value has to deal with it. |
518 | */ |
519 | retval = xmlrpc_datetime_new(envP, dt); |
520 | } |
521 | |
522 | return retval; |
523 | } |
524 | |
525 | |
526 | |
527 | #pragma runtime_checks("u", restore) |
528 | |
529 | |
530 | |
531 | xmlrpc_value * |
532 | xmlrpc_datetime_new_usec(xmlrpc_env * const envP, |
533 | time_t const secs, |
534 | unsigned int const usecs) { |
535 | |
536 | xmlrpc_value * valueP; |
537 | |
538 | if (usecs >= 1000000) |
539 | xmlrpc_faultf(envP, "Number of fractional microseconds must be less " |
540 | "than one million. You specified %u", usecs); |
541 | else { |
542 | struct tm brokenTime; |
543 | xmlrpc_datetime dt; |
544 | |
545 | xmlrpc_gmtime(secs, &brokenTime); |
546 | |
547 | dt.s = brokenTime.tm_sec; |
548 | dt.m = brokenTime.tm_min; |
549 | dt.h = brokenTime.tm_hour; |
550 | dt.D = brokenTime.tm_mday; |
551 | dt.M = brokenTime.tm_mon + 1; |
552 | dt.Y = 1900 + brokenTime.tm_year; |
553 | dt.u = usecs; |
554 | |
555 | valueP = xmlrpc_datetime_new(envP, dt); |
556 | } |
557 | return valueP; |
558 | } |
559 | |
560 | |
561 | |
562 | xmlrpc_value * |
563 | xmlrpc_datetime_new_sec(xmlrpc_env * const envP, |
564 | time_t const value) { |
565 | |
566 | return xmlrpc_datetime_new_usec(envP, value, 0); |
567 | } |
568 | |
569 | |
570 | |
571 | #if XMLRPC_HAVE_TIMEVAL1 |
572 | |
573 | xmlrpc_value * |
574 | xmlrpc_datetime_new_timeval(xmlrpc_env * const envP, |
575 | struct timeval const value) { |
576 | |
577 | return xmlrpc_datetime_new_usec(envP, value.tv_sec, value.tv_usec); |
578 | } |
579 | #endif |
580 | |
581 | |
582 | |
583 | #if XMLRPC_HAVE_TIMESPEC1 |
584 | |
585 | xmlrpc_value * |
586 | xmlrpc_datetime_new_timespec(xmlrpc_env * const envP, |
587 | struct timespec const value) { |
588 | |
589 | return xmlrpc_datetime_new_usec(envP, value.tv_sec, value.tv_nsec/1000); |
590 | } |
591 | #endif |
592 | |
593 | |
594 | |
595 | void |
596 | xmlrpc_destroyDatetime(xmlrpc_value * const datetimeP) { |
597 | |
598 | const char ** const readBufferP = datetimeP->_cache; |
599 | |
600 | if (*readBufferP) |
601 | xmlrpc_strfree(*readBufferP); |
602 | |
603 | free(datetimeP->_cache); |
604 | } |