From 5c9baf54e7af994391aa0510f666b364ff2e657b Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 27 Jan 2017 16:46:26 +0200 Subject: Fix for memory leak in applications, like QT,that calls my_thread_global_init() + my_thrad_global_end() repeatadily. This caused THR_KEY_mysys to be allocated multiple times. Deletion of THR_KEY_mysys was originally in my_thread_global_end() but was moved to my_end() as DBUG uses THR_KEY_mysys and DBUG is released after my_thread_global_end() is called. Releasing DBUG before my_thread_global_end() and move THR_KEY_mysys back into my_thread_global_end() could be a solution, but as safe_mutex and other things called by my_thread_global_end is using DBUG it may not be completely safe. To solve this, I used the simple solution to add a marker that THR_KEY_mysys is created and not re-create it in my_thread_global_init if it already exists. --- mysys/my_init.c | 2 +- mysys/my_thr_init.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'mysys') diff --git a/mysys/my_init.c b/mysys/my_init.c index 99efba14a73..5f6650f0ec9 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -226,7 +226,7 @@ Voluntary context switches %ld, Involuntary context switches %ld\n", /* At very last, delete mysys key, it is used everywhere including DBUG */ pthread_key_delete(THR_KEY_mysys); - my_init_done=0; + my_init_done= my_thr_key_mysys_exists= 0; } /* my_end */ #ifndef DBUG_OFF diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 3e4d091944b..aefd3564185 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -60,6 +60,8 @@ static uint get_thread_lib(void); /** True if @c my_thread_global_init() has been called. */ static my_bool my_thread_global_init_done= 0; +/* True if THR_KEY_mysys is created */ +my_bool my_thr_key_mysys_exists= 0; /* @@ -185,11 +187,20 @@ my_bool my_thread_global_init(void) return 0; my_thread_global_init_done= 1; - if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0) + /* + THR_KEY_mysys is deleted in my_end() as DBUG libraries are using it even + after my_thread_global_end() is called. + my_thr_key_mysys_exist is used to protect against application like QT + that calls my_thread_global_init() + my_thread_global_end() multiple times + without calling my_init() + my_end(). + */ + if (!my_thr_key_mysys_exists && + (pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0) { fprintf(stderr, "Can't initialize threads: error %d\n", pth_ret); return 1; } + my_thr_key_mysys_exists= 1; /* Mutex used by my_thread_init() and after my_thread_destroy_mutex() */ my_thread_init_internal_mutex(); -- cgit v1.2.1 From 3cba74e032050b126eaf1fd27072b1afaeef79b3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 18 Feb 2017 10:01:31 +0100 Subject: cleanup: fn_format, remove dead code my_realpath() ignores MY_xxx flags anyway --- mysys/mf_format.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'mysys') diff --git a/mysys/mf_format.c b/mysys/mf_format.c index d20ce882459..996fee68bd1 100644 --- a/mysys/mf_format.c +++ b/mysys/mf_format.c @@ -97,13 +97,8 @@ char * fn_format(char * to, const char *name, const char *dir, pos=strmake(strmov(to,dev),name,length); (void) strmov(pos,ext); /* Don't convert extension */ } - /* - If MY_RETURN_REAL_PATH and MY_RESOLVE_SYMLINK is given, only do - realpath if the file is a symbolic link - */ if (flag & MY_RETURN_REAL_PATH) - (void) my_realpath(to, to, MYF(flag & MY_RESOLVE_SYMLINKS ? - MY_RESOLVE_LINK: 0)); + (void) my_realpath(to, to, MYF(0)); else if (flag & MY_RESOLVE_SYMLINKS) { strmov(buff,to); -- cgit v1.2.1 From 24d8bc707a3d3161229b1cfc94b34dc50473bc59 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 18 Feb 2017 10:08:49 +0100 Subject: cleanup: my_register_filename() Don't let my_register_filename() fail because strdup() failed. Better to have NULL for a filename, then to fail the already successful open(). Filenames are only used for error reporting and there was already code to ignore OOMs (my_fdopen()) and to cope with missing filenames (my_filename()). --- mysys/my_create.c | 20 +++----------------- mysys/my_div.c | 2 +- mysys/my_fopen.c | 18 ++++++------------ mysys/my_open.c | 27 +++++++++------------------ 4 files changed, 19 insertions(+), 48 deletions(-) (limited to 'mysys') diff --git a/mysys/my_create.c b/mysys/my_create.c index 2e4e8eb1af2..e9a1365ca19 100644 --- a/mysys/my_create.c +++ b/mysys/my_create.c @@ -36,7 +36,7 @@ File my_create(const char *FileName, int CreateFlags, int access_flags, myf MyFlags) { - int fd, rc; + int fd; DBUG_ENTER("my_create"); DBUG_PRINT("my",("Name: '%s' CreateFlags: %d AccessFlags: %d MyFlags: %d", FileName, CreateFlags, access_flags, MyFlags)); @@ -54,21 +54,7 @@ File my_create(const char *FileName, int CreateFlags, int access_flags, fd= -1; } - rc= my_register_filename(fd, FileName, FILE_BY_CREATE, + fd= my_register_filename(fd, FileName, FILE_BY_CREATE, EE_CANTCREATEFILE, MyFlags); - /* - my_register_filename() may fail on some platforms even if the call to - *open() above succeeds. In this case, don't leave the stale file because - callers assume the file to not exist if my_create() fails, so they don't - do any cleanups. - */ - if (unlikely(fd >= 0 && rc < 0)) - { - int tmp= my_errno; - my_close(fd, MyFlags); - my_delete(FileName, MyFlags); - my_errno= tmp; - } - - DBUG_RETURN(rc); + DBUG_RETURN(fd); } /* my_create */ diff --git a/mysys/my_div.c b/mysys/my_div.c index 660b87e5ab4..44eb5392421 100644 --- a/mysys/my_div.c +++ b/mysys/my_div.c @@ -27,7 +27,7 @@ char * my_filename(File fd) { DBUG_ENTER("my_filename"); - if ((uint) fd >= (uint) my_file_limit) + if ((uint) fd >= (uint) my_file_limit || !my_file_info[fd].name) DBUG_RETURN((char*) "UNKNOWN"); if (fd >= 0 && my_file_info[fd].type != UNOPEN) { diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c index cc1019365ac..99a9035c0c2 100644 --- a/mysys/my_fopen.c +++ b/mysys/my_fopen.c @@ -69,19 +69,13 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags) DBUG_RETURN(fd); /* safeguard */ } mysql_mutex_lock(&THR_LOCK_open); - if ((my_file_info[filedesc].name= (char*) - my_strdup(filename,MyFlags))) - { - my_stream_opened++; - my_file_total_opened++; - my_file_info[filedesc].type= STREAM_BY_FOPEN; - mysql_mutex_unlock(&THR_LOCK_open); - DBUG_PRINT("exit",("stream: 0x%lx", (long) fd)); - DBUG_RETURN(fd); - } + my_file_info[filedesc].name= (char*) my_strdup(filename,MyFlags); + my_stream_opened++; + my_file_total_opened++; + my_file_info[filedesc].type= STREAM_BY_FOPEN; mysql_mutex_unlock(&THR_LOCK_open); - (void) my_fclose(fd,MyFlags); - my_errno=ENOMEM; + DBUG_PRINT("exit",("stream: 0x%lx", (long) fd)); + DBUG_RETURN(fd); } else my_errno=errno; diff --git a/mysys/my_open.c b/mysys/my_open.c index 645d6709358..d19db0aaf0c 100644 --- a/mysys/my_open.c +++ b/mysys/my_open.c @@ -131,25 +131,16 @@ File my_register_filename(File fd, const char *FileName, enum file_type thread_safe_increment(my_file_opened,&THR_LOCK_open); DBUG_RETURN(fd); /* safeguard */ } - else - { - mysql_mutex_lock(&THR_LOCK_open); - if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags))) - { - my_file_opened++; - my_file_total_opened++; - my_file_info[fd].type = type_of_file; - mysql_mutex_unlock(&THR_LOCK_open); - DBUG_PRINT("exit",("fd: %d",fd)); - DBUG_RETURN(fd); - } - mysql_mutex_unlock(&THR_LOCK_open); - my_errno= ENOMEM; - } - (void) my_close(fd, MyFlags); + mysql_mutex_lock(&THR_LOCK_open); + my_file_info[fd].name = (char*) my_strdup(FileName, MyFlags); + my_file_opened++; + my_file_total_opened++; + my_file_info[fd].type = type_of_file; + mysql_mutex_unlock(&THR_LOCK_open); + DBUG_PRINT("exit",("fd: %d",fd)); + DBUG_RETURN(fd); } - else - my_errno= errno; + my_errno= errno; DBUG_PRINT("error",("Got error %d on open", my_errno)); if (MyFlags & (MY_FFNF | MY_FAE | MY_WME)) -- cgit v1.2.1 From c826ac9d539fa66d45afd0ca0d54b2579fcbb797 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 18 Feb 2017 10:10:34 +0100 Subject: cleanup: mysys_test_invalid_symlink Remove maria_test_invalid_symlink() and myisam_test_invalid_symlink(), introduce mysys_test_invalid_symlink(). Other engines might need it too --- mysys/my_symlink.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'mysys') diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index b0e910f7ba0..bc01a68263d 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -1,5 +1,6 @@ /* Copyright (c) 2001, 2011, Oracle and/or its affiliates + Copyright (c) 2010, 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,6 +24,14 @@ #include #endif +static int always_valid(const char *filename __attribute__((unused))) +{ + return 0; +} + +int (*mysys_test_invalid_symlink)(const char *filename)= always_valid; + + /* Reads the content of a symbolic link If the file is not a symbolic link, return the original file name in to. -- cgit v1.2.1 From d78d0d459d10dd12069de82d6735f1acf183c631 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 18 Feb 2017 10:38:14 +0100 Subject: cleanup: NO_OPEN_3 was never defined --- mysys/my_open.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'mysys') diff --git a/mysys/my_open.c b/mysys/my_open.c index d19db0aaf0c..24d5c881372 100644 --- a/mysys/my_open.c +++ b/mysys/my_open.c @@ -45,10 +45,8 @@ File my_open(const char *FileName, int Flags, myf MyFlags) MyFlags|= my_global_flags; #if defined(_WIN32) fd= my_win_open(FileName, Flags); -#elif !defined(NO_OPEN_3) - fd = open(FileName, Flags, my_umask); /* Normal unix */ #else - fd = open((char *) FileName, Flags); + fd = open(FileName, Flags, my_umask); #endif fd= my_register_filename(fd, FileName, FILE_BY_OPEN, -- cgit v1.2.1 From b27fd90ad36f4194665744cc1dcdd05f2d0b47ef Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 15 Feb 2017 18:45:19 +0100 Subject: MDEV-11902 mi_open race condition TOCTOU bug. The path is checked to be valid, symlinks are resolved. Then the resolved path is opened. Between the check and the open, there's a window when one can replace some path component with a symlink, bypassing validity checks. Fix: after we resolved all symlinks in the path, don't allow open() to resolve symlinks, there should be none. Compared to the old MyISAM/Aria code: * fastpath. Opening of not-symlinked files is just one open(), no fn_format() and lstat() anymore. * opening of symlinked tables doesn't do fn_format() and lstat() either. it also doesn't to realpath() (which was lstat-ing every path component), instead if opens every path component with O_PATH. * share->data_file_name stores realpath(path) not readlink(path). So, SHOW CREATE TABLE needs to do lstat/readlink() now (see ::info()), and certain error messages (cannot open file "XXX") show the real file path with all symlinks resolved. --- mysys/my_open.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 2 deletions(-) (limited to 'mysys') diff --git a/mysys/my_open.c b/mysys/my_open.c index 24d5c881372..0effc4bedda 100644 --- a/mysys/my_open.c +++ b/mysys/my_open.c @@ -15,9 +15,14 @@ #include "mysys_priv.h" #include "mysys_err.h" -#include +#include #include +#if !defined(O_PATH) && defined(O_EXEC) /* FreeBSD */ +#define O_PATH O_EXEC +#endif + +static int open_nosymlinks(const char *pathname, int flags, int mode); /* Open a file @@ -46,7 +51,10 @@ File my_open(const char *FileName, int Flags, myf MyFlags) #if defined(_WIN32) fd= my_win_open(FileName, Flags); #else - fd = open(FileName, Flags, my_umask); + if (MyFlags & MY_NOSYMLINKS) + fd = open_nosymlinks(FileName, Flags, my_umask); + else + fd = open(FileName, Flags, my_umask); #endif fd= my_register_filename(fd, FileName, FILE_BY_OPEN, @@ -174,3 +182,81 @@ void my_print_open_files(void) } #endif + +/** + like open(), but with symlinks are not accepted anywhere in the path + + This is used for opening symlinked tables for DATA/INDEX DIRECTORY. + The paths there have been realpath()-ed. So, we can assume here that + + * `pathname` is an absolute path + * no '.', '..', and '//' in the path + * file exists +*/ +static int open_nosymlinks(const char *pathname, int flags, int mode) +{ +#ifndef O_PATH +#ifdef HAVE_REALPATH + char buf[PATH_MAX+1]; + if (realpath(pathname, buf) == NULL) + return -1; + if (strcmp(pathname, buf)) + { + errno= ENOTDIR; + return -1; + } +#endif + return open(pathname, flags, mode | O_NOFOLLOW); +#else + + char buf[PATH_MAX+1]; + char *s= buf, *e= buf+1, *end= strnmov(buf, pathname, sizeof(buf)); + int fd, dfd= -1; + + if (*end) + { + errno= ENAMETOOLONG; + return -1; + } + + if (*s != '/') /* not an absolute path */ + { + errno= ENOENT; + return -1; + } + + for (;;) + { + if (*e == '/') /* '//' in the path */ + { + errno= ENOENT; + goto err; + } + while (*e && *e != '/') + e++; + *e= 0; + if (!memcmp(s, ".", 2) || !memcmp(s, "..", 3)) + { + errno= ENOENT; + goto err; + } + + fd = openat(dfd, s, O_NOFOLLOW | (e < end ? O_PATH : flags), mode); + if (fd < 0) + goto err; + + if (dfd >= 0) + close(dfd); + + dfd= fd; + s= ++e; + + if (e >= end) + return fd; + } +err: + if (dfd >= 0) + close(dfd); + return -1; +#endif +} -- cgit v1.2.1 From 6d50324558e79d6e90848059bf7cd918685b02ba Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 20 Feb 2017 22:41:17 +0100 Subject: support MY_NOSYMLINKS in my_delete() --- mysys/my_delete.c | 11 ++++++- mysys/my_open.c | 88 ++++-------------------------------------------------- mysys/my_symlink.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++ mysys/mysys_priv.h | 28 +++++++++++++++++ 4 files changed, 118 insertions(+), 84 deletions(-) (limited to 'mysys') diff --git a/mysys/my_delete.c b/mysys/my_delete.c index 155e925e9ba..8487f1d2e5a 100644 --- a/mysys/my_delete.c +++ b/mysys/my_delete.c @@ -21,6 +21,12 @@ static int my_win_unlink(const char *name); #endif +CREATE_NOSYMLINK_FUNCTION( + unlink_nosymlinks(const char *pathname), + unlinkat(dfd, filename, 0), + unlink(pathname) +); + int my_delete(const char *name, myf MyFlags) { int err; @@ -30,7 +36,10 @@ int my_delete(const char *name, myf MyFlags) #ifdef _WIN32 err = my_win_unlink(name); #else - err = unlink(name); + if (MyFlags & MY_NOSYMLINKS) + err= unlink_nosymlinks(name); + else + err= unlink(name); #endif if(err) diff --git a/mysys/my_open.c b/mysys/my_open.c index 0effc4bedda..cafb94ef558 100644 --- a/mysys/my_open.c +++ b/mysys/my_open.c @@ -18,11 +18,11 @@ #include #include -#if !defined(O_PATH) && defined(O_EXEC) /* FreeBSD */ -#define O_PATH O_EXEC -#endif - -static int open_nosymlinks(const char *pathname, int flags, int mode); +CREATE_NOSYMLINK_FUNCTION( + open_nosymlinks(const char *pathname, int flags, int mode), + openat(dfd, filename, O_NOFOLLOW | flags, mode), + open(pathname, O_NOFOLLOW | flags, mode) +); /* Open a file @@ -182,81 +182,3 @@ void my_print_open_files(void) } #endif - -/** - like open(), but with symlinks are not accepted anywhere in the path - - This is used for opening symlinked tables for DATA/INDEX DIRECTORY. - The paths there have been realpath()-ed. So, we can assume here that - - * `pathname` is an absolute path - * no '.', '..', and '//' in the path - * file exists -*/ -static int open_nosymlinks(const char *pathname, int flags, int mode) -{ -#ifndef O_PATH -#ifdef HAVE_REALPATH - char buf[PATH_MAX+1]; - if (realpath(pathname, buf) == NULL) - return -1; - if (strcmp(pathname, buf)) - { - errno= ENOTDIR; - return -1; - } -#endif - return open(pathname, flags, mode | O_NOFOLLOW); -#else - - char buf[PATH_MAX+1]; - char *s= buf, *e= buf+1, *end= strnmov(buf, pathname, sizeof(buf)); - int fd, dfd= -1; - - if (*end) - { - errno= ENAMETOOLONG; - return -1; - } - - if (*s != '/') /* not an absolute path */ - { - errno= ENOENT; - return -1; - } - - for (;;) - { - if (*e == '/') /* '//' in the path */ - { - errno= ENOENT; - goto err; - } - while (*e && *e != '/') - e++; - *e= 0; - if (!memcmp(s, ".", 2) || !memcmp(s, "..", 3)) - { - errno= ENOENT; - goto err; - } - - fd = openat(dfd, s, O_NOFOLLOW | (e < end ? O_PATH : flags), mode); - if (fd < 0) - goto err; - - if (dfd >= 0) - close(dfd); - - dfd= fd; - s= ++e; - - if (e >= end) - return fd; - } -err: - if (dfd >= 0) - close(dfd); - return -1; -#endif -} diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index bc01a68263d..ed35fff41e9 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -177,3 +177,78 @@ int my_realpath(char *to, const char *filename, myf MyFlags) #endif return 0; } + +#ifdef HAVE_OPEN_PARENT_DIR_NOSYMLINKS +/** opens the parent dir. walks the path, and does not resolve symlinks + + returns the pointer to the file name (basename) within the pathname + or NULL in case of an error + + stores the parent dir (dirname) file descriptor in pdfd. + It can be -1 even if there was no error! + + This is used for symlinked tables for DATA/INDEX DIRECTORY. + The paths there have been realpath()-ed. So, we can assume here that + + * `pathname` is an absolute path + * no '.', '..', and '//' in the path + * file exists +*/ + +const char *my_open_parent_dir_nosymlinks(const char *pathname, int *pdfd) +{ + char buf[PATH_MAX+1]; + char *s= buf, *e= buf+1, *end= strnmov(buf, pathname, sizeof(buf)); + int fd, dfd= -1; + + if (*end) + { + errno= ENAMETOOLONG; + return NULL; + } + + if (*s != '/') /* not an absolute path */ + { + errno= ENOENT; + return NULL; + } + + for (;;) + { + if (*e == '/') /* '//' in the path */ + { + errno= ENOENT; + goto err; + } + while (*e && *e != '/') + e++; + *e= 0; + + if (!memcmp(s, ".", 2) || !memcmp(s, "..", 3)) + { + errno= ENOENT; + goto err; + } + + if (++e >= end) + { + *pdfd= dfd; + return pathname + (s - buf); + } + + fd = openat(dfd, s, O_NOFOLLOW | O_PATH); + if (fd < 0) + goto err; + + if (dfd >= 0) + close(dfd); + + dfd= fd; + s= e; + } +err: + if (dfd >= 0) + close(dfd); + return NULL; +} +#endif diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h index f5d2f301837..4b489504c26 100644 --- a/mysys/mysys_priv.h +++ b/mysys/mysys_priv.h @@ -89,6 +89,34 @@ void sf_free(void *ptr); void my_error_unregister_all(void); +#if !defined(O_PATH) && defined(O_EXEC) /* FreeBSD */ +#define O_PATH O_EXEC +#endif + +#ifdef O_PATH +#define HAVE_OPEN_PARENT_DIR_NOSYMLINKS +const char *my_open_parent_dir_nosymlinks(const char *pathname, int *pdfd); +#define NOSYMLINK_FUNCTION_BODY(AT,NOAT) \ + int dfd, res; \ + const char *filename= my_open_parent_dir_nosymlinks(pathname, &dfd); \ + if (filename == NULL) return -1; \ + res= AT; \ + if (dfd >= 0) close(dfd); \ + return res; +#elif defined(HAVE_REALPATH) +#define NOSYMLINK_FUNCTION_BODY(AT,NOAT) \ + char buf[PATH_MAX+1]; \ + if (realpath(pathname, buf) == NULL) return -1; \ + if (strcmp(pathname, buf)) { errno= ENOTDIR; return -1; } \ + return NOAT; +#else +#define NOSYMLINK_FUNCTION_BODY(AT,NOAT) \ + return NOAT; +#endif + +#define CREATE_NOSYMLINK_FUNCTION(PROTO,AT,NOAT) \ +static int PROTO { NOSYMLINK_FUNCTION_BODY(AT,NOAT) } + #ifdef _WIN32 #include /* my_winfile.c exports, should not be used outside mysys */ -- cgit v1.2.1 From 93cb0246b8c883c4f5010468892986fa1d5ba379 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 20 Feb 2017 11:07:38 +0100 Subject: race-condition safe implementation of mi_delete_table/maria_delete_table --- mysys/my_symlink2.c | 28 ++++++++++++++++++++++++++++ mysys/my_sync.c | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'mysys') diff --git a/mysys/my_symlink2.c b/mysys/my_symlink2.c index fcaf78ccff6..66b823aeafe 100644 --- a/mysys/my_symlink2.c +++ b/mysys/my_symlink2.c @@ -182,3 +182,31 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags) DBUG_RETURN(result); #endif /* HAVE_READLINK */ } + +/** delete a - possibly symlinked - table file + + This is used to delete a file that is part of a table (e.g. MYI or MYD + file of MyISAM) when dropping a table. A file might be a symlink - + if the table was created with DATA DIRECTORY or INDEX DIRECTORY - + in this case both the symlink and the symlinked file are deleted, + but only if the symlinked file is not in the datadir. +*/ +int my_handler_delete_with_symlink(PSI_file_key key, const char *name, + const char *ext, myf sync_dir) +{ + char orig[FN_REFLEN], real[FN_REFLEN]; + int res= 0; + DBUG_ENTER("my_handler_delete_with_symlink"); + + fn_format(orig, name, "", ext, MY_UNPACK_FILENAME | MY_APPEND_EXT); + if (my_is_symlink(orig)) + { + /* + Delete the symlinked file only if the symlink is not + pointing into datadir. + */ + if (!(my_realpath(real, orig, MYF(0)) || mysys_test_invalid_symlink(real))) + res= mysql_file_delete(key, real, MYF(MY_NOSYMLINKS | MY_WME | sync_dir)); + } + DBUG_RETURN(mysql_file_delete(key, orig, MYF(MY_WME | sync_dir)) || res); +} diff --git a/mysys/my_sync.c b/mysys/my_sync.c index 88bcb685271..77e7befebed 100644 --- a/mysys/my_sync.c +++ b/mysys/my_sync.c @@ -199,7 +199,7 @@ int my_sync_dir_by_file(const char *file_name __attribute__((unused)), char dir_name[FN_REFLEN]; size_t dir_name_length; dirname_part(dir_name, file_name, &dir_name_length); - return my_sync_dir(dir_name, my_flags); + return my_sync_dir(dir_name, my_flags & ~MY_NOSYMLINKS); #else return 0; #endif -- cgit v1.2.1 From d72dbb41229ceb6434ecd3e23d559bb7b39dd15f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 20 Feb 2017 22:40:47 +0100 Subject: bugfix: remove my_delete_with_symlink() it was race condition prone. instead use either a pair of my_delete() calls with already resolved paths, or a safe high-level function my_handler_delete_with_symlink(), like MyISAM and Aria already do. --- mysys/my_symlink2.c | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'mysys') diff --git a/mysys/my_symlink2.c b/mysys/my_symlink2.c index 66b823aeafe..5fe7b8fcae9 100644 --- a/mysys/my_symlink2.c +++ b/mysys/my_symlink2.c @@ -91,27 +91,6 @@ File my_create_with_symlink(const char *linkname, const char *filename, DBUG_RETURN(file); } -/* - If the file was a symlink, delete both symlink and the file which the - symlink pointed to. -*/ - -int my_delete_with_symlink(const char *name, myf MyFlags) -{ - char link_name[FN_REFLEN]; - int was_symlink= (!my_disable_symlinks && - !my_readlink(link_name, name, MYF(0))); - int result; - DBUG_ENTER("my_delete_with_symlink"); - - if (!(result=my_delete(name, MyFlags))) - { - if (was_symlink) - result=my_delete(link_name, MyFlags); - } - DBUG_RETURN(result); -} - /* If the file is a normal file, just rename it. If the file is a symlink: -- cgit v1.2.1 From 606a4a48475c95480751755e811e0b6c76ce1c3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Fri, 3 Mar 2017 20:12:48 +0200 Subject: Post MDEV-11902 Fix test failures in maria and myisam storage engines my_readline can fail due to missing file. Make my_readline report this condition separately so that we can catch it and report an appropriate error message to the user. --- mysys/my_symlink.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'mysys') diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index ed35fff41e9..72648d4c9a8 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -129,6 +129,11 @@ int my_is_symlink(const char *filename __attribute__((unused))) to is guaranteed to never set to a string longer than FN_REFLEN (including the end \0) + + On error returns -1, unless error is file not found, in which case it + is 1. + + Sets my_errno to specific error number. */ int my_realpath(char *to, const char *filename, myf MyFlags) @@ -154,7 +159,10 @@ int my_realpath(char *to, const char *filename, myf MyFlags) if (MyFlags & MY_WME) my_error(EE_REALPATH, MYF(0), filename, my_errno); my_load_path(to, filename, NullS); - result= -1; + if (my_errno == ENOENT) + result= 1; + else + result= -1; } DBUG_RETURN(result); #elif defined(_WIN32) -- cgit v1.2.1 From f65c9f825d164cf79dd6d5897ef144abba40ff6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 7 Mar 2017 15:52:17 +0200 Subject: mysql_client_test_nonblock fails when compiled with clang mysql_client uses some inline assembly code to switch thread stacks. This works, however tools that perform backtrace get confused to fix this we write a specific constant to signify bottom of stack. This constant is needed when compiling with CLang as well. --- mysys/my_context.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'mysys') diff --git a/mysys/my_context.c b/mysys/my_context.c index 5ddb2ccd566..6960b0c6c5a 100644 --- a/mysys/my_context.c +++ b/mysys/my_context.c @@ -206,7 +206,8 @@ my_context_spawn(struct my_context *c, void (*f)(void *), void *d) ( "movq %%rsp, (%[save])\n\t" "movq %[stack], %%rsp\n\t" -#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) && !defined(__INTEL_COMPILER) +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __clang__) && \ + !defined(__INTEL_COMPILER) /* This emits a DWARF DW_CFA_undefined directive to make the return address undefined. This indicates that this is the top of the stack frame, and -- cgit v1.2.1