From ef78401e6b136577fb1703a6820743ab404631b1 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 24 Jun 2015 13:03:08 +0900 Subject: [PATCH 6/8] Add pg_readlink to get value of a symbolic link This is similar to Posix's readlink, except that PostgreSQL restrictions are applied to the source path queried, similarly to other functions of genfile.c. --- doc/src/sgml/func.sgml | 9 +++++++ src/backend/utils/adt/genfile.c | 54 +++++++++++++++++++++++++++++++++++++++++ src/include/catalog/pg_proc.h | 2 ++ src/include/utils/builtins.h | 1 + 4 files changed, 66 insertions(+) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 20b91ab..81a8090 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -17855,6 +17855,15 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); an error. + + + pg_readlink(filename text) + + text + + Return value of a symbolic link. + + diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index 456061b..94ff7d6 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -585,3 +585,57 @@ pg_ls_dir_extended(PG_FUNCTION_ARGS) { return ls_dir_wrapper(fcinfo); } + + +/* + * pg_readlink - Find the real location of the provided symbolic link. + */ +Datum +pg_readlink(PG_FUNCTION_ARGS) +{ + text *sourcepath_t = PG_GETARG_TEXT_P(0); + char *sourcepath; + char targetpath[MAXPGPATH]; + int rllen; + bool if_not_exists = false; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to read files")))); + + /* Check for option if_not_exists */ + if (PG_NARGS() == 2 && !PG_ARGISNULL(1)) + if_not_exists = PG_GETARG_BOOL(1); + +#if defined(HAVE_READLINK) || defined(WIN32) + sourcepath = convert_and_check_filename(sourcepath_t); + + rllen = readlink(sourcepath, targetpath, sizeof(targetpath)); + if (rllen < 0) + { + if (if_not_exists && errno == ENOENT) + PG_RETURN_NULL(); + else + 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'; + + PG_RETURN_TEXT_P(cstring_to_text(targetpath)); +#else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("readline is not available on this platform"))); + PG_RETURN_NULL(); +#endif +} diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 36d3e15..11dd80d 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3207,6 +3207,8 @@ DATA(insert OID = 2625 ( pg_ls_dir PGNSP PGUID 12 1 1000 0 0 f f f f t t v 1 0 DESCR("list all files in a directory"); DATA(insert OID = 3297 ( pg_ls_dir PGNSP PGUID 12 1 1000 0 0 f f f f t t v 3 0 25 "25 16 16" _null_ _null_ _null_ _null_ _null_ pg_ls_dir_extended _null_ _null_ _null_ )); DESCR("list all files in a directory"); +DATA(insert OID = 3298 ( pg_readlink PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 25 "25" _null_ _null_ _null_ _null_ _null_ pg_readlink _null_ _null_ _null_ )); +DESCR("read value of a symbolic link"); DATA(insert OID = 2626 ( pg_sleep PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2278 "701" _null_ _null_ _null_ _null_ _null_ pg_sleep _null_ _null_ _null_ )); DESCR("sleep for the specified time in seconds"); DATA(insert OID = 3935 ( pg_sleep_for PGNSP PGUID 14 1 0 0 0 f f f f t f v 1 0 2278 "1186" _null_ _null_ _null_ _null_ _null_ "select pg_catalog.pg_sleep(extract(epoch from pg_catalog.clock_timestamp() operator(pg_catalog.+) $1) operator(pg_catalog.-) extract(epoch from pg_catalog.clock_timestamp()))" _null_ _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 446cda6..27a4fd8 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -485,6 +485,7 @@ extern Datum pg_read_binary_file_all(PG_FUNCTION_ARGS); extern Datum pg_read_binary_file_all_extended(PG_FUNCTION_ARGS); extern Datum pg_ls_dir(PG_FUNCTION_ARGS); extern Datum pg_ls_dir_extended(PG_FUNCTION_ARGS); +extern Datum pg_readlink(PG_FUNCTION_ARGS); /* misc.c */ extern Datum current_database(PG_FUNCTION_ARGS); -- 2.4.4