1818#include <time.h>
1919
2020#include "access/xlog_internal.h" /* for pg_start/stop_backup */
21+ #include "catalog/catalog.h"
2122#include "catalog/pg_type.h"
2223#include "lib/stringinfo.h"
2324#include "libpq/libpq.h"
@@ -44,6 +45,7 @@ typedef struct
4445
4546
4647static int64 sendDir (char * path ,int basepathlen ,bool sizeonly );
48+ static int64 sendTablespace (char * path ,bool sizeonly );
4749static bool sendFile (char * readfilename ,char * tarfilename ,
4850struct stat * statbuf ,bool missing_ok );
4951static void sendFileWithContent (const char * filename ,const char * content );
@@ -137,7 +139,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
137139ti = palloc (sizeof (tablespaceinfo ));
138140ti -> oid = pstrdup (de -> d_name );
139141ti -> path = pstrdup (linkpath );
140- ti -> size = opt -> progress ?sendDir ( linkpath , strlen ( linkpath ) , true) :-1 ;
142+ ti -> size = opt -> progress ?sendTablespace ( fullpath , true) :-1 ;
141143tablespaces = lappend (tablespaces ,ti );
142144#else
143145
@@ -172,29 +174,26 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
172174pq_sendint (& buf ,0 ,2 );/* natts */
173175pq_endmessage (& buf );
174176
175- /* In the main tar, include the backup_label first. */
176- if (ti -> path == NULL )
177- sendFileWithContent (BACKUP_LABEL_FILE ,labelfile );
178-
179- sendDir (ti -> path == NULL ?"." :ti -> path ,
180- ti -> path == NULL ?1 :strlen (ti -> path ),
181- false);
182-
183- /* In the main tar, include pg_control last. */
184177if (ti -> path == NULL )
185178{
186179struct stat statbuf ;
187180
181+ /* In the main tar, include the backup_label first... */
182+ sendFileWithContent (BACKUP_LABEL_FILE ,labelfile );
183+
184+ /* ... then the bulk of the files ... */
185+ sendDir ("." ,1 , false);
186+
187+ /* ... and pg_control after everything else. */
188188if (lstat (XLOG_CONTROL_FILE ,& statbuf )!= 0 )
189- {
190189ereport (ERROR ,
191190(errcode_for_file_access (),
192191errmsg ("could not stat control file \"%s\": %m" ,
193192XLOG_CONTROL_FILE )));
194- }
195-
196193sendFile (XLOG_CONTROL_FILE ,XLOG_CONTROL_FILE ,& statbuf , false);
197194}
195+ else
196+ sendTablespace (ti -> path , false);
198197
199198/*
200199 * If we're including WAL, and this is the main data directory we
@@ -722,6 +721,49 @@ sendFileWithContent(const char *filename, const char *content)
722721}
723722}
724723
724+ /*
725+ * Include the tablespace directory pointed to by 'path' in the output tar
726+ * stream. If 'sizeonly' is true, we just calculate a total length and return
727+ * it, without actually sending anything.
728+ */
729+ static int64
730+ sendTablespace (char * path ,bool sizeonly )
731+ {
732+ int64 size ;
733+ char pathbuf [MAXPGPATH ];
734+ struct stat statbuf ;
735+
736+ /*
737+ * 'path' points to the tablespace location, but we only want to include
738+ * the version directory in it that belongs to us.
739+ */
740+ snprintf (pathbuf ,sizeof (pathbuf ),"%s/%s" ,path ,
741+ TABLESPACE_VERSION_DIRECTORY );
742+
743+ /*
744+ * Store a directory entry in the tar file so we get the permissions right.
745+ */
746+ if (lstat (pathbuf ,& statbuf )!= 0 )
747+ {
748+ if (errno != ENOENT )
749+ ereport (ERROR ,
750+ (errcode_for_file_access (),
751+ errmsg ("could not stat file or directory \"%s\": %m" ,
752+ pathbuf )));
753+
754+ /* If the tablespace went away while scanning, it's no error. */
755+ return 0 ;
756+ }
757+ if (!sizeonly )
758+ _tarWriteHeader (TABLESPACE_VERSION_DIRECTORY ,NULL ,& statbuf );
759+ size = 512 ;/* Size of the header just added */
760+
761+ /* Send all the files in the tablespace version directory */
762+ size += sendDir (pathbuf ,strlen (path ),sizeonly );
763+
764+ return size ;
765+ }
766+
725767/*
726768 * Include all files from the given directory in the output tar stream. If
727769 * 'sizeonly' is true, we just calculate a total length and return it, without