/* Copyright (C) 2000 MySQL AB

   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
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "mysys_priv.h"
#include <m_string.h>
#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
#include <sys/stat.h>      /* 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 ';'
#else
#define DELIM ':'
#endif

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;
  tmpnam_trycount=0;
  tmpnam_lasttry=FALSE;
  while (!t_arr.elements)
  {
    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
      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)&copy))
            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)&copy))
          return TRUE;
#endif
        pathlist=end+1;
      }
      while (*end);
    }
    tmpnam_trycount++;
  }

  freeze_size(&t_arr);
  tmpdir->list=(char **)t_arr.buffer;
  tmpdir->max=t_arr.elements-1;
  tmpdir->cur=0;
  return FALSE;
}

char *my_tmpdir(MY_TMPDIR *tmpdir)
{
  char *dir;
  pthread_mutex_lock(&tmpdir->mutex);
  dir=tmpdir->list[tmpdir->cur];
  tmpdir->cur= (tmpdir->cur == tmpdir->max) ? 0 : tmpdir->cur+1;
  pthread_mutex_unlock(&tmpdir->mutex);
  return dir;
}

void free_tmpdir(MY_TMPDIR *tmpdir)
{
  uint i;
  for (i=0; i<=tmpdir->max; i++)
    my_free(tmpdir->list[i], MYF(0));
  my_free((gptr)tmpdir->list, MYF(0));
  pthread_mutex_destroy(&tmpdir->mutex);
}

