diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index cf2f07e6707..94c067038c5 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -126,14 +126,19 @@ int my_is_symlink(const char *filename __attribute__((unused))) } /* - Resolve all symbolic links in path - 'to' may be equal to 'filename' + Resolve all symbolic links in path. - to is guaranteed to never set to a string longer than FN_REFLEN - (including the end \0) + If path is relative, assume current directory and replace with absolute. + If filename is empty string, resolve path to current directory. + + Resolved path is placed in the 'to' buffer, and is guaranteed to never + be longer than FN_REFLEN (including the end \0); 'to' may be equal to + 'filename'. On error returns -1, unless error is file not found, in which case it - is 1. + is 1; 'to' will then be populated with a fallback value as specified by + my_load_path() with null own_path_prefix; symlinks will not be + resolved. Sets my_errno to specific error number. */ @@ -144,10 +149,12 @@ int my_realpath(char *to, const char *filename, myf MyFlags) int result=0; char buff[BUFF_LEN]; char *ptr; + static const char cur_dir[] = {FN_CURLIB, '\0'}; DBUG_ENTER("my_realpath"); DBUG_PRINT("info",("executing realpath")); - if ((ptr=realpath(filename,buff))) + /* realpath won't accept empty string - use "." instead */ + if ((ptr=realpath(filename[0] ? filename : cur_dir, buff))) strmake(to, ptr, FN_REFLEN-1); else { diff --git a/unittest/mysys/CMakeLists.txt b/unittest/mysys/CMakeLists.txt index 927c0e83dc7..10527add496 100644 --- a/unittest/mysys/CMakeLists.txt +++ b/unittest/mysys/CMakeLists.txt @@ -14,7 +14,8 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA MY_ADD_TESTS(base64 bitmap byte_order crc32 dynstring lf my_atomic my_getopt - my_malloc my_rdtsc queues stack_allocation stacktrace waiting_threads + my_malloc my_rdtsc my_symlink queues stack_allocation stacktrace + waiting_threads LINK_LIBRARIES mysys) MY_ADD_TESTS(my_vsnprintf LINK_LIBRARIES strings mysys) ADD_DEFINITIONS(${SSL_DEFINES}) diff --git a/unittest/mysys/my_symlink-t.c b/unittest/mysys/my_symlink-t.c new file mode 100644 index 00000000000..f35c28133d1 --- /dev/null +++ b/unittest/mysys/my_symlink-t.c @@ -0,0 +1,85 @@ +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "tap.h" + +static void test_my_realpath() +{ +#ifndef HAVE_REALPATH + skip(2, "realpath not supported"); + return; +#else + char cwd[PATH_MAX]; + char *resolved_cwd; + char result[FN_REFLEN]; + char link_name[64] = {0}; + int errcode; + if (getcwd(cwd, sizeof(cwd)) == NULL) + { + diag("getcwd() failed: %s", strerror(errno)); + skip(2, "getcwd() failed"); + return; + } + + resolved_cwd= realpath(cwd, NULL); + if (!resolved_cwd) + { + diag("realpath() failed: %s", strerror(errno)); + skip(2, "realpath() failed"); + return; + } + + /* Call my_realpath with empty string in current working directory, + expecting resolved abolute path to that directory */ + errcode= my_realpath(result, "", MYF(0)); + ok(errcode == 0, "my_realpath returned error code: %d", errcode); + ok(!strcmp(result, resolved_cwd), + "Output of my_realpath: %s, expected: %s", + result, resolved_cwd); + /* Creae a symlink, chdir to it and resolve empty string */ + + /* Generate a unique name for the symlink */ + srand(time(NULL)); + snprintf(link_name, sizeof(link_name), "my_link_%d.%06d", getpid(), rand() % 1000000); + if (symlink(cwd, link_name) != 0) + { + diag("symlink() failed: %s", strerror(errno)); + skip(1, "symlink() failed"); + goto cwd_cleanup; + } + if (chdir(link_name) != 0) + { + diag("chdir() failed: %s", strerror(errno)); + skip(1, "chdir() failed"); + goto link_cleanup; + } + errcode= my_realpath(result, "", MYF(0)); + ok(errcode == 0, "my_realpath returned error code: %d", errcode); + ok(!strcmp(result, resolved_cwd), + "Output of my_realpath: %s, expected: %s", + result, resolved_cwd); +link_cleanup: + unlink(link_name); +cwd_cleanup: + free(resolved_cwd); +#endif +} + +int main(int argc __attribute__((unused)),char *argv[]) +{ + MY_INIT(argv[0]); + plan(4); + + test_my_realpath(); + + my_end(0); + return exit_status(); +}