Coverage Report

Created: 2023-10-10 06:31

/src/dovecot/src/lib/time-util.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
2
3
#include "lib.h"
4
#include "time-util.h"
5
6
#include <time.h>
7
8
#define STRFTIME_MAX_BUFSIZE (1024*64)
9
10
void i_gettimeofday(struct timeval *tv_r)
11
1
{
12
1
  if (gettimeofday(tv_r, NULL) < 0)
13
0
    i_fatal("gettimeofday() failed: %m");
14
1
}
15
16
uint64_t i_nanoseconds(void)
17
0
{
18
0
  struct timespec ts;
19
20
0
  if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
21
0
    i_fatal("clock_gettime() failed: %m");
22
0
  return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
23
0
}
24
25
int timeval_cmp(const struct timeval *tv1, const struct timeval *tv2)
26
0
{
27
0
  if (tv1->tv_sec < tv2->tv_sec)
28
0
    return -1;
29
0
  if (tv1->tv_sec > tv2->tv_sec)
30
0
    return 1;
31
0
  if (tv1->tv_usec < tv2->tv_usec)
32
0
    return -1;
33
0
  if (tv1->tv_usec > tv2->tv_usec)
34
0
    return 1;
35
0
  return 0;
36
0
}
37
38
int timeval_cmp_margin(const struct timeval *tv1, const struct timeval *tv2,
39
  unsigned int usec_margin)
40
0
{
41
0
  long long secs_diff, usecs_diff;
42
0
  int sec_margin, ret;
43
44
0
  if (tv1->tv_sec < tv2->tv_sec) {
45
0
    sec_margin = ((int)usec_margin / 1000000) + 1;
46
0
    secs_diff = (long long)tv2->tv_sec - (long long)tv1->tv_sec;
47
0
    if (secs_diff > sec_margin)
48
0
      return -1;
49
0
    usecs_diff = secs_diff * 1000000LL +
50
0
      (tv2->tv_usec - tv1->tv_usec);
51
0
    ret = -1;
52
0
  } else if (tv1->tv_sec > tv2->tv_sec) {
53
0
    sec_margin = ((int)usec_margin / 1000000) + 1;
54
0
    secs_diff = (long long)tv1->tv_sec - (long long)tv2->tv_sec;
55
0
    if (secs_diff > sec_margin)
56
0
      return 1;
57
0
    usecs_diff = secs_diff * 1000000LL +
58
0
      (tv1->tv_usec - tv2->tv_usec);
59
0
    ret = 1;
60
0
  } else if (tv1->tv_usec < tv2->tv_usec) {
61
0
    usecs_diff = tv2->tv_usec - tv1->tv_usec;
62
0
    ret = -1;
63
0
  } else {
64
0
    usecs_diff = tv1->tv_usec - tv2->tv_usec;
65
0
    ret = 1;
66
0
  }
67
0
  i_assert(usecs_diff >= 0);
68
0
  return (unsigned long long)usecs_diff > usec_margin ? ret : 0;
69
0
}
70
71
int timeval_diff_msecs(const struct timeval *tv1, const struct timeval *tv2)
72
0
{
73
0
  long long diff = timeval_diff_usecs(tv1, tv2) / 1000LL;
74
#ifdef DEBUG
75
  /* FIXME v2.4: Remove the ifdef */
76
  i_assert(diff <= INT_MAX);
77
#endif
78
0
  return (int)diff;
79
0
}
80
81
long long timeval_diff_usecs(const struct timeval *tv1,
82
           const struct timeval *tv2)
83
0
{
84
0
  time_t secs;
85
0
  int usecs;
86
87
0
  secs = tv1->tv_sec - tv2->tv_sec;
88
0
  usecs = tv1->tv_usec - tv2->tv_usec;
89
0
  if (usecs < 0) {
90
0
    secs--;
91
0
    usecs += 1000000;
92
0
  }
93
0
  return ((long long)secs * 1000000LL) + usecs;
94
0
}
95
96
time_t time_to_local_day_start(time_t t)
97
0
{
98
0
  const struct tm *day_tm;
99
0
  struct tm tm;
100
0
  time_t new_start_time;
101
102
0
  day_tm = localtime(&t);
103
0
  i_zero(&tm);
104
0
  tm.tm_year = day_tm->tm_year;
105
0
  tm.tm_mon = day_tm->tm_mon;
106
0
  tm.tm_mday = day_tm->tm_mday;
107
0
  tm.tm_isdst = -1;
108
0
  new_start_time = mktime(&tm);
109
0
  i_assert(new_start_time != (time_t)-1);
110
0
  return new_start_time;
111
0
}
112
113
static const char *strftime_real(const char *fmt, const struct tm *tm)
114
0
{
115
0
  size_t bufsize = strlen(fmt) + 32;
116
0
  char *buf = t_buffer_get(bufsize);
117
0
  size_t ret;
118
119
0
  while ((ret = strftime(buf, bufsize, fmt, tm)) == 0) {
120
0
    bufsize *= 2;
121
0
    i_assert(bufsize <= STRFTIME_MAX_BUFSIZE);
122
0
    buf = t_buffer_get(bufsize);
123
0
  }
124
0
  t_buffer_alloc(ret + 1);
125
0
  return buf;
126
0
}
127
128
const char *t_strftime(const char *fmt, const struct tm *tm)
129
0
{
130
0
  return strftime_real(fmt, tm);
131
0
}
132
133
const char *t_strflocaltime(const char *fmt, time_t t)
134
0
{
135
0
  return strftime_real(fmt, localtime(&t));
136
0
}
137
138
const char *t_strfgmtime(const char *fmt, time_t t)
139
0
{
140
0
  return strftime_real(fmt, gmtime(&t));
141
0
}
142
143
int str_to_timeval(const char *str, struct timeval *tv_r)
144
0
{
145
0
  tv_r->tv_usec = 0;
146
147
0
  const char *p = strchr(str, '.');
148
0
  if (p == NULL)
149
0
    return str_to_time(str, &tv_r->tv_sec);
150
151
0
  int ret;
152
0
  T_BEGIN {
153
0
    ret = str_to_time(t_strdup_until(str, p++), &tv_r->tv_sec);
154
0
  } T_END;
155
0
  if (ret < 0 || p[0] == '\0')
156
0
    return -1;
157
158
0
  unsigned int len = strlen(p);
159
0
  if (len > 6)
160
0
    return -1; /* we don't support sub-microseconds */
161
0
  char usecs_str[7] = "000000";
162
0
  memcpy(usecs_str, p, len);
163
164
0
  unsigned int usec;
165
0
  if (str_to_uint(usecs_str, &usec) < 0)
166
0
    return -1;
167
0
  tv_r->tv_usec = usec;
168
0
  return 0;
169
0
}