1919
2020#include "access/xlog_internal.h" /* for pg_start/stop_backup */
2121#include "catalog/pg_type.h"
22+ #include "common/relpath.h"
2223#include "lib/stringinfo.h"
2324#include "libpq/libpq.h"
2425#include "libpq/pqformat.h"
@@ -45,6 +46,7 @@ typedef struct
4546
4647
4748static int64 sendDir (char * path ,int basepathlen ,bool sizeonly );
49+ static int64 sendTablespace (char * path ,bool sizeonly );
4850static bool sendFile (char * readfilename ,char * tarfilename ,
4951struct stat * statbuf ,bool missing_ok );
5052static void sendFileWithContent (const char * filename ,const char * content );
@@ -146,7 +148,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
146148ti = palloc (sizeof (tablespaceinfo ));
147149ti -> oid = pstrdup (de -> d_name );
148150ti -> path = pstrdup (linkpath );
149- ti -> size = opt -> progress ?sendDir ( linkpath , strlen ( linkpath ) , true) :-1 ;
151+ ti -> size = opt -> progress ?sendTablespace ( fullpath , true) :-1 ;
150152tablespaces = lappend (tablespaces ,ti );
151153#else
152154
@@ -181,29 +183,26 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
181183pq_sendint (& buf ,0 ,2 );/* natts */
182184pq_endmessage (& buf );
183185
184- /* In the main tar, include the backup_label first. */
185- if (ti -> path == NULL )
186- sendFileWithContent (BACKUP_LABEL_FILE ,labelfile );
187-
188- sendDir (ti -> path == NULL ?"." :ti -> path ,
189- ti -> path == NULL ?1 :strlen (ti -> path ),
190- false);
191-
192- /* In the main tar, include pg_control last. */
193186if (ti -> path == NULL )
194187{
195188struct stat statbuf ;
196189
190+ /* In the main tar, include the backup_label first... */
191+ sendFileWithContent (BACKUP_LABEL_FILE ,labelfile );
192+
193+ /* ... then the bulk of the files ... */
194+ sendDir ("." ,1 , false);
195+
196+ /* ... and pg_control after everything else. */
197197if (lstat (XLOG_CONTROL_FILE ,& statbuf )!= 0 )
198- {
199198ereport (ERROR ,
200199(errcode_for_file_access (),
201200errmsg ("could not stat control file \"%s\": %m" ,
202201XLOG_CONTROL_FILE )));
203- }
204-
205202sendFile (XLOG_CONTROL_FILE ,XLOG_CONTROL_FILE ,& statbuf , false);
206203}
204+ else
205+ sendTablespace (ti -> path , false);
207206
208207/*
209208 * If we're including WAL, and this is the main data directory we
@@ -728,6 +727,49 @@ sendFileWithContent(const char *filename, const char *content)
728727}
729728}
730729
730+ /*
731+ * Include the tablespace directory pointed to by 'path' in the output tar
732+ * stream. If 'sizeonly' is true, we just calculate a total length and return
733+ * it, without actually sending anything.
734+ */
735+ static int64
736+ sendTablespace (char * path ,bool sizeonly )
737+ {
738+ int64 size ;
739+ char pathbuf [MAXPGPATH ];
740+ struct stat statbuf ;
741+
742+ /*
743+ * 'path' points to the tablespace location, but we only want to include
744+ * the version directory in it that belongs to us.
745+ */
746+ snprintf (pathbuf ,sizeof (pathbuf ),"%s/%s" ,path ,
747+ TABLESPACE_VERSION_DIRECTORY );
748+
749+ /*
750+ * Store a directory entry in the tar file so we get the permissions right.
751+ */
752+ if (lstat (pathbuf ,& statbuf )!= 0 )
753+ {
754+ if (errno != ENOENT )
755+ ereport (ERROR ,
756+ (errcode_for_file_access (),
757+ errmsg ("could not stat file or directory \"%s\": %m" ,
758+ pathbuf )));
759+
760+ /* If the tablespace went away while scanning, it's no error. */
761+ return 0 ;
762+ }
763+ if (!sizeonly )
764+ _tarWriteHeader (TABLESPACE_VERSION_DIRECTORY ,NULL ,& statbuf );
765+ size = 512 ;/* Size of the header just added */
766+
767+ /* Send all the files in the tablespace version directory */
768+ size += sendDir (pathbuf ,strlen (path ),sizeonly );
769+
770+ return size ;
771+ }
772+
731773/*
732774 * Include all files from the given directory in the output tar stream. If
733775 * 'sizeonly' is true, we just calculate a total length and return it, without