On Wed, Mar 24, 2021 at 07:56:59PM -0700, Noah Misch wrote:
> That would entail forbidding various shell metacharacters in @testtablespace@.
> One could avoid imposing such a restriction by adding a mkdir() function to
> regress.c and writing it like:
> 
> CREATE FUNCTION mkdir(text)
>    RETURNS void AS '@libdir@/regress@DLSUFFIX@', 'regress_mkdir'
>    LANGUAGE C STRICT\;
>   REVOKE ALL ON FUNCTION mkdir FROM public;
> SELECT mkdir('@testtablespace@');
> CREATE TABLESPACE regress_tblspace LOCATION '@testtablespace@';

Sounds simple.

>> I doubt that all the Windows environments would be able to get their
>> hands on that.
> 
>> And I am not sure either that this would work when it
>> comes to the CI case, again on Windows.
> 
> How might a CI provider break that?

I am wondering about potential issues when it comes to create the
base tablespace path from the Postgres backend, while HEAD does it
while relying on a restricted token obtained when starting
pg_regress.

I have compiled a simple patch that uses a SQL function for the base
tablespace directory creation, that I have tested on Linux and MSVC.
To get some coverage with the CF bot, I am adding a CF entry with this
thread.

I am still not sure if people would prefer this approach over what's
on HEAD.  So if there are any opinions, please feel free.
--
Michael
diff --git a/src/test/regress/input/tablespace.source b/src/test/regress/input/tablespace.source
index c133e73499..0c1a9929c2 100644
--- a/src/test/regress/input/tablespace.source
+++ b/src/test/regress/input/tablespace.source
@@ -1,3 +1,10 @@
+-- Create the tablespace path.
+CREATE FUNCTION mkdir(text)
+  RETURNS void AS '@libdir@/regress@DLSUFFIX@', 'regress_mkdir'
+  LANGUAGE C STRICT;
+SELECT mkdir('@testtablespace@');
+DROP FUNCTION mkdir(text);
+
 -- create a tablespace using WITH clause
 CREATE TABLESPACE regress_tblspacewith LOCATION '@testtablespace@' WITH (some_nonexistent_parameter = true); -- fail
 CREATE TABLESPACE regress_tblspacewith LOCATION '@testtablespace@' WITH (random_page_cost = 3.0); -- ok
diff --git a/src/test/regress/output/tablespace.source b/src/test/regress/output/tablespace.source
index 1bbe7e0323..ea07211d1a 100644
--- a/src/test/regress/output/tablespace.source
+++ b/src/test/regress/output/tablespace.source
@@ -1,3 +1,14 @@
+-- Create the tablespace path.
+CREATE FUNCTION mkdir(text)
+  RETURNS void AS '@libdir@/regress@DLSUFFIX@', 'regress_mkdir'
+  LANGUAGE C STRICT;
+SELECT mkdir('@testtablespace@');
+ mkdir 
+-------
+ 
+(1 row)
+
+DROP FUNCTION mkdir(text);
 -- create a tablespace using WITH clause
 CREATE TABLESPACE regress_tblspacewith LOCATION '@testtablespace@' WITH (some_nonexistent_parameter = true); -- fail
 ERROR:  unrecognized parameter "some_nonexistent_parameter"
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index b7d80bd9bb..dbb2e8bea7 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -506,23 +506,6 @@ convert_sourcefiles_in(const char *source_subdir, const char *dest_dir, const ch
 
 	snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", outputdir);
 
-	/*
-	 * Clean out the test tablespace dir, or create it if it doesn't exist. On
-	 * Windows, doing this cleanup here makes possible to run the regression
-	 * tests as a Windows administrative user account with the restricted
-	 * token obtained when starting pg_regress.
-	 */
-	if (directory_exists(testtablespace))
-	{
-		if (!rmtree(testtablespace, true))
-		{
-			fprintf(stderr, _("\n%s: could not remove test tablespace \"%s\"\n"),
-					progname, testtablespace);
-			exit(2);
-		}
-	}
-	make_directory(testtablespace);
-
 	/* finally loop on each file and do the replacement */
 	for (name = names; *name; name++)
 	{
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 1990cbb6a1..a884b5ed71 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -18,6 +18,7 @@
 
 #include <math.h>
 #include <signal.h>
+#include <sys/stat.h>
 
 #include "access/detoast.h"
 #include "access/htup_details.h"
@@ -80,6 +81,43 @@ static void regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 
 PG_MODULE_MAGIC;
 
+static bool
+directory_exists(const char *dir)
+{
+	struct stat st;
+
+	if (stat(dir, &st) != 0)
+		return false;
+	if (S_ISDIR(st.st_mode))
+		return true;
+	return false;
+}
+
+/*
+ * Create a new directory for the tests, to be used for tablespaces.
+ * If this directory exists, clean up its contents and create it again
+ * from scratch.
+ */
+PG_FUNCTION_INFO_V1(regress_mkdir);
+
+Datum
+regress_mkdir(PG_FUNCTION_ARGS)
+{
+	char *dir = text_to_cstring(PG_GETARG_TEXT_PP(0));
+
+	if (!superuser())
+		elog(ERROR, "must be superuser to create paths");
+
+	if (directory_exists(dir))
+	{
+		if (!rmtree(dir, true))
+			elog(ERROR, "could not remove path \"%s\"\n", dir);
+	}
+	if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
+		elog(ERROR, "could not create directory \"%s\": %m", dir);
+
+	PG_RETURN_VOID();
+}
 
 /* return the point where two paths intersect, or NULL if no intersection. */
 PG_FUNCTION_INFO_V1(interpt_pp);

Attachment: signature.asc
Description: PGP signature

Reply via email to