diff --git a/src/gausskernel/optimizer/commands/tablespace.cpp b/src/gausskernel/optimizer/commands/tablespace.cpp index cf13efc25005190fa04752b8b354611f95ff2f3e..3ca2a56e6de104d5e215c094c594f078759821e5 100644 --- a/src/gausskernel/optimizer/commands/tablespace.cpp +++ b/src/gausskernel/optimizer/commands/tablespace.cpp @@ -100,6 +100,8 @@ static void createtbspc_abort_callback(bool isCommit, const void* arg); Datum CanonicalizeTablespaceOptions(Datum datum); +#define CHECK_PATH_RETRY_COUNT 100 + #define CANONICALIZE_PATH(path) \ do { \ if (NULL != (path)) { \ @@ -2478,12 +2480,56 @@ char* get_tablespace_name(Oid spc_oid) return result; } +bool IsPathContainsSymlink(char* path) +{ + struct stat statbuf; + errno_t rc; + char* ptr = path; + + if (*ptr == '/') { + ++ptr; + } + + for (bool isLast = false; !isLast; ++ptr) { + if (*ptr == '\0') { + isLast = true; + } else if (*ptr != '/') { + continue; + } + + if (!isLast && ptr[1] == '\0') { + isLast = true; + } + + *ptr = '\0'; + rc = memset_s(&statbuf, sizeof(statbuf), 0, sizeof(statbuf)); + if (rc != EOK) { + continue; + } + + if (lstat(path, &statbuf) == 0 && S_ISLNK(statbuf.st_mode)) { + return true; + } + + if (!isLast) { + *ptr = '/'; + } + } + + return false; +} + /* check if the dir(location) is exist, if not create it */ void check_create_dir(char* location) { int ret; + int retryCount = 0; + bool hasLink = IsPathContainsSymlink(location); recheck: + if (hasLink) { + ++retryCount; + } /* We believe that the location we got from the record is credible. */ switch (ret = pg_check_dir(location)) { case 0: { @@ -2492,6 +2538,14 @@ recheck: if (pg_mkdir_p_used_by_gaussdb(tmplocation, S_IRWXU) == -1) { if (errno == EEXIST) { pfree_ext(tmplocation); + + if (hasLink && retryCount > CHECK_PATH_RETRY_COUNT) { + ereport(ERROR, (errmodule(MOD_TBLSPC), + errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("recheck location \"%s\" exeed max times.", location), + errdetail("the location contains symbolic link, the linked path likely has been deleted."))); + } + goto recheck; } else ereport(ERROR, diff --git a/src/test/regress/input/tablespace.source b/src/test/regress/input/tablespace.source index 338166234646a883bf460f0531cd5caffe810839..0548e8e4991252f75466b570c7feccff51b342d7 100644 --- a/src/test/regress/input/tablespace.source +++ b/src/test/regress/input/tablespace.source @@ -140,4 +140,11 @@ DROP TABLESPACE testspace; -- symlink location \! mkdir -p @testtablespace@/symlink/sym1 \! ln -s @testtablespace@/symlink/sym1 @testtablespace@/symlink/sym2 -CREATE TABLESPACE test_symlink LOCATION '@testtablespace@/symlink/sym2'; \ No newline at end of file +CREATE TABLESPACE test_symlink LOCATION '@testtablespace@/symlink/sym2'; + +-- check linked path deleted +\! mkdir -p @testtablespace@/symlink/will_delete +\! ln -s @testtablespace@/symlink/will_delete @testtablespace@/symlink/will_delete_link +\! rm -rf @testtablespace@/symlink/will_delete + +CREATE TABLESPACE deleted_symlink LOCATION '@testtablespace@/symlink/will_delete_link/local'; diff --git a/src/test/regress/output/tablespace_1.source b/src/test/regress/output/tablespace_1.source index 1d507edb804ea4126f03851e58768045465b8afe..5c5e542fd5fbb7d4a7c8d78d4e58d67e2c79b152 100644 --- a/src/test/regress/output/tablespace_1.source +++ b/src/test/regress/output/tablespace_1.source @@ -272,3 +272,10 @@ DROP TABLESPACE testspace; \! ln -s @testtablespace@/symlink/sym1 @testtablespace@/symlink/sym2 CREATE TABLESPACE test_symlink LOCATION '@testtablespace@/symlink/sym2'; ERROR: location "@testtablespace@/symlink/sym2" is symbolic link +-- check linked path deleted +\! mkdir -p @testtablespace@/symlink/will_delete +\! ln -s @testtablespace@/symlink/will_delete @testtablespace@/symlink/will_delete_link +\! rm -rf @testtablespace@/symlink/will_delete +CREATE TABLESPACE deleted_symlink LOCATION '@testtablespace@/symlink/will_delete_link/local'; +ERROR: recheck location "@testtablespace@/symlink/will_delete_link" exeed max times. +DETAIL: the location contains symbolic link, the linked path likely has been deleted.