mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Replace pgwin32_is_junction() with lstat().
Now that lstat() reports junction points with S_IFLNK/S_ISLINK(), and unlink() can unlink them, there is no need for conditional code for Windows in a few places. That was expressed by testing for WIN32 or S_ISLNK, which we can now constant-fold. The coding around pgwin32_is_junction() was a bit suspect anyway, as we never checked for errors, and we also know that errors can be spuriously reported because of transient sharing violations on this OS. The lstat()-based code has handling for that. This also reverts4fc6b6eeon master only. That was done because lstat() didn't previously work for symlinks (junction points), but now it does. Tested-by: Andrew Dunstan <andrew@dunslane.net> Discussion: https://postgr.es/m/CA%2BhUKGLfOOeyZpm5ByVcAt7x5Pn-%3DxGRNCvgiUPVVzjFLtnY0w%40mail.gmail.com (cherry picked from commit5fc88c5d53) Author: Thomas Munro <tmunro@postgresql.org> Author: Alexandra Wang <alexandra.wang.oss@gmail.com>
This commit is contained in:
		
				
					committed by
					
						
						Andrew Dunstan
					
				
			
			
				
	
			
			
			
						parent
						
							f2a4a137bb
						
					
				
				
					commit
					f95ad555de
				
			@@ -1325,13 +1325,7 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Allow symbolic links in pg_tblspc only */
 | 
			
		||||
		if (strcmp(path, "./pg_tblspc") == 0 &&
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
			S_ISLNK(statbuf.st_mode)
 | 
			
		||||
#else
 | 
			
		||||
			pgwin32_is_junction(pathbuf)
 | 
			
		||||
#endif
 | 
			
		||||
			)
 | 
			
		||||
		if (strcmp(path, "./pg_tblspc") == 0 && S_ISLNK(statbuf.st_mode))
 | 
			
		||||
		{
 | 
			
		||||
#if defined(HAVE_READLINK) || defined(WIN32)
 | 
			
		||||
			char		linkpath[MAXPGPATH];
 | 
			
		||||
@@ -1815,11 +1809,7 @@ static void
 | 
			
		||||
convert_link_to_directory(const char *pathbuf, struct stat *statbuf)
 | 
			
		||||
{
 | 
			
		||||
	/* If symlink, write it as a directory anyway */
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
	if (S_ISLNK(statbuf->st_mode))
 | 
			
		||||
#else
 | 
			
		||||
	if (pgwin32_is_junction(pathbuf))
 | 
			
		||||
#endif
 | 
			
		||||
		statbuf->st_mode = S_IFDIR | pg_dir_create_mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -807,8 +807,7 @@ destroy_tablespace_directories(Oid tablespaceoid, bool redo)
 | 
			
		||||
	/*
 | 
			
		||||
	 * Try to remove the symlink.  We must however deal with the possibility
 | 
			
		||||
	 * that it's a directory instead of a symlink --- this could happen during
 | 
			
		||||
	 * WAL replay (see TablespaceCreateDbspace), and it is also the case on
 | 
			
		||||
	 * Windows where junction points lstat() as directories.
 | 
			
		||||
	 * WAL replay (see TablespaceCreateDbspace).
 | 
			
		||||
	 *
 | 
			
		||||
	 * Note: in the redo case, we'll return true if this final step fails;
 | 
			
		||||
	 * there's no point in retrying it.  Also, ENOENT should provoke no more
 | 
			
		||||
@@ -838,7 +837,6 @@ remove_symlink:
 | 
			
		||||
							linkloc)));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#ifdef S_ISLNK
 | 
			
		||||
	else if (S_ISLNK(st.st_mode))
 | 
			
		||||
	{
 | 
			
		||||
		if (unlink(linkloc) < 0)
 | 
			
		||||
@@ -851,7 +849,6 @@ remove_symlink:
 | 
			
		||||
							linkloc)));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		/* Refuse to remove anything that's not a directory or symlink */
 | 
			
		||||
@@ -929,7 +926,6 @@ remove_tablespace_symlink(const char *linkloc)
 | 
			
		||||
					 errmsg("could not remove directory \"%s\": %m",
 | 
			
		||||
							linkloc)));
 | 
			
		||||
	}
 | 
			
		||||
#ifdef S_ISLNK
 | 
			
		||||
	else if (S_ISLNK(st.st_mode))
 | 
			
		||||
	{
 | 
			
		||||
		if (unlink(linkloc) < 0 && errno != ENOENT)
 | 
			
		||||
@@ -938,7 +934,6 @@ remove_tablespace_symlink(const char *linkloc)
 | 
			
		||||
					 errmsg("could not remove symbolic link \"%s\": %m",
 | 
			
		||||
							linkloc)));
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		/* Refuse to remove anything that's not a directory or symlink */
 | 
			
		||||
 
 | 
			
		||||
@@ -3440,7 +3440,6 @@ SyncDataDirectory(void)
 | 
			
		||||
	 */
 | 
			
		||||
	xlog_is_symlink = false;
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
	{
 | 
			
		||||
		struct stat st;
 | 
			
		||||
 | 
			
		||||
@@ -3452,10 +3451,6 @@ SyncDataDirectory(void)
 | 
			
		||||
		else if (S_ISLNK(st.st_mode))
 | 
			
		||||
			xlog_is_symlink = true;
 | 
			
		||||
	}
 | 
			
		||||
#else
 | 
			
		||||
	if (pgwin32_is_junction("pg_wal"))
 | 
			
		||||
		xlog_is_symlink = true;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_SYNCFS
 | 
			
		||||
	if (recovery_init_sync_method == RECOVERY_INIT_SYNC_METHOD_SYNCFS)
 | 
			
		||||
 
 | 
			
		||||
@@ -283,9 +283,7 @@ pg_tablespace_location(PG_FUNCTION_ARGS)
 | 
			
		||||
	char		sourcepath[MAXPGPATH];
 | 
			
		||||
	char		targetpath[MAXPGPATH];
 | 
			
		||||
	int			rllen;
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
	struct stat st;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * It's useful to apply this function to pg_class.reltablespace, wherein
 | 
			
		||||
@@ -316,10 +314,6 @@ pg_tablespace_location(PG_FUNCTION_ARGS)
 | 
			
		||||
	 * created with allow_in_place_tablespaces enabled.  If a directory is
 | 
			
		||||
	 * found, a relative path to the data directory is returned.
 | 
			
		||||
	 */
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
	if (!pgwin32_is_junction(sourcepath))
 | 
			
		||||
		PG_RETURN_TEXT_P(cstring_to_text(sourcepath));
 | 
			
		||||
#else
 | 
			
		||||
	if (lstat(sourcepath, &st) < 0)
 | 
			
		||||
	{
 | 
			
		||||
		ereport(ERROR,
 | 
			
		||||
@@ -330,7 +324,6 @@ pg_tablespace_location(PG_FUNCTION_ARGS)
 | 
			
		||||
 | 
			
		||||
	if (!S_ISLNK(st.st_mode))
 | 
			
		||||
		PG_RETURN_TEXT_P(cstring_to_text(sourcepath));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * In presence of a link or a junction point, return the path pointing to.
 | 
			
		||||
 
 | 
			
		||||
@@ -388,11 +388,7 @@ scan_directory(const char *basedir, const char *subdir, bool sizeonly)
 | 
			
		||||
			if (!sizeonly)
 | 
			
		||||
				scan_file(fn, segmentno);
 | 
			
		||||
		}
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
		else if (S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
 | 
			
		||||
#else
 | 
			
		||||
		else if (S_ISDIR(st.st_mode) || pgwin32_is_junction(fn))
 | 
			
		||||
#endif
 | 
			
		||||
		{
 | 
			
		||||
			/*
 | 
			
		||||
			 * If going through the entries of pg_tblspc, we assume to operate
 | 
			
		||||
 
 | 
			
		||||
@@ -431,11 +431,7 @@ recurse_dir(const char *datadir, const char *parentpath,
 | 
			
		||||
			/* recurse to handle subdirectories */
 | 
			
		||||
			recurse_dir(datadir, path, callback);
 | 
			
		||||
		}
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
		else if (S_ISLNK(fst.st_mode))
 | 
			
		||||
#else
 | 
			
		||||
		else if (pgwin32_is_junction(fullpath))
 | 
			
		||||
#endif
 | 
			
		||||
		{
 | 
			
		||||
#if defined(HAVE_READLINK) || defined(WIN32)
 | 
			
		||||
			char		link_target[MAXPGPATH];
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,6 @@ fsync_pgdata(const char *pg_data,
 | 
			
		||||
	 */
 | 
			
		||||
	xlog_is_symlink = false;
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
	{
 | 
			
		||||
		struct stat st;
 | 
			
		||||
 | 
			
		||||
@@ -88,10 +87,6 @@ fsync_pgdata(const char *pg_data,
 | 
			
		||||
		else if (S_ISLNK(st.st_mode))
 | 
			
		||||
			xlog_is_symlink = true;
 | 
			
		||||
	}
 | 
			
		||||
#else
 | 
			
		||||
	if (pgwin32_is_junction(pg_wal))
 | 
			
		||||
		xlog_is_symlink = true;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If possible, hint to the kernel that we're soon going to fsync the data
 | 
			
		||||
@@ -459,27 +454,9 @@ get_dirent_type(const char *path,
 | 
			
		||||
			result = PGFILETYPE_REG;
 | 
			
		||||
		else if (S_ISDIR(fst.st_mode))
 | 
			
		||||
			result = PGFILETYPE_DIR;
 | 
			
		||||
#ifdef S_ISLNK
 | 
			
		||||
		else if (S_ISLNK(fst.st_mode))
 | 
			
		||||
			result = PGFILETYPE_LNK;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if defined(WIN32) && !defined(_MSC_VER)
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we're on native Windows (not Cygwin, which has its own POSIX
 | 
			
		||||
	 * symlinks), but not using the MSVC compiler, then we're using a
 | 
			
		||||
	 * readdir() emulation provided by the MinGW runtime that has no d_type.
 | 
			
		||||
	 * Since the lstat() fallback code reports junction points as directories,
 | 
			
		||||
	 * we need an extra system call to check if we should report them as
 | 
			
		||||
	 * symlinks instead, following our convention.
 | 
			
		||||
	 */
 | 
			
		||||
	if (result == PGFILETYPE_DIR &&
 | 
			
		||||
		!look_through_symlinks &&
 | 
			
		||||
		pgwin32_is_junction(path))
 | 
			
		||||
		result = PGFILETYPE_LNK;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -288,7 +288,6 @@ extern int	pgunlink(const char *path);
 | 
			
		||||
#if defined(WIN32) && !defined(__CYGWIN__)
 | 
			
		||||
extern int	pgsymlink(const char *oldpath, const char *newpath);
 | 
			
		||||
extern int	pgreadlink(const char *path, char *buf, size_t size);
 | 
			
		||||
extern bool pgwin32_is_junction(const char *path);
 | 
			
		||||
 | 
			
		||||
#define symlink(oldpath, newpath)	pgsymlink(oldpath, newpath)
 | 
			
		||||
#define readlink(path, buf, size)	pgreadlink(path, buf, size)
 | 
			
		||||
 
 | 
			
		||||
@@ -236,7 +236,6 @@ extern pgoff_t _pgftello64(FILE *stream);
 | 
			
		||||
 */
 | 
			
		||||
extern int	pgsymlink(const char *oldpath, const char *newpath);
 | 
			
		||||
extern int	pgreadlink(const char *path, char *buf, size_t size);
 | 
			
		||||
extern bool pgwin32_is_junction(const char *path);
 | 
			
		||||
 | 
			
		||||
#define symlink(oldpath, newpath)	pgsymlink(oldpath, newpath)
 | 
			
		||||
#define readlink(path, buf, size)	pgreadlink(path, buf, size)
 | 
			
		||||
 
 | 
			
		||||
@@ -336,20 +336,4 @@ pgreadlink(const char *path, char *buf, size_t size)
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Assumes the file exists, so will return false if it doesn't
 | 
			
		||||
 * (since a nonexistent file is not a junction)
 | 
			
		||||
 */
 | 
			
		||||
bool
 | 
			
		||||
pgwin32_is_junction(const char *path)
 | 
			
		||||
{
 | 
			
		||||
	DWORD		attr = GetFileAttributes(path);
 | 
			
		||||
 | 
			
		||||
	if (attr == INVALID_FILE_ATTRIBUTES)
 | 
			
		||||
	{
 | 
			
		||||
		_dosmaperr(GetLastError());
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	return ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT);
 | 
			
		||||
}
 | 
			
		||||
#endif							/* defined(WIN32) && !defined(__CYGWIN__) */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user