#include "postgres.h"
#include <ctype.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>
#include "miscadmin.h"
#include "pgtz.h"
#include "storage/fd.h"
#include "utils/hsearch.h"
Go to the source code of this file.
Data Structures | |
struct | pg_tz_cache |
struct | pg_tzenum |
Defines | |
#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 char * | pg_TZDIR (void) |
int | pg_open_tzfile (const char *name, char *canonname) |
static bool | init_timezone_hashtable (void) |
pg_tz * | pg_tzset (const char *name) |
void | pg_timezone_initialize (void) |
pg_tzenum * | pg_tzenumerate_start (void) |
void | pg_tzenumerate_end (pg_tzenum *dir) |
pg_tz * | pg_tzenumerate_next (pg_tzenum *dir) |
Variables | |
pg_tz * | session_timezone = NULL |
pg_tz * | log_timezone = NULL |
static HTAB * | timezone_cache = NULL |
#define MAX_TZDIR_DEPTH 10 |
Definition at line 324 of file pgtz.c.
Referenced by pg_tzenumerate_next().
static bool init_timezone_hashtable | ( | void | ) | [static] |
Definition at line 184 of file pgtz.c.
References HASHCTL::entrysize, hash_create(), HASH_ELEM, HASHCTL::keysize, MemSet, and TZ_STRLEN_MAX.
Referenced by pg_tzset().
{ HASHCTL hash_ctl; MemSet(&hash_ctl, 0, sizeof(hash_ctl)); hash_ctl.keysize = TZ_STRLEN_MAX + 1; hash_ctl.entrysize = sizeof(pg_tz_cache); timezone_cache = hash_create("Timezones", 4, &hash_ctl, HASH_ELEM); if (!timezone_cache) return false; return true; }
int pg_open_tzfile | ( | const char * | name, | |
char * | canonname | |||
) |
Definition at line 75 of file pgtz.c.
References MAXPGPATH, PG_BINARY, pg_TZDIR(), scan_directory_ci(), strlcpy(), and TZ_STRLEN_MAX.
{ const char *fname; char fullname[MAXPGPATH]; int fullnamelen; int orignamelen; /* * Loop to split the given name into directory levels; for each level, * search using scan_directory_ci(). */ strcpy(fullname, pg_TZDIR()); orignamelen = fullnamelen = strlen(fullname); fname = name; for (;;) { const char *slashptr; int fnamelen; slashptr = strchr(fname, '/'); if (slashptr) fnamelen = slashptr - fname; else fnamelen = strlen(fname); if (fullnamelen + 1 + fnamelen >= MAXPGPATH) return -1; /* not gonna fit */ if (!scan_directory_ci(fullname, fname, fnamelen, fullname + fullnamelen + 1, MAXPGPATH - fullnamelen - 1)) return -1; fullname[fullnamelen++] = '/'; fullnamelen += strlen(fullname + fullnamelen); if (slashptr) fname = slashptr + 1; else break; } if (canonname) strlcpy(canonname, fullname + orignamelen + 1, TZ_STRLEN_MAX + 1); return open(fullname, O_RDONLY | PG_BINARY, 0); }
void pg_timezone_initialize | ( | void | ) |
Definition at line 302 of file pgtz.c.
References pg_tzset().
Referenced by InitializeGUCOptions().
{ /* * We may not yet know where PGSHAREDIR is (in particular this is true in * an EXEC_BACKEND subprocess). So use "GMT", which pg_tzset forces to be * interpreted without reference to the filesystem. This corresponds to * the bootstrap default for these variables in guc.c, although in * principle it could be different. */ session_timezone = pg_tzset("GMT"); log_timezone = session_timezone; }
static const char* pg_TZDIR | ( | void | ) | [static] |
Definition at line 42 of file pgtz.c.
References get_share_path(), MAXPGPATH, my_exec_path, and strlcpy().
Referenced by pg_open_tzfile(), and pg_tzenumerate_start().
{ #ifndef SYSTEMTZDIR /* normal case: timezone stuff is under our share dir */ static bool done_tzdir = false; static char tzdir[MAXPGPATH]; if (done_tzdir) return tzdir; get_share_path(my_exec_path, tzdir); strlcpy(tzdir + strlen(tzdir), "/timezone", MAXPGPATH - strlen(tzdir)); done_tzdir = true; return tzdir; #else /* we're configured to use system's timezone database */ return SYSTEMTZDIR; #endif }
void pg_tzenumerate_end | ( | pg_tzenum * | dir | ) |
Definition at line 355 of file pgtz.c.
References pg_tzenum::depth, pg_tzenum::dirdesc, pg_tzenum::dirname, FreeDir(), and pfree().
Referenced by pg_timezone_names().
Definition at line 367 of file pgtz.c.
References AllocateDir(), pg_tzenum::baselen, pg_tzenum::depth, pg_tzenum::dirdesc, pg_tzenum::dirname, ereport, errcode_for_file_access(), errmsg(), errmsg_internal(), ERROR, FreeDir(), MAX_TZDIR_DEPTH, MAXPGPATH, pfree(), pg_tz_acceptable(), pstrdup(), ReadDir(), snprintf(), pg_tz::state, TRUE, pg_tzenum::tz, tzload(), and pg_tz::TZname.
Referenced by pg_timezone_names().
{ while (dir->depth >= 0) { struct dirent *direntry; char fullname[MAXPGPATH]; struct stat statbuf; direntry = ReadDir(dir->dirdesc[dir->depth], dir->dirname[dir->depth]); if (!direntry) { /* End of this directory */ FreeDir(dir->dirdesc[dir->depth]); pfree(dir->dirname[dir->depth]); dir->depth--; continue; } if (direntry->d_name[0] == '.') continue; snprintf(fullname, MAXPGPATH, "%s/%s", dir->dirname[dir->depth], direntry->d_name); if (stat(fullname, &statbuf) != 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not stat \"%s\": %m", fullname))); if (S_ISDIR(statbuf.st_mode)) { /* Step into the subdirectory */ if (dir->depth >= MAX_TZDIR_DEPTH - 1) ereport(ERROR, (errmsg_internal("timezone directory stack overflow"))); dir->depth++; dir->dirname[dir->depth] = pstrdup(fullname); dir->dirdesc[dir->depth] = AllocateDir(fullname); if (!dir->dirdesc[dir->depth]) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open directory \"%s\": %m", fullname))); /* Start over reading in the new directory */ continue; } /* * Load this timezone using tzload() not pg_tzset(), so we don't fill * the cache */ if (tzload(fullname + dir->baselen, dir->tz.TZname, &dir->tz.state, TRUE) != 0) { /* Zone could not be loaded, ignore it */ continue; } if (!pg_tz_acceptable(&dir->tz)) { /* Ignore leap-second zones */ continue; } /* Timezone loaded OK. */ return &dir->tz; } /* Nothing more found */ return NULL; }
pg_tzenum* pg_tzenumerate_start | ( | void | ) |
Definition at line 338 of file pgtz.c.
References AllocateDir(), pg_tzenum::baselen, pg_tzenum::depth, pg_tzenum::dirdesc, pg_tzenum::dirname, ereport, errcode_for_file_access(), errmsg(), ERROR, palloc0(), pg_TZDIR(), and pstrdup().
Referenced by pg_timezone_names().
{ pg_tzenum *ret = (pg_tzenum *) palloc0(sizeof(pg_tzenum)); char *startdir = pstrdup(pg_TZDIR()); ret->baselen = strlen(startdir) + 1; ret->depth = 0; ret->dirname[0] = startdir; ret->dirdesc[0] = AllocateDir(startdir); if (!ret->dirdesc[0]) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open directory \"%s\": %m", startdir))); return ret; }
pg_tz* pg_tzset | ( | const char * | name | ) |
Definition at line 218 of file pgtz.c.
References elog, ERROR, FALSE, HASH_ENTER, HASH_FIND, hash_search(), init_timezone_hashtable(), NULL, pg_toupper(), pg_tz::state, TRUE, pg_tz_cache::tz, TZ_STRLEN_MAX, tzload(), pg_tz::TZname, and tzparse().
Referenced by check_log_timezone(), check_timezone(), DecodeDateTime(), DecodeTimeOnly(), pg_timezone_initialize(), timestamp_zone(), timestamptz_zone(), and timetz_zone().
{ pg_tz_cache *tzp; struct state tzstate; char uppername[TZ_STRLEN_MAX + 1]; char canonname[TZ_STRLEN_MAX + 1]; char *p; if (strlen(name) > TZ_STRLEN_MAX) return NULL; /* not going to fit */ if (!timezone_cache) if (!init_timezone_hashtable()) return NULL; /* * Upcase the given name to perform a case-insensitive hashtable search. * (We could alternatively downcase it, but we prefer upcase so that we * can get consistently upcased results from tzparse() in case the name is * a POSIX-style timezone spec.) */ p = uppername; while (*name) *p++ = pg_toupper((unsigned char) *name++); *p = '\0'; tzp = (pg_tz_cache *) hash_search(timezone_cache, uppername, HASH_FIND, NULL); if (tzp) { /* Timezone found in cache, nothing more to do */ return &tzp->tz; } /* * "GMT" is always sent to tzparse(), as per discussion above. */ if (strcmp(uppername, "GMT") == 0) { if (tzparse(uppername, &tzstate, TRUE) != 0) { /* This really, really should not happen ... */ elog(ERROR, "could not initialize GMT time zone"); } /* Use uppercase name as canonical */ strcpy(canonname, uppername); } else if (tzload(uppername, canonname, &tzstate, TRUE) != 0) { if (uppername[0] == ':' || tzparse(uppername, &tzstate, FALSE) != 0) { /* Unknown timezone. Fail our call instead of loading GMT! */ return NULL; } /* For POSIX timezone specs, use uppercase name as canonical */ strcpy(canonname, uppername); } /* Save timezone in the cache */ tzp = (pg_tz_cache *) hash_search(timezone_cache, uppername, HASH_ENTER, NULL); /* hash_search already copied uppername into the hash key */ strcpy(tzp->tz.TZname, canonname); memcpy(&tzp->tz.state, &tzstate, sizeof(tzstate)); return &tzp->tz; }
static bool scan_directory_ci | ( | const char * | dirname, | |
const char * | fname, | |||
int | fnamelen, | |||
char * | canonname, | |||
int | canonnamelen | |||
) | [static] |
Definition at line 126 of file pgtz.c.
References AllocateDir(), dirent::d_name, ereport, errcode_for_file_access(), errmsg(), FreeDir(), LOG, NULL, pg_strncasecmp(), ReadDir(), and strlcpy().
Referenced by pg_open_tzfile().
{ bool found = false; DIR *dirdesc; struct dirent *direntry; dirdesc = AllocateDir(dirname); if (!dirdesc) { ereport(LOG, (errcode_for_file_access(), errmsg("could not open directory \"%s\": %m", dirname))); return false; } while ((direntry = ReadDir(dirdesc, dirname)) != NULL) { /* * Ignore . and .., plus any other "hidden" files. This is a security * measure to prevent access to files outside the timezone directory. */ if (direntry->d_name[0] == '.') continue; if (strlen(direntry->d_name) == fnamelen && pg_strncasecmp(direntry->d_name, fname, fnamelen) == 0) { /* Found our match */ strlcpy(canonname, direntry->d_name, canonnamelen); found = true; break; } } FreeDir(dirdesc); return found; }
pg_tz* log_timezone = NULL |
Definition at line 30 of file pgtz.c.
Referenced by assign_log_timezone(), do_pg_start_backup(), do_pg_stop_backup(), log_line_prefix(), logfile_getname(), set_next_rotation_time(), setup_formatted_log_time(), setup_formatted_start_time(), show_log_timezone(), and str_time().
pg_tz* session_timezone = NULL |
Definition at line 27 of file pgtz.c.
Referenced by abstime2tm(), assign_timezone(), check_timezone(), date2timestamptz(), DecodeDateTime(), DecodeTimeOnly(), DetermineTimeZoneOffset(), show_timezone(), time_timetz(), timeofday(), timestamp2timestamptz(), timestamp2tm(), timestamp_abstime(), timestamptz_pl_interval(), timestamptz_trunc(), and to_timestamp().
HTAB* timezone_cache = NULL [static] |