aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/xlog.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/transam/xlog.c')
-rw-r--r--src/backend/access/transam/xlog.c123
1 files changed, 68 insertions, 55 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 9be0cb236d3..6f8810e1490 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10702,19 +10702,17 @@ issue_xlog_fsync(int fd, XLogSegNo segno)
* active at the same time, and they don't conflict with an exclusive backup
* either.
*
- * tablespaces is required only when this function is called while
- * the streaming base backup requested by pg_basebackup is running.
- * NULL should be specified otherwise.
+ * labelfile and tblspcmapfile must be passed as NULL when starting an
+ * exclusive backup, and as initially-empty StringInfos for a non-exclusive
+ * backup.
+ *
+ * If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
+ * describing the cluster's tablespaces.
*
* tblspcmapfile is required mainly for tar format in windows as native windows
* utilities are not able to create symlinks while extracting files from tar.
* However for consistency, the same is used for all platforms.
*
- * needtblspcmapfile is true for the cases (exclusive backup and for
- * non-exclusive backup only when tar format is used for taking backup)
- * when backup needs to generate tablespace_map file, it is used to
- * embed escape character before newline character in tablespace path.
- *
* Returns the minimum WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *starttli_p.
*
@@ -10727,7 +10725,7 @@ issue_xlog_fsync(int fd, XLogSegNo segno)
XLogRecPtr
do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
- StringInfo tblspcmapfile, bool needtblspcmapfile)
+ StringInfo tblspcmapfile)
{
bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
@@ -10940,9 +10938,10 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
XLogFileName(xlogfilename, starttli, _logSegNo, wal_segment_size);
/*
- * Construct tablespace_map file
+ * Construct tablespace_map file. If caller isn't interested in this,
+ * we make a local StringInfo.
*/
- if (exclusive)
+ if (tblspcmapfile == NULL)
tblspcmapfile = makeStringInfo();
datadirpathlen = strlen(DataDir);
@@ -10955,11 +10954,11 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char linkpath[MAXPGPATH];
char *relpath = NULL;
int rllen;
- StringInfoData buflinkpath;
- char *s = linkpath;
+ StringInfoData escapedpath;
+ char *s;
- /* Skip special stuff */
- if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+ /* Skip anything that doesn't look like a tablespace */
+ if (strspn(de->d_name, "0123456789") != strlen(de->d_name))
continue;
snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
@@ -10983,18 +10982,15 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
linkpath[rllen] = '\0';
/*
- * Add the escape character '\\' before newline in a string to
- * ensure that we can distinguish between the newline in the
- * tablespace path and end of line while reading tablespace_map
- * file during archive recovery.
+ * Build a backslash-escaped version of the link path to include
+ * in the tablespace map file.
*/
- initStringInfo(&buflinkpath);
-
- while (*s)
+ initStringInfo(&escapedpath);
+ for (s = linkpath; *s; s++)
{
- if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
- appendStringInfoChar(&buflinkpath, '\\');
- appendStringInfoChar(&buflinkpath, *s++);
+ if (*s == '\n' || *s == '\r' || *s == '\\')
+ appendStringInfoChar(&escapedpath, '\\');
+ appendStringInfoChar(&escapedpath, *s);
}
/*
@@ -11009,16 +11005,17 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
ti = palloc(sizeof(tablespaceinfo));
ti->oid = pstrdup(de->d_name);
- ti->path = pstrdup(buflinkpath.data);
+ ti->path = pstrdup(linkpath);
ti->rpath = relpath ? pstrdup(relpath) : NULL;
ti->size = -1;
if (tablespaces)
*tablespaces = lappend(*tablespaces, ti);
- appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
+ appendStringInfo(tblspcmapfile, "%s %s\n",
+ ti->oid, escapedpath.data);
- pfree(buflinkpath.data);
+ pfree(escapedpath.data);
#else
/*
@@ -11034,9 +11031,10 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
FreeDir(tblspcdir);
/*
- * Construct backup label file
+ * Construct backup label file. If caller isn't interested in this,
+ * we make a local StringInfo.
*/
- if (exclusive)
+ if (labelfile == NULL)
labelfile = makeStringInfo();
/* Use the log timezone here, not the session timezone */
@@ -11898,22 +11896,20 @@ read_backup_label(XLogRecPtr *checkPointLoc, bool *backupEndRequired,
* recovering from a backup dump file, and we therefore need to create symlinks
* as per the information present in tablespace_map file.
*
- * Returns true if a tablespace_map file was found (and fills the link
- * information for all the tablespace links present in file); returns false
- * if not.
+ * Returns true if a tablespace_map file was found (and fills *tablespaces
+ * with a tablespaceinfo struct for each tablespace listed in the file);
+ * returns false if not.
*/
static bool
read_tablespace_map(List **tablespaces)
{
tablespaceinfo *ti;
FILE *lfp;
- char tbsoid[MAXPGPATH];
- char *tbslinkpath;
char str[MAXPGPATH];
int ch,
- prev_ch = -1,
- i = 0,
+ i,
n;
+ bool was_backslash;
/*
* See if tablespace_map file is present
@@ -11932,38 +11928,55 @@ read_tablespace_map(List **tablespaces)
/*
* Read and parse the link name and path lines from tablespace_map file
* (this code is pretty crude, but we are not expecting any variability in
- * the file format). While taking backup we embed escape character '\\'
- * before newline in tablespace path, so that during reading of
- * tablespace_map file, we could distinguish newline in tablespace path
- * and end of line. Now while reading tablespace_map file, remove the
- * escape character that has been added in tablespace path during backup.
+ * the file format). De-escape any backslashes that were inserted.
*/
+ i = 0;
+ was_backslash = false;
while ((ch = fgetc(lfp)) != EOF)
{
- if ((ch == '\n' || ch == '\r') && prev_ch != '\\')
+ if (!was_backslash && (ch == '\n' || ch == '\r'))
{
+ if (i == 0)
+ continue; /* \r immediately followed by \n */
+
+ /*
+ * The de-escaped line should contain an OID followed by exactly
+ * one space followed by a path. The path might start with
+ * spaces, so don't be too liberal about parsing.
+ */
str[i] = '\0';
- if (sscanf(str, "%s %n", tbsoid, &n) != 1)
+ n = 0;
+ while (str[n] && str[n] != ' ')
+ n++;
+ if (n < 1 || n >= i - 1)
ereport(FATAL,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("invalid data in file \"%s\"", TABLESPACE_MAP)));
- tbslinkpath = str + n;
- i = 0;
-
- ti = palloc(sizeof(tablespaceinfo));
- ti->oid = pstrdup(tbsoid);
- ti->path = pstrdup(tbslinkpath);
+ str[n++] = '\0';
+ ti = palloc0(sizeof(tablespaceinfo));
+ ti->oid = pstrdup(str);
+ ti->path = pstrdup(str + n);
*tablespaces = lappend(*tablespaces, ti);
+
+ i = 0;
continue;
}
- else if ((ch == '\n' || ch == '\r') && prev_ch == '\\')
- str[i - 1] = ch;
- else if (i < sizeof(str) - 1)
- str[i++] = ch;
- prev_ch = ch;
+ else if (!was_backslash && ch == '\\')
+ was_backslash = true;
+ else
+ {
+ if (i < sizeof(str) - 1)
+ str[i++] = ch;
+ was_backslash = false;
+ }
}
+ if (i != 0 || was_backslash) /* last line not terminated? */
+ ereport(FATAL,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("invalid data in file \"%s\"", TABLESPACE_MAP)));
+
if (ferror(lfp) || FreeFile(lfp))
ereport(FATAL,
(errcode_for_file_access(),