/
datetime.c
452 lines (388 loc) · 11.7 KB
/
datetime.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
/*
* datetime.c
*
* (C) Copyright IBM Corp. 2013
*
* THIS FILE IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC LICENSE
* ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE
* CONSTITUTES RECIPIENTS ACCEPTANCE OF THE AGREEMENT.
*
* You can obtain a current copy of the Eclipse Public License from
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* Author: Frank Scheffler
* Contributions: Adrian Schuur <schuur@de.ibm.com>
*
* Description:
*
* CMPIDateTime implementation.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "native.h"
/*
* ! This structure stores the information needed to represent time for
* CMPI providers.
*/
struct native_datetime {
CMPIDateTime dt; /* !< the inheriting data structure */
int refCount;
int mem_state; /* !< states, whether this object is
* registered within the memory
* mangagement or represents a cloned
* object */
char cimDt[26];
};
static struct native_datetime *__new_datetime(int state, const char *cimDt,
CMPIStatus *rc);
/****************************************************************************/
// ! Releases a previously cloned CMPIDateTime object from memory.
/*
* ! To achieve this, the object is simply added to the thread-based
* memory management to be freed later.
*
* \param dt the object to be released
*
* \return CMPI_RC_OK.
*/
static CMPIStatus
__dtft_release(CMPIDateTime *dt)
{
struct native_datetime *ndt = (struct native_datetime *) dt;
if (ndt->mem_state && ndt->mem_state != MEM_RELEASED) {
memUnlinkEncObj(ndt->mem_state);
ndt->mem_state = MEM_RELEASED;
free(ndt);
CMReturn(CMPI_RC_OK);
}
CMReturn(CMPI_RC_ERR_FAILED);
}
// ! Clones an existing CMPIDateTime object.
/*
* ! The function simply calls __new_datetime() with the data fields
* extracted from dt.
*
* \param dt the object to be cloned \param rc return code pointer
*
* \return a copy of the given CMPIDateTime object that won't be freed
* from memory before calling __dtft_release().
*/
static CMPIDateTime *
__dtft_clone(const CMPIDateTime *dt, CMPIStatus *rc)
{
struct native_datetime *ndt = (struct native_datetime *) dt;
struct native_datetime *new =
__new_datetime(MEM_NOT_TRACKED, ndt->cimDt, rc);
return (CMPIDateTime *) new;
}
CMPIUint64
chars2bin(const char *string, CMPIStatus *rc)
{
/**
* \brief chars2bin(): Converts a string time to microseconds since epoch.
*
* includes the offset in the result, but uses the local timezone
* and DST settings. string is of the form:
* yyyymmddhhmmss mmmmmmsutc
* 20050503104354.000000:000
* 20080813104354.000000+500
* the : indicates that it is an interval.
*/
CMPIUint64 msecs,
secs;
CMPIBoolean interval;
char *str;
int offset = 0;
str = strdup(string);
interval = (str[21] == ':');
if ((str[21] == '+') || (str[21] == '-')) {
// If we found an offset in the timestamp
// convert it to seconds, and save it
offset = atoi(str + 21) * 60ULL;
}
str[21] = 0;
msecs = strtoull(str + 15, NULL, 10);
str[14] = 0;
secs = strtoull(str + 12, NULL, 10);
str[12] = 0;
secs += strtoull(str + 10, NULL, 10) * 60ULL;
str[10] = 0;
secs += strtoull(str + 8, NULL, 10) * 60ULL * 60ULL;
str[8] = 0;
if (interval) {
secs += strtoull(str, NULL, 10) * 60ULL * 60ULL * 24ULL;
msecs = msecs + (secs * 1000000ULL);
}
else {
struct tm tmp;
time_t sse;
memset(&tmp, 0, sizeof(struct tm));
tzset();
tmp.tm_mday = atoi(str + 6);
str[6] = 0;
tmp.tm_mon = atoi(str + 4) - 1;
str[4] = 0;
tmp.tm_year = atoi(str) - 1900;
if((sse = timegm(&tmp)) < 0) {
CMSetStatus(rc, CMPI_RC_ERR_INVALID_PARAMETER);
}
msecs = msecs + (secs * 1000000ULL);
msecs += (CMPIUint64) sse * 1000000ULL;
// Add in the offset
msecs -= offset * 1000000ULL;
}
free(str);
return msecs;
}
static void
bin2chars(CMPIUint64 msecs, CMPIBoolean interval, CMPIStatus *rc,
char *str_time)
{
/** /brief bin2chars(): Converts microseconds since epoch to a string time.
*
* Uses the current timezone as the basis for the conversion, but will determine
* if DST was in effect at the time in the input.
*/
time_t secs = msecs / 1000000ULL;
unsigned long usecs = msecs % 1000000ULL;
if (interval) {
unsigned long long useconds,
seconds,
mins,
hrs,
days;
/* ddddddddhhmmss.mmmmmm:000, at most 8 characters for day */
const unsigned long long day_limit = 99999999;
seconds = msecs / 1000000ULL;
useconds = msecs % 1000000ULL;
mins = seconds / 60ULL;
seconds %= 60ULL;
hrs = mins / 60ULL;
mins %= 60ULL;
/* Modify to avoid datetime string overflow when the time duration overflow */
days = ((hrs / 24ULL) > day_limit) ? day_limit : (hrs / 24ULL);
hrs %= 24ULL;
sprintf(str_time, "%8.8llu%2.2llu%2.2llu%2.2llu.%6.6llu:000",
days, hrs, mins, seconds, useconds);
}
else {
struct tm tm_time;
char us_utc_time[11];
if (localtime_r(&secs, &tm_time) == NULL) {
if (rc)
CMSetStatus(rc, CMPI_RC_ERR_FAILED);
return;
}
tzset();
snprintf(us_utc_time, 11, "%6.6ld%+4.3ld",
usecs, (tm_time.tm_isdst != 0) * 60 - timezone / 60);
strftime(str_time, 26, "%Y%m%d%H%M%S.", &tm_time);
strcat(str_time, us_utc_time);
}
}
// ! Extracts the binary time from the encapsulated CMPIDateTime object.
/*
* ! \param dt the native CMPIDateTime to be extracted. \param rc return
* code pointer
*
* \return an amount of microseconds.
*/
static CMPIUint64
__dtft_getBinaryFormat(const CMPIDateTime *dt, CMPIStatus *rc)
{
struct native_datetime *ndt = (struct native_datetime *) dt;
if (rc)
CMSetStatus(rc, CMPI_RC_OK);
return chars2bin(ndt->cimDt, rc);
}
// ! Gives back a string representation of the time object.
/*
* ! \param dt the native CMPIDateTime to be converted. \param rc return
* code pointer
*
* \return a string that has one of the following formats:
*
* - yyyymmddhhmmss.mmmmmmsutc (for absolute times) -
* ddddddddhhmmss.mmmmmm:000 (for time intervals)
*/
void
dateTime2chars(CMPIDateTime *dt, CMPIStatus *rc, char *str_time)
{
struct native_datetime *ndt = (struct native_datetime *) dt;
strcpy(str_time, ndt->cimDt);
if (rc)
CMSetStatus(rc, CMPI_RC_OK);
}
static CMPIString *
__dtft_getStringFormat(const CMPIDateTime *dt, CMPIStatus *rc)
{
struct native_datetime *ndt = (struct native_datetime *) dt;
if (rc)
CMSetStatus(rc, CMPI_RC_OK);
return sfcb_native_new_CMPIString(ndt->cimDt, rc, 0);
}
static CMPIBoolean
__dtft_isInterval(const CMPIDateTime *dt, CMPIStatus *rc)
{
struct native_datetime *ndt = (struct native_datetime *) dt;
if (rc)
CMSetStatus(rc, CMPI_RC_OK);
return ndt->cimDt[21] == ':' ? 1 : 0;
}
static CMPIDateTimeFT dtft = {
NATIVE_FT_VERSION,
__dtft_release,
__dtft_clone,
__dtft_getBinaryFormat,
__dtft_getStringFormat,
__dtft_isInterval
};
// ! Creates a new native_datetime object.
/*
* ! The newly allocated object's function table is initialized to point
* to the native functions in this file.
*
* \param mm_add MEM_TRACKED for a regular object, MEM_NOT_TRACKED for
* cloned ones \param msecs the binary time to be stored \param interval
* the interval flag to be stored \param rc return code pointer
*
* \return a fully initialized native_datetime object pointer.
*/
static struct native_datetime *
__new_datetime(int mm_add, const char *cimDt, CMPIStatus *rc)
{
static CMPIDateTime dt = {
"CMPIDateTime",
&dtft
};
struct native_datetime ndt,
*tNdt;
int state;
ndt.dt = dt;
tNdt = memAddEncObj(mm_add, &ndt, sizeof(ndt), &state);
tNdt->mem_state = state;
tNdt->refCount = 0;
strcpy(tNdt->cimDt, cimDt);
if (rc)
CMSetStatus(rc, CMPI_RC_OK);
return (struct native_datetime *) tNdt;
}
// ! Creates a native CMPIDateTime representing the current time.
/*
* ! This function calculates the current time and stores it within a new
* native_datetime object.
*
* \param rc return code pointer
*
* \return a pointer to a native CMPIDateTime.
*/
static CMPIDateTime *
_new_CMPIDateTime(CMPIStatus *rc, int mm_add)
{
struct timeval tv;
struct timezone tz;
CMPIUint64 msecs;
char cimDt[26];
gettimeofday(&tv, &tz);
msecs = (CMPIUint64) 1000000 *(CMPIUint64) tv.tv_sec
+ (CMPIUint64) tv.tv_usec;
bin2chars(msecs, 0, rc, cimDt);
return (CMPIDateTime *) __new_datetime(mm_add, cimDt, rc);
}
CMPIDateTime *
sfcb_native_new_CMPIDateTime(CMPIStatus *rc)
{
return _new_CMPIDateTime(rc, MEM_TRACKED);;
}
CMPIDateTime *
NewCMPIDateTime(CMPIStatus *rc)
{
return _new_CMPIDateTime(rc, MEM_NOT_TRACKED);;
}
// ! Creates a native CMPIDateTime given a fixed binary time.
/*
* ! This calls is simply passed on to __new_datetime().
*
* \param time fixed time-stamp in microseconds \param interval states, if
* the time-stamp is to be treated as interval \param rc return code
* pointer
*
* \return a pointer to a native CMPIDateTime.
*
* \sa __dtft_getBinaryFormat()
*/
static CMPIDateTime *
_new_CMPIDateTime_fromBinary(CMPIUint64 msecs,
CMPIBoolean interval,
CMPIStatus *rc, int mm_add)
{
char cimDt[26];
bin2chars(msecs, interval, rc, cimDt);
return (CMPIDateTime *) __new_datetime(mm_add, cimDt, rc);
}
CMPIDateTime *
sfcb_native_new_CMPIDateTime_fromBinary(CMPIUint64 msecs,
CMPIBoolean interval,
CMPIStatus *rc)
{
return _new_CMPIDateTime_fromBinary(msecs, interval, rc, MEM_TRACKED);
}
CMPIDateTime *
NewCMPIDateTimeFromBinary(CMPIUint64 msecs,
CMPIBoolean interval, CMPIStatus *rc)
{
return _new_CMPIDateTime_fromBinary(msecs, interval, rc,
MEM_NOT_TRACKED);
}
// ! Creates a native CMPIDateTime given a fixed time in string
// representation.
/*
* ! This function assumes the given string to have one of the following
* formats:
*
* - for absolute times: yyyymmddhhmmss.mmmmmmsutc - for time intervals:
* ddddddddhhmmss.mmmmmm:000
*
* \param string the time to be converted into internal representation
* \param rc return code pointer #include <limits.h>
*
*
* \return a pointer to a native CMPIDateTime.
*
* \sa __dtft_getStringFormat()
*/
static CMPIDateTime *
_new_CMPIDateTime_fromChars(const char *string, CMPIStatus *rc, int mm_add)
{
if (string == NULL || strlen(string) != 25 ||
(string[21] != '-' && string[21] != '+' && string[21] != ':')) {
if (rc)
CMSetStatus(rc, CMPI_RC_ERR_INVALID_PARAMETER);
return NULL;
}
return (CMPIDateTime *) __new_datetime(mm_add, string, rc);
}
CMPIDateTime *
sfcb_native_new_CMPIDateTime_fromChars(const char *string, CMPIStatus *rc)
{
return _new_CMPIDateTime_fromChars(string, rc, MEM_TRACKED);
}
CMPIDateTime *
NewCMPIDateTimeFromChars(const char *string, CMPIStatus *rc)
{
return _new_CMPIDateTime_fromChars(string, rc, MEM_NOT_TRACKED);
}
/****************************************************************************/
/*** Local Variables: ***/
/*** mode: C ***/
/*** c-basic-offset: 8 ***/
/*** End: ***/
/* MODELINES */
/* DO NOT EDIT BELOW THIS COMMENT */
/* Modelines are added by 'make pretty' */
/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
/* vi:set ts=2 sts=2 sw=2 expandtab: */