]> granicus.if.org Git - postgresql/commitdiff
Fix handling of symlinked pg_stat_tmp and pg_replslot
authorMagnus Hagander <magnus@hagander.net>
Mon, 7 Nov 2016 13:47:30 +0000 (14:47 +0100)
committerMagnus Hagander <magnus@hagander.net>
Mon, 7 Nov 2016 13:47:30 +0000 (14:47 +0100)
This was already fixed in HEAD as part of 6ad8ac60 but was not
backpatched.

Also change the way pg_xlog is handled to be the same as the other
directories.

Patch from me with pg_xlog addition from Michael Paquier, test updates
from David Steele.

src/backend/replication/basebackup.c
src/bin/pg_basebackup/t/010_pg_basebackup.pl

index da9b7a6f0de791ea4f09e4beeaeb6bc945c28306..426f6c85e1b08289d941d28a8f100a82f5247ee8 100644 (file)
@@ -57,6 +57,8 @@ static bool sendFile(char *readfilename, char *tarfilename,
 static void sendFileWithContent(const char *filename, const char *content);
 static void _tarWriteHeader(const char *filename, const char *linktarget,
                                struct stat * statbuf);
+static int64 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat * statbuf,
+                        bool sizeonly);
 static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
@@ -969,9 +971,7 @@ sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces,
                if ((statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0) ||
                  strncmp(de->d_name, PG_STAT_TMP_DIR, strlen(PG_STAT_TMP_DIR)) == 0)
                {
-                       if (!sizeonly)
-                               _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf);
-                       size += 512;
+                       size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
                        continue;
                }
 
@@ -981,9 +981,7 @@ sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces,
                 */
                if (strcmp(de->d_name, "pg_replslot") == 0)
                {
-                       if (!sizeonly)
-                               _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf);
-                       size += 512;            /* Size of the header just added */
+                       size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
                        continue;
                }
 
@@ -994,18 +992,8 @@ sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces,
                 */
                if (strcmp(pathbuf, "./pg_xlog") == 0)
                {
-                       if (!sizeonly)
-                       {
-                               /* If pg_xlog is a symlink, write it as a directory anyway */
-#ifndef WIN32
-                               if (S_ISLNK(statbuf.st_mode))
-#else
-                               if (pgwin32_is_junction(pathbuf))
-#endif
-                                       statbuf.st_mode = S_IFDIR | S_IRWXU;
-                               _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf);
-                       }
-                       size += 512;            /* Size of the header just added */
+                       /* If pg_xlog is a symlink, write it as a directory anyway */
+                       size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
 
                        /*
                         * Also send archive_status directory (by hackishly reusing
@@ -1247,6 +1235,30 @@ _tarWriteHeader(const char *filename, const char *linktarget,
        pq_putmessage('d', h, 512);
 }
 
+/*
+ * Write tar header for a directory.  If the entry in statbuf is a link then
+ * write it as a directory anyway.
+ */
+static int64
+_tarWriteDir(const char *pathbuf, int basepathlen, struct stat * statbuf,
+                        bool sizeonly)
+{
+       if (sizeonly)
+               /* Directory headers are always 512 bytes */
+               return 512;
+
+       /* If symlink, write it as a directory anyway */
+#ifndef WIN32
+       if (S_ISLNK(statbuf->st_mode))
+#else
+       if (pgwin32_is_junction(pathbuf))
+#endif
+               statbuf->st_mode = S_IFDIR | S_IRWXU;
+
+       _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf);
+       return 512;
+}
+
 /*
  * Increment the network transfer counter by the given number of bytes,
  * and sleep if necessary to comply with the requested network transfer
index 6c33936d25f02a1d34e3ceabb3c620641ebea10c..a83f3af2f47a84ab87a1eb84ba3c1eaea2373394 100644 (file)
@@ -4,7 +4,7 @@ use Cwd;
 use Config;
 use PostgresNode;
 use TestLib;
-use Test::More tests => 51;
+use Test::More tests => 52;
 
 program_help_ok('pg_basebackup');
 program_version_ok('pg_basebackup');
@@ -102,7 +102,17 @@ unlink "$pgdata/$superlongname";
 # skip on Windows.
 SKIP:
 {
-       skip "symlinks not supported on Windows", 10 if ($windows_os);
+       skip "symlinks not supported on Windows", 11 if ($windows_os);
+
+       # Move pg_replslot out of $pgdata and create a symlink to it.
+       $node->stop;
+
+       rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
+                  or BAIL_OUT "could not move $pgdata/pg_replslot";
+       symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot")
+                  or BAIL_OUT "could not symlink to $pgdata/pg_replslot";
+
+       $node->start;
 
        # Create a temporary directory in the system location and symlink it
        # to our physical temp location.  That way we can use shorter names
@@ -140,6 +150,8 @@ SKIP:
                "tablespace symlink was updated");
        closedir $dh;
 
+       ok(-d "$tempdir/backup1/pg_replslot", 'pg_replslot symlink copied as directory');
+
        mkdir "$tempdir/tbl=spc2";
        $node->safe_psql('postgres', "DROP TABLE test1;");
        $node->safe_psql('postgres', "DROP TABLESPACE tblspc1;");