diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c index 7d17f8b33e..22836ca01a 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -340,12 +340,22 @@ tablespace_list_append(const char *arg) pg_fatal("invalid tablespace mapping format \"%s\", must be \"OLDDIR=NEWDIR\"", arg); /* - * This check isn't absolutely necessary. But all tablespaces are created - * with absolute directories, so specifying a non-absolute path here would - * just never match, possibly confusing users. It's also good to be - * consistent with the new_dir check. + * All tablespaces are created with absolute directories, so specifying a + * non-absolute path here would just never match, possibly confusing users. + * Since we don't know whether the remote side is Windows or not, and it + * might be different than the local side, permit any path that could be + * absolute under either set of rules. + * + * (There is little practical risk of confusion here, because someone + * running entirely on Linux isn't likely to have a relative path that + * begins with a backslash or something that looks like a drive + * specification. If they do, and they also incorrectly believe that + * a relative path is acceptable here, we'll silently fail to warn them + * of their mistake, and the -T option will just not get applied, same + * as if they'd specified -T for a nonexistent tablespace.) */ - if (!is_absolute_path(cell->old_dir)) + if (!is_nonwindows_absolute_path(cell->old_dir) && + !is_windows_absolute_path(cell->old_dir)) pg_fatal("old directory is not an absolute path in tablespace mapping: %s", cell->old_dir); diff --git a/src/include/port.h b/src/include/port.h index 69d8818d61..02189d59b1 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -78,28 +78,32 @@ extern void get_parent_directory(char *path); extern char **pgfnames(const char *path); extern void pgfnames_cleanup(char **filenames); +#define IS_NONWINDOWS_DIR_SEP(ch) ((ch) == '/') +#define is_nonwindows_absolute_path(filename) \ +( \ + IS_NONWINDOWS_DIR_SEP((filename)[0]) \ +) + +#define IS_WINDOWS_DIR_SEP(ch) ((ch) == '/' || (ch) == '\\') +/* See path_is_relative_and_below_cwd() for how we handle 'E:abc'. */ +#define is_windows_absolute_path(filename) \ +( \ + IS_WINDOWS_DIR_SEP((filename)[0]) || \ + (isalpha((unsigned char) ((filename)[0])) && (filename)[1] == ':' && \ + IS_WINDOWS_DIR_SEP((filename)[2])) \ +) + /* - * is_absolute_path + * is_absolute_path and IS_DIR_SEP * - * By making this a macro we avoid needing to include path.c in libpq. + * By using macros here we avoid needing to include path.c in libpq. */ #ifndef WIN32 -#define IS_DIR_SEP(ch) ((ch) == '/') - -#define is_absolute_path(filename) \ -( \ - IS_DIR_SEP((filename)[0]) \ -) +#define IS_DIR_SEP(ch) IS_NONWINDOWS_DIR_SEP(ch) +#define is_absolute_path(filename) is_nonwindows_absolute_path(filename) #else -#define IS_DIR_SEP(ch) ((ch) == '/' || (ch) == '\\') - -/* See path_is_relative_and_below_cwd() for how we handle 'E:abc'. */ -#define is_absolute_path(filename) \ -( \ - IS_DIR_SEP((filename)[0]) || \ - (isalpha((unsigned char) ((filename)[0])) && (filename)[1] == ':' && \ - IS_DIR_SEP((filename)[2])) \ -) +#define IS_DIR_SEP(ch) IS_WINDOWS_DIR_SEP(ch) +#define is_absolute_path(filename) is_windows_absolute_path(filename) #endif /*