Coverage Report

Created: 2026-09-06 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/httpd/srclib/apr/time/unix/time.c
Line
Count
Source
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
 * contributor license agreements.  See the NOTICE file distributed with
3
 * this work for additional information regarding copyright ownership.
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * (the "License"); you may not use this file except in compliance with
6
 * the License.  You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include "apr_portable.h"
18
#include "apr_time.h"
19
#include "apr_lib.h"
20
#include "apr_private.h"
21
#include "apr_strings.h"
22
23
/* private APR headers */
24
#include "apr_arch_internal_time.h"
25
26
/* System Headers required for time library */
27
#if APR_HAVE_SYS_TIME_H
28
#include <sys/time.h>
29
#endif
30
#if APR_HAVE_UNISTD_H
31
#include <unistd.h>
32
#endif
33
#ifdef HAVE_TIME_H
34
#include <time.h>
35
#endif
36
/* End System Headers */
37
38
#if !defined(HAVE_STRUCT_TM_TM_GMTOFF) && !defined(HAVE_STRUCT_TM___TM_GMTOFF)
39
static apr_int32_t server_gmt_offset;
40
#define NO_GMTOFF_IN_STRUCT_TM
41
#endif
42
43
static apr_int32_t get_offset(struct tm *tm)
44
0
{
45
0
#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
46
0
    return tm->tm_gmtoff;
47
#elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
48
    return tm->__tm_gmtoff;
49
#else
50
    if (tm->tm_isdst)
51
        return server_gmt_offset + 3600;
52
    return server_gmt_offset;
53
#endif
54
0
}
55
56
APR_DECLARE(apr_status_t) apr_time_ansi_put(apr_time_t *result,
57
                                            time_t input)
58
3.69k
{
59
3.69k
    *result = (apr_time_t)input * APR_USEC_PER_SEC;
60
3.69k
    return APR_SUCCESS;
61
3.69k
}
62
63
/* NB NB NB NB This returns GMT!!!!!!!!!! */
64
APR_DECLARE(apr_time_t) apr_time_now(void)
65
553
{
66
553
    struct timeval tv;
67
553
    gettimeofday(&tv, NULL);
68
553
    return tv.tv_sec * (apr_time_t)APR_USEC_PER_SEC + (apr_time_t)tv.tv_usec;
69
553
}
70
71
static void explode_time(apr_time_exp_t *xt, apr_time_t t,
72
                         apr_int32_t offset, int use_localtime)
73
0
{
74
0
    struct tm tm;
75
0
    time_t tt = (t / APR_USEC_PER_SEC) + offset;
76
0
    xt->tm_usec = t % APR_USEC_PER_SEC;
77
78
0
#if APR_HAS_THREADS && defined (_POSIX_THREAD_SAFE_FUNCTIONS)
79
0
    if (use_localtime)
80
0
        localtime_r(&tt, &tm);
81
0
    else
82
0
        gmtime_r(&tt, &tm);
83
#else
84
    if (use_localtime)
85
        tm = *localtime(&tt);
86
    else
87
        tm = *gmtime(&tt);
88
#endif
89
90
0
    xt->tm_sec  = tm.tm_sec;
91
0
    xt->tm_min  = tm.tm_min;
92
0
    xt->tm_hour = tm.tm_hour;
93
0
    xt->tm_mday = tm.tm_mday;
94
0
    xt->tm_mon  = tm.tm_mon;
95
0
    xt->tm_year = tm.tm_year;
96
0
    xt->tm_wday = tm.tm_wday;
97
0
    xt->tm_yday = tm.tm_yday;
98
0
    xt->tm_isdst = tm.tm_isdst;
99
0
    xt->tm_gmtoff = get_offset(&tm);
100
0
}
101
102
APR_DECLARE(apr_status_t) apr_time_exp_tz(apr_time_exp_t *result,
103
                                          apr_time_t input, apr_int32_t offs)
104
0
{
105
0
    explode_time(result, input, offs, 0);
106
0
    result->tm_gmtoff = offs;
107
0
    return APR_SUCCESS;
108
0
}
109
110
APR_DECLARE(apr_status_t) apr_time_exp_gmt(apr_time_exp_t *result,
111
                                           apr_time_t input)
112
0
{
113
0
    return apr_time_exp_tz(result, input, 0);
114
0
}
115
116
APR_DECLARE(apr_status_t) apr_time_exp_lt(apr_time_exp_t *result,
117
                                                apr_time_t input)
118
0
{
119
#if defined(__EMX__)
120
    /* EMX gcc (OS/2) has a timezone global we can use */
121
    return apr_time_exp_tz(result, input, -timezone);
122
#else
123
0
    explode_time(result, input, 0, 1);
124
0
    return APR_SUCCESS;
125
0
#endif /* __EMX__ */
126
0
}
127
128
APR_DECLARE(apr_status_t) apr_time_exp_get(apr_time_t *t, apr_time_exp_t *xt)
129
0
{
130
0
    apr_time_t year = xt->tm_year;
131
0
    apr_time_t days;
132
0
    static const int dayoffset[12] =
133
0
    {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275};
134
135
0
    if (xt->tm_mon < 0 || xt->tm_mon >= 12)
136
0
        return APR_EBADDATE;
137
138
    /* shift new year to 1st March in order to make leap year calc easy */
139
140
0
    if (xt->tm_mon < 2)
141
0
        year--;
142
143
    /* Find number of days since 1st March 1900 (in the Gregorian calendar). */
144
145
0
    days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4;
146
0
    days += dayoffset[xt->tm_mon] + xt->tm_mday - 1;
147
0
    days -= 25508;              /* 1 jan 1970 is 25508 days since 1 mar 1900 */
148
0
    days = ((days * 24 + xt->tm_hour) * 60 + xt->tm_min) * 60 + xt->tm_sec;
149
150
0
    if (days < 0) {
151
0
        return APR_EBADDATE;
152
0
    }
153
0
    *t = days * APR_USEC_PER_SEC + xt->tm_usec;
154
0
    return APR_SUCCESS;
155
0
}
156
157
APR_DECLARE(apr_status_t) apr_time_exp_gmt_get(apr_time_t *t,
158
                                               apr_time_exp_t *xt)
159
0
{
160
0
    apr_status_t status = apr_time_exp_get(t, xt);
161
0
    if (status == APR_SUCCESS)
162
0
        *t -= (apr_time_t) xt->tm_gmtoff * APR_USEC_PER_SEC;
163
0
    return status;
164
0
}
165
166
APR_DECLARE(apr_status_t) apr_os_imp_time_get(apr_os_imp_time_t **ostime,
167
                                              apr_time_t *aprtime)
168
0
{
169
0
    (*ostime)->tv_usec = *aprtime % APR_USEC_PER_SEC;
170
0
    (*ostime)->tv_sec = *aprtime / APR_USEC_PER_SEC;
171
0
    return APR_SUCCESS;
172
0
}
173
174
APR_DECLARE(apr_status_t) apr_os_exp_time_get(apr_os_exp_time_t **ostime,
175
                                              apr_time_exp_t *aprtime)
176
0
{
177
0
    (*ostime)->tm_sec  = aprtime->tm_sec;
178
0
    (*ostime)->tm_min  = aprtime->tm_min;
179
0
    (*ostime)->tm_hour = aprtime->tm_hour;
180
0
    (*ostime)->tm_mday = aprtime->tm_mday;
181
0
    (*ostime)->tm_mon  = aprtime->tm_mon;
182
0
    (*ostime)->tm_year = aprtime->tm_year;
183
0
    (*ostime)->tm_wday = aprtime->tm_wday;
184
0
    (*ostime)->tm_yday = aprtime->tm_yday;
185
0
    (*ostime)->tm_isdst = aprtime->tm_isdst;
186
187
0
#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
188
0
    (*ostime)->tm_gmtoff = aprtime->tm_gmtoff;
189
#elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
190
    (*ostime)->__tm_gmtoff = aprtime->tm_gmtoff;
191
#endif
192
193
0
    return APR_SUCCESS;
194
0
}
195
196
APR_DECLARE(apr_status_t) apr_os_imp_time_put(apr_time_t *aprtime,
197
                                              apr_os_imp_time_t **ostime,
198
                                              apr_pool_t *cont)
199
0
{
200
0
    *aprtime = (*ostime)->tv_sec * APR_USEC_PER_SEC + (*ostime)->tv_usec;
201
0
    return APR_SUCCESS;
202
0
}
203
204
APR_DECLARE(apr_status_t) apr_os_exp_time_put(apr_time_exp_t *aprtime,
205
                                              apr_os_exp_time_t **ostime,
206
                                              apr_pool_t *cont)
207
0
{
208
0
    aprtime->tm_sec = (*ostime)->tm_sec;
209
0
    aprtime->tm_min = (*ostime)->tm_min;
210
0
    aprtime->tm_hour = (*ostime)->tm_hour;
211
0
    aprtime->tm_mday = (*ostime)->tm_mday;
212
0
    aprtime->tm_mon = (*ostime)->tm_mon;
213
0
    aprtime->tm_year = (*ostime)->tm_year;
214
0
    aprtime->tm_wday = (*ostime)->tm_wday;
215
0
    aprtime->tm_yday = (*ostime)->tm_yday;
216
0
    aprtime->tm_isdst = (*ostime)->tm_isdst;
217
218
0
#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
219
0
    aprtime->tm_gmtoff = (*ostime)->tm_gmtoff;
220
#elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
221
    aprtime->tm_gmtoff = (*ostime)->__tm_gmtoff;
222
#endif
223
224
0
    return APR_SUCCESS;
225
0
}
226
227
APR_DECLARE(void) apr_sleep(apr_interval_time_t t)
228
0
{
229
#ifdef OS2
230
    DosSleep((t + 999) / 1000);
231
#elif defined(HAVE_NANOSLEEP)
232
    struct timespec ts;
233
0
    ts.tv_sec = t / APR_USEC_PER_SEC;
234
0
    ts.tv_nsec = (t % APR_USEC_PER_SEC) * 1000;
235
0
    nanosleep(&ts, NULL);
236
#else
237
    struct timeval tv;
238
    tv.tv_usec = t % APR_USEC_PER_SEC;
239
    tv.tv_sec = t / APR_USEC_PER_SEC;
240
    select(0, NULL, NULL, NULL, &tv);
241
#endif
242
0
}
243
244
#ifdef OS2
245
APR_DECLARE(apr_status_t) apr_os2_time_to_apr_time(apr_time_t *result,
246
                                                   FDATE os2date,
247
                                                   FTIME os2time)
248
{
249
  struct tm tmpdate;
250
251
  memset(&tmpdate, 0, sizeof(tmpdate));
252
  tmpdate.tm_hour  = os2time.hours;
253
  tmpdate.tm_min   = os2time.minutes;
254
  tmpdate.tm_sec   = os2time.twosecs * 2;
255
256
  tmpdate.tm_mday  = os2date.day;
257
  tmpdate.tm_mon   = os2date.month - 1;
258
  tmpdate.tm_year  = os2date.year + 80;
259
  tmpdate.tm_isdst = -1;
260
261
  *result = mktime(&tmpdate) * APR_USEC_PER_SEC;
262
  return APR_SUCCESS;
263
}
264
265
APR_DECLARE(apr_status_t) apr_apr_time_to_os2_time(FDATE *os2date,
266
                                                   FTIME *os2time,
267
                                                   apr_time_t aprtime)
268
{
269
    time_t ansitime = aprtime / APR_USEC_PER_SEC;
270
    struct tm *lt;
271
    lt = localtime(&ansitime);
272
    os2time->hours    = lt->tm_hour;
273
    os2time->minutes  = lt->tm_min;
274
    os2time->twosecs  = lt->tm_sec / 2;
275
276
    os2date->day      = lt->tm_mday;
277
    os2date->month    = lt->tm_mon + 1;
278
    os2date->year     = lt->tm_year - 80;
279
    return APR_SUCCESS;
280
}
281
#endif
282
283
APR_DECLARE(void) apr_unix_setup_time(void)
284
0
{
285
#ifdef NO_GMTOFF_IN_STRUCT_TM
286
    /* Precompute the offset from GMT on systems where it's not
287
       in struct tm.
288
289
       Note: This offset is normalized to be independent of daylight
290
       savings time; if the calculation happens to be done in a
291
       time/place where a daylight savings adjustment is in effect,
292
       the returned offset has the same value that it would have
293
       in the same location if daylight savings were not in effect.
294
       The reason for this is that the returned offset can be
295
       applied to a past or future timestamp in explode_time(),
296
       so the DST adjustment obtained from the current time won't
297
       necessarily be applicable.
298
299
       mktime() is the inverse of localtime(); so, presumably,
300
       passing in a struct tm made by gmtime() let's us calculate
301
       the true GMT offset. However, there's a catch: if daylight
302
       savings is in effect, gmtime()will set the tm_isdst field
303
       and confuse mktime() into returning a time that's offset
304
       by one hour. In that case, we must adjust the calculated GMT
305
       offset.
306
307
     */
308
309
    struct timeval now;
310
    time_t t1, t2;
311
    struct tm t;
312
313
    gettimeofday(&now, NULL);
314
    t1 = now.tv_sec;
315
    t2 = 0;
316
317
#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
318
    gmtime_r(&t1, &t);
319
#else
320
    t = *gmtime(&t1);
321
#endif
322
    t.tm_isdst = 0; /* we know this GMT time isn't daylight-savings */
323
    t2 = mktime(&t);
324
    server_gmt_offset = (apr_int32_t) difftime(t1, t2);
325
#endif /* NO_GMTOFF_IN_STRUCT_TM */
326
0
}
327
328
329
/* A noop on all known Unix implementations */
330
APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p)
331
0
{
332
0
    return;
333
0
}
334
335