LCOV - differential code coverage report
Current view: top level - contrib/adminpack - adminpack.c (source / functions) Coverage Total Hit UNC UIC UBC CBC EUB
Current: Differential Code Coverage HEAD vs 15 Lines: 45.7 % 173 79 1 7 86 79 8
Current Date: 2023-04-08 15:15:32 Functions: 70.8 % 24 17 1 6 17
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * adminpack.c
       4                 :  *
       5                 :  *
       6                 :  * Copyright (c) 2002-2023, PostgreSQL Global Development Group
       7                 :  *
       8                 :  * Author: Andreas Pflug <pgadmin@pse-consulting.de>
       9                 :  *
      10                 :  * IDENTIFICATION
      11                 :  *    contrib/adminpack/adminpack.c
      12                 :  *
      13                 :  *-------------------------------------------------------------------------
      14                 :  */
      15                 : #include "postgres.h"
      16                 : 
      17                 : #include <sys/file.h>
      18                 : #include <sys/stat.h>
      19                 : #include <unistd.h>
      20                 : 
      21                 : #include "catalog/pg_authid.h"
      22                 : #include "catalog/pg_type.h"
      23                 : #include "funcapi.h"
      24                 : #include "miscadmin.h"
      25                 : #include "postmaster/syslogger.h"
      26                 : #include "storage/fd.h"
      27                 : #include "utils/acl.h"
      28                 : #include "utils/builtins.h"
      29                 : #include "utils/datetime.h"
      30                 : 
      31                 : 
      32                 : #ifdef WIN32
      33                 : 
      34                 : #ifdef rename
      35                 : #undef rename
      36                 : #endif
      37                 : 
      38                 : #ifdef unlink
      39                 : #undef unlink
      40                 : #endif
      41                 : #endif
      42                 : 
      43 CBC           1 : PG_MODULE_MAGIC;
      44                 : 
      45               1 : PG_FUNCTION_INFO_V1(pg_file_write);
      46               4 : PG_FUNCTION_INFO_V1(pg_file_write_v1_1);
      47               2 : PG_FUNCTION_INFO_V1(pg_file_sync);
      48               1 : PG_FUNCTION_INFO_V1(pg_file_rename);
      49               2 : PG_FUNCTION_INFO_V1(pg_file_rename_v1_1);
      50               1 : PG_FUNCTION_INFO_V1(pg_file_unlink);
      51               2 : PG_FUNCTION_INFO_V1(pg_file_unlink_v1_1);
      52               1 : PG_FUNCTION_INFO_V1(pg_logdir_ls);
      53               1 : PG_FUNCTION_INFO_V1(pg_logdir_ls_v1_1);
      54                 : 
      55                 : static int64 pg_file_write_internal(text *file, text *data, bool replace);
      56                 : static bool pg_file_rename_internal(text *file1, text *file2, text *file3);
      57                 : static Datum pg_logdir_ls_internal(FunctionCallInfo fcinfo);
      58                 : 
      59                 : 
      60                 : /*-----------------------
      61                 :  * some helper functions
      62                 :  */
      63                 : 
      64                 : /*
      65                 :  * Convert a "text" filename argument to C string, and check it's allowable.
      66                 :  *
      67                 :  * Filename may be absolute or relative to the DataDir, but we only allow
      68                 :  * absolute paths that match DataDir.
      69                 :  */
      70                 : static char *
      71              23 : convert_and_check_filename(text *arg)
      72                 : {
      73              23 :     char       *filename = text_to_cstring(arg);
      74                 : 
      75              23 :     canonicalize_path(filename);    /* filename can change length here */
      76                 : 
      77                 :     /*
      78                 :      * Members of the 'pg_write_server_files' role are allowed to access any
      79                 :      * files on the server as the PG user, so no need to do any further checks
      80                 :      * here.
      81                 :      */
      82              23 :     if (has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES))
      83              19 :         return filename;
      84                 : 
      85                 :     /*
      86                 :      * User isn't a member of the pg_write_server_files role, so check if it's
      87                 :      * allowable
      88                 :      */
      89               4 :     if (is_absolute_path(filename))
      90                 :     {
      91                 :         /* Allow absolute paths if within DataDir */
      92               3 :         if (!path_is_prefix_of_path(DataDir, filename))
      93               2 :             ereport(ERROR,
      94                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
      95                 :                      errmsg("absolute path not allowed")));
      96                 :     }
      97               1 :     else if (!path_is_relative_and_below_cwd(filename))
      98               1 :         ereport(ERROR,
      99                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     100                 :                  errmsg("path must be in or below the data directory")));
     101                 : 
     102               1 :     return filename;
     103                 : }
     104                 : 
     105                 : 
     106                 : /*
     107                 :  * check for superuser, bark if not.
     108                 :  */
     109                 : static void
     110 UBC           0 : requireSuperuser(void)
     111                 : {
     112               0 :     if (!superuser())
     113               0 :         ereport(ERROR,
     114                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     115                 :                  errmsg("only superuser may access generic file functions")));
     116               0 : }
     117                 : 
     118                 : 
     119                 : 
     120                 : /* ------------------------------------
     121                 :  * pg_file_write - old version
     122                 :  *
     123                 :  * The superuser() check here must be kept as the library might be upgraded
     124                 :  * without the extension being upgraded, meaning that in pre-1.1 installations
     125                 :  * these functions could be called by any user.
     126                 :  */
     127                 : Datum
     128               0 : pg_file_write(PG_FUNCTION_ARGS)
     129                 : {
     130               0 :     text       *file = PG_GETARG_TEXT_PP(0);
     131               0 :     text       *data = PG_GETARG_TEXT_PP(1);
     132               0 :     bool        replace = PG_GETARG_BOOL(2);
     133               0 :     int64       count = 0;
     134                 : 
     135               0 :     requireSuperuser();
     136                 : 
     137               0 :     count = pg_file_write_internal(file, data, replace);
     138                 : 
     139               0 :     PG_RETURN_INT64(count);
     140                 : }
     141                 : 
     142                 : /* ------------------------------------
     143                 :  * pg_file_write_v1_1 - Version 1.1
     144                 :  *
     145                 :  * As of adminpack version 1.1, we no longer need to check if the user
     146                 :  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
     147                 :  * Users can then grant access to it based on their policies.
     148                 :  *
     149                 :  * Otherwise identical to pg_file_write (above).
     150                 :  */
     151                 : Datum
     152 CBC           8 : pg_file_write_v1_1(PG_FUNCTION_ARGS)
     153                 : {
     154               8 :     text       *file = PG_GETARG_TEXT_PP(0);
     155               8 :     text       *data = PG_GETARG_TEXT_PP(1);
     156               8 :     bool        replace = PG_GETARG_BOOL(2);
     157               8 :     int64       count = 0;
     158                 : 
     159               8 :     count = pg_file_write_internal(file, data, replace);
     160                 : 
     161               4 :     PG_RETURN_INT64(count);
     162                 : }
     163                 : 
     164                 : /* ------------------------------------
     165                 :  * pg_file_write_internal - Workhorse for pg_file_write functions.
     166                 :  *
     167                 :  * This handles the actual work for pg_file_write.
     168                 :  */
     169                 : static int64
     170               8 : pg_file_write_internal(text *file, text *data, bool replace)
     171                 : {
     172                 :     FILE       *f;
     173                 :     char       *filename;
     174               8 :     int64       count = 0;
     175                 : 
     176               8 :     filename = convert_and_check_filename(file);
     177                 : 
     178               5 :     if (!replace)
     179                 :     {
     180                 :         struct stat fst;
     181                 : 
     182               4 :         if (stat(filename, &fst) >= 0)
     183               1 :             ereport(ERROR,
     184                 :                     (errcode(ERRCODE_DUPLICATE_FILE),
     185                 :                      errmsg("file \"%s\" exists", filename)));
     186                 : 
     187               3 :         f = AllocateFile(filename, "wb");
     188                 :     }
     189                 :     else
     190               1 :         f = AllocateFile(filename, "ab");
     191                 : 
     192               4 :     if (!f)
     193 UBC           0 :         ereport(ERROR,
     194                 :                 (errcode_for_file_access(),
     195                 :                  errmsg("could not open file \"%s\" for writing: %m",
     196                 :                         filename)));
     197                 : 
     198 CBC           4 :     count = fwrite(VARDATA_ANY(data), 1, VARSIZE_ANY_EXHDR(data), f);
     199               4 :     if (count != VARSIZE_ANY_EXHDR(data) || FreeFile(f))
     200 UBC           0 :         ereport(ERROR,
     201                 :                 (errcode_for_file_access(),
     202                 :                  errmsg("could not write file \"%s\": %m", filename)));
     203                 : 
     204 CBC           4 :     return (count);
     205                 : }
     206                 : 
     207                 : /* ------------------------------------
     208                 :  * pg_file_sync
     209                 :  *
     210                 :  * We REVOKE EXECUTE on the function from PUBLIC.
     211                 :  * Users can then grant access to it based on their policies.
     212                 :  */
     213                 : Datum
     214               3 : pg_file_sync(PG_FUNCTION_ARGS)
     215                 : {
     216                 :     char       *filename;
     217                 :     struct stat fst;
     218                 : 
     219               3 :     filename = convert_and_check_filename(PG_GETARG_TEXT_PP(0));
     220                 : 
     221               3 :     if (stat(filename, &fst) < 0)
     222               1 :         ereport(ERROR,
     223                 :                 (errcode_for_file_access(),
     224                 :                  errmsg("could not stat file \"%s\": %m", filename)));
     225                 : 
     226               2 :     fsync_fname_ext(filename, S_ISDIR(fst.st_mode), false, ERROR);
     227                 : 
     228               2 :     PG_RETURN_VOID();
     229                 : }
     230                 : 
     231                 : /* ------------------------------------
     232                 :  * pg_file_rename - old version
     233                 :  *
     234                 :  * The superuser() check here must be kept as the library might be upgraded
     235                 :  * without the extension being upgraded, meaning that in pre-1.1 installations
     236                 :  * these functions could be called by any user.
     237                 :  */
     238                 : Datum
     239 UBC           0 : pg_file_rename(PG_FUNCTION_ARGS)
     240                 : {
     241                 :     text       *file1;
     242                 :     text       *file2;
     243                 :     text       *file3;
     244                 :     bool        result;
     245                 : 
     246               0 :     requireSuperuser();
     247                 : 
     248               0 :     if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
     249               0 :         PG_RETURN_NULL();
     250                 : 
     251               0 :     file1 = PG_GETARG_TEXT_PP(0);
     252               0 :     file2 = PG_GETARG_TEXT_PP(1);
     253                 : 
     254               0 :     if (PG_ARGISNULL(2))
     255               0 :         file3 = NULL;
     256                 :     else
     257               0 :         file3 = PG_GETARG_TEXT_PP(2);
     258                 : 
     259               0 :     result = pg_file_rename_internal(file1, file2, file3);
     260                 : 
     261               0 :     PG_RETURN_BOOL(result);
     262                 : }
     263                 : 
     264                 : /* ------------------------------------
     265                 :  * pg_file_rename_v1_1 - Version 1.1
     266                 :  *
     267                 :  * As of adminpack version 1.1, we no longer need to check if the user
     268                 :  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
     269                 :  * Users can then grant access to it based on their policies.
     270                 :  *
     271                 :  * Otherwise identical to pg_file_write (above).
     272                 :  */
     273                 : Datum
     274 CBC           3 : pg_file_rename_v1_1(PG_FUNCTION_ARGS)
     275                 : {
     276                 :     text       *file1;
     277                 :     text       *file2;
     278                 :     text       *file3;
     279                 :     bool        result;
     280                 : 
     281               3 :     if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
     282 UBC           0 :         PG_RETURN_NULL();
     283                 : 
     284 CBC           3 :     file1 = PG_GETARG_TEXT_PP(0);
     285               3 :     file2 = PG_GETARG_TEXT_PP(1);
     286                 : 
     287               3 :     if (PG_ARGISNULL(2))
     288               2 :         file3 = NULL;
     289                 :     else
     290               1 :         file3 = PG_GETARG_TEXT_PP(2);
     291                 : 
     292               3 :     result = pg_file_rename_internal(file1, file2, file3);
     293                 : 
     294               3 :     PG_RETURN_BOOL(result);
     295                 : }
     296                 : 
     297                 : /* ------------------------------------
     298                 :  * pg_file_rename_internal - Workhorse for pg_file_rename functions.
     299                 :  *
     300                 :  * This handles the actual work for pg_file_rename.
     301                 :  */
     302                 : static bool
     303               3 : pg_file_rename_internal(text *file1, text *file2, text *file3)
     304                 : {
     305                 :     char       *fn1,
     306                 :                *fn2,
     307                 :                *fn3;
     308                 :     int         rc;
     309                 : 
     310               3 :     fn1 = convert_and_check_filename(file1);
     311               3 :     fn2 = convert_and_check_filename(file2);
     312                 : 
     313               3 :     if (file3 == NULL)
     314               2 :         fn3 = NULL;
     315                 :     else
     316               1 :         fn3 = convert_and_check_filename(file3);
     317                 : 
     318               3 :     if (access(fn1, W_OK) < 0)
     319                 :     {
     320               1 :         ereport(WARNING,
     321                 :                 (errcode_for_file_access(),
     322                 :                  errmsg("file \"%s\" is not accessible: %m", fn1)));
     323                 : 
     324               1 :         return false;
     325                 :     }
     326                 : 
     327               2 :     if (fn3 && access(fn2, W_OK) < 0)
     328                 :     {
     329 UBC           0 :         ereport(WARNING,
     330                 :                 (errcode_for_file_access(),
     331                 :                  errmsg("file \"%s\" is not accessible: %m", fn2)));
     332                 : 
     333               0 :         return false;
     334                 :     }
     335                 : 
     336 CBC           2 :     rc = access(fn3 ? fn3 : fn2, W_OK);
     337               2 :     if (rc >= 0 || errno != ENOENT)
     338                 :     {
     339 UBC           0 :         ereport(ERROR,
     340                 :                 (errcode(ERRCODE_DUPLICATE_FILE),
     341                 :                  errmsg("cannot rename to target file \"%s\"",
     342                 :                         fn3 ? fn3 : fn2)));
     343                 :     }
     344                 : 
     345 CBC           2 :     if (fn3)
     346                 :     {
     347               1 :         if (rename(fn2, fn3) != 0)
     348                 :         {
     349 UBC           0 :             ereport(ERROR,
     350                 :                     (errcode_for_file_access(),
     351                 :                      errmsg("could not rename \"%s\" to \"%s\": %m",
     352                 :                             fn2, fn3)));
     353                 :         }
     354 CBC           1 :         if (rename(fn1, fn2) != 0)
     355                 :         {
     356 UBC           0 :             ereport(WARNING,
     357                 :                     (errcode_for_file_access(),
     358                 :                      errmsg("could not rename \"%s\" to \"%s\": %m",
     359                 :                             fn1, fn2)));
     360                 : 
     361               0 :             if (rename(fn3, fn2) != 0)
     362                 :             {
     363               0 :                 ereport(ERROR,
     364                 :                         (errcode_for_file_access(),
     365                 :                          errmsg("could not rename \"%s\" back to \"%s\": %m",
     366                 :                                 fn3, fn2)));
     367                 :             }
     368                 :             else
     369                 :             {
     370               0 :                 ereport(ERROR,
     371                 :                         (errcode(ERRCODE_UNDEFINED_FILE),
     372                 :                          errmsg("renaming \"%s\" to \"%s\" was reverted",
     373                 :                                 fn2, fn3)));
     374                 :             }
     375                 :         }
     376                 :     }
     377 CBC           1 :     else if (rename(fn1, fn2) != 0)
     378                 :     {
     379 UBC           0 :         ereport(ERROR,
     380                 :                 (errcode_for_file_access(),
     381                 :                  errmsg("could not rename \"%s\" to \"%s\": %m", fn1, fn2)));
     382                 :     }
     383                 : 
     384 CBC           2 :     return true;
     385                 : }
     386                 : 
     387                 : 
     388                 : /* ------------------------------------
     389                 :  * pg_file_unlink - old version
     390                 :  *
     391                 :  * The superuser() check here must be kept as the library might be upgraded
     392                 :  * without the extension being upgraded, meaning that in pre-1.1 installations
     393                 :  * these functions could be called by any user.
     394                 :  */
     395                 : Datum
     396 UBC           0 : pg_file_unlink(PG_FUNCTION_ARGS)
     397                 : {
     398                 :     char       *filename;
     399                 : 
     400               0 :     requireSuperuser();
     401                 : 
     402               0 :     filename = convert_and_check_filename(PG_GETARG_TEXT_PP(0));
     403                 : 
     404               0 :     if (access(filename, W_OK) < 0)
     405                 :     {
     406               0 :         if (errno == ENOENT)
     407               0 :             PG_RETURN_BOOL(false);
     408                 :         else
     409               0 :             ereport(ERROR,
     410                 :                     (errcode_for_file_access(),
     411                 :                      errmsg("file \"%s\" is not accessible: %m", filename)));
     412                 :     }
     413                 : 
     414               0 :     if (unlink(filename) < 0)
     415                 :     {
     416               0 :         ereport(WARNING,
     417                 :                 (errcode_for_file_access(),
     418                 :                  errmsg("could not unlink file \"%s\": %m", filename)));
     419                 : 
     420               0 :         PG_RETURN_BOOL(false);
     421                 :     }
     422               0 :     PG_RETURN_BOOL(true);
     423                 : }
     424                 : 
     425                 : 
     426                 : /* ------------------------------------
     427                 :  * pg_file_unlink_v1_1 - Version 1.1
     428                 :  *
     429                 :  * As of adminpack version 1.1, we no longer need to check if the user
     430                 :  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
     431                 :  * Users can then grant access to it based on their policies.
     432                 :  *
     433                 :  * Otherwise identical to pg_file_unlink (above).
     434                 :  */
     435                 : Datum
     436 CBC           5 : pg_file_unlink_v1_1(PG_FUNCTION_ARGS)
     437                 : {
     438                 :     char       *filename;
     439                 : 
     440               5 :     filename = convert_and_check_filename(PG_GETARG_TEXT_PP(0));
     441                 : 
     442               5 :     if (access(filename, W_OK) < 0)
     443                 :     {
     444               2 :         if (errno == ENOENT)
     445               2 :             PG_RETURN_BOOL(false);
     446                 :         else
     447 UBC           0 :             ereport(ERROR,
     448                 :                     (errcode_for_file_access(),
     449                 :                      errmsg("file \"%s\" is not accessible: %m", filename)));
     450                 :     }
     451                 : 
     452 CBC           3 :     if (unlink(filename) < 0)
     453                 :     {
     454 UBC           0 :         ereport(WARNING,
     455                 :                 (errcode_for_file_access(),
     456                 :                  errmsg("could not unlink file \"%s\": %m", filename)));
     457                 : 
     458               0 :         PG_RETURN_BOOL(false);
     459                 :     }
     460 CBC           3 :     PG_RETURN_BOOL(true);
     461                 : }
     462                 : 
     463                 : /* ------------------------------------
     464                 :  * pg_logdir_ls - Old version
     465                 :  *
     466                 :  * The superuser() check here must be kept as the library might be upgraded
     467                 :  * without the extension being upgraded, meaning that in pre-1.1 installations
     468                 :  * these functions could be called by any user.
     469                 :  */
     470                 : Datum
     471 UBC           0 : pg_logdir_ls(PG_FUNCTION_ARGS)
     472                 : {
     473               0 :     if (!superuser())
     474               0 :         ereport(ERROR,
     475                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     476                 :                  errmsg("only superuser can list the log directory")));
     477                 : 
     478               0 :     return (pg_logdir_ls_internal(fcinfo));
     479                 : }
     480                 : 
     481                 : /* ------------------------------------
     482                 :  * pg_logdir_ls_v1_1 - Version 1.1
     483                 :  *
     484                 :  * As of adminpack version 1.1, we no longer need to check if the user
     485                 :  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
     486                 :  * Users can then grant access to it based on their policies.
     487                 :  *
     488                 :  * Otherwise identical to pg_logdir_ls (above).
     489                 :  */
     490                 : Datum
     491               0 : pg_logdir_ls_v1_1(PG_FUNCTION_ARGS)
     492                 : {
     493               0 :     return (pg_logdir_ls_internal(fcinfo));
     494                 : }
     495                 : 
     496                 : static Datum
     497               0 : pg_logdir_ls_internal(FunctionCallInfo fcinfo)
     498                 : {
     499               0 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
     500                 :     bool        randomAccess;
     501                 :     TupleDesc   tupdesc;
     502                 :     Tuplestorestate *tupstore;
     503                 :     AttInMetadata *attinmeta;
     504                 :     DIR        *dirdesc;
     505                 :     struct dirent *de;
     506                 :     MemoryContext oldcontext;
     507                 : 
     508               0 :     if (strcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log") != 0)
     509               0 :         ereport(ERROR,
     510                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     511                 :                  errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'")));
     512                 : 
     513                 :     /* check to see if caller supports us returning a tuplestore */
     514               0 :     if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
     515               0 :         ereport(ERROR,
     516                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     517                 :                  errmsg("set-valued function called in context that cannot accept a set")));
     518               0 :     if (!(rsinfo->allowedModes & SFRM_Materialize))
     519               0 :         ereport(ERROR,
     520                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
     521                 :                  errmsg("materialize mode required, but it is not allowed in this context")));
     522                 : 
     523                 :     /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
     524               0 :     oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
     525                 : 
     526               0 :     tupdesc = CreateTemplateTupleDesc(2);
     527               0 :     TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime",
     528                 :                        TIMESTAMPOID, -1, 0);
     529               0 :     TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename",
     530                 :                        TEXTOID, -1, 0);
     531                 : 
     532               0 :     randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
     533               0 :     tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
     534               0 :     rsinfo->returnMode = SFRM_Materialize;
     535               0 :     rsinfo->setResult = tupstore;
     536               0 :     rsinfo->setDesc = tupdesc;
     537                 : 
     538               0 :     MemoryContextSwitchTo(oldcontext);
     539                 : 
     540               0 :     attinmeta = TupleDescGetAttInMetadata(tupdesc);
     541                 : 
     542               0 :     dirdesc = AllocateDir(Log_directory);
     543               0 :     while ((de = ReadDir(dirdesc, Log_directory)) != NULL)
     544                 :     {
     545                 :         char       *values[2];
     546                 :         HeapTuple   tuple;
     547                 :         char        timestampbuf[32];
     548                 :         char       *field[MAXDATEFIELDS];
     549                 :         char        lowstr[MAXDATELEN + 1];
     550                 :         int         dtype;
     551                 :         int         nf,
     552                 :                     ftype[MAXDATEFIELDS];
     553                 :         fsec_t      fsec;
     554               0 :         int         tz = 0;
     555                 :         struct pg_tm date;
     556                 :         DateTimeErrorExtra extra;
     557                 : 
     558                 :         /*
     559                 :          * Default format: postgresql-YYYY-MM-DD_HHMMSS.log
     560                 :          */
     561 UIC           0 :         if (strlen(de->d_name) != 32
     562 UBC           0 :             || strncmp(de->d_name, "postgresql-", 11) != 0
     563               0 :             || de->d_name[21] != '_'
     564               0 :             || strcmp(de->d_name + 28, ".log") != 0)
     565               0 :             continue;
     566 EUB             : 
     567                 :         /* extract timestamp portion of filename */
     568 UIC           0 :         strcpy(timestampbuf, de->d_name + 11);
     569 UBC           0 :         timestampbuf[17] = '\0';
     570 EUB             : 
     571                 :         /* parse and decode expected timestamp to verify it's OK format */
     572 UIC           0 :         if (ParseDateTime(timestampbuf, lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))
     573 UBC           0 :             continue;
     574 EUB             : 
     575 UNC           0 :         if (DecodeDateTime(field, ftype, nf,
     576                 :                            &dtype, &date, &fsec, &tz, &extra))
     577 UBC           0 :             continue;
     578                 : 
     579 EUB             :         /* Seems the timestamp is OK; prepare and return tuple */
     580                 : 
     581 UIC           0 :         values[0] = timestampbuf;
     582               0 :         values[1] = psprintf("%s/%s", Log_directory, de->d_name);
     583 EUB             : 
     584 UBC           0 :         tuple = BuildTupleFromCStrings(attinmeta, values);
     585                 : 
     586               0 :         tuplestore_puttuple(tupstore, tuple);
     587                 :     }
     588 EUB             : 
     589 UIC           0 :     FreeDir(dirdesc);
     590               0 :     return (Datum) 0;
     591 EUB             : }
        

Generated by: LCOV version v1.16-55-g56c0a2a