LCOV - differential code coverage report
Current view: top level - src/timezone - pgtz.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 89.0 % 145 129 16 129
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 10 10 10
Baseline: 16@8cea358b128 Branches: 71.2 % 80 57 23 57
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 89.0 % 145 129 16 129
Function coverage date bins:
(240..) days: 100.0 % 10 10 10
Branch coverage date bins:
(240..) days: 71.2 % 80 57 23 57

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * pgtz.c
                                  4                 :                :  *    Timezone Library Integration Functions
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
                                  7                 :                :  *
                                  8                 :                :  * IDENTIFICATION
                                  9                 :                :  *    src/timezone/pgtz.c
                                 10                 :                :  *
                                 11                 :                :  *-------------------------------------------------------------------------
                                 12                 :                :  */
                                 13                 :                : #include "postgres.h"
                                 14                 :                : 
                                 15                 :                : #include <ctype.h>
                                 16                 :                : #include <fcntl.h>
                                 17                 :                : #include <time.h>
                                 18                 :                : 
                                 19                 :                : #include "common/file_utils.h"
                                 20                 :                : #include "datatype/timestamp.h"
                                 21                 :                : #include "miscadmin.h"
                                 22                 :                : #include "pgtz.h"
                                 23                 :                : #include "storage/fd.h"
                                 24                 :                : #include "utils/hsearch.h"
                                 25                 :                : 
                                 26                 :                : 
                                 27                 :                : /* Current session timezone (controlled by TimeZone GUC) */
                                 28                 :                : pg_tz      *session_timezone = NULL;
                                 29                 :                : 
                                 30                 :                : /* Current log timezone (controlled by log_timezone GUC) */
                                 31                 :                : pg_tz      *log_timezone = NULL;
                                 32                 :                : 
                                 33                 :                : 
                                 34                 :                : static bool scan_directory_ci(const char *dirname,
                                 35                 :                :                               const char *fname, int fnamelen,
                                 36                 :                :                               char *canonname, int canonnamelen);
                                 37                 :                : 
                                 38                 :                : 
                                 39                 :                : /*
                                 40                 :                :  * Return full pathname of timezone data directory
                                 41                 :                :  */
                                 42                 :                : static const char *
 7288 bruce@momjian.us           43                 :CBC        9478 : pg_TZDIR(void)
                                 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                 :                : 
 7289                            50         [ +  + ]:           9478 :     if (done_tzdir)
                                 51                 :           8653 :         return tzdir;
                                 52                 :                : 
 7271                            53                 :            825 :     get_share_path(my_exec_path, tzdir);
 6390 tgl@sss.pgh.pa.us          54                 :            825 :     strlcpy(tzdir + strlen(tzdir), "/timezone", MAXPGPATH - strlen(tzdir));
                                 55                 :                : 
                                 56                 :            825 :     done_tzdir = true;
 7289 bruce@momjian.us           57                 :            825 :     return tzdir;
                                 58                 :                : #else
                                 59                 :                :     /* we're configured to use system's timezone database */
                                 60                 :                :     return SYSTEMTZDIR;
                                 61                 :                : #endif
                                 62                 :                : }
                                 63                 :                : 
                                 64                 :                : 
                                 65                 :                : /*
                                 66                 :                :  * Given a timezone name, open() the timezone data file.  Return the
                                 67                 :                :  * file descriptor if successful, -1 if not.
                                 68                 :                :  *
                                 69                 :                :  * The input name is searched for case-insensitively (we assume that the
                                 70                 :                :  * timezone database does not contain case-equivalent names).
                                 71                 :                :  *
                                 72                 :                :  * If "canonname" is not NULL, then on success the canonical spelling of the
                                 73                 :                :  * given name is stored there (the buffer must be > TZ_STRLEN_MAX bytes!).
                                 74                 :                :  */
                                 75                 :                : int
 6390 tgl@sss.pgh.pa.us          76                 :           9470 : pg_open_tzfile(const char *name, char *canonname)
                                 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 */
 2539                            84                 :           9470 :     strlcpy(fullname, pg_TZDIR(), sizeof(fullname));
                                 85                 :           9470 :     orignamelen = fullnamelen = strlen(fullname);
                                 86                 :                : 
                                 87         [ -  + ]:           9470 :     if (fullnamelen + 1 + strlen(name) >= MAXPGPATH)
 2539 tgl@sss.pgh.pa.us          88                 :UBC           0 :         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                 :                :      */
 2539 tgl@sss.pgh.pa.us          97         [ +  + ]:CBC        9470 :     if (canonname == NULL)
                                 98                 :                :     {
                                 99                 :                :         int         result;
                                100                 :                : 
                                101                 :           4950 :         fullname[fullnamelen] = '/';
                                102                 :                :         /* test above ensured this will fit: */
                                103                 :           4950 :         strcpy(fullname + fullnamelen + 1, name);
                                104                 :           4950 :         result = open(fullname, O_RDONLY | PG_BINARY, 0);
                                105         [ +  - ]:           4950 :         if (result >= 0)
                                106                 :           4950 :             return result;
                                107                 :                :         /* If that didn't work, fall through to do it the hard way */
 2534 tgl@sss.pgh.pa.us         108                 :UBC           0 :         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                 :                :      */
 6390 tgl@sss.pgh.pa.us         115                 :CBC        4520 :     fname = name;
                                116                 :                :     for (;;)
                                117                 :            994 :     {
                                118                 :                :         const char *slashptr;
                                119                 :                :         int         fnamelen;
                                120                 :                : 
                                121                 :           5514 :         slashptr = strchr(fname, '/');
                                122         [ +  + ]:           5514 :         if (slashptr)
                                123                 :           1009 :             fnamelen = slashptr - fname;
                                124                 :                :         else
                                125                 :           4505 :             fnamelen = strlen(fname);
                                126         [ +  + ]:           5514 :         if (!scan_directory_ci(fullname, fname, fnamelen,
                                127                 :           5514 :                                fullname + fullnamelen + 1,
                                128                 :                :                                MAXPGPATH - fullnamelen - 1))
                                129                 :            214 :             return -1;
                                130                 :           5300 :         fullname[fullnamelen++] = '/';
                                131                 :           5300 :         fullnamelen += strlen(fullname + fullnamelen);
                                132         [ +  + ]:           5300 :         if (slashptr)
                                133                 :            994 :             fname = slashptr + 1;
                                134                 :                :         else
                                135                 :           4306 :             break;
                                136                 :                :     }
                                137                 :                : 
                                138         [ +  - ]:           4306 :     if (canonname)
                                139                 :           4306 :         strlcpy(canonname, fullname + orignamelen + 1, TZ_STRLEN_MAX + 1);
                                140                 :                : 
                                141                 :           4306 :     return open(fullname, O_RDONLY | PG_BINARY, 0);
                                142                 :                : }
                                143                 :                : 
                                144                 :                : 
                                145                 :                : /*
                                146                 :                :  * Scan specified directory for a case-insensitive match to fname
                                147                 :                :  * (of length fnamelen --- fname may not be null terminated!).  If found,
                                148                 :                :  * copy the actual filename into canonname and return true.
                                149                 :                :  */
                                150                 :                : static bool
                                151                 :           5514 : scan_directory_ci(const char *dirname, const char *fname, int fnamelen,
                                152                 :                :                   char *canonname, int canonnamelen)
                                153                 :                : {
                                154                 :           5514 :     bool        found = false;
                                155                 :                :     DIR        *dirdesc;
                                156                 :                :     struct dirent *direntry;
                                157                 :                : 
                                158                 :           5514 :     dirdesc = AllocateDir(dirname);
                                159                 :                : 
 2323                           160         [ +  + ]:         215665 :     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                 :                :          */
 6390                           166         [ +  + ]:         215451 :         if (direntry->d_name[0] == '.')
                                167                 :          11028 :             continue;
                                168                 :                : 
                                169   [ +  +  +  + ]:         238464 :         if (strlen(direntry->d_name) == fnamelen &&
                                170                 :          34041 :             pg_strncasecmp(direntry->d_name, fname, fnamelen) == 0)
                                171                 :                :         {
                                172                 :                :             /* Found our match */
                                173                 :           5300 :             strlcpy(canonname, direntry->d_name, canonnamelen);
                                174                 :           5300 :             found = true;
                                175                 :           5300 :             break;
                                176                 :                :         }
                                177                 :                :     }
                                178                 :                : 
                                179                 :           5514 :     FreeDir(dirdesc);
                                180                 :                : 
                                181                 :           5514 :     return found;
                                182                 :                : }
                                183                 :                : 
                                184                 :                : 
                                185                 :                : /*
                                186                 :                :  * We keep loaded timezones in a hashtable so we don't have to
                                187                 :                :  * load and parse the TZ definition file every time one is selected.
                                188                 :                :  * Because we want timezone names to be found case-insensitively,
                                189                 :                :  * the hash key is the uppercased name of the zone.
                                190                 :                :  */
                                191                 :                : typedef struct
                                192                 :                : {
                                193                 :                :     /* tznameupper contains the all-upper-case name of the timezone */
                                194                 :                :     char        tznameupper[TZ_STRLEN_MAX + 1];
                                195                 :                :     pg_tz       tz;
                                196                 :                : } pg_tz_cache;
                                197                 :                : 
                                198                 :                : static HTAB *timezone_cache = NULL;
                                199                 :                : 
                                200                 :                : 
                                201                 :                : static bool
 6935 bruce@momjian.us          202                 :            928 : init_timezone_hashtable(void)
                                203                 :                : {
                                204                 :                :     HASHCTL     hash_ctl;
                                205                 :                : 
 6792 tgl@sss.pgh.pa.us         206                 :            928 :     hash_ctl.keysize = TZ_STRLEN_MAX + 1;
 6390                           207                 :            928 :     hash_ctl.entrysize = sizeof(pg_tz_cache);
                                208                 :                : 
 6935 bruce@momjian.us          209                 :            928 :     timezone_cache = hash_create("Timezones",
                                210                 :                :                                  4,
                                211                 :                :                                  &hash_ctl,
                                212                 :                :                                  HASH_ELEM | HASH_STRINGS);
                                213         [ -  + ]:            928 :     if (!timezone_cache)
 6935 bruce@momjian.us          214                 :UBC           0 :         return false;
                                215                 :                : 
 6935 bruce@momjian.us          216                 :CBC         928 :     return true;
                                217                 :                : }
                                218                 :                : 
                                219                 :                : /*
                                220                 :                :  * Load a timezone from file or from cache.
                                221                 :                :  * Does not verify that the timezone is acceptable!
                                222                 :                :  *
                                223                 :                :  * "GMT" is always interpreted as the tzparse() definition, without attempting
                                224                 :                :  * to load a definition from the filesystem.  This has a number of benefits:
                                225                 :                :  * 1. It's guaranteed to succeed, so we don't have the failure mode wherein
                                226                 :                :  * the bootstrap default timezone setting doesn't work (as could happen if
                                227                 :                :  * the OS attempts to supply a leap-second-aware version of "GMT").
                                228                 :                :  * 2. Because we aren't accessing the filesystem, we can safely initialize
                                229                 :                :  * the "GMT" zone definition before my_exec_path is known.
                                230                 :                :  * 3. It's quick enough that we don't waste much time when the bootstrap
                                231                 :                :  * default timezone setting is later overridden from postgresql.conf.
                                232                 :                :  */
                                233                 :                : pg_tz *
  573 pg@bowt.ie                234                 :          15421 : pg_tzset(const char *tzname)
                                235                 :                : {
                                236                 :                :     pg_tz_cache *tzp;
                                237                 :                :     struct state tzstate;
                                238                 :                :     char        uppername[TZ_STRLEN_MAX + 1];
                                239                 :                :     char        canonname[TZ_STRLEN_MAX + 1];
                                240                 :                :     char       *p;
                                241                 :                : 
                                242         [ -  + ]:          15421 :     if (strlen(tzname) > TZ_STRLEN_MAX)
 6935 bruce@momjian.us          243                 :UBC           0 :         return NULL;            /* not going to fit */
                                244                 :                : 
 6935 bruce@momjian.us          245         [ +  + ]:CBC       15421 :     if (!timezone_cache)
                                246         [ -  + ]:            928 :         if (!init_timezone_hashtable())
 6935 bruce@momjian.us          247                 :UBC           0 :             return NULL;
                                248                 :                : 
                                249                 :                :     /*
                                250                 :                :      * Upcase the given name to perform a case-insensitive hashtable search.
                                251                 :                :      * (We could alternatively downcase it, but we prefer upcase so that we
                                252                 :                :      * can get consistently upcased results from tzparse() in case the name is
                                253                 :                :      * a POSIX-style timezone spec.)
                                254                 :                :      */
 6390 tgl@sss.pgh.pa.us         255                 :CBC       15421 :     p = uppername;
  573 pg@bowt.ie                256         [ +  + ]:         160113 :     while (*tzname)
                                257                 :         144692 :         *p++ = pg_toupper((unsigned char) *tzname++);
 6390 tgl@sss.pgh.pa.us         258                 :          15421 :     *p = '\0';
                                259                 :                : 
                                260                 :          15421 :     tzp = (pg_tz_cache *) hash_search(timezone_cache,
                                261                 :                :                                       uppername,
                                262                 :                :                                       HASH_FIND,
                                263                 :                :                                       NULL);
 6935 bruce@momjian.us          264         [ +  + ]:          15421 :     if (tzp)
                                265                 :                :     {
                                266                 :                :         /* Timezone found in cache, nothing more to do */
 6390 tgl@sss.pgh.pa.us         267                 :           9973 :         return &tzp->tz;
                                268                 :                :     }
                                269                 :                : 
                                270                 :                :     /*
                                271                 :                :      * "GMT" is always sent to tzparse(), as per discussion above.
                                272                 :                :      */
 4601                           273         [ +  + ]:           5448 :     if (strcmp(uppername, "GMT") == 0)
                                274                 :                :     {
 2939                           275         [ -  + ]:            928 :         if (!tzparse(uppername, &tzstate, true))
                                276                 :                :         {
                                277                 :                :             /* This really, really should not happen ... */
 4601 tgl@sss.pgh.pa.us         278         [ #  # ]:UBC           0 :             elog(ERROR, "could not initialize GMT time zone");
                                279                 :                :         }
                                280                 :                :         /* Use uppercase name as canonical */
 4601 tgl@sss.pgh.pa.us         281                 :CBC         928 :         strcpy(canonname, uppername);
                                282                 :                :     }
 2939                           283         [ +  + ]:           4520 :     else if (tzload(uppername, canonname, &tzstate, true) != 0)
                                284                 :                :     {
                                285   [ +  -  +  + ]:            214 :         if (uppername[0] == ':' || !tzparse(uppername, &tzstate, false))
                                286                 :                :         {
                                287                 :                :             /* Unknown timezone. Fail our call instead of loading GMT! */
 6935 bruce@momjian.us          288                 :             48 :             return NULL;
                                289                 :                :         }
                                290                 :                :         /* For POSIX timezone specs, use uppercase name as canonical */
 6390 tgl@sss.pgh.pa.us         291                 :            166 :         strcpy(canonname, uppername);
                                292                 :                :     }
                                293                 :                : 
                                294                 :                :     /* Save timezone in the cache */
                                295                 :           5400 :     tzp = (pg_tz_cache *) hash_search(timezone_cache,
                                296                 :                :                                       uppername,
                                297                 :                :                                       HASH_ENTER,
                                298                 :                :                                       NULL);
                                299                 :                : 
                                300                 :                :     /* hash_search already copied uppername into the hash key */
                                301                 :           5400 :     strcpy(tzp->tz.TZname, canonname);
                                302                 :           5400 :     memcpy(&tzp->tz.state, &tzstate, sizeof(tzstate));
                                303                 :                : 
                                304                 :           5400 :     return &tzp->tz;
                                305                 :                : }
                                306                 :                : 
                                307                 :                : /*
                                308                 :                :  * Load a fixed-GMT-offset timezone.
                                309                 :                :  * This is used for SQL-spec SET TIME ZONE INTERVAL 'foo' cases.
                                310                 :                :  * It's otherwise equivalent to pg_tzset().
                                311                 :                :  *
                                312                 :                :  * The GMT offset is specified in seconds, positive values meaning west of
                                313                 :                :  * Greenwich (ie, POSIX not ISO sign convention).  However, we use ISO
                                314                 :                :  * sign convention in the displayable abbreviation for the zone.
                                315                 :                :  *
                                316                 :                :  * Caution: this can fail (return NULL) if the specified offset is outside
                                317                 :                :  * the range allowed by the zic library.
                                318                 :                :  */
                                319                 :                : pg_tz *
 3817                           320                 :             39 : pg_tzset_offset(long gmtoffset)
                                321                 :                : {
                                322                 :             39 :     long        absoffset = (gmtoffset < 0) ? -gmtoffset : gmtoffset;
                                323                 :                :     char        offsetstr[64];
                                324                 :                :     char        tzname[128];
                                325                 :                : 
                                326                 :             39 :     snprintf(offsetstr, sizeof(offsetstr),
                                327                 :                :              "%02ld", absoffset / SECS_PER_HOUR);
 2541                           328                 :             39 :     absoffset %= SECS_PER_HOUR;
 3817                           329         [ +  + ]:             39 :     if (absoffset != 0)
                                330                 :                :     {
                                331                 :              9 :         snprintf(offsetstr + strlen(offsetstr),
                                332                 :              9 :                  sizeof(offsetstr) - strlen(offsetstr),
                                333                 :                :                  ":%02ld", absoffset / SECS_PER_MINUTE);
 2541                           334                 :              9 :         absoffset %= SECS_PER_MINUTE;
 3817                           335         [ -  + ]:              9 :         if (absoffset != 0)
 3817 tgl@sss.pgh.pa.us         336                 :UBC           0 :             snprintf(offsetstr + strlen(offsetstr),
                                337                 :              0 :                      sizeof(offsetstr) - strlen(offsetstr),
                                338                 :                :                      ":%02ld", absoffset);
                                339                 :                :     }
 3817 tgl@sss.pgh.pa.us         340         [ +  + ]:CBC          39 :     if (gmtoffset > 0)
                                341                 :             12 :         snprintf(tzname, sizeof(tzname), "<-%s>+%s",
                                342                 :                :                  offsetstr, offsetstr);
                                343                 :                :     else
                                344                 :             27 :         snprintf(tzname, sizeof(tzname), "<+%s>-%s",
                                345                 :                :                  offsetstr, offsetstr);
                                346                 :                : 
                                347                 :             39 :     return pg_tzset(tzname);
                                348                 :                : }
                                349                 :                : 
                                350                 :                : 
                                351                 :                : /*
                                352                 :                :  * Initialize timezone library
                                353                 :                :  *
                                354                 :                :  * This is called before GUC variable initialization begins.  Its purpose
                                355                 :                :  * is to ensure that log_timezone has a valid value before any logging GUC
                                356                 :                :  * variables could become set to values that require elog.c to provide
                                357                 :                :  * timestamps (e.g., log_line_prefix).  We may as well initialize
                                358                 :                :  * session_timezone to something valid, too.
                                359                 :                :  */
                                360                 :                : void
 7268 bruce@momjian.us          361                 :            928 : pg_timezone_initialize(void)
                                362                 :                : {
                                363                 :                :     /*
                                364                 :                :      * We may not yet know where PGSHAREDIR is (in particular this is true in
                                365                 :                :      * an EXEC_BACKEND subprocess).  So use "GMT", which pg_tzset forces to be
                                366                 :                :      * interpreted without reference to the filesystem.  This corresponds to
                                367                 :                :      * the bootstrap default for these variables in guc_tables.c, although in
                                368                 :                :      * principle it could be different.
                                369                 :                :      */
 4601 tgl@sss.pgh.pa.us         370                 :            928 :     session_timezone = pg_tzset("GMT");
                                371                 :            928 :     log_timezone = session_timezone;
 7268                           372                 :            928 : }
                                373                 :                : 
                                374                 :                : 
                                375                 :                : /*
                                376                 :                :  * Functions to enumerate available timezones
                                377                 :                :  *
                                378                 :                :  * Note that pg_tzenumerate_next() will return a pointer into the pg_tzenum
                                379                 :                :  * structure, so the data is only valid up to the next call.
                                380                 :                :  *
                                381                 :                :  * All data is allocated using palloc in the current context.
                                382                 :                :  */
                                383                 :                : #define MAX_TZDIR_DEPTH 10
                                384                 :                : 
                                385                 :                : struct pg_tzenum
                                386                 :                : {
                                387                 :                :     int         baselen;
                                388                 :                :     int         depth;
                                389                 :                :     DIR        *dirdesc[MAX_TZDIR_DEPTH];
                                390                 :                :     char       *dirname[MAX_TZDIR_DEPTH];
                                391                 :                :     struct pg_tz tz;
                                392                 :                : };
                                393                 :                : 
                                394                 :                : /* typedef pg_tzenum is declared in pgtime.h */
                                395                 :                : 
                                396                 :                : pg_tzenum *
 6402 bruce@momjian.us          397                 :              8 : pg_tzenumerate_start(void)
                                398                 :                : {
                                399                 :              8 :     pg_tzenum  *ret = (pg_tzenum *) palloc0(sizeof(pg_tzenum));
                                400                 :              8 :     char       *startdir = pstrdup(pg_TZDIR());
                                401                 :                : 
 6420 tgl@sss.pgh.pa.us         402                 :              8 :     ret->baselen = strlen(startdir) + 1;
                                403                 :              8 :     ret->depth = 0;
                                404                 :              8 :     ret->dirname[0] = startdir;
                                405                 :              8 :     ret->dirdesc[0] = AllocateDir(startdir);
 6402 bruce@momjian.us          406         [ -  + ]:              8 :     if (!ret->dirdesc[0])
 6420 tgl@sss.pgh.pa.us         407         [ #  # ]:UBC           0 :         ereport(ERROR,
                                408                 :                :                 (errcode_for_file_access(),
                                409                 :                :                  errmsg("could not open directory \"%s\": %m", startdir)));
 6420 tgl@sss.pgh.pa.us         410                 :CBC           8 :     return ret;
                                411                 :                : }
                                412                 :                : 
                                413                 :                : void
                                414                 :              8 : pg_tzenumerate_end(pg_tzenum *dir)
                                415                 :                : {
                                416         [ -  + ]:              8 :     while (dir->depth >= 0)
                                417                 :                :     {
 6420 tgl@sss.pgh.pa.us         418                 :UBC           0 :         FreeDir(dir->dirdesc[dir->depth]);
                                419                 :              0 :         pfree(dir->dirname[dir->depth]);
                                420                 :              0 :         dir->depth--;
                                421                 :                :     }
 6420 tgl@sss.pgh.pa.us         422                 :CBC           8 :     pfree(dir);
                                423                 :              8 : }
                                424                 :                : 
                                425                 :                : pg_tz *
                                426                 :           4784 : pg_tzenumerate_next(pg_tzenum *dir)
                                427                 :                : {
                                428         [ +  + ]:           5448 :     while (dir->depth >= 0)
                                429                 :                :     {
                                430                 :                :         struct dirent *direntry;
                                431                 :                :         char        fullname[MAXPGPATH * 2];
                                432                 :                : 
                                433                 :           5440 :         direntry = ReadDir(dir->dirdesc[dir->depth], dir->dirname[dir->depth]);
                                434                 :                : 
                                435         [ +  + ]:           5440 :         if (!direntry)
                                436                 :                :         {
                                437                 :                :             /* End of this directory */
                                438                 :            168 :             FreeDir(dir->dirdesc[dir->depth]);
                                439                 :            168 :             pfree(dir->dirname[dir->depth]);
                                440                 :            168 :             dir->depth--;
                                441                 :            664 :             continue;
                                442                 :                :         }
                                443                 :                : 
                                444         [ +  + ]:           5272 :         if (direntry->d_name[0] == '.')
                                445                 :            336 :             continue;
                                446                 :                : 
 2560 peter_e@gmx.net           447                 :           4936 :         snprintf(fullname, sizeof(fullname), "%s/%s",
 6420 tgl@sss.pgh.pa.us         448                 :           4936 :                  dir->dirname[dir->depth], direntry->d_name);
                                449                 :                : 
  590 michael@paquier.xyz       450         [ +  + ]:           4936 :         if (get_dirent_type(fullname, direntry, true, ERROR) == PGFILETYPE_DIR)
                                451                 :                :         {
                                452                 :                :             /* Step into the subdirectory */
 6402 bruce@momjian.us          453         [ -  + ]:            160 :             if (dir->depth >= MAX_TZDIR_DEPTH - 1)
 6420 tgl@sss.pgh.pa.us         454         [ #  # ]:UBC           0 :                 ereport(ERROR,
                                455                 :                :                         (errmsg_internal("timezone directory stack overflow")));
 6420 tgl@sss.pgh.pa.us         456                 :CBC         160 :             dir->depth++;
                                457                 :            160 :             dir->dirname[dir->depth] = pstrdup(fullname);
                                458                 :            160 :             dir->dirdesc[dir->depth] = AllocateDir(fullname);
 6402 bruce@momjian.us          459         [ -  + ]:            160 :             if (!dir->dirdesc[dir->depth])
 6420 tgl@sss.pgh.pa.us         460         [ #  # ]:UBC           0 :                 ereport(ERROR,
                                461                 :                :                         (errcode_for_file_access(),
                                462                 :                :                          errmsg("could not open directory \"%s\": %m",
                                463                 :                :                                 fullname)));
                                464                 :                : 
                                465                 :                :             /* Start over reading in the new directory */
 6420 tgl@sss.pgh.pa.us         466                 :CBC         160 :             continue;
                                467                 :                :         }
                                468                 :                : 
                                469                 :                :         /*
                                470                 :                :          * Load this timezone using tzload() not pg_tzset(), so we don't fill
                                471                 :                :          * the cache.  Also, don't ask for the canonical spelling: we already
                                472                 :                :          * know it, and pg_open_tzfile's way of finding it out is pretty
                                473                 :                :          * inefficient.
                                474                 :                :          */
 2539                           475         [ -  + ]:           4776 :         if (tzload(fullname + dir->baselen, NULL, &dir->tz.state, true) != 0)
                                476                 :                :         {
                                477                 :                :             /* Zone could not be loaded, ignore it */
 6420 tgl@sss.pgh.pa.us         478                 :UBC           0 :             continue;
                                479                 :                :         }
                                480                 :                : 
 4601 tgl@sss.pgh.pa.us         481         [ -  + ]:CBC        4776 :         if (!pg_tz_acceptable(&dir->tz))
                                482                 :                :         {
                                483                 :                :             /* Ignore leap-second zones */
 5631 tgl@sss.pgh.pa.us         484                 :UBC           0 :             continue;
                                485                 :                :         }
                                486                 :                : 
                                487                 :                :         /* OK, return the canonical zone name spelling. */
 2539 tgl@sss.pgh.pa.us         488                 :CBC        4776 :         strlcpy(dir->tz.TZname, fullname + dir->baselen,
                                489                 :                :                 sizeof(dir->tz.TZname));
                                490                 :                : 
                                491                 :                :         /* Timezone loaded OK. */
 6420                           492                 :           4776 :         return &dir->tz;
                                493                 :                :     }
                                494                 :                : 
                                495                 :                :     /* Nothing more found */
                                496                 :              8 :     return NULL;
                                497                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622