21#include "TimeZoneIanaAbbrevMap.h"
29#include <winpr/atexit.h>
30#include <winpr/string.h>
31#include <winpr/synch.h>
38} TimeZoneInanaAbbrevMapEntry;
40const static char* zonepath =
"/usr/share/zoneinfo";
42static TimeZoneInanaAbbrevMapEntry* TimeZoneIanaAbbrevMap =
nullptr;
43static size_t TimeZoneIanaAbbrevMapSize = 0;
45static void append(
const char* iana,
const char* sname)
47 const size_t size = TimeZoneIanaAbbrevMapSize + 1;
49 TimeZoneInanaAbbrevMapEntry* tmp =
50 realloc(TimeZoneIanaAbbrevMap, size *
sizeof(TimeZoneInanaAbbrevMapEntry));
53 TimeZoneIanaAbbrevMap = tmp;
54 TimeZoneIanaAbbrevMapSize = size;
56 TimeZoneInanaAbbrevMapEntry* cur = &TimeZoneIanaAbbrevMap[size - 1];
57 cur->Abbrev = _strdup(sname);
58 cur->Iana = _strdup(iana);
61static void append_timezone(
const char* dir,
const char* name)
69 winpr_asprintf(&tz, &len,
"%s", name);
74 winpr_asprintf(&tz, &len,
"%s/%s", dir, name);
79 char* oldtz = setNewAndSaveOldTZ(tz);
81 const time_t t = time(
nullptr);
82 struct tm lt = WINPR_C_ARRAY_INIT;
83 (void)localtime_r(&t, <);
84 append(tz, lt.tm_zone);
85 restoreSavedTZ(oldtz);
89static void handle_link(
const char* base,
const char* dir,
const char* name);
91static char* topath(
const char* base,
const char* bname,
const char* name)
96 if (!base && !bname && !name)
100 return _strdup(bname);
103 return _strdup(base);
106 return _strdup(name);
109 winpr_asprintf(&path, &plen,
"%s/%s", bname, name);
111 winpr_asprintf(&path, &plen,
"%s/%s", base, name);
113 winpr_asprintf(&path, &plen,
"%s/%s", base, bname);
115 winpr_asprintf(&path, &plen,
"%s/%s/%s", base, bname, name);
119static void iterate_subdir_recursive(
const char* base,
const char* bname,
const char* name)
121 char* path = topath(base, bname, name);
125 DIR* d = opendir(path);
128 struct dirent* dp =
nullptr;
130 while ((dp = readdir(d)) !=
nullptr)
136 if (strcmp(dp->d_name,
".") == 0)
138 if (strcmp(dp->d_name,
"..") == 0)
140 iterate_subdir_recursive(path, dp->d_name,
nullptr);
144 handle_link(base, bname, dp->d_name);
147 append_timezone(bname, dp->d_name);
158static char* get_link_target(
const char* base,
const char* dir,
const char* name)
160 char* apath =
nullptr;
161 char* path = topath(base, dir, name);
167 char* target =
nullptr;
171 char* tmp = realloc(target, size + 1);
177 memset(target, 0, size + 1);
178 rc = readlink(path, target, size);
181 }
while ((
size_t)rc >= size);
183 apath = topath(base, dir, target);
190void handle_link(
const char* base,
const char* dir,
const char* name)
194 char* target = get_link_target(base, dir, name);
197 struct stat s = WINPR_C_ARRAY_INIT;
198 const int rc3 = stat(target, &s);
200 isDir = S_ISDIR(s.st_mode);
208 iterate_subdir_recursive(base, dir, name);
211 append_timezone(dir, name);
218static void TimeZoneIanaAbbrevCleanup(
void)
220 if (!TimeZoneIanaAbbrevMap)
223 for (
size_t x = 0; x < TimeZoneIanaAbbrevMapSize; x++)
225 TimeZoneInanaAbbrevMapEntry* entry = &TimeZoneIanaAbbrevMap[x];
229 free(TimeZoneIanaAbbrevMap);
230 TimeZoneIanaAbbrevMap =
nullptr;
231 TimeZoneIanaAbbrevMapSize = 0;
234static BOOL CALLBACK TimeZoneIanaAbbrevInitialize(WINPR_ATTR_UNUSED
PINIT_ONCE once,
235 WINPR_ATTR_UNUSED PVOID param,
236 WINPR_ATTR_UNUSED PVOID* context)
238 iterate_subdir_recursive(zonepath,
nullptr,
nullptr);
239 (void)winpr_atexit(TimeZoneIanaAbbrevCleanup);
244size_t TimeZoneIanaAbbrevGet(
const char* abbrev,
const char** list,
size_t listsize)
246 static INIT_ONCE init_guard = INIT_ONCE_STATIC_INIT;
248 if (!InitOnceExecuteOnce(&init_guard, TimeZoneIanaAbbrevInitialize,
nullptr,
nullptr))
252 for (
size_t x = 0; x < TimeZoneIanaAbbrevMapSize; x++)
254 const TimeZoneInanaAbbrevMapEntry* entry = &TimeZoneIanaAbbrevMap[x];
255 if (strcmp(abbrev, entry->Abbrev) == 0)
258 list[rc] = entry->Iana;