diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 07ca0dc..8c15d62 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -834,8 +834,11 @@ SELECT pg_start_backup('label');
      <function>pg_start_backup</> creates a <firstterm>backup label</> file,
      called <filename>backup_label</>, in the cluster directory with
      information about your backup, including the start time and label
-     string.  The file is critical to the integrity of the backup, should
-     you need to restore from it.
+     string.  On Windows, this function also  creates a
+     <firstterm>symlink label</> file, called <filename>symlink_label</>,
+     in the cluster directory with information about symbolic links in
+     <filename>pg_tblspc/</>.  Both the files are critical to the integrity of
+     the backup, should you need to restore from it.
     </para>
 
     <para>
@@ -963,17 +966,19 @@ SELECT pg_stop_backup();
 
    <para>
     It's also worth noting that the <function>pg_start_backup</> function
-    makes a file named <filename>backup_label</> in the database cluster
-    directory, which is removed by <function>pg_stop_backup</>.
-    This file will of course be archived as a part of your backup dump file.
-    The backup label file includes the label string you gave to
-    <function>pg_start_backup</>, as well as the time at which
-    <function>pg_start_backup</> was run, and the name of the starting WAL
-    file.  In case of confusion it is therefore possible to look inside a
-    backup dump file and determine exactly which backup session the dump file
-    came from.  However, this file is not merely for your information; its
-    presence and contents are critical to the proper operation of the system's
-    recovery process.
+    makes a file named <filename>backup_label</> and on windows another
+    file named<filename>symlink_label</> in the database cluster directory,
+    which are removed by <function>pg_stop_backup</>.  These files will of
+    course be archived as a part of your backup dump file.  The backup label
+    file includes the label string you gave to <function>pg_start_backup</>,
+    as well as the time at which <function>pg_start_backup</> was run, and
+    the name of the starting WAL file.  In case of confusion it is therefore
+    possible to look inside a backup dump file and determine exactly which
+    backup session the dump file came from.  The symlink label file includes
+    the symbolic link name as it exists in the directory
+    <filename>pg_tblspc/</> and the full path of symolic link.  These files
+    are not merely for your information; their presence and contents are critical
+    to the proper operation of the system's recovery process.
    </para>
 
    <para>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 7195df8..b1ecce6 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -16265,7 +16265,8 @@ SELECT set_config('log_statement_stats', 'off', false);
     <function>pg_start_backup</> accepts an
     arbitrary user-defined label for the backup.  (Typically this would be
     the name under which the backup dump file will be stored.)  The function
-    writes a backup label file (<filename>backup_label</>) into the
+    writes a backup label file (<filename>backup_label</>) and in case of
+    windows symlink label file (<filename>symlink_label</>) also into the
     database cluster's data directory, performs a checkpoint,
     and then returns the backup's starting transaction log location as text.
     The user can ignore this result value, but it is
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 34f2fc0..90f17e9 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -40,6 +40,7 @@
 #include "pgstat.h"
 #include "postmaster/bgwriter.h"
 #include "postmaster/startup.h"
+#include "replication/basebackup.h"
 #include "replication/logical.h"
 #include "replication/slot.h"
 #include "replication/snapbuild.h"
@@ -802,6 +803,9 @@ static void xlog_outrec(StringInfo buf, XLogRecord *record);
 static void pg_start_backup_callback(int code, Datum arg);
 static bool read_backup_label(XLogRecPtr *checkPointLoc,
 				  bool *backupEndRequired, bool *backupFromStandby);
+#ifdef WIN32
+static bool read_symlink_label(List	**tablespaces);
+#endif
 static void rm_redo_error_callback(void *arg);
 static int	get_sync_bit(int method);
 
@@ -6004,6 +6008,9 @@ StartupXLOG(void)
 	bool		wasShutdown;
 	bool		reachedStopPoint = false;
 	bool		haveBackupLabel = false;
+#ifdef WIN32
+	bool		haveSymlinkLabel = false;
+#endif
 	XLogRecPtr	RecPtr,
 				checkPointLoc,
 				EndOfLog;
@@ -6078,16 +6085,6 @@ StartupXLOG(void)
 	ValidateXLOGDirectoryStructure();
 
 	/*
-	 * Clear out any old relcache cache files.  This is *necessary* if we do
-	 * any WAL replay, since that would probably result in the cache files
-	 * being out of sync with database reality.  In theory we could leave them
-	 * in place if the database had been cleanly shut down, but it seems
-	 * safest to just remove them always and let them be rebuilt during the
-	 * first backend startup.
-	 */
-	RelationCacheInitFileRemove();
-
-	/*
 	 * Initialize on the assumption we want to recover to the latest timeline
 	 * that's active according to pg_control.
 	 */
@@ -6156,6 +6153,9 @@ StartupXLOG(void)
 	if (read_backup_label(&checkPointLoc, &backupEndRequired,
 						  &backupFromStandby))
 	{
+#ifdef WIN32
+		List	*tablespaces = NIL;
+#endif
 		/*
 		 * Archive recovery was requested, and thanks to the backup label
 		 * file, we know how far we need to replay to reach consistency. Enter
@@ -6200,6 +6200,61 @@ StartupXLOG(void)
 					 errhint("If you are not restoring from a backup, try removing the file \"%s/backup_label\".", DataDir)));
 			wasShutdown = false;	/* keep compiler quiet */
 		}
+
+#ifdef WIN32
+		/* read the symlink file if present and create symlinks */
+		if (read_symlink_label(&tablespaces))
+		{
+			ListCell   *lc;
+			struct stat st;
+
+			foreach(lc, tablespaces)
+			{
+				tablespaceinfo *ti = lfirst(lc);
+				char	*linkloc;
+
+				linkloc = psprintf("pg_tblspc/%s", ti->oid);
+
+				/*
+				 * Remove the existing symlink if any and Create the symlink
+				 * under PGDATA.  We need to use rmtree instead of rmdir as
+				 * the link location might contain directories/files corresponding
+				 * to actual path, some tar utilities does that way while extracting
+				 * symlinks.
+				 */
+				if (lstat(linkloc, &st) == 0 && S_ISDIR(st.st_mode))
+				{
+					if (!rmtree(linkloc,true))
+						ereport(ERROR,
+								(errcode_for_file_access(),
+								 errmsg("could not remove directory \"%s\": %m",
+										linkloc)));
+				}
+				else
+				{
+					if (unlink(linkloc) < 0 && errno != ENOENT)
+						ereport(ERROR,
+								(errcode_for_file_access(),
+								 errmsg("could not remove symbolic link \"%s\": %m",
+										linkloc)));
+				}
+
+				if (symlink(ti->path, linkloc) < 0)
+					ereport(ERROR,
+							(errcode_for_file_access(),
+							 errmsg("could not create symbolic link \"%s\": %m",
+									linkloc)));
+
+				pfree(ti->oid);
+				pfree(ti->path);
+				pfree(ti);
+			}
+
+			/* set flag to delete it later */
+			haveSymlinkLabel = true;
+		}
+#endif
+
 		/* set flag to delete it later */
 		haveBackupLabel = true;
 	}
@@ -6274,6 +6329,20 @@ StartupXLOG(void)
 	}
 
 	/*
+	 * Clear out any old relcache cache files.  This is *necessary* if we do
+	 * any WAL replay, since that would probably result in the cache files
+	 * being out of sync with database reality.  In theory we could leave them
+	 * in place if the database had been cleanly shut down, but it seems
+	 * safest to just remove them always and let them be rebuilt during the
+	 * first backend startup.  These files needs to be removed from all
+	 * directories including pg_tblspc, however for windows the symlinks are
+	 * created only after reading symlink file in case of archive recovery
+	 * from backup, so needs to clear old relcache files here after creating
+	 * symlinks.
+	 */
+	RelationCacheInitFileRemove();
+
+	/*
 	 * If the location of the checkpoint record is not on the expected
 	 * timeline in the history of the requested timeline, we cannot proceed:
 	 * the backup is not part of the history of the requested timeline.
@@ -6526,6 +6595,25 @@ StartupXLOG(void)
 								BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
 		}
 
+#ifdef WIN32
+		/*
+		 * If there was a symlink label file, it's done its job and the
+		 * symlinks have been created.  We must get rid of the label file
+		 * so that if we crash during recovery, we don't create symlinks
+		 * again.  It seems prudent though to just rename the file out of
+		 * the way rather than delete it completely.
+		 */
+		if (haveSymlinkLabel)
+		{
+			unlink(SYMLINK_LABEL_OLD);
+			if (rename(SYMLINK_LABEL_FILE, SYMLINK_LABEL_OLD) != 0)
+				ereport(FATAL,
+						(errcode_for_file_access(),
+						 errmsg("could not rename file \"%s\" to \"%s\": %m",
+								SYMLINK_LABEL_FILE, SYMLINK_LABEL_OLD)));
+		}
+#endif
+
 		/* Check that the GUCs used to generate the WAL allow recovery */
 		CheckRequiredParameterValues();
 
@@ -9780,16 +9868,21 @@ XLogFileNameP(TimeLineID tli, XLogSegNo segno)
  *
  * There are two kind of backups: exclusive and non-exclusive. An exclusive
  * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup label file of an exclusive backup is written to
- * $PGDATA/backup_label, and it is removed by pg_stop_backup().
+ * at a time. The backup and symlink label files of an exclusive backup are
+ * written to $PGDATA/backup_label and $PGDATA/symlink_label, and they are
+ * removed by pg_stop_backup().
  *
  * A non-exclusive backup is used for the streaming base backups (see
  * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label file is not written to disk. Instead, its would-be
- * contents are returned in *labelfile, and the caller is responsible for
- * including it in the backup archive as 'backup_label'. There can be many
- * non-exclusive backups active at the same time, and they don't conflict
- * with an exclusive backup either.
+ * is that the backup, symlink label files are not written to disk. Instead,
+ * there would-be contents are returned in *labelfile and *symlinkfile, and
+ * the caller is responsible for including them in the backup archive as
+ * 'backup_label' and 'symlink_label'. There can be many non-exclusive backups
+ * active at the same time, and they don't conflict with an exclusive backup
+ * either.
+ *
+ * symlinkfile is required only for tar format in windows as native windows
+ * utilities are not able to create symlinks while extracting files from tar.
  *
  * Returns the minimum WAL position that must be present to restore from this
  * backup, and the corresponding timeline ID in *starttli_p.
@@ -9802,7 +9895,8 @@ XLogFileNameP(TimeLineID tli, XLogSegNo segno)
  */
 XLogRecPtr
 do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
-				   char **labelfile)
+				   char **labelfile, DIR *tblspcdir, List **tablespaces,
+				   char **symlinkfile, bool infotbssize)
 {
 	bool		exclusive = (labelfile == NULL);
 	bool		backup_started_in_recovery = false;
@@ -9816,6 +9910,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 	struct stat stat_buf;
 	FILE	   *fp;
 	StringInfoData labelfbuf;
+#ifdef WIN32
+	StringInfoData symlinkfbuf;
+#endif
 
 	backup_started_in_recovery = RecoveryInProgress();
 
@@ -9886,6 +9983,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 	PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
 	{
 		bool		gotUniqueStartpoint = false;
+		struct dirent *de;
+		tablespaceinfo *ti;
+		int			datadirpathlen;
 
 		/*
 		 * Force an XLOG file switch before the checkpoint, to ensure that the
@@ -10007,6 +10107,82 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 		XLByteToSeg(startpoint, _logSegNo);
 		XLogFileName(xlogfilename, ThisTimeLineID, _logSegNo);
 
+#ifdef WIN32
+		/*
+		 * Construct symlink file
+		 */
+		initStringInfo(&symlinkfbuf);
+#endif
+
+		datadirpathlen = strlen(DataDir);
+
+		/* Collect information about all tablespaces */
+		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
+		{
+			char		fullpath[MAXPGPATH];
+			char		linkpath[MAXPGPATH];
+			char	   *relpath = NULL;
+			int			rllen;
+
+			/* Skip special stuff */
+			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+				continue;
+
+			snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
+
+#if defined(HAVE_READLINK) || defined(WIN32)
+			rllen = readlink(fullpath, linkpath, sizeof(linkpath));
+			if (rllen < 0)
+			{
+				ereport(WARNING,
+						(errmsg("could not read symbolic link \"%s\": %m",
+								fullpath)));
+				continue;
+			}
+			else if (rllen >= sizeof(linkpath))
+			{
+				ereport(WARNING,
+						(errmsg("symbolic link \"%s\" target is too long",
+								fullpath)));
+				continue;
+			}
+			linkpath[rllen] = '\0';
+
+			/*
+			 * Relpath holds the relative path of the tablespace directory
+			 * when it's located within PGDATA, or NULL if it's located
+			 * elsewhere.
+			 */
+			if (rllen > datadirpathlen &&
+				strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
+				IS_DIR_SEP(linkpath[datadirpathlen]))
+				relpath = linkpath + datadirpathlen + 1;
+
+			ti = palloc(sizeof(tablespaceinfo));
+			ti->oid = pstrdup(de->d_name);
+			ti->path = pstrdup(linkpath);
+			ti->rpath = relpath ? pstrdup(relpath) : NULL;
+			ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+
+			if(tablespaces)
+			   *tablespaces = lappend(*tablespaces, ti);
+
+#ifdef WIN32
+			appendStringInfo(&symlinkfbuf, "%s %s\n", ti->oid, ti->path);
+#endif
+#else
+
+			/*
+			 * If the platform does not have symbolic links, it should not be
+			 * possible to have tablespaces - clearly somebody else created
+			 * them. Warn about it and ignore.
+			 */
+			ereport(WARNING,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				  errmsg("tablespaces are not supported on this platform")));
+#endif
+		}
+
 		/*
 		 * Construct backup label file
 		 */
@@ -10070,9 +10246,55 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 						 errmsg("could not write file \"%s\": %m",
 								BACKUP_LABEL_FILE)));
 			pfree(labelfbuf.data);
+
+#ifdef WIN32
+			/* Write backup symlink file. */
+			if (symlinkfbuf.len > 0)
+			{
+				if (stat(SYMLINK_LABEL_FILE, &stat_buf) != 0)
+				{
+					if (errno != ENOENT)
+						ereport(ERROR,
+								(errcode_for_file_access(),
+								 errmsg("could not stat file \"%s\": %m",
+										SYMLINK_LABEL_FILE)));
+				}
+				else
+					ereport(ERROR,
+							(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+							 errmsg("a backup is already in progress"),
+							 errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
+									 SYMLINK_LABEL_FILE)));
+
+				fp = AllocateFile(SYMLINK_LABEL_FILE, "w");
+
+				if (!fp)
+					ereport(ERROR,
+							(errcode_for_file_access(),
+							 errmsg("could not create file \"%s\": %m",
+									SYMLINK_LABEL_FILE)));
+				if (fwrite(symlinkfbuf.data, symlinkfbuf.len, 1, fp) != 1 ||
+					fflush(fp) != 0 ||
+					pg_fsync(fileno(fp)) != 0 ||
+					ferror(fp) ||
+					FreeFile(fp))
+					ereport(ERROR,
+							(errcode_for_file_access(),
+							 errmsg("could not write file \"%s\": %m",
+									SYMLINK_LABEL_FILE)));
+			}
+
+			pfree(symlinkfbuf.data);
+#endif
 		}
 		else
+		{
 			*labelfile = labelfbuf.data;
+#ifdef WIN32
+			if (symlinkfbuf.len > 0)
+				*symlinkfile = symlinkfbuf.data;
+#endif
+		}
 	}
 	PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
 
@@ -10244,6 +10466,14 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
 					(errcode_for_file_access(),
 					 errmsg("could not remove file \"%s\": %m",
 							BACKUP_LABEL_FILE)));
+
+#ifdef WIN32
+		/*
+		 * Remove symlink file if present, symlink file is created
+		 * only if there are tablespaces.
+		 */
+		unlink(SYMLINK_LABEL_FILE);
+#endif
 	}
 
 	/*
@@ -10654,6 +10884,74 @@ read_backup_label(XLogRecPtr *checkPointLoc, bool *backupEndRequired,
 	return true;
 }
 
+#ifdef WIN32
+/*
+ * read_symlink_label: check to see if a symlink_label file is present
+ *
+ * If we see a symlink_label during recovery, we assume that we are recovering
+ * from a backup dump file, and we therefore need to create symlinks as per
+ * the information present in symlink file.
+ *
+ * Returns TRUE if a symlink_label was found (and fills the link information
+ * for all the tablespace links present in file); returns FALSE if not.
+ */
+static bool
+read_symlink_label(List	**tablespaces)
+{
+	tablespaceinfo *ti;
+	FILE	   *lfp;
+	char		ch;
+	char		tbsoid[MAXPGPATH];
+	char		tbslinkpath[MAXPGPATH];
+
+	/*
+	 * See if symlink file is present
+	 */
+	lfp = AllocateFile(SYMLINK_LABEL_FILE, "r");
+	if (!lfp)
+	{
+		if (errno != ENOENT)
+			ereport(FATAL,
+					(errcode_for_file_access(),
+					 errmsg("could not read file \"%s\": %m",
+							SYMLINK_LABEL_FILE)));
+		return false;			/* it's not there, all is fine */
+	}
+
+	/*
+	 * Read and parse the link name and path lines from symlink file (this code
+	 * is pretty crude, but we are not expecting any variability in the file
+	 * format).
+	 */
+	while (!feof(lfp))
+	{
+		ti = palloc(sizeof(tablespaceinfo));
+		if (fscanf(lfp, "%s %s%c", tbsoid, tbslinkpath, &ch) != 3 || ch != '\n')
+		{
+			if (feof(lfp))
+				break;
+			else
+				ereport(FATAL,
+						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						 errmsg("invalid data in file \"%s\"", SYMLINK_LABEL_FILE)));
+		}
+
+		ti->oid = pstrdup(tbsoid);
+		ti->path = pstrdup(tbslinkpath);
+
+		*tablespaces = lappend(*tablespaces, ti);
+	}
+
+	if (ferror(lfp) || FreeFile(lfp))
+		ereport(FATAL,
+				(errcode_for_file_access(),
+				 errmsg("could not read file \"%s\": %m",
+						SYMLINK_LABEL_FILE)));
+
+	return true;
+}
+#endif
+
 /*
  * Error context callback for errors occurring during rm_redo().
  */
@@ -10687,11 +10985,14 @@ BackupInProgress(void)
 }
 
 /*
- * CancelBackup: rename the "backup_label" file to cancel backup mode
+ * CancelBackup: rename the "backup_label"/"symlink_label" file to cancel
+ *				 backup mode
  *
  * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Note that this will render an online backup in progress useless.
- * To correctly finish an online backup, pg_stop_backup must be called.
+ * Similarly, if the "symlink_label" file exists, it will be renamed to
+ * "symlink_label.old". Note that this will render an online backup in progress
+ * useless. To correctly finish an online backup, pg_stop_backup must be
+ * called.
  */
 void
 CancelBackup(void)
@@ -10720,6 +11021,31 @@ CancelBackup(void)
 				 errdetail("Could not rename \"%s\" to \"%s\": %m.",
 						   BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
 	}
+
+#ifdef WIN32
+	/* if the file is not there, return */
+	if (stat(SYMLINK_LABEL_FILE, &stat_buf) < 0)
+		return;
+
+	/* remove leftover file from previously canceled backup if it exists */
+	unlink(SYMLINK_LABEL_OLD);
+
+	if (rename(SYMLINK_LABEL_FILE, SYMLINK_LABEL_OLD) == 0)
+	{
+		ereport(LOG,
+				(errmsg("online backup mode canceled"),
+				 errdetail("\"%s\" was renamed to \"%s\".",
+						   SYMLINK_LABEL_FILE, SYMLINK_LABEL_OLD)));
+	}
+	else
+	{
+		ereport(WARNING,
+				(errcode_for_file_access(),
+				 errmsg("online backup mode was not canceled"),
+				 errdetail("Could not rename \"%s\" to \"%s\": %m.",
+						   SYMLINK_LABEL_FILE, SYMLINK_LABEL_OLD)));
+	}
+#endif
 }
 
 /*
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 133143d..d8864d9 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -51,6 +51,7 @@ pg_start_backup(PG_FUNCTION_ARGS)
 	bool		fast = PG_GETARG_BOOL(1);
 	char	   *backupidstr;
 	XLogRecPtr	startpoint;
+	DIR		   *dir;
 
 	backupidstr = text_to_cstring(backupid);
 
@@ -59,7 +60,16 @@ pg_start_backup(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 		   errmsg("must be superuser or replication role to run a backup")));
 
-	startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL);
+	/* Make sure we can open the directory with tablespaces in it */
+	dir = AllocateDir("pg_tblspc");
+	if (!dir)
+		ereport(ERROR,
+				(errmsg("could not open directory \"%s\": %m", "pg_tblspc")));
+
+	startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
+									dir, NULL, NULL, false);
+
+	FreeDir(dir);
 
 	PG_RETURN_LSN(startpoint);
 }
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index fbcecbb..8925148 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -46,11 +46,12 @@ typedef struct
 	bool		nowait;
 	bool		includewal;
 	uint32		maxrate;
+	bool		sendsymlinkfile;
 } basebackup_options;
 
 
-static int64 sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces);
-static int64 sendTablespace(char *path, bool sizeonly);
+static int64 sendDir(char *path, int basepathlen, bool sizeonly,
+					 List *tablespaces, bool sendsymlinkinfo);
 static bool sendFile(char *readfilename, char *tarfilename,
 		 struct stat * statbuf, bool missing_ok);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -93,15 +94,6 @@ static int64 elapsed_min_unit;
 /* The last check of the transfer rate. */
 static int64 throttled_last;
 
-typedef struct
-{
-	char	   *oid;
-	char	   *path;
-	char	   *rpath;			/* relative path within PGDATA, or NULL */
-	int64		size;
-} tablespaceinfo;
-
-
 /*
  * Called when ERROR or FATAL happens in perform_base_backup() after
  * we have started the backup - make sure we end it!
@@ -126,14 +118,17 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
 	XLogRecPtr	endptr;
 	TimeLineID	endtli;
 	char	   *labelfile;
+	char	   *symlinkfile = NULL;
 	int			datadirpathlen;
+	List	   *tablespaces = NIL;
 
 	datadirpathlen = strlen(DataDir);
 
 	backup_started_in_recovery = RecoveryInProgress();
 
 	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
-								  &labelfile);
+								  &labelfile, tblspcdir, &tablespaces,
+								  &symlinkfile, opt->progress);
 	/*
 	 * Once do_pg_start_backup has been called, ensure that any failure causes
 	 * us to abort the backup so we don't "leak" a backup counter. For this reason,
@@ -143,9 +138,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
 
 	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
 	{
-		List	   *tablespaces = NIL;
 		ListCell   *lc;
-		struct dirent *de;
 		tablespaceinfo *ti;
 
 		SendXlogRecPtrResult(startptr, starttli);
@@ -162,70 +155,9 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
 		else
 			statrelpath = pgstat_stat_directory;
 
-		/* Collect information about all tablespaces */
-		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
-		{
-			char		fullpath[MAXPGPATH];
-			char		linkpath[MAXPGPATH];
-			char	   *relpath = NULL;
-			int			rllen;
-
-			/* Skip special stuff */
-			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
-				continue;
-
-			snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
-
-#if defined(HAVE_READLINK) || defined(WIN32)
-			rllen = readlink(fullpath, linkpath, sizeof(linkpath));
-			if (rllen < 0)
-			{
-				ereport(WARNING,
-						(errmsg("could not read symbolic link \"%s\": %m",
-								fullpath)));
-				continue;
-			}
-			else if (rllen >= sizeof(linkpath))
-			{
-				ereport(WARNING,
-						(errmsg("symbolic link \"%s\" target is too long",
-								fullpath)));
-				continue;
-			}
-			linkpath[rllen] = '\0';
-
-			/*
-			 * Relpath holds the relative path of the tablespace directory
-			 * when it's located within PGDATA, or NULL if it's located
-			 * elsewhere.
-			 */
-			if (rllen > datadirpathlen &&
-				strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
-				IS_DIR_SEP(linkpath[datadirpathlen]))
-				relpath = linkpath + datadirpathlen + 1;
-
-			ti = palloc(sizeof(tablespaceinfo));
-			ti->oid = pstrdup(de->d_name);
-			ti->path = pstrdup(linkpath);
-			ti->rpath = relpath ? pstrdup(relpath) : NULL;
-			ti->size = opt->progress ? sendTablespace(fullpath, true) : -1;
-			tablespaces = lappend(tablespaces, ti);
-#else
-
-			/*
-			 * If the platform does not have symbolic links, it should not be
-			 * possible to have tablespaces - clearly somebody else created
-			 * them. Warn about it and ignore.
-			 */
-			ereport(WARNING,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				  errmsg("tablespaces are not supported on this platform")));
-#endif
-		}
-
 		/* Add a node for the base directory at the end */
 		ti = palloc0(sizeof(tablespaceinfo));
-		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces) : -1;
+		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
 		tablespaces = lappend(tablespaces, ti);
 
 		/* Send tablespace header */
@@ -274,8 +206,17 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
 				/* In the main tar, include the backup_label first... */
 				sendFileWithContent(BACKUP_LABEL_FILE, labelfile);
 
-				/* ... then the bulk of the files ... */
-				sendDir(".", 1, false, tablespaces);
+				/*
+				 * Send symlink file if required and then the bulk of the
+				 * files
+				 */
+				if (symlinkfile && opt->sendsymlinkfile)
+				{
+					sendFileWithContent(SYMLINK_LABEL_FILE, symlinkfile);
+					sendDir(".", 1, false, tablespaces, false);
+				}
+				else
+					sendDir(".", 1, false, tablespaces, true);
 
 				/* ... and pg_control after everything else. */
 				if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
@@ -555,6 +496,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_nowait = false;
 	bool		o_wal = false;
 	bool		o_maxrate = false;
+	bool		o_sendsymlinkfile = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -625,6 +567,20 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			opt->maxrate = (uint32) maxrate;
 			o_maxrate = true;
 		}
+		else if (strcmp(defel->defname, "tar") == 0)
+		{
+			/*
+			 * symlinkfile is required only for tar format in windows as
+			 * native windows utilites are not able create symlinks while
+			 * extracting files from tar.
+			 */
+			if (o_sendsymlinkfile)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+			opt->sendsymlinkfile = true;
+			o_sendsymlinkfile = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
@@ -853,7 +809,7 @@ sendFileWithContent(const char *filename, const char *content)
  *
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
-static int64
+int64
 sendTablespace(char *path, bool sizeonly)
 {
 	int64		size;
@@ -887,7 +843,7 @@ sendTablespace(char *path, bool sizeonly)
 	size = 512;					/* Size of the header just added */
 
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), sizeonly, NIL);
+	size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
 
 	return size;
 }
@@ -899,9 +855,14 @@ sendTablespace(char *path, bool sizeonly)
  *
  * Omit any directory in the tablespaces list, to avoid backing up
  * tablespaces twice when they were created inside PGDATA.
+ *
+ * If sendsymlinkinfo is false, we don't need to include symlink
+ * information inside tar file as it will be sent separately in
+ * symlink_label file.
  */
 static int64
-sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces)
+sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces,
+		bool sendsymlinkinfo)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -929,13 +890,17 @@ sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces)
 			continue;
 
 		/*
-		 * If there's a backup_label file, it belongs to a backup started by
-		 * the user with pg_start_backup(). It is *not* correct for this
-		 * backup, our backup_label is injected into the tar separately.
+		 * If there's a backup_label or symlink file, it belongs to a backup
+		 * started by the user with pg_start_backup(). It is *not* correct for
+		 * this backup, our backup_label/symlink is injected into the tar
+		 * separately.
 		 */
 		if (strcmp(de->d_name, BACKUP_LABEL_FILE) == 0)
 			continue;
 
+		if (strcmp(de->d_name, SYMLINK_LABEL_FILE) == 0)
+			continue;
+
 		/*
 		 * Check if the postmaster has signaled us to exit, and abort with an
 		 * error in that case. The error handler further up will call
@@ -1026,6 +991,7 @@ sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces)
 
 		/* Allow symbolic links in pg_tblspc only */
 		if (strcmp(path, "./pg_tblspc") == 0 &&
+			sendsymlinkinfo &&
 #ifndef WIN32
 			S_ISLNK(statbuf.st_mode)
 #else
@@ -1100,7 +1066,7 @@ sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces)
 				}
 			}
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces);
+				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, true);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index 154aaac..25c7311 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -71,6 +71,7 @@ Node *replication_parse_result;
 %token K_NOWAIT
 %token K_MAX_RATE
 %token K_WAL
+%token K_TAR
 %token K_TIMELINE
 %token K_PHYSICAL
 %token K_LOGICAL
@@ -119,7 +120,7 @@ identify_system:
 			;
 
 /*
- * BASE_BACKUP [LABEL '<label>'] [PROGRESS] [FAST] [WAL] [NOWAIT] [MAX_RATE %d]
+ * BASE_BACKUP [LABEL '<label>'] [PROGRESS] [FAST] [WAL] [NOWAIT] [MAX_RATE %d] [TAR]
  */
 base_backup:
 			K_BASE_BACKUP base_backup_opt_list
@@ -168,6 +169,11 @@ base_backup_opt:
 				  $$ = makeDefElem("max_rate",
 								   (Node *)makeInteger($2));
 				}
+			| K_TAR
+				{
+				  $$ = makeDefElem("tar",
+								   (Node *)makeInteger(TRUE));
+				}
 			;
 
 create_replication_slot:
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index a257124..e373d51 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -88,6 +88,7 @@ NOWAIT			{ return K_NOWAIT; }
 PROGRESS			{ return K_PROGRESS; }
 MAX_RATE		{ return K_MAX_RATE; }
 WAL			{ return K_WAL; }
+TAR			{ return K_TAR; }
 TIMELINE			{ return K_TIMELINE; }
 START_REPLICATION	{ return K_START_REPLICATION; }
 CREATE_REPLICATION_SLOT		{ return K_CREATE_REPLICATION_SLOT; }
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 8b9acea..25d7491 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -1651,13 +1651,14 @@ BaseBackup(void)
 		maxrate_clause = psprintf("MAX_RATE %u", maxrate);
 
 	basebkp =
-		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s",
+		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s",
 				 escaped_label,
 				 showprogress ? "PROGRESS" : "",
 				 includewal && !streamwal ? "WAL" : "",
 				 fastcheckpoint ? "FAST" : "",
 				 includewal ? "NOWAIT" : "",
-				 maxrate_clause ? maxrate_clause : "");
+				 maxrate_clause ? maxrate_clause : "",
+				 format == 't'  ? "TAR": "");
 
 	if (PQsendQuery(conn, basebkp) == 0)
 	{
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 7d6db49..5c70812 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -15,8 +15,10 @@
 #include "access/xlogdefs.h"
 #include "datatype/timestamp.h"
 #include "lib/stringinfo.h"
+#include "nodes/pg_list.h"
 #include "storage/block.h"
 #include "storage/buf.h"
+#include "storage/fd.h"
 #include "storage/relfilenode.h"
 #include "utils/pg_crc.h"
 
@@ -349,7 +351,8 @@ extern void SetWalWriterSleeping(bool sleeping);
  * Starting/stopping a base backup
  */
 extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
-				   TimeLineID *starttli_p, char **labelfile);
+				   TimeLineID *starttli_p, char **labelfile, DIR *tblspcdir,
+				   List **tablespaces, char **symlinkfile, bool infotbssize);
 extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
 				  TimeLineID *stoptli_p);
 extern void do_pg_abort_backup(void);
@@ -358,4 +361,7 @@ extern void do_pg_abort_backup(void);
 #define BACKUP_LABEL_FILE		"backup_label"
 #define BACKUP_LABEL_OLD		"backup_label.old"
 
+#define SYMLINK_LABEL_FILE		"symlink_label"
+#define SYMLINK_LABEL_OLD		"symlink_label.old"
+
 #endif   /* XLOG_H */
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index 988bce7..3540602 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -21,6 +21,16 @@
 #define MAX_RATE_UPPER	1048576
 
 
+typedef struct
+{
+	char	   *oid;
+	char	   *path;
+	char	   *rpath;			/* relative path within PGDATA, or NULL */
+	int64		size;
+} tablespaceinfo;
+
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
+extern int64 sendTablespace(char *path, bool sizeonly);
+
 #endif   /* _BASEBACKUP_H */
