]> granicus.if.org Git - postgresql/commitdiff
Un-DOS-ify newly added files.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 30 May 2006 21:34:15 +0000 (21:34 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 30 May 2006 21:34:15 +0000 (21:34 +0000)
contrib/adminpack/Makefile
contrib/adminpack/adminpack.c
contrib/adminpack/adminpack.sql.in

index 808d0be74b50984a78509df855fb231418bc1fe2..6187c6a2585a412b6fc2fb8308627ec153fed3f3 100644 (file)
@@ -1,15 +1,15 @@
-MODULE_big = adminpack\r
-PG_CPPFLAGS = -I$(libpq_srcdir)\r
-DATA_built = adminpack.sql\r
-DOCS = README.adminpack\r
-OBJS = adminpack.o\r
-\r
-ifdef USE_PGXS\r
-PGXS := $(shell pg_config --pgxs)\r
-include $(PGXS)\r
-else\r
-subdir = contrib/adminpack\r
-top_builddir = ../..\r
-include $(top_builddir)/src/Makefile.global\r
-include $(top_srcdir)/contrib/contrib-global.mk\r
-endif\r
+MODULE_big = adminpack
+PG_CPPFLAGS = -I$(libpq_srcdir)
+DATA_built = adminpack.sql
+DOCS = README.adminpack
+OBJS = adminpack.o
+
+ifdef USE_PGXS
+PGXS := $(shell pg_config --pgxs)
+include $(PGXS)
+else
+subdir = contrib/adminpack
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
index 683a8e916c5ee1d71e87e2d5cbbae7868a366c41..a9c8b4933ba62757ecfaa7ff2dd95d3458fa8249 100644 (file)
-/*-------------------------------------------------------------------------\r
- *\r
- * admin81.c\r
- *\r
- *\r
- * Copyright (c) 2002 - 2006, PostgreSQL Global Development Group\r
- * \r
- * Author: Andreas Pflug <pgadmin@pse-consulting.de>\r
- *\r
- * IDENTIFICATION\r
- *       $PostgreSQL: pgsql/contrib/adminpack/adminpack.c,v 1.1 2006/05/30 12:07:31 momjian Exp $\r
- *\r
- *-------------------------------------------------------------------------\r
- */\r
-#include "postgres.h"\r
-\r
-#include <sys/file.h>\r
-#include <sys/stat.h>\r
-#include <unistd.h>\r
-#include <dirent.h>\r
-\r
-#include "miscadmin.h"\r
-#include "storage/fd.h"\r
-#include "catalog/pg_type.h"\r
-#include "funcapi.h"\r
-#include "utils/datetime.h"\r
-\r
-\r
-#ifdef WIN32\r
-\r
-#ifdef rename\r
-#undef rename\r
-#endif\r
-\r
-#ifdef unlink\r
-#undef unlink\r
-#endif\r
-\r
-#endif\r
-\r
-extern DLLIMPORT char *DataDir;\r
-extern DLLIMPORT char *Log_directory;\r
-extern DLLIMPORT char *Log_filename;\r
-\r
-Datum pg_file_write(PG_FUNCTION_ARGS);\r
-Datum pg_file_rename(PG_FUNCTION_ARGS);\r
-Datum pg_file_unlink(PG_FUNCTION_ARGS);\r
-Datum pg_logdir_ls(PG_FUNCTION_ARGS);\r
-\r
-PG_FUNCTION_INFO_V1(pg_file_write);\r
-PG_FUNCTION_INFO_V1(pg_file_rename);\r
-PG_FUNCTION_INFO_V1(pg_file_unlink);\r
-PG_FUNCTION_INFO_V1(pg_logdir_ls);\r
-\r
-typedef struct \r
-{\r
-       char *location;\r
-       DIR *dirdesc;\r
-} directory_fctx;\r
-\r
-/*-----------------------\r
- * some helper functions\r
- */\r
-\r
-/*\r
- * Return an absolute path. Argument may be absolute or \r
- * relative to the DataDir.\r
- */\r
-static char *absClusterPath(text *arg, bool logAllowed)\r
-{\r
-       char *filename;\r
-       int len=VARSIZE(arg) - VARHDRSZ;\r
-       int dlen = strlen(DataDir);\r
-\r
-       filename = palloc(len+1);\r
-       memcpy(filename, VARDATA(arg), len);\r
-       filename[len] = 0;\r
-\r
-       if (strstr(filename, "..") != NULL)\r
-         ereport(ERROR,\r
-                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),\r
-                          (errmsg("No .. allowed in filenames"))));\r
-       \r
-       if (is_absolute_path(filename))\r
-       {\r
-           if (logAllowed && !strncmp(filename, Log_directory, strlen(Log_directory)))\r
-                   return filename;\r
-               if (strncmp(filename, DataDir, dlen))\r
-                   ereport(ERROR,\r
-                                       (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),\r
-                                        (errmsg("Absolute path not allowed"))));\r
-\r
-               return filename;\r
-       }\r
-       else\r
-       {\r
-           char *absname = palloc(dlen+len+2);\r
-               sprintf(absname, "%s/%s", DataDir, filename);\r
-               pfree(filename);\r
-               return absname;\r
-       }\r
-}\r
-\r
-\r
-/*\r
- * check for superuser, bark if not.\r
- */\r
-static void\r
-requireSuperuser(void)\r
-{\r
-       if (!superuser())\r
-           ereport(ERROR,\r
-                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),\r
-                                (errmsg("only superuser may access generic file functions"))));\r
-}\r
-\r
-\r
-\r
-/* ------------------------------------\r
- * generic file handling functions\r
- */\r
-\r
-Datum pg_file_write(PG_FUNCTION_ARGS)\r
-{\r
-       FILE *f;\r
-       char *filename;\r
-       text *data;\r
-       int64 count = 0;\r
-\r
-       requireSuperuser();\r
-\r
-       filename = absClusterPath(PG_GETARG_TEXT_P(0), false);\r
-       data = PG_GETARG_TEXT_P(1);\r
-\r
-       if (PG_ARGISNULL(2) || !PG_GETARG_BOOL(2))\r
-       {\r
-           struct stat fst;\r
-               if (stat(filename, &fst) >= 0)\r
-                   ereport(ERROR,\r
-                                       (ERRCODE_DUPLICATE_FILE,\r
-                                        errmsg("file %s exists", filename)));\r
-\r
-           f = fopen(filename, "wb");\r
-       }\r
-       else\r
-           f = fopen(filename, "ab");\r
-\r
-       if (!f)\r
-       {\r
-               ereport(ERROR,\r
-                               (errcode_for_file_access(),\r
-                                errmsg("could open file %s for writing: %m", filename)));\r
-       }\r
-\r
-       if (VARSIZE(data) != 0)\r
-       {\r
-               count = fwrite(VARDATA(data), 1, VARSIZE(data) - VARHDRSZ, f);\r
-\r
-               if (count != VARSIZE(data) - VARHDRSZ)\r
-                   ereport(ERROR,\r
-                                       (errcode_for_file_access(),\r
-                                        errmsg("error writing file %s: %m", filename)));\r
-       }\r
-       fclose(f);\r
-\r
-       PG_RETURN_INT64(count);\r
-}\r
-\r
-\r
-Datum pg_file_rename(PG_FUNCTION_ARGS)\r
-{\r
-    char *fn1, *fn2, *fn3;\r
-       int rc;\r
-\r
-       requireSuperuser();\r
-\r
-       if (PG_ARGISNULL(0) || PG_ARGISNULL(1))\r
-               PG_RETURN_NULL();\r
-\r
-       fn1=absClusterPath(PG_GETARG_TEXT_P(0), false);\r
-       fn2=absClusterPath(PG_GETARG_TEXT_P(1), false);\r
-       if (PG_ARGISNULL(2))\r
-           fn3=0;\r
-       else\r
-           fn3=absClusterPath(PG_GETARG_TEXT_P(2), false);\r
-\r
-       if (access(fn1, W_OK) < 0)\r
-       {\r
-               ereport(WARNING,\r
-                               (errcode_for_file_access(),\r
-                                errmsg("file %s not accessible: %m", fn1)));\r
-\r
-           PG_RETURN_BOOL(false);\r
-       }\r
-\r
-       if (fn3 && access(fn2, W_OK) < 0)\r
-       {\r
-               ereport(WARNING,\r
-                               (errcode_for_file_access(),\r
-                                errmsg("file %s not accessible: %m", fn2)));\r
-\r
-           PG_RETURN_BOOL(false);\r
-       }\r
-\r
-\r
-       rc = access(fn3 ? fn3 : fn2, 2);\r
-       if (rc >= 0 || errno != ENOENT)\r
-       {\r
-               ereport(ERROR,\r
-                               (ERRCODE_DUPLICATE_FILE,\r
-                                errmsg("cannot rename to target file %s", fn3 ? fn3 : fn2)));\r
-       }\r
-       \r
-       if (fn3)\r
-       {\r
-           if (rename(fn2, fn3) != 0)\r
-               {\r
-                       ereport(ERROR,\r
-                                       (errcode_for_file_access(),\r
-                                        errmsg("could not rename %s to %s: %m", fn2, fn3)));\r
-               }\r
-               if (rename(fn1, fn2) != 0)\r
-               {\r
-                       ereport(WARNING,\r
-                                       (errcode_for_file_access(),\r
-                                        errmsg("could not rename %s to %s: %m", fn1, fn2)));\r
-\r
-                       if (rename(fn3, fn2) != 0)\r
-                       {\r
-                               ereport(ERROR,\r
-                                               (errcode_for_file_access(),\r
-                                                errmsg("could not rename %s back to %s: %m", fn3, fn2)));\r
-                       }\r
-                       else\r
-                       {\r
-                               ereport(ERROR,\r
-                                               (ERRCODE_UNDEFINED_FILE,\r
-                                                errmsg("renaming %s to %s was reverted", fn2, fn3)));\r
-\r
-                       }\r
-               }\r
-       }\r
-       else if (rename(fn1, fn2) != 0)\r
-       {\r
-                       ereport(WARNING,\r
-                                       (errcode_for_file_access(),\r
-                                        errmsg("renaming %s to %s %m", fn1, fn2)));\r
-               ereport(ERROR,\r
-                               (errcode_for_file_access(),\r
-                                errmsg("could not rename %s to %s: %m", fn1, fn2)));\r
-       }\r
-\r
-       PG_RETURN_BOOL(true);\r
-}\r
-\r
-\r
-Datum pg_file_unlink(PG_FUNCTION_ARGS)\r
-{\r
-    char *filename;\r
-\r
-       requireSuperuser();\r
-\r
-    filename = absClusterPath(PG_GETARG_TEXT_P(0), false);\r
-\r
-       if (access(filename, W_OK) < 0)\r
-       {\r
-           if (errno == ENOENT)\r
-                   PG_RETURN_BOOL(false);\r
-               else\r
-                   ereport(ERROR,\r
-                                       (errcode_for_file_access(),\r
-                                        errmsg("file %s not accessible: %m", filename)));\r
-\r
-       }\r
-\r
-       if (unlink(filename) < 0)\r
-       {\r
-               ereport(WARNING,\r
-                               (errcode_for_file_access(),\r
-                                errmsg("could not unlink file %s: %m", filename)));\r
-\r
-               PG_RETURN_BOOL(false);\r
-       }\r
-       PG_RETURN_BOOL(true);\r
-}\r
-\r
-\r
-Datum pg_logdir_ls(PG_FUNCTION_ARGS)\r
-{\r
-       FuncCallContext *funcctx;\r
-       struct dirent *de;\r
-       directory_fctx *fctx;\r
-\r
-       if (!superuser()) \r
-               ereport(ERROR,\r
-                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),\r
-                                (errmsg("only superuser can list the log directory"))));\r
-       \r
-       if (memcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log", 30) != 0)\r
-               ereport(ERROR,\r
-                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),\r
-                                (errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'"))));\r
-\r
-       if (SRF_IS_FIRSTCALL())\r
-       {\r
-               MemoryContext oldcontext;\r
-               TupleDesc tupdesc;\r
-\r
-               funcctx=SRF_FIRSTCALL_INIT();\r
-               oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);\r
-\r
-               fctx = palloc(sizeof(directory_fctx));\r
-               if (is_absolute_path(Log_directory))\r
-                   fctx->location = Log_directory;\r
-               else\r
-               {\r
-                       fctx->location = palloc(strlen(DataDir) + strlen(Log_directory) +2);\r
-                       sprintf(fctx->location, "%s/%s", DataDir, Log_directory);\r
-               }\r
-               tupdesc = CreateTemplateTupleDesc(2, false);\r
-               TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime",\r
-                                                  TIMESTAMPOID, -1, 0);\r
-               TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename",\r
-                                                  TEXTOID, -1, 0);\r
-\r
-               funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);\r
-               \r
-               fctx->dirdesc = AllocateDir(fctx->location);\r
-\r
-               if (!fctx->dirdesc)\r
-                   ereport(ERROR,\r
-                                       (errcode_for_file_access(),\r
-                                        errmsg("%s is not browsable: %m", fctx->location)));\r
-\r
-               funcctx->user_fctx = fctx;\r
-               MemoryContextSwitchTo(oldcontext);\r
-       }\r
-\r
-       funcctx=SRF_PERCALL_SETUP();\r
-       fctx = (directory_fctx*) funcctx->user_fctx;\r
-\r
-       if (!fctx->dirdesc)  /* not a readable directory  */\r
-               SRF_RETURN_DONE(funcctx);\r
-\r
-       while ((de = readdir(fctx->dirdesc)) != NULL)\r
-       {\r
-               char *values[2];\r
-               HeapTuple tuple;\r
-            \r
-               char            *field[MAXDATEFIELDS];\r
-               char            lowstr[MAXDATELEN + 1];\r
-               int             dtype;\r
-               int             nf, ftype[MAXDATEFIELDS];\r
-               fsec_t          fsec;\r
-               int             tz = 0;\r
-               struct          pg_tm date;\r
-\r
-               /*\r
-                * Default format:\r
-                *        postgresql-YYYY-MM-DD_HHMMSS.log\r
-                */\r
-               if (strlen(de->d_name) != 32\r
-                   || memcmp(de->d_name, "postgresql-", 11)\r
-                       || de->d_name[21] != '_'\r
-                       || strcmp(de->d_name + 28, ".log"))\r
-                     continue;\r
-\r
-               values[1] = palloc(strlen(fctx->location) + strlen(de->d_name) + 2);\r
-               sprintf(values[1], "%s/%s", fctx->location, de->d_name);\r
-\r
-               values[0] = de->d_name + 11;       /* timestamp */\r
-               values[0][17] = 0;\r
-\r
-                    /* parse and decode expected timestamp */\r
-               if (ParseDateTime(values[0], lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))\r
-                   continue;\r
-\r
-               if (DecodeDateTime(field, ftype, nf, &dtype, &date, &fsec, &tz))\r
-                   continue;\r
-\r
-               /* Seems the format fits the expected format; feed it into the tuple */\r
-\r
-               tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);\r
-\r
-               SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));\r
-       }\r
-\r
-       FreeDir(fctx->dirdesc);\r
-       SRF_RETURN_DONE(funcctx);\r
-}\r
+/*-------------------------------------------------------------------------
+ *
+ * admin81.c
+ *
+ *
+ * Copyright (c) 2002 - 2006, PostgreSQL Global Development Group
+ * 
+ * Author: Andreas Pflug <pgadmin@pse-consulting.de>
+ *
+ * IDENTIFICATION
+ *       $PostgreSQL: pgsql/contrib/adminpack/adminpack.c,v 1.2 2006/05/30 21:34:15 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "miscadmin.h"
+#include "storage/fd.h"
+#include "catalog/pg_type.h"
+#include "funcapi.h"
+#include "utils/datetime.h"
+
+
+#ifdef WIN32
+
+#ifdef rename
+#undef rename
+#endif
+
+#ifdef unlink
+#undef unlink
+#endif
+
+#endif
+
+extern DLLIMPORT char *DataDir;
+extern DLLIMPORT char *Log_directory;
+extern DLLIMPORT char *Log_filename;
+
+PG_MODULE_MAGIC;
+
+Datum pg_file_write(PG_FUNCTION_ARGS);
+Datum pg_file_rename(PG_FUNCTION_ARGS);
+Datum pg_file_unlink(PG_FUNCTION_ARGS);
+Datum pg_logdir_ls(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(pg_file_write);
+PG_FUNCTION_INFO_V1(pg_file_rename);
+PG_FUNCTION_INFO_V1(pg_file_unlink);
+PG_FUNCTION_INFO_V1(pg_logdir_ls);
+
+typedef struct 
+{
+       char *location;
+       DIR *dirdesc;
+} directory_fctx;
+
+/*-----------------------
+ * some helper functions
+ */
+
+/*
+ * Return an absolute path. Argument may be absolute or 
+ * relative to the DataDir.
+ */
+static char *absClusterPath(text *arg, bool logAllowed)
+{
+       char *filename;
+       int len=VARSIZE(arg) - VARHDRSZ;
+       int dlen = strlen(DataDir);
+
+       filename = palloc(len+1);
+       memcpy(filename, VARDATA(arg), len);
+       filename[len] = 0;
+
+       if (strstr(filename, "..") != NULL)
+         ereport(ERROR,
+                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                          (errmsg("No .. allowed in filenames"))));
+       
+       if (is_absolute_path(filename))
+       {
+           if (logAllowed && !strncmp(filename, Log_directory, strlen(Log_directory)))
+                   return filename;
+               if (strncmp(filename, DataDir, dlen))
+                   ereport(ERROR,
+                                       (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                        (errmsg("Absolute path not allowed"))));
+
+               return filename;
+       }
+       else
+       {
+           char *absname = palloc(dlen+len+2);
+               sprintf(absname, "%s/%s", DataDir, filename);
+               pfree(filename);
+               return absname;
+       }
+}
+
+
+/*
+ * check for superuser, bark if not.
+ */
+static void
+requireSuperuser(void)
+{
+       if (!superuser())
+           ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                (errmsg("only superuser may access generic file functions"))));
+}
+
+
+
+/* ------------------------------------
+ * generic file handling functions
+ */
+
+Datum pg_file_write(PG_FUNCTION_ARGS)
+{
+       FILE *f;
+       char *filename;
+       text *data;
+       int64 count = 0;
+
+       requireSuperuser();
+
+       filename = absClusterPath(PG_GETARG_TEXT_P(0), false);
+       data = PG_GETARG_TEXT_P(1);
+
+       if (PG_ARGISNULL(2) || !PG_GETARG_BOOL(2))
+       {
+           struct stat fst;
+               if (stat(filename, &fst) >= 0)
+                   ereport(ERROR,
+                                       (ERRCODE_DUPLICATE_FILE,
+                                        errmsg("file %s exists", filename)));
+
+           f = fopen(filename, "wb");
+       }
+       else
+           f = fopen(filename, "ab");
+
+       if (!f)
+       {
+               ereport(ERROR,
+                               (errcode_for_file_access(),
+                                errmsg("could open file %s for writing: %m", filename)));
+       }
+
+       if (VARSIZE(data) != 0)
+       {
+               count = fwrite(VARDATA(data), 1, VARSIZE(data) - VARHDRSZ, f);
+
+               if (count != VARSIZE(data) - VARHDRSZ)
+                   ereport(ERROR,
+                                       (errcode_for_file_access(),
+                                        errmsg("error writing file %s: %m", filename)));
+       }
+       fclose(f);
+
+       PG_RETURN_INT64(count);
+}
+
+
+Datum pg_file_rename(PG_FUNCTION_ARGS)
+{
+    char *fn1, *fn2, *fn3;
+       int rc;
+
+       requireSuperuser();
+
+       if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+               PG_RETURN_NULL();
+
+       fn1=absClusterPath(PG_GETARG_TEXT_P(0), false);
+       fn2=absClusterPath(PG_GETARG_TEXT_P(1), false);
+       if (PG_ARGISNULL(2))
+           fn3=0;
+       else
+           fn3=absClusterPath(PG_GETARG_TEXT_P(2), false);
+
+       if (access(fn1, W_OK) < 0)
+       {
+               ereport(WARNING,
+                               (errcode_for_file_access(),
+                                errmsg("file %s not accessible: %m", fn1)));
+
+           PG_RETURN_BOOL(false);
+       }
+
+       if (fn3 && access(fn2, W_OK) < 0)
+       {
+               ereport(WARNING,
+                               (errcode_for_file_access(),
+                                errmsg("file %s not accessible: %m", fn2)));
+
+           PG_RETURN_BOOL(false);
+       }
+
+
+       rc = access(fn3 ? fn3 : fn2, 2);
+       if (rc >= 0 || errno != ENOENT)
+       {
+               ereport(ERROR,
+                               (ERRCODE_DUPLICATE_FILE,
+                                errmsg("cannot rename to target file %s", fn3 ? fn3 : fn2)));
+       }
+       
+       if (fn3)
+       {
+           if (rename(fn2, fn3) != 0)
+               {
+                       ereport(ERROR,
+                                       (errcode_for_file_access(),
+                                        errmsg("could not rename %s to %s: %m", fn2, fn3)));
+               }
+               if (rename(fn1, fn2) != 0)
+               {
+                       ereport(WARNING,
+                                       (errcode_for_file_access(),
+                                        errmsg("could not rename %s to %s: %m", fn1, fn2)));
+
+                       if (rename(fn3, fn2) != 0)
+                       {
+                               ereport(ERROR,
+                                               (errcode_for_file_access(),
+                                                errmsg("could not rename %s back to %s: %m", fn3, fn2)));
+                       }
+                       else
+                       {
+                               ereport(ERROR,
+                                               (ERRCODE_UNDEFINED_FILE,
+                                                errmsg("renaming %s to %s was reverted", fn2, fn3)));
+
+                       }
+               }
+       }
+       else if (rename(fn1, fn2) != 0)
+       {
+                       ereport(WARNING,
+                                       (errcode_for_file_access(),
+                                        errmsg("renaming %s to %s %m", fn1, fn2)));
+               ereport(ERROR,
+                               (errcode_for_file_access(),
+                                errmsg("could not rename %s to %s: %m", fn1, fn2)));
+       }
+
+       PG_RETURN_BOOL(true);
+}
+
+
+Datum pg_file_unlink(PG_FUNCTION_ARGS)
+{
+    char *filename;
+
+       requireSuperuser();
+
+    filename = absClusterPath(PG_GETARG_TEXT_P(0), false);
+
+       if (access(filename, W_OK) < 0)
+       {
+           if (errno == ENOENT)
+                   PG_RETURN_BOOL(false);
+               else
+                   ereport(ERROR,
+                                       (errcode_for_file_access(),
+                                        errmsg("file %s not accessible: %m", filename)));
+
+       }
+
+       if (unlink(filename) < 0)
+       {
+               ereport(WARNING,
+                               (errcode_for_file_access(),
+                                errmsg("could not unlink file %s: %m", filename)));
+
+               PG_RETURN_BOOL(false);
+       }
+       PG_RETURN_BOOL(true);
+}
+
+
+Datum pg_logdir_ls(PG_FUNCTION_ARGS)
+{
+       FuncCallContext *funcctx;
+       struct dirent *de;
+       directory_fctx *fctx;
+
+       if (!superuser()) 
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                (errmsg("only superuser can list the log directory"))));
+       
+       if (memcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log", 30) != 0)
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                (errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'"))));
+
+       if (SRF_IS_FIRSTCALL())
+       {
+               MemoryContext oldcontext;
+               TupleDesc tupdesc;
+
+               funcctx=SRF_FIRSTCALL_INIT();
+               oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+               fctx = palloc(sizeof(directory_fctx));
+               if (is_absolute_path(Log_directory))
+                   fctx->location = Log_directory;
+               else
+               {
+                       fctx->location = palloc(strlen(DataDir) + strlen(Log_directory) +2);
+                       sprintf(fctx->location, "%s/%s", DataDir, Log_directory);
+               }
+               tupdesc = CreateTemplateTupleDesc(2, false);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime",
+                                                  TIMESTAMPOID, -1, 0);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename",
+                                                  TEXTOID, -1, 0);
+
+               funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
+               
+               fctx->dirdesc = AllocateDir(fctx->location);
+
+               if (!fctx->dirdesc)
+                   ereport(ERROR,
+                                       (errcode_for_file_access(),
+                                        errmsg("%s is not browsable: %m", fctx->location)));
+
+               funcctx->user_fctx = fctx;
+               MemoryContextSwitchTo(oldcontext);
+       }
+
+       funcctx=SRF_PERCALL_SETUP();
+       fctx = (directory_fctx*) funcctx->user_fctx;
+
+       if (!fctx->dirdesc)  /* not a readable directory  */
+               SRF_RETURN_DONE(funcctx);
+
+       while ((de = readdir(fctx->dirdesc)) != NULL)
+       {
+               char *values[2];
+               HeapTuple tuple;
+            
+               char            *field[MAXDATEFIELDS];
+               char            lowstr[MAXDATELEN + 1];
+               int             dtype;
+               int             nf, ftype[MAXDATEFIELDS];
+               fsec_t          fsec;
+               int             tz = 0;
+               struct          pg_tm date;
+
+               /*
+                * Default format:
+                *        postgresql-YYYY-MM-DD_HHMMSS.log
+                */
+               if (strlen(de->d_name) != 32
+                   || memcmp(de->d_name, "postgresql-", 11)
+                       || de->d_name[21] != '_'
+                       || strcmp(de->d_name + 28, ".log"))
+                     continue;
+
+               values[1] = palloc(strlen(fctx->location) + strlen(de->d_name) + 2);
+               sprintf(values[1], "%s/%s", fctx->location, de->d_name);
+
+               values[0] = de->d_name + 11;       /* timestamp */
+               values[0][17] = 0;
+
+                    /* parse and decode expected timestamp */
+               if (ParseDateTime(values[0], lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))
+                   continue;
+
+               if (DecodeDateTime(field, ftype, nf, &dtype, &date, &fsec, &tz))
+                   continue;
+
+               /* Seems the format fits the expected format; feed it into the tuple */
+
+               tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
+
+               SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+       }
+
+       FreeDir(fctx->dirdesc);
+       SRF_RETURN_DONE(funcctx);
+}
index f1b2bd916cac4e3f406310144c7ec9373c2dd516..1a3cc10bf8859a89d23f71a5b0fb4d1218e1a179 100644 (file)
@@ -1,41 +1,41 @@
-/* ***********************************************\r
- * Administrative functions for PostgreSQL \r
- * *********************************************** */\r
-\r
-/* generic file access functions */\r
-\r
-CREATE FUNCTION pg_catalog.pg_file_write(text, text, bool) RETURNS bigint\r
-   AS 'MODULE_PATHNAME', 'pg_file_write'\r
-       LANGUAGE C VOLATILE STRICT;\r
-\r
-CREATE FUNCTION pg_catalog.pg_file_rename(text, text, text) RETURNS bool\r
-   AS 'MODULE_PATHNAME', 'pg_file_rename'\r
-       LANGUAGE C VOLATILE;\r
-\r
-CREATE FUNCTION pg_catalog.pg_file_unlink(text) RETURNS bool\r
-   AS 'MODULE_PATHNAME', 'pg_file_unlink'\r
-       LANGUAGE C VOLATILE STRICT;\r
-\r
-CREATE FUNCTION pg_catalog.pg_file_rename(text, text) RETURNS bool\r
-   AS 'SELECT pg_file_rename($1, $2, NULL); '\r
-       LANGUAGE SQL VOLATILE STRICT;\r
-\r
-CREATE FUNCTION pg_catalog.pg_logdir_ls() RETURNS setof record\r
-   AS 'MODULE_PATHNAME', 'pg_logdir_ls'\r
-       LANGUAGE C VOLATILE STRICT;\r
-\r
-\r
-/* compatibility redefines */\r
-\r
-CREATE FUNCTION pg_catalog.pg_logfile_rotate() RETURNS int4\r
-  AS 'pg_rotate_logfile'\r
-   LANGUAGE INTERNAL VOLATILE STRICT;\r
-\r
-CREATE FUNCTION pg_catalog.pg_file_read(text, bigint, bigint) RETURNS text\r
-   AS 'pg_read_file'\r
-       LANGUAGE INTERNAL VOLATILE STRICT;\r
-\r
-CREATE FUNCTION pg_catalog.pg_file_length(text) RETURNS bigint\r
-   AS 'SELECT size FROM pg_stat_file($1)'\r
-    LANGUAGE SQL VOLATILE STRICT;\r
-\r
+/* ***********************************************
+ * Administrative functions for PostgreSQL 
+ * *********************************************** */
+
+/* generic file access functions */
+
+CREATE FUNCTION pg_catalog.pg_file_write(text, text, bool) RETURNS bigint
+   AS 'MODULE_PATHNAME', 'pg_file_write'
+       LANGUAGE C VOLATILE STRICT;
+
+CREATE FUNCTION pg_catalog.pg_file_rename(text, text, text) RETURNS bool
+   AS 'MODULE_PATHNAME', 'pg_file_rename'
+       LANGUAGE C VOLATILE;
+
+CREATE FUNCTION pg_catalog.pg_file_unlink(text) RETURNS bool
+   AS 'MODULE_PATHNAME', 'pg_file_unlink'
+       LANGUAGE C VOLATILE STRICT;
+
+CREATE FUNCTION pg_catalog.pg_file_rename(text, text) RETURNS bool
+   AS 'SELECT pg_file_rename($1, $2, NULL); '
+       LANGUAGE SQL VOLATILE STRICT;
+
+CREATE FUNCTION pg_catalog.pg_logdir_ls() RETURNS setof record
+   AS 'MODULE_PATHNAME', 'pg_logdir_ls'
+       LANGUAGE C VOLATILE STRICT;
+
+
+/* compatibility redefines */
+
+CREATE FUNCTION pg_catalog.pg_logfile_rotate() RETURNS int4
+  AS 'pg_rotate_logfile'
+   LANGUAGE INTERNAL VOLATILE STRICT;
+
+CREATE FUNCTION pg_catalog.pg_file_read(text, bigint, bigint) RETURNS text
+   AS 'pg_read_file'
+       LANGUAGE INTERNAL VOLATILE STRICT;
+
+CREATE FUNCTION pg_catalog.pg_file_length(text) RETURNS bigint
+   AS 'SELECT size FROM pg_stat_file($1)'
+    LANGUAGE SQL VOLATILE STRICT;
+