Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/winpr/libwinpr/timezone/timezone.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Time Zone
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2024 Armin Novak <anovak@thincast.com>
7
 * Copyright 2024 Thincast Technologies GmbH
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <winpr/config.h>
23
24
#include <winpr/environment.h>
25
#include <winpr/wtypes.h>
26
#include <winpr/timezone.h>
27
#include <winpr/crt.h>
28
#include <winpr/assert.h>
29
#include <winpr/file.h>
30
#include "../log.h"
31
32
#define TAG WINPR_TAG("timezone")
33
34
#ifndef MIN
35
134k
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
36
#endif
37
38
#include "TimeZoneNameMap.h"
39
#include "TimeZoneIanaAbbrevMap.h"
40
41
#ifndef _WIN32
42
43
#include <time.h>
44
#include <unistd.h>
45
46
#endif
47
48
#if !defined(_WIN32)
49
static char* winpr_read_unix_timezone_identifier_from_file(FILE* fp)
50
89.8k
{
51
89.8k
  const INT CHUNK_SIZE = 32;
52
89.8k
  INT64 rc = 0;
53
89.8k
  INT64 read = 0;
54
89.8k
  INT64 length = CHUNK_SIZE;
55
89.8k
  char* tzid = NULL;
56
57
89.8k
  tzid = (char*)malloc((size_t)length);
58
89.8k
  if (!tzid)
59
0
    return NULL;
60
61
89.8k
  do
62
89.8k
  {
63
89.8k
    rc = fread(tzid + read, 1, length - read - 1, fp);
64
89.8k
    if (rc > 0)
65
89.8k
      read += rc;
66
67
89.8k
    if (read < (length - 1))
68
89.8k
      break;
69
70
0
    length += CHUNK_SIZE;
71
0
    char* tmp = (char*)realloc(tzid, length);
72
0
    if (!tmp)
73
0
    {
74
0
      free(tzid);
75
0
      return NULL;
76
0
    }
77
78
0
    tzid = tmp;
79
0
  } while (rc > 0);
80
81
89.8k
  if (ferror(fp))
82
0
  {
83
0
    free(tzid);
84
0
    return NULL;
85
0
  }
86
87
89.8k
  tzid[read] = '\0';
88
89.8k
  if (read > 0)
89
89.8k
  {
90
89.8k
    if (tzid[read - 1] == '\n')
91
89.8k
      tzid[read - 1] = '\0';
92
89.8k
  }
93
94
89.8k
  return tzid;
95
89.8k
}
96
97
static char* winpr_get_timezone_from_link(const char* links[], size_t count)
98
89.8k
{
99
89.8k
  const char* _links[] = { "/etc/localtime", "/etc/TZ" };
100
101
89.8k
  if (links == NULL)
102
0
  {
103
0
    links = _links;
104
0
    count = ARRAYSIZE(_links);
105
0
  }
106
107
  /*
108
   * On linux distros such as Redhat or Archlinux, a symlink at /etc/localtime
109
   * will point to /usr/share/zoneinfo/region/place where region/place could be
110
   * America/Montreal for example.
111
   * Some distributions do have to symlink at /etc/TZ.
112
   */
113
114
89.8k
  for (size_t x = 0; x < count; x++)
115
89.8k
  {
116
89.8k
    char* tzid = NULL;
117
89.8k
    const char* link = links[x];
118
89.8k
    char* buf = realpath(link, NULL);
119
120
89.8k
    if (buf)
121
89.8k
    {
122
89.8k
      size_t sep = 0;
123
89.8k
      size_t alloc = 0;
124
89.8k
      size_t pos = 0;
125
89.8k
      size_t len = pos = strlen(buf);
126
127
      /* find the position of the 2nd to last "/" */
128
718k
      for (size_t i = 1; i <= len; i++)
129
718k
      {
130
718k
        const size_t curpos = len - i;
131
718k
        const char cur = buf[curpos];
132
133
718k
        if (cur == '/')
134
179k
          sep++;
135
718k
        if (sep >= 2)
136
89.8k
        {
137
89.8k
          alloc = i;
138
89.8k
          pos = len - i + 1;
139
89.8k
          break;
140
89.8k
        }
141
718k
      }
142
143
89.8k
      if ((len == 0) || (sep != 2))
144
0
        goto end;
145
146
89.8k
      tzid = (char*)calloc(alloc + 1, sizeof(char));
147
148
89.8k
      if (!tzid)
149
0
        goto end;
150
151
89.8k
      strncpy(tzid, &buf[pos], alloc);
152
89.8k
      WLog_DBG(TAG, "tzid: %s", tzid);
153
89.8k
      goto end;
154
89.8k
    }
155
156
89.8k
  end:
157
89.8k
    free(buf);
158
89.8k
    if (tzid)
159
89.8k
      return tzid;
160
89.8k
  }
161
162
0
  return NULL;
163
89.8k
}
164
165
#if defined(ANDROID)
166
#include "../utils/android.h"
167
168
static char* winpr_get_android_timezone_identifier(void)
169
{
170
  char* tzid = NULL;
171
  JNIEnv* jniEnv;
172
173
  /* Preferred: Try to get identifier from java TimeZone class */
174
  if (jniVm && ((*jniVm)->GetEnv(jniVm, (void**)&jniEnv, JNI_VERSION_1_6) == JNI_OK))
175
  {
176
    const char* raw;
177
    jclass jObjClass;
178
    jobject jObj;
179
    jmethodID jDefaultTimezone;
180
    jmethodID jTimezoneIdentifier;
181
    jstring tzJId;
182
    jboolean attached = (*jniVm)->AttachCurrentThread(jniVm, &jniEnv, NULL);
183
    jObjClass = (*jniEnv)->FindClass(jniEnv, "java/util/TimeZone");
184
185
    if (!jObjClass)
186
      goto fail;
187
188
    jDefaultTimezone =
189
        (*jniEnv)->GetStaticMethodID(jniEnv, jObjClass, "getDefault", "()Ljava/util/TimeZone;");
190
191
    if (!jDefaultTimezone)
192
      goto fail;
193
194
    jObj = (*jniEnv)->CallStaticObjectMethod(jniEnv, jObjClass, jDefaultTimezone);
195
196
    if (!jObj)
197
      goto fail;
198
199
    jTimezoneIdentifier =
200
        (*jniEnv)->GetMethodID(jniEnv, jObjClass, "getID", "()Ljava/lang/String;");
201
202
    if (!jTimezoneIdentifier)
203
      goto fail;
204
205
    tzJId = (*jniEnv)->CallObjectMethod(jniEnv, jObj, jTimezoneIdentifier);
206
207
    if (!tzJId)
208
      goto fail;
209
210
    raw = (*jniEnv)->GetStringUTFChars(jniEnv, tzJId, 0);
211
212
    if (raw)
213
      tzid = _strdup(raw);
214
215
    (*jniEnv)->ReleaseStringUTFChars(jniEnv, tzJId, raw);
216
  fail:
217
218
    if (attached)
219
      (*jniVm)->DetachCurrentThread(jniVm);
220
  }
221
222
  /* Fall back to property, might not be available. */
223
  if (!tzid)
224
  {
225
    FILE* fp = popen("getprop persist.sys.timezone", "r");
226
227
    if (fp)
228
    {
229
      tzid = winpr_read_unix_timezone_identifier_from_file(fp);
230
      pclose(fp);
231
    }
232
  }
233
234
  return tzid;
235
}
236
#endif
237
238
static char* winpr_get_unix_timezone_identifier_from_file(void)
239
89.8k
{
240
#if defined(ANDROID)
241
  return winpr_get_android_timezone_identifier();
242
#else
243
89.8k
  FILE* fp = NULL;
244
89.8k
  char* tzid = NULL;
245
#if !defined(WINPR_TIMEZONE_FILE)
246
#error \
247
    "Please define WINPR_TIMEZONE_FILE with the path to your timezone file (e.g. /etc/timezone or similar)"
248
#else
249
89.8k
  fp = winpr_fopen(WINPR_TIMEZONE_FILE, "r");
250
89.8k
#endif
251
252
89.8k
  if (NULL == fp)
253
0
    return NULL;
254
255
89.8k
  tzid = winpr_read_unix_timezone_identifier_from_file(fp);
256
89.8k
  fclose(fp);
257
89.8k
  if (tzid != NULL)
258
89.8k
    WLog_DBG(TAG, "tzid: %s", tzid);
259
89.8k
  return tzid;
260
89.8k
#endif
261
89.8k
}
262
263
static char* winpr_time_zone_from_env(void)
264
89.8k
{
265
89.8k
  LPCSTR tz = "TZ";
266
89.8k
  char* tzid = NULL;
267
268
89.8k
  DWORD nSize = GetEnvironmentVariableA(tz, NULL, 0);
269
89.8k
  if (nSize > 0)
270
0
  {
271
0
    tzid = (char*)calloc(nSize, sizeof(char));
272
0
    if (!tzid)
273
0
      goto fail;
274
0
    if (!GetEnvironmentVariableA(tz, tzid, nSize))
275
0
      goto fail;
276
0
    else if (tzid[0] == ':')
277
0
    {
278
      /* Remove leading colon, see tzset(3) */
279
0
      memmove(tzid, tzid + 1, nSize - sizeof(char));
280
0
    }
281
0
  }
282
283
89.8k
  return tzid;
284
285
0
fail:
286
0
  free(tzid);
287
0
  return NULL;
288
89.8k
}
289
290
static char* winpr_translate_time_zone(const char* tzid)
291
89.8k
{
292
89.8k
  const char* zipath = "/usr/share/zoneinfo/";
293
89.8k
  char* buf = NULL;
294
89.8k
  const char* links[] = { buf };
295
296
89.8k
  if (!tzid)
297
0
    return NULL;
298
299
89.8k
  if (tzid[0] == '/')
300
0
  {
301
    /* Full path given in TZ */
302
0
    links[0] = tzid;
303
0
  }
304
89.8k
  else
305
89.8k
  {
306
89.8k
    size_t bsize = 0;
307
89.8k
    winpr_asprintf(&buf, &bsize, "%s%s", zipath, tzid);
308
89.8k
    links[0] = buf;
309
89.8k
  }
310
311
89.8k
  char* ntzid = winpr_get_timezone_from_link(links, 1);
312
89.8k
  free(buf);
313
89.8k
  return ntzid;
314
89.8k
}
315
316
static char* winpr_guess_time_zone(void)
317
89.8k
{
318
89.8k
  char* tzid = winpr_time_zone_from_env();
319
89.8k
  if (tzid)
320
0
    goto end;
321
89.8k
  tzid = winpr_get_unix_timezone_identifier_from_file();
322
89.8k
  if (tzid)
323
89.8k
    goto end;
324
0
  tzid = winpr_get_timezone_from_link(NULL, 0);
325
0
  if (tzid)
326
0
    goto end;
327
328
89.8k
end:
329
89.8k
{
330
89.8k
  char* ntzid = winpr_translate_time_zone(tzid);
331
89.8k
  if (ntzid)
332
89.8k
  {
333
89.8k
    free(tzid);
334
89.8k
    return ntzid;
335
89.8k
  }
336
0
  return tzid;
337
89.8k
}
338
89.8k
}
339
340
static SYSTEMTIME tm2systemtime(const struct tm* t)
341
179k
{
342
179k
  SYSTEMTIME st = { 0 };
343
344
179k
  if (t)
345
0
  {
346
0
    st.wYear = (WORD)1900 + t->tm_year;
347
0
    st.wMonth = (WORD)t->tm_mon;
348
0
    st.wDay = (WORD)t->tm_mday;
349
0
    st.wDayOfWeek = (WORD)t->tm_wday;
350
0
    st.wHour = (WORD)t->tm_hour;
351
0
    st.wMinute = (WORD)t->tm_min;
352
0
    st.wSecond = (WORD)t->tm_sec;
353
0
    st.wMilliseconds = 0;
354
0
  }
355
179k
  return st;
356
179k
}
357
358
static LONG get_gmtoff_min(const struct tm* t)
359
89.8k
{
360
89.8k
  WINPR_ASSERT(t);
361
89.8k
  return -(LONG)(t->tm_gmtoff / 60l);
362
89.8k
}
363
364
static struct tm next_day(const struct tm* start)
365
98.3M
{
366
98.3M
  struct tm cur = *start;
367
98.3M
  cur.tm_hour = 0;
368
98.3M
  cur.tm_min = 0;
369
98.3M
  cur.tm_sec = 0;
370
98.3M
  cur.tm_isdst = -1;
371
98.3M
  cur.tm_mday++;
372
98.3M
  const time_t t = mktime(&cur);
373
98.3M
  localtime_r(&t, &cur);
374
98.3M
  return cur;
375
98.3M
}
376
377
static struct tm adjust_time(const struct tm* start, int hour, int minute)
378
0
{
379
0
  struct tm cur = *start;
380
0
  cur.tm_hour = hour;
381
0
  cur.tm_min = minute;
382
0
  cur.tm_sec = 0;
383
0
  cur.tm_isdst = -1;
384
0
  const time_t t = mktime(&cur);
385
0
  localtime_r(&t, &cur);
386
0
  return cur;
387
0
}
388
389
static SYSTEMTIME get_transition_time(const struct tm* start, BOOL toDst)
390
0
{
391
0
  BOOL toggled = FALSE;
392
0
  struct tm first = adjust_time(start, 0, 0);
393
0
  for (int hour = 0; hour < 24; hour++)
394
0
  {
395
0
    for (int minute = 0; minute < 60; minute++)
396
0
    {
397
0
      struct tm cur = adjust_time(start, hour, minute);
398
0
      if (cur.tm_isdst != first.tm_isdst)
399
0
        toggled = TRUE;
400
401
0
      if (toggled)
402
0
      {
403
0
        if (toDst && (cur.tm_isdst > 0))
404
0
          return tm2systemtime(&cur);
405
0
        else if (!toDst && (cur.tm_isdst == 0))
406
0
          return tm2systemtime(&cur);
407
0
      }
408
0
    }
409
0
  }
410
0
  return tm2systemtime(start);
411
0
}
412
413
static BOOL get_transition_date(const struct tm* start, BOOL toDst, SYSTEMTIME* pdate)
414
179k
{
415
179k
  WINPR_ASSERT(start);
416
179k
  WINPR_ASSERT(pdate);
417
418
179k
  *pdate = tm2systemtime(NULL);
419
420
179k
  if (start->tm_isdst < 0)
421
0
    return FALSE;
422
423
179k
  BOOL val = start->tm_isdst > 0; // the year starts with DST or not
424
179k
  BOOL toggled = FALSE;
425
179k
  struct tm cur = *start;
426
65.7M
  for (int day = 1; day <= 365; day++)
427
65.5M
  {
428
65.5M
    cur = next_day(&cur);
429
65.5M
    const BOOL curDst = (cur.tm_isdst > 0);
430
65.5M
    if ((val != curDst) && !toggled)
431
0
      toggled = TRUE;
432
433
65.5M
    if (toggled)
434
0
    {
435
0
      if (toDst && curDst)
436
0
      {
437
0
        *pdate = get_transition_time(&cur, toDst);
438
0
        return TRUE;
439
0
      }
440
0
      if (!toDst && !curDst)
441
0
      {
442
0
        *pdate = get_transition_time(&cur, toDst);
443
0
        return TRUE;
444
0
      }
445
0
    }
446
65.5M
  }
447
179k
  return FALSE;
448
179k
}
449
450
static LONG get_bias(const struct tm* start, BOOL dstBias)
451
179k
{
452
179k
  if ((start->tm_isdst > 0) && dstBias)
453
0
    return get_gmtoff_min(start);
454
179k
  if ((start->tm_isdst == 0) && !dstBias)
455
89.8k
    return get_gmtoff_min(start);
456
89.8k
  if (start->tm_isdst < 0)
457
0
    return get_gmtoff_min(start);
458
459
89.8k
  struct tm cur = *start;
460
32.8M
  for (int day = 1; day <= 365; day++)
461
32.7M
  {
462
32.7M
    cur = next_day(&cur);
463
32.7M
    if ((cur.tm_isdst > 0) && dstBias)
464
0
      return get_gmtoff_min(&cur);
465
32.7M
    else if ((cur.tm_isdst == 0) && !dstBias)
466
0
      return get_gmtoff_min(&cur);
467
32.7M
  }
468
89.8k
  return 0;
469
89.8k
}
470
471
static BOOL map_iana_id(const char* iana, LPTIME_ZONE_INFORMATION tz)
472
89.8k
{
473
89.8k
  const char* winId = TimeZoneIanaToWindows(iana, TIME_ZONE_NAME_ID);
474
89.8k
  if (!winId)
475
0
    return FALSE;
476
477
89.8k
  const char* winStd = TimeZoneIanaToWindows(iana, TIME_ZONE_NAME_STANDARD);
478
89.8k
  const char* winDst = TimeZoneIanaToWindows(iana, TIME_ZONE_NAME_DAYLIGHT);
479
480
89.8k
  ConvertUtf8ToWChar(winStd, tz->StandardName, ARRAYSIZE(tz->StandardName));
481
89.8k
  ConvertUtf8ToWChar(winDst, tz->DaylightName, ARRAYSIZE(tz->DaylightName));
482
483
89.8k
  return TRUE;
484
89.8k
}
485
486
DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation)
487
89.8k
{
488
89.8k
  const char** list = NULL;
489
89.8k
  char* tzid = NULL;
490
89.8k
  const char* defaultName = "Client Local Time";
491
89.8k
  DWORD res = TIME_ZONE_ID_UNKNOWN;
492
89.8k
  const TIME_ZONE_INFORMATION empty = { 0 };
493
89.8k
  LPTIME_ZONE_INFORMATION tz = lpTimeZoneInformation;
494
495
89.8k
  WINPR_ASSERT(tz);
496
497
89.8k
  *tz = empty;
498
89.8k
  ConvertUtf8ToWChar(defaultName, tz->StandardName, ARRAYSIZE(tz->StandardName));
499
500
89.8k
  const time_t t = time(NULL);
501
89.8k
  struct tm tres = { 0 };
502
89.8k
  struct tm* local_time = localtime_r(&t, &tres);
503
89.8k
  if (!local_time)
504
0
    goto out_error;
505
506
89.8k
  tz->Bias = get_bias(local_time, FALSE);
507
89.8k
  if (local_time->tm_isdst >= 0)
508
89.8k
  {
509
    /* DST bias is the difference between standard time and DST in minutes */
510
89.8k
    const LONG d = get_bias(local_time, TRUE);
511
89.8k
    tz->DaylightBias = -1 * labs(tz->Bias - d);
512
89.8k
    get_transition_date(local_time, FALSE, &tz->StandardDate);
513
89.8k
    get_transition_date(local_time, TRUE, &tz->DaylightDate);
514
89.8k
  }
515
516
89.8k
  tzid = winpr_guess_time_zone();
517
89.8k
  if (!map_iana_id(tzid, tz))
518
0
  {
519
0
    const size_t len = TimeZoneIanaAbbrevGet(local_time->tm_zone, NULL, 0);
520
0
    list = calloc(len, sizeof(char*));
521
0
    if (!list)
522
0
      goto out_error;
523
0
    const size_t size = TimeZoneIanaAbbrevGet(local_time->tm_zone, list, len);
524
0
    for (size_t x = 0; x < size; x++)
525
0
    {
526
0
      const char* id = list[x];
527
0
      if (map_iana_id(id, tz))
528
0
      {
529
0
        res = (local_time->tm_isdst) ? TIME_ZONE_ID_DAYLIGHT : TIME_ZONE_ID_STANDARD;
530
0
        break;
531
0
      }
532
0
    }
533
0
  }
534
89.8k
  else
535
89.8k
    res = (local_time->tm_isdst) ? TIME_ZONE_ID_DAYLIGHT : TIME_ZONE_ID_STANDARD;
536
537
89.8k
out_error:
538
89.8k
  free(tzid);
539
89.8k
  free(list);
540
89.8k
  switch (res)
541
89.8k
  {
542
0
    case TIME_ZONE_ID_DAYLIGHT:
543
89.8k
    case TIME_ZONE_ID_STANDARD:
544
89.8k
      WLog_DBG(TAG, "tz: Bias=%" PRId32 " sn='%s' dln='%s'", tz->Bias, tz->StandardName,
545
89.8k
               tz->DaylightName);
546
89.8k
      break;
547
0
    default:
548
0
      WLog_DBG(TAG, "tz not found, using computed bias %" PRId32 ".", tz->Bias);
549
0
      break;
550
89.8k
  }
551
552
89.8k
  return res;
553
89.8k
}
554
555
BOOL SetTimeZoneInformation(const TIME_ZONE_INFORMATION* lpTimeZoneInformation)
556
0
{
557
0
  WINPR_UNUSED(lpTimeZoneInformation);
558
0
  return FALSE;
559
0
}
560
561
BOOL SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime, LPFILETIME lpFileTime)
562
0
{
563
0
  WINPR_UNUSED(lpSystemTime);
564
0
  WINPR_UNUSED(lpFileTime);
565
0
  return FALSE;
566
0
}
567
568
BOOL FileTimeToSystemTime(const FILETIME* lpFileTime, LPSYSTEMTIME lpSystemTime)
569
0
{
570
0
  WINPR_UNUSED(lpFileTime);
571
0
  WINPR_UNUSED(lpSystemTime);
572
0
  return FALSE;
573
0
}
574
575
BOOL SystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION lpTimeZone,
576
                                     LPSYSTEMTIME lpUniversalTime, LPSYSTEMTIME lpLocalTime)
577
0
{
578
0
  WINPR_UNUSED(lpTimeZone);
579
0
  WINPR_UNUSED(lpUniversalTime);
580
0
  WINPR_UNUSED(lpLocalTime);
581
0
  return FALSE;
582
0
}
583
584
BOOL TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,
585
                                     LPSYSTEMTIME lpLocalTime, LPSYSTEMTIME lpUniversalTime)
586
0
{
587
0
  WINPR_UNUSED(lpTimeZoneInformation);
588
0
  WINPR_UNUSED(lpLocalTime);
589
0
  WINPR_UNUSED(lpUniversalTime);
590
0
  return FALSE;
591
0
}
592
593
#endif
594
595
/*
596
 * GetDynamicTimeZoneInformation is provided by the SDK if _WIN32_WINNT >= 0x0600 in SDKs above 7.1A
597
 * and incorrectly if _WIN32_WINNT >= 0x0501 in older SDKs
598
 */
599
#if !defined(_WIN32) ||                                                  \
600
    (defined(_WIN32) && (defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0600 || \
601
                         !defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0501)) /* Windows Vista */
602
603
DWORD GetDynamicTimeZoneInformation(PDYNAMIC_TIME_ZONE_INFORMATION pTimeZoneInformation)
604
44.9k
{
605
44.9k
  TIME_ZONE_INFORMATION tz = { 0 };
606
44.9k
  const DWORD rc = GetTimeZoneInformation(&tz);
607
608
44.9k
  WINPR_ASSERT(pTimeZoneInformation);
609
44.9k
  pTimeZoneInformation->Bias = tz.Bias;
610
44.9k
  memcpy(pTimeZoneInformation->StandardName, tz.StandardName,
611
44.9k
         MIN(sizeof(tz.StandardName), sizeof(pTimeZoneInformation->StandardName)));
612
44.9k
  pTimeZoneInformation->StandardDate = tz.StandardDate;
613
44.9k
  pTimeZoneInformation->StandardBias = tz.StandardBias;
614
615
44.9k
  memcpy(pTimeZoneInformation->DaylightName, tz.DaylightName,
616
44.9k
         MIN(sizeof(tz.DaylightName), sizeof(pTimeZoneInformation->DaylightName)));
617
44.9k
  pTimeZoneInformation->DaylightDate = tz.DaylightDate;
618
44.9k
  pTimeZoneInformation->DaylightBias = tz.DaylightBias;
619
620
44.9k
  memcpy(pTimeZoneInformation->TimeZoneKeyName, tz.StandardName,
621
44.9k
         MIN(sizeof(tz.StandardName), sizeof(pTimeZoneInformation->TimeZoneKeyName)));
622
623
  /* https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-dynamic_time_zone_information
624
   */
625
44.9k
  pTimeZoneInformation->DynamicDaylightTimeDisabled = FALSE;
626
44.9k
  return rc;
627
44.9k
}
628
629
BOOL SetDynamicTimeZoneInformation(const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation)
630
0
{
631
0
  WINPR_UNUSED(lpTimeZoneInformation);
632
0
  return FALSE;
633
0
}
634
635
BOOL GetTimeZoneInformationForYear(USHORT wYear, PDYNAMIC_TIME_ZONE_INFORMATION pdtzi,
636
                                   LPTIME_ZONE_INFORMATION ptzi)
637
0
{
638
0
  WINPR_UNUSED(wYear);
639
0
  WINPR_UNUSED(pdtzi);
640
0
  WINPR_UNUSED(ptzi);
641
0
  return FALSE;
642
0
}
643
644
#endif
645
646
#if !defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0601)) /* Windows 7 */
647
648
BOOL SystemTimeToTzSpecificLocalTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation,
649
                                       const SYSTEMTIME* lpUniversalTime, LPSYSTEMTIME lpLocalTime)
650
0
{
651
0
  WINPR_UNUSED(lpTimeZoneInformation);
652
0
  WINPR_UNUSED(lpUniversalTime);
653
0
  WINPR_UNUSED(lpLocalTime);
654
0
  return FALSE;
655
0
}
656
657
BOOL TzSpecificLocalTimeToSystemTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation,
658
                                       const SYSTEMTIME* lpLocalTime, LPSYSTEMTIME lpUniversalTime)
659
0
{
660
0
  WINPR_UNUSED(lpTimeZoneInformation);
661
0
  WINPR_UNUSED(lpLocalTime);
662
0
  WINPR_UNUSED(lpUniversalTime);
663
0
  return FALSE;
664
0
}
665
666
#endif
667
668
#if !defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0602)) /* Windows 8 */
669
670
DWORD EnumDynamicTimeZoneInformation(const DWORD dwIndex,
671
                                     PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation)
672
0
{
673
0
  WINPR_UNUSED(dwIndex);
674
0
  WINPR_UNUSED(lpTimeZoneInformation);
675
0
  return 0;
676
0
}
677
678
DWORD GetDynamicTimeZoneInformationEffectiveYears(
679
    const PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation, LPDWORD FirstYear, LPDWORD LastYear)
680
0
{
681
0
  WINPR_UNUSED(lpTimeZoneInformation);
682
0
  WINPR_UNUSED(FirstYear);
683
0
  WINPR_UNUSED(LastYear);
684
0
  return 0;
685
0
}
686
687
#endif