--- mf_tempdir.orig.c Wed Jul 19 17:10:42 2006 +++ mf_tempdir.c Sat Nov 18 03:03:34 2006 @@ -16,6 +16,9 @@ #include "mysys_priv.h" #include +#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) +#include /* needed for tmp dir writability check, which is currently done only under DOSish OS's */ +#endif #if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) #define DELIM ';' @@ -25,36 +28,96 @@ my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist) { + /* Get information into which directories temporary files should be placed: + If pathlist is specified: use this information (stage 0). + Else: Try, in turn, environment variables TMPDIR, TEMPDIR, TMP, TEMP (Windows; others only use TMPDIR). + (Call these attempts stage 1 through stage 4.) + Assume that this is a list of directories separated by ';' (Windows) or ':' (others). + For each such directory, check whether it exists and is writable. If yes, add it to a list + of tmp directories; otherwise, ignore this entry. + As soon as one of the stages yields one or more tmp directries, return without checking subsequent stages. + If none is successful, try '\' as a last resort (stage 5). This will be returned without writability check. + Gisbert W. Selke, 2006-11-18, for free use within MySQL. + */ char *end, *copy; char buff[FN_REFLEN]; DYNAMIC_ARRAY t_arr; +#if defined(__WIN__) || defined(OS2) || defined(__NETWARE__) + struct _stat stat_buffer; /* writability check: currently done only under DOSish OS's, should be used generally. */ +#endif + uint tmpnam_trycount; + my_bool tmpnam_lasttry=FALSE; pthread_mutex_init(&tmpdir->mutex, MY_MUTEX_INIT_FAST); if (my_init_dynamic_array(&t_arr, sizeof(char*), 1, 5)) return TRUE; - if (!pathlist || !pathlist[0]) + tmpnam_trycount=0; + tmpnam_lasttry=FALSE; + while (!t_arr.elements) { - /* Get default temporary directory */ - pathlist=getenv("TMPDIR"); /* Use this if possible */ -#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) - if (!pathlist) - pathlist=getenv("TEMP"); - if (!pathlist) - pathlist=getenv("TMP"); + switch(tmpnam_trycount) + { + case 0 : break; /* Try initial assignment */ + case 1 : pathlist=getenv("TMPDIR"); break; /* Try this next if possible */ +#if defined(__WIN__) || defined(OS2) || defined(__NETWARE__) + case 2 : pathlist=getenv("TEMPDIR"); break; /* Try these only under DOSish OS's */ + case 3 : pathlist=getenv("TMP"); break; + case 4 : pathlist=getenv("TEMP"); break; #endif - if (!pathlist || !pathlist[0]) - pathlist=(char*) P_tmpdir; - } - do - { - end=strcend(pathlist, DELIM); - convert_dirname(buff, pathlist, end); - if (!(copy=my_strdup(buff, MYF(MY_WME)))) - return TRUE; - if (insert_dynamic(&t_arr, (gptr)©)) - return TRUE; - pathlist=end+1; + default : pathlist=(char*) P_tmpdir; tmpnam_lasttry=TRUE; break; /* Last resort */ + } + if ((pathlist && pathlist[0]) || tmpnam_lasttry) + { + do + { + end=strcend(pathlist, DELIM); + convert_dirname(buff, pathlist, end); +#if defined(__WIN__) || defined(OS2) || defined(__NETWARE__) + /* The putative dirname now has a directory delimiter at its end, which is not liked by _stat. + So we remove it temporarily before we check whether directory exists and is writable. + */ + copy = (char *)memchr(buff, '\0', FN_REFLEN) - 1; + if ((copy-buff > 0) && (*copy == FN_LIBCHAR) && ((copy-buff == 0) || (*(copy-1) != FN_DEVCHAR))) + { + *copy = '\0'; + } + else + { + copy = NULL; + } + /* writability check: currently done only under DOSish OS's, should be used generally: + Use only writable directories, if possible, but make sure we're never without at least one. + */ + if (tmpnam_lasttry || + ((_stat(buff, &stat_buffer) >= 0) && + (stat_buffer.st_mode & _S_IFDIR) && + (stat_buffer.st_mode & _S_IWRITE) + ) + ) + { + /* Restore final dir delimiter if we removed it earlier on: */ + if (copy) *copy = FN_LIBCHAR; + if (!(copy=my_strdup(buff, MYF(MY_WME)))) + return TRUE; + if (insert_dynamic(&t_arr, (gptr)©)) + return TRUE; + } +#else + /* For other OS's, we currently don't check accessibility and writability, but only because + I (gws) cannot test it. So, the whole ifdef monkeying should really be removed so that + all OS's get the same treatment. + */ + if (!(copy=my_strdup(buff, MYF(MY_WME)))) + return TRUE; + if (insert_dynamic(&t_arr, (gptr)©)) + return TRUE; +#endif + pathlist=end+1; + } + while (*end); + } + tmpnam_trycount++; } - while (*end); + freeze_size(&t_arr); tmpdir->list=(char **)t_arr.buffer; tmpdir->max=t_arr.elements-1;