PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pgtz.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <fcntl.h>
#include <time.h>
#include "common/file_utils.h"
#include "datatype/timestamp.h"
#include "miscadmin.h"
#include "pgtz.h"
#include "storage/fd.h"
#include "utils/hsearch.h"
Include dependency graph for pgtz.c:

Go to the source code of this file.

Data Structures

struct  pg_tz_cache
 
struct  pg_tzenum
 

Macros

#define MAX_TZDIR_DEPTH   10
 

Functions

static bool scan_directory_ci (const char *dirname, const char *fname, int fnamelen, char *canonname, int canonnamelen)
 
static const charpg_TZDIR (void)
 
int pg_open_tzfile (const char *name, char *canonname)
 
static bool init_timezone_hashtable (void)
 
pg_tzpg_tzset (const char *tzname)
 
pg_tzpg_tzset_offset (long gmtoffset)
 
void pg_timezone_initialize (void)
 
pg_tzenumpg_tzenumerate_start (void)
 
void pg_tzenumerate_end (pg_tzenum *dir)
 
pg_tzpg_tzenumerate_next (pg_tzenum *dir)
 

Variables

pg_tzsession_timezone = NULL
 
pg_tzlog_timezone = NULL
 
static HTABtimezone_cache = NULL
 

Macro Definition Documentation

◆ MAX_TZDIR_DEPTH

#define MAX_TZDIR_DEPTH   10

Definition at line 363 of file pgtz.c.

Function Documentation

◆ init_timezone_hashtable()

static bool init_timezone_hashtable ( void  )
static

Definition at line 202 of file pgtz.c.

203{
205
207 hash_ctl.entrysize = sizeof(pg_tz_cache);
208
209 timezone_cache = hash_create("Timezones",
210 4,
211 &hash_ctl,
213 if (!timezone_cache)
214 return false;
215
216 return true;
217}
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:360
#define HASH_STRINGS
Definition hsearch.h:91
#define HASH_ELEM
Definition hsearch.h:90
#define TZ_STRLEN_MAX
Definition pgtime.h:54
static HTAB * timezone_cache
Definition pgtz.c:198
static int fb(int x)
Size keysize
Definition hsearch.h:69

References fb(), hash_create(), HASH_ELEM, HASH_STRINGS, HASHCTL::keysize, timezone_cache, and TZ_STRLEN_MAX.

Referenced by pg_tzset().

◆ pg_open_tzfile()

int pg_open_tzfile ( const char name,
char canonname 
)

Definition at line 76 of file pgtz.c.

77{
78 const char *fname;
79 char fullname[MAXPGPATH];
80 int fullnamelen;
81 int orignamelen;
82
83 /* Initialize fullname with base name of tzdata directory */
84 strlcpy(fullname, pg_TZDIR(), sizeof(fullname));
86
87 if (fullnamelen + 1 + strlen(name) >= MAXPGPATH)
88 return -1; /* not gonna fit */
89
90 /*
91 * If the caller doesn't need the canonical spelling, first just try to
92 * open the name as-is. This can be expected to succeed if the given name
93 * is already case-correct, or if the filesystem is case-insensitive; and
94 * we don't need to distinguish those situations if we aren't tasked with
95 * reporting the canonical spelling.
96 */
97 if (canonname == NULL)
98 {
99 int result;
100
101 fullname[fullnamelen] = '/';
102 /* test above ensured this will fit: */
105 if (result >= 0)
106 return result;
107 /* If that didn't work, fall through to do it the hard way */
108 fullname[fullnamelen] = '\0';
109 }
110
111 /*
112 * Loop to split the given name into directory levels; for each level,
113 * search using scan_directory_ci().
114 */
115 fname = name;
116 for (;;)
117 {
118 const char *slashptr;
119 int fnamelen;
120
121 slashptr = strchr(fname, '/');
122 if (slashptr)
123 fnamelen = slashptr - fname;
124 else
125 fnamelen = strlen(fname);
127 fullname + fullnamelen + 1,
128 MAXPGPATH - fullnamelen - 1))
129 return -1;
130 fullname[fullnamelen++] = '/';
132 if (slashptr)
133 fname = slashptr + 1;
134 else
135 break;
136 }
137
138 if (canonname)
140
141 return open(fullname, O_RDONLY | PG_BINARY, 0);
142}
#define PG_BINARY
Definition c.h:1431
uint32 result
#define MAXPGPATH
static const char * pg_TZDIR(void)
Definition pgtz.c:43
static bool scan_directory_ci(const char *dirname, const char *fname, int fnamelen, char *canonname, int canonnamelen)
Definition pgtz.c:151
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition strlcpy.c:45
const char * name

References fb(), MAXPGPATH, name, PG_BINARY, pg_TZDIR(), result, scan_directory_ci(), strlcpy(), and TZ_STRLEN_MAX.

◆ pg_timezone_initialize()

void pg_timezone_initialize ( void  )

Definition at line 341 of file pgtz.c.

342{
343 /*
344 * We may not yet know where PGSHAREDIR is (in particular this is true in
345 * an EXEC_BACKEND subprocess). So use "GMT", which pg_tzset forces to be
346 * interpreted without reference to the filesystem. This corresponds to
347 * the bootstrap default for these variables in guc_parameters.dat,
348 * although in principle it could be different.
349 */
350 session_timezone = pg_tzset("GMT");
352}
pg_tz * log_timezone
Definition pgtz.c:31
pg_tz * pg_tzset(const char *tzname)
Definition pgtz.c:224
pg_tz * session_timezone
Definition pgtz.c:28

References log_timezone, pg_tzset(), and session_timezone.

Referenced by InitializeGUCOptions().

◆ pg_TZDIR()

static const char * pg_TZDIR ( void  )
static

Definition at line 43 of file pgtz.c.

44{
45#ifndef SYSTEMTZDIR
46 /* normal case: timezone stuff is under our share dir */
47 static bool done_tzdir = false;
48 static char tzdir[MAXPGPATH];
49
50 if (done_tzdir)
51 return tzdir;
52
54 strlcpy(tzdir + strlen(tzdir), "/timezone", MAXPGPATH - strlen(tzdir));
55
56 done_tzdir = true;
57 return tzdir;
58#else
59 /* we're configured to use system's timezone database */
60 return SYSTEMTZDIR;
61#endif
62}
char my_exec_path[MAXPGPATH]
Definition globals.c:83
void get_share_path(const char *my_exec_path, char *ret_path)
Definition path.c:919

References fb(), get_share_path(), MAXPGPATH, my_exec_path, and strlcpy().

Referenced by pg_open_tzfile(), and pg_tzenumerate_start().

◆ pg_tzenumerate_end()

void pg_tzenumerate_end ( pg_tzenum dir)

Definition at line 394 of file pgtz.c.

395{
396 while (dir->depth >= 0)
397 {
398 FreeDir(dir->dirdesc[dir->depth]);
399 pfree(dir->dirname[dir->depth]);
400 dir->depth--;
401 }
402 pfree(dir);
403}
int FreeDir(DIR *dir)
Definition fd.c:3009
void pfree(void *pointer)
Definition mcxt.c:1619
char * dirname[MAX_TZDIR_DEPTH]
Definition pgtz.c:370
int depth
Definition pgtz.c:368
DIR * dirdesc[MAX_TZDIR_DEPTH]
Definition pgtz.c:369

References pg_tzenum::depth, pg_tzenum::dirdesc, pg_tzenum::dirname, FreeDir(), and pfree().

Referenced by pg_timezone_names().

◆ pg_tzenumerate_next()

pg_tz * pg_tzenumerate_next ( pg_tzenum dir)

Definition at line 406 of file pgtz.c.

407{
408 while (dir->depth >= 0)
409 {
410 struct dirent *direntry;
411 char fullname[MAXPGPATH * 2];
412
413 direntry = ReadDir(dir->dirdesc[dir->depth], dir->dirname[dir->depth]);
414
415 if (!direntry)
416 {
417 /* End of this directory */
418 FreeDir(dir->dirdesc[dir->depth]);
419 pfree(dir->dirname[dir->depth]);
420 dir->depth--;
421 continue;
422 }
423
424 if (direntry->d_name[0] == '.')
425 continue;
426
427 snprintf(fullname, sizeof(fullname), "%s/%s",
428 dir->dirname[dir->depth], direntry->d_name);
429
431 {
432 /* Step into the subdirectory */
433 if (dir->depth >= MAX_TZDIR_DEPTH - 1)
435 (errmsg_internal("timezone directory stack overflow")));
436 dir->depth++;
437 dir->dirname[dir->depth] = pstrdup(fullname);
438 dir->dirdesc[dir->depth] = AllocateDir(fullname);
439 if (!dir->dirdesc[dir->depth])
442 errmsg("could not open directory \"%s\": %m",
443 fullname)));
444
445 /* Start over reading in the new directory */
446 continue;
447 }
448
449 /*
450 * Load this timezone using pg_tzload() not pg_tzset(), so we don't
451 * fill the cache. Also, don't ask for the canonical spelling: we
452 * already know it, and pg_open_tzfile's way of finding it out is
453 * pretty inefficient.
454 */
455 if (!pg_tzload(fullname + dir->baselen, NULL, &dir->tz.state))
456 {
457 /* Zone could not be loaded, ignore it */
458 continue;
459 }
460
461 if (!pg_tz_acceptable(&dir->tz))
462 {
463 /* Ignore leap-second zones */
464 continue;
465 }
466
467 /* OK, return the canonical zone name spelling. */
468 strlcpy(dir->tz.TZname, fullname + dir->baselen,
469 sizeof(dir->tz.TZname));
470
471 /* Timezone loaded OK. */
472 return &dir->tz;
473 }
474
475 /* Nothing more found */
476 return NULL;
477}
int errcode_for_file_access(void)
Definition elog.c:898
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
DIR * AllocateDir(const char *dirname)
Definition fd.c:2891
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition fd.c:2957
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
Definition file_utils.c:547
@ PGFILETYPE_DIR
Definition file_utils.h:23
bool pg_tzload(const char *name, char *canonname, struct state *sp)
Definition localtime.c:1590
char * pstrdup(const char *in)
Definition mcxt.c:1910
static char * errmsg
bool pg_tz_acceptable(pg_tz *tz)
Definition localtime.c:2028
#define MAX_TZDIR_DEPTH
Definition pgtz.c:363
#define snprintf
Definition port.h:261
char TZname[TZ_STRLEN_MAX+1]
Definition pgtz.h:107
struct state state
Definition pgtz.h:108
int baselen
Definition pgtz.c:367
struct pg_tz tz
Definition pgtz.c:371

References AllocateDir(), pg_tzenum::baselen, pg_tzenum::depth, pg_tzenum::dirdesc, pg_tzenum::dirname, ereport, errcode_for_file_access(), errmsg, errmsg_internal(), ERROR, fb(), FreeDir(), get_dirent_type(), MAX_TZDIR_DEPTH, MAXPGPATH, pfree(), pg_tz_acceptable(), pg_tzload(), PGFILETYPE_DIR, pstrdup(), ReadDir(), snprintf, pg_tz::state, strlcpy(), pg_tzenum::tz, and pg_tz::TZname.

Referenced by pg_timezone_names().

◆ pg_tzenumerate_start()

pg_tzenum * pg_tzenumerate_start ( void  )

Definition at line 377 of file pgtz.c.

378{
380 char *startdir = pstrdup(pg_TZDIR());
381
382 ret->baselen = strlen(startdir) + 1;
383 ret->depth = 0;
384 ret->dirname[0] = startdir;
385 ret->dirdesc[0] = AllocateDir(startdir);
386 if (!ret->dirdesc[0])
389 errmsg("could not open directory \"%s\": %m", startdir)));
390 return ret;
391}
#define palloc0_object(type)
Definition fe_memutils.h:90

References AllocateDir(), pg_tzenum::baselen, pg_tzenum::depth, pg_tzenum::dirdesc, pg_tzenum::dirname, ereport, errcode_for_file_access(), errmsg, ERROR, fb(), palloc0_object, pg_TZDIR(), and pstrdup().

Referenced by pg_timezone_names().

◆ pg_tzset()

pg_tz * pg_tzset ( const char tzname)

Definition at line 224 of file pgtz.c.

225{
226 pg_tz_cache *tzp;
227 struct state tzstate;
228 char uppername[TZ_STRLEN_MAX + 1];
229 char canonname[TZ_STRLEN_MAX + 1];
230 char *p;
231
233 return NULL; /* not going to fit */
234
235 if (!timezone_cache)
237 return NULL;
238
239 /*
240 * Upcase the given name to perform a case-insensitive hashtable search.
241 * (We could alternatively downcase it, but we prefer upcase so that we
242 * can get consistently upcased results from pg_tzload() in case the name
243 * is a POSIX-style timezone spec.)
244 */
245 p = uppername;
246 while (*tzname)
247 *p++ = pg_toupper((unsigned char) *tzname++);
248 *p = '\0';
249
251 uppername,
252 HASH_FIND,
253 NULL);
254 if (tzp)
255 {
256 /* Timezone found in cache, nothing more to do */
257 return &tzp->tz;
258 }
259
260 /*
261 * Let the IANA tzdb code interpret the time zone name.
262 */
264 {
265 if (strcmp(uppername, "GMT") == 0)
266 {
267 /* This really, really should not happen ... */
268 elog(ERROR, "could not initialize GMT time zone");
269 }
270 /* Unknown timezone. Fail our call instead of loading GMT! */
271 return NULL;
272 }
273
274 /* Save timezone in the cache */
276 uppername,
278 NULL);
279
280 /* hash_search already copied uppername into the hash key */
281 strcpy(tzp->tz.TZname, canonname);
282 memcpy(&tzp->tz.state, &tzstate, sizeof(tzstate));
283
284 return &tzp->tz;
285}
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
#define elog(elevel,...)
Definition elog.h:228
@ HASH_FIND
Definition hsearch.h:108
@ HASH_ENTER
Definition hsearch.h:109
static bool init_timezone_hashtable(void)
Definition pgtz.c:202
unsigned char pg_toupper(unsigned char ch)
pg_tz tz
Definition pgtz.c:195

References elog, ERROR, fb(), HASH_ENTER, HASH_FIND, hash_search(), init_timezone_hashtable(), memcpy(), pg_toupper(), pg_tzload(), pg_tz::state, timezone_cache, pg_tz_cache::tz, TZ_STRLEN_MAX, and pg_tz::TZname.

Referenced by check_log_timezone(), check_timezone(), DecodeDateTime(), DecodeTimeOnly(), DecodeTimezoneName(), FetchDynamicTimeZone(), pg_timezone_initialize(), and pg_tzset_offset().

◆ pg_tzset_offset()

pg_tz * pg_tzset_offset ( long  gmtoffset)

Definition at line 300 of file pgtz.c.

301{
302 long absoffset = (gmtoffset < 0) ? -gmtoffset : gmtoffset;
303 char offsetstr[64];
304 char tzname[128];
305
307 "%02ld", absoffset / SECS_PER_HOUR);
309 if (absoffset != 0)
310 {
312 sizeof(offsetstr) - strlen(offsetstr),
313 ":%02ld", absoffset / SECS_PER_MINUTE);
315 if (absoffset != 0)
317 sizeof(offsetstr) - strlen(offsetstr),
318 ":%02ld", absoffset);
319 }
320 if (gmtoffset > 0)
321 snprintf(tzname, sizeof(tzname), "<-%s>+%s",
323 else
324 snprintf(tzname, sizeof(tzname), "<+%s>-%s",
326
327 return pg_tzset(tzname);
328}
#define SECS_PER_HOUR
Definition timestamp.h:127
#define SECS_PER_MINUTE
Definition timestamp.h:128

References fb(), pg_tzset(), SECS_PER_HOUR, SECS_PER_MINUTE, and snprintf.

Referenced by check_timezone(), and DecodeTimezoneNameToTz().

◆ scan_directory_ci()

static bool scan_directory_ci ( const char dirname,
const char fname,
int  fnamelen,
char canonname,
int  canonnamelen 
)
static

Definition at line 151 of file pgtz.c.

153{
154 bool found = false;
155 DIR *dirdesc;
156 struct dirent *direntry;
157
158 dirdesc = AllocateDir(dirname);
159
160 while ((direntry = ReadDirExtended(dirdesc, dirname, LOG)) != NULL)
161 {
162 /*
163 * Ignore . and .., plus any other "hidden" files. This is a security
164 * measure to prevent access to files outside the timezone directory.
165 */
166 if (direntry->d_name[0] == '.')
167 continue;
168
169 if (strlen(direntry->d_name) == fnamelen &&
170 pg_strncasecmp(direntry->d_name, fname, fnamelen) == 0)
171 {
172 /* Found our match */
174 found = true;
175 break;
176 }
177 }
178
179 FreeDir(dirdesc);
180
181 return found;
182}
#define LOG
Definition elog.h:32
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition fd.c:2972
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition dirent.c:26

References AllocateDir(), fb(), FreeDir(), LOG, pg_strncasecmp(), ReadDirExtended(), and strlcpy().

Referenced by pg_open_tzfile().

Variable Documentation

◆ log_timezone

◆ session_timezone

◆ timezone_cache

HTAB* timezone_cache = NULL
static

Definition at line 198 of file pgtz.c.

Referenced by init_timezone_hashtable(), and pg_tzset().