21#include "TimeZoneIanaAbbrevMap.h"
29#include <winpr/string.h>
30#include <winpr/synch.h>
37} TimeZoneInanaAbbrevMapEntry;
39const static char* zonepath =
"/usr/share/zoneinfo";
41static TimeZoneInanaAbbrevMapEntry* TimeZoneIanaAbbrevMap = NULL;
42static size_t TimeZoneIanaAbbrevMapSize = 0;
44static void append(
const char* iana,
const char* sname)
46 const size_t size = TimeZoneIanaAbbrevMapSize + 1;
48 TimeZoneInanaAbbrevMapEntry* tmp =
49 realloc(TimeZoneIanaAbbrevMap, size *
sizeof(TimeZoneInanaAbbrevMapEntry));
52 TimeZoneIanaAbbrevMap = tmp;
53 TimeZoneIanaAbbrevMapSize = size;
55 TimeZoneInanaAbbrevMapEntry* cur = &TimeZoneIanaAbbrevMap[size - 1];
56 cur->Abbrev = _strdup(sname);
57 cur->Iana = _strdup(iana);
60static void append_timezone(
const char* dir,
const char* name)
68 winpr_asprintf(&tz, &len,
"%s", name);
73 winpr_asprintf(&tz, &len,
"%s/%s", dir, name);
78 char* oldtz = setNewAndSaveOldTZ(tz);
80 const time_t t = time(NULL);
82 (void)localtime_r(&t, <);
83 append(tz, lt.tm_zone);
84 restoreSavedTZ(oldtz);
88static void handle_link(
const char* base,
const char* dir,
const char* name);
90static char* topath(
const char* base,
const char* bname,
const char* name)
95 if (!base && !bname && !name)
99 return _strdup(bname);
102 return _strdup(base);
105 return _strdup(name);
108 winpr_asprintf(&path, &plen,
"%s/%s", bname, name);
110 winpr_asprintf(&path, &plen,
"%s/%s", base, name);
112 winpr_asprintf(&path, &plen,
"%s/%s", base, bname);
114 winpr_asprintf(&path, &plen,
"%s/%s/%s", base, bname, name);
118static void iterate_subdir_recursive(
const char* base,
const char* bname,
const char* name)
120 char* path = topath(base, bname, name);
124 DIR* d = opendir(path);
127 struct dirent* dp = NULL;
129 while ((dp = readdir(d)) != NULL)
135 if (strcmp(dp->d_name,
".") == 0)
137 if (strcmp(dp->d_name,
"..") == 0)
139 iterate_subdir_recursive(path, dp->d_name, NULL);
143 handle_link(base, bname, dp->d_name);
146 append_timezone(bname, dp->d_name);
157static char* get_link_target(
const char* base,
const char* dir,
const char* name)
160 char* path = topath(base, dir, name);
170 char* tmp = realloc(target, size + 1);
176 memset(target, 0, size + 1);
177 rc = readlink(path, target, size);
180 }
while ((
size_t)rc >= size);
182 apath = topath(base, dir, target);
189void handle_link(
const char* base,
const char* dir,
const char* name)
193 char* target = get_link_target(base, dir, name);
196 struct stat s = { 0 };
197 const int rc3 = stat(target, &s);
199 isDir = S_ISDIR(s.st_mode);
207 iterate_subdir_recursive(base, dir, name);
210 append_timezone(dir, name);
217static void TimeZoneIanaAbbrevCleanup(
void)
219 if (!TimeZoneIanaAbbrevMap)
222 for (
size_t x = 0; x < TimeZoneIanaAbbrevMapSize; x++)
224 TimeZoneInanaAbbrevMapEntry* entry = &TimeZoneIanaAbbrevMap[x];
228 free(TimeZoneIanaAbbrevMap);
229 TimeZoneIanaAbbrevMap = NULL;
230 TimeZoneIanaAbbrevMapSize = 0;
233static BOOL CALLBACK TimeZoneIanaAbbrevInitialize(WINPR_ATTR_UNUSED
PINIT_ONCE once,
234 WINPR_ATTR_UNUSED PVOID param,
235 WINPR_ATTR_UNUSED PVOID* context)
237 iterate_subdir_recursive(zonepath, NULL, NULL);
238 (void)atexit(TimeZoneIanaAbbrevCleanup);
243size_t TimeZoneIanaAbbrevGet(
const char* abbrev,
const char** list,
size_t listsize)
245 static INIT_ONCE init_guard = INIT_ONCE_STATIC_INIT;
247 InitOnceExecuteOnce(&init_guard, TimeZoneIanaAbbrevInitialize, NULL, NULL);
250 for (
size_t x = 0; x < TimeZoneIanaAbbrevMapSize; x++)
252 const TimeZoneInanaAbbrevMapEntry* entry = &TimeZoneIanaAbbrevMap[x];
253 if (strcmp(abbrev, entry->Abbrev) == 0)
256 list[rc] = entry->Iana;