#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] |
1.7.1