diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/tablespace.c | 89 |
1 files changed, 65 insertions, 24 deletions
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 4ec1affbfb1..ff0d904b7a8 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -627,31 +627,9 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid) /* * In recovery, remove old symlink, in case it points to the wrong place. - * - * On Windows, junction points act like directories so we must be able to - * apply rmdir; in general it seems best to make this code work like the - * symlink removal code in destroy_tablespace_directories, except that - * failure to remove is always an ERROR. */ if (InRecovery) - { - if (lstat(linkloc, &st) == 0 && S_ISDIR(st.st_mode)) - { - if (rmdir(linkloc) < 0) - 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))); - } - } + remove_tablespace_symlink(linkloc); /* * Create the symlink under PGDATA @@ -802,7 +780,8 @@ remove_symlink: errmsg("could not remove directory \"%s\": %m", linkloc))); } - else +#ifdef S_ISLNK + else if (S_ISLNK(st.st_mode)) { if (unlink(linkloc) < 0) { @@ -814,6 +793,15 @@ remove_symlink: linkloc))); } } +#endif + else + { + /* Refuse to remove anything that's not a directory or symlink */ + ereport(redo ? LOG : ERROR, + (ERRCODE_SYSTEM_ERROR, + errmsg("not a directory or symbolic link: \"%s\"", + linkloc))); + } pfree(linkloc_with_version_dir); pfree(linkloc); @@ -848,6 +836,59 @@ directory_is_empty(const char *path) return true; } +/* + * remove_tablespace_symlink + * + * This function removes symlinks in pg_tblspc. On Windows, junction points + * act like directories so we must be able to apply rmdir. This function + * works like the symlink removal code in destroy_tablespace_directories, + * except that failure to remove is always an ERROR. But if the file doesn't + * exist at all, that's OK. + */ +void +remove_tablespace_symlink(const char *linkloc) +{ + struct stat st; + + if (lstat(linkloc, &st) != 0) + { + if (errno == ENOENT) + return; + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not stat \"%s\": %m", linkloc))); + } + + if (S_ISDIR(st.st_mode)) + { + /* + * This will fail if the directory isn't empty, but not + * if it's a junction point. + */ + if (rmdir(linkloc) < 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not remove directory \"%s\": %m", + linkloc))); + } +#ifdef S_ISLNK + else if (S_ISLNK(st.st_mode)) + { + if (unlink(linkloc) < 0 && errno != ENOENT) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not remove symbolic link \"%s\": %m", + linkloc))); + } +#endif + else + { + /* Refuse to remove anything that's not a directory or symlink */ + ereport(ERROR, + (errmsg("not a directory or symbolic link: \"%s\"", + linkloc))); + } +} /* * Rename a tablespace |