summaryrefslogtreecommitdiff
path: root/src/backend/catalog/pg_tablespace.c
blob: 6aca24c231e176f1d0a9499a92bd5681df996823 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*-------------------------------------------------------------------------
 *
 * pg_tablespace.c
 *	  routines to support manipulation of the pg_tablespace relation
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/catalog/pg_tablespace.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include <unistd.h>
#include <sys/stat.h>

#include "catalog/pg_tablespace.h"
#include "commands/tablespace.h"
#include "miscadmin.h"


/*
 * get_tablespace_location
 *		Get a tablespace's location as a C-string, by its OID
 */
char *
get_tablespace_location(Oid tablespaceOid)
{
	char		sourcepath[MAXPGPATH];
	char		targetpath[MAXPGPATH];
	int			rllen;
	struct stat st;

	/*
	 * It's useful to apply this to pg_class.reltablespace, wherein zero means
	 * "the database's default tablespace".  So, rather than throwing an error
	 * for zero, we choose to assume that's what is meant.
	 */
	if (tablespaceOid == InvalidOid)
		tablespaceOid = MyDatabaseTableSpace;

	/*
	 * Return empty string for the cluster's default tablespaces
	 */
	if (tablespaceOid == DEFAULTTABLESPACE_OID ||
		tablespaceOid == GLOBALTABLESPACE_OID)
		return pstrdup("");

	/*
	 * Find the location of the tablespace by reading the symbolic link that
	 * is in pg_tblspc/<oid>.
	 */
	snprintf(sourcepath, sizeof(sourcepath), "%s/%u", PG_TBLSPC_DIR, tablespaceOid);

	/*
	 * Before reading the link, check if the source path is a link or a
	 * junction point.  Note that a directory is possible for a tablespace
	 * created with allow_in_place_tablespaces enabled.  If a directory is
	 * found, a relative path to the data directory is returned.
	 */
	if (lstat(sourcepath, &st) < 0)
		ereport(ERROR,
				errcode_for_file_access(),
				errmsg("could not stat file \"%s\": %m",
					   sourcepath));

	if (!S_ISLNK(st.st_mode))
		return pstrdup(sourcepath);

	/*
	 * In presence of a link or a junction point, return the path pointed to.
	 */
	rllen = readlink(sourcepath, targetpath, sizeof(targetpath));
	if (rllen < 0)
		ereport(ERROR,
				errcode_for_file_access(),
				errmsg("could not read symbolic link \"%s\": %m",
					   sourcepath));
	if (rllen >= sizeof(targetpath))
		ereport(ERROR,
				errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
				errmsg("symbolic link \"%s\" target is too long",
					   sourcepath));
	targetpath[rllen] = '\0';

	return pstrdup(targetpath);
}