bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

new module for temporary files in temporary directories


From: Bruno Haible
Subject: new module for temporary files in temporary directories
Date: Wed, 28 Jun 2006 20:30:13 +0200
User-agent: KMail/1.9.1

Hi,

Programs which create several temporary files or want to prescribe
a given basename to the files can do so easily by using a temporary
directory, and the temporary files inside this temporary directory.

When implementing this approach, however, the bookkeeping needed for
proper cleanup of the files and directories becomes cumbersome.

I'd like to propose a module which supports temporary directories,
and cleans them up either upon request or at a fatal signal.

Btw, this would also be good behaviour for the 'sort' program: Often,
when I shutdown my machine while an 'updatedb' process is in progress,
several big sortXXXXXXX files are left over in $TMPDIR.

Bruno


============================= clean-temp.h =============================
/* Temporary directories and temporary files with automatic cleanup.
   Copyright (C) 2006 Free Software Foundation, Inc.
   Written by Bruno Haible <address@hidden>, 2006.

   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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#ifndef _CLEAN_TEMP_H
#define _CLEAN_TEMP_H

#ifdef __cplusplus
extern "C" {
#endif


/* Temporary directories and temporary files should be automatically removed
   when the program exits either normally or through a fatal signal.  We can't
   rely on the "unlink before close" idiom, because it works only on Unix and
   also - if no signal blocking is used - leaves a time window where a fatal
   signal would not clean up the temporary file.

   This module provides support for temporary directories and temporary files
   inside these temporary directories.  Temporary files without temporary
   directories are not supported here.  */

struct temp_dir
{
  /* The absolute pathname of the directory.  */
  const char * const dir_name;
  /* More fields are present here, but not public.  */
};

/* Create a temporary directory.
   PREFIX is used as a prefix for the name of the temporary directory. It
   should be short and still give an indication about the program.
   Return a fresh 'struct temp_dir' on success.  Upon error, an error message
   is shown and NULL is returned.  */
extern struct temp_dir * create_temp_dir (const char *prefix);

/* Register the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
   needs to be removed before DIR can be removed.
   Should be called before the file ABSOLUTE_FILE_NAME is created.  */
extern void enqueue_temp_file (struct temp_dir *dir,
                               const char *absolute_file_name);

/* Unregister the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
   needs to be removed before DIR can be removed.
   Should be called when the file ABSOLUTE_FILE_NAME could not be created.  */
extern void dequeue_temp_file (struct temp_dir *dir,
                               const char *absolute_file_name);

/* Register the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
   that needs to be removed before DIR can be removed.
   Should be called before the subdirectory ABSOLUTE_DIR_NAME is created.  */
extern void enqueue_temp_subdir (struct temp_dir *dir,
                                 const char *absolute_dir_name);

/* Unregister the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
   that needs to be removed before DIR can be removed.
   Should be called when the subdirectory ABSOLUTE_DIR_NAME could not be
   created.  */
extern void dequeue_temp_subdir (struct temp_dir *dir,
                                 const char *absolute_dir_name);

/* Remove the given ABSOLUTE_FILE_NAME and unregister it.  */
extern void cleanup_temp_file (struct temp_dir *dir,
                               const char *absolute_file_name);

/* Remove the given ABSOLUTE_DIR_NAME and unregister it.  */
extern void cleanup_temp_subdir (struct temp_dir *dir,
                                 const char *absolute_dir_name);

/* Remove all registered files and subdirectories inside DIR.  */
extern void cleanup_temp_dir_contents (struct temp_dir *dir);

/* Remove all registered files and subdirectories inside DIR and DIR itself.
   DIR cannot be used any more after this call.  */
extern void cleanup_temp_dir (struct temp_dir *dir);


#ifdef __cplusplus
}
#endif

#endif /* _CLEAN_TEMP_H */
============================= clean-temp.c =============================
/* Temporary directories and temporary files with automatic cleanup.
   Copyright (C) 2001, 2003, 2006 Free Software Foundation, Inc.
   Written by Bruno Haible <address@hidden>, 2006.

   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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

/* Specification.  */
#include "clean-temp.h"

#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "error.h"
#include "fatal-signal.h"
#include "pathmax.h"
#include "tmpdir.h"
#include "mkdtemp.h"
#include "xalloc.h"
#include "xallocsa.h"
#include "gettext.h"

#define _(str) gettext (str)


/* The use of 'volatile' in the types below (and ISO C 99 section 5.1.2.3.(5))
   ensure that while constructing or modifying the data structures, the field
   values are written to memory in the order of the C statements.  So the
   signal handler can rely on these field values to be up to date.  */

/* Registry for a single temporary directory.
   'struct temp_dir' from the public header file overlaps with this.  */
struct tempdir
{
  /* The absolute pathname of the directory.  */
  char * volatile dirname;
  /* Absolute pathnames of subdirectories.  */
  char * volatile * volatile subdir;
  size_t volatile subdir_count;
  size_t subdir_allocated;
  /* Absolute pathnames of files.  */
  char * volatile * volatile file;
  size_t volatile file_count;
  size_t file_allocated;
};

/* List of all temporary directories.  */
static struct
{
  struct tempdir * volatile * volatile tempdir_list;
  size_t volatile tempdir_count;
  size_t tempdir_allocated;
} cleanup_list /* = { NULL, 0, 0 } */;

/* The signal handler.  It gets called asynchronously.  */
static void
cleanup ()
{
  size_t i;

  for (i = 0; i < cleanup_list.tempdir_count; i++)
    {
      struct tempdir *dir = cleanup_list.tempdir_list[i];

      if (dir != NULL)
        {
          size_t j;

          /* First cleanup the files in the subdirectories.  */
          for (j = dir->file_count; ; )
            if (j > 0)
              {
                const char *file = dir->file[--j];
                if (file != NULL)
                  unlink (file);
              }
            else
              break;

          /* Then cleanup the subdirectories.  */
          for (j = dir->subdir_count; ; )
            if (j > 0)
              {
                const char *subdir = dir->subdir[--j];
                if (subdir != NULL)
                  rmdir (subdir);
              }
            else
              break;

          /* Then cleanup the temporary directory itself.  */
          rmdir (dir->dirname);
        }
    }
}

/* Create a temporary directory.
   PREFIX is used as a prefix for the name of the temporary directory. It
   should be short and still give an indication about the program.
   Return a fresh 'struct temp_dir' on success.  Upon error, an error message
   is shown and NULL is returned.  */
struct temp_dir *
create_temp_dir (const char *prefix)
{
  struct tempdir * volatile *tmpdirp = NULL;
  struct tempdir *tmpdir;
  size_t i;
  char *template;
  char *tmpdirname;

  /* See whether it can take the slot of an earlier temporary directory
     already cleaned up.  */
  for (i = 0; i < cleanup_list.tempdir_count; i++)
    if (cleanup_list.tempdir_list[i] == NULL)
      {
        tmpdirp = &cleanup_list.tempdir_list[i];
        break;
      }
  if (tmpdirp == NULL)
    {
      /* See whether the array needs to be extended.  */
      if (cleanup_list.tempdir_count == cleanup_list.tempdir_allocated)
        {
          /* Note that we cannot use xrealloc(), because then the cleanup()
             function could access an already deallocated array.  */
          struct tempdir * volatile *old_array = cleanup_list.tempdir_list;
          size_t old_allocated = cleanup_list.tempdir_allocated;
          size_t new_allocated = 2 * cleanup_list.tempdir_allocated + 1;
          struct tempdir * volatile *new_array =
            (struct tempdir * volatile *)
            xmalloc (new_allocated * sizeof (struct tempdir * volatile));

          if (old_allocated == 0)
            /* First use of this facility.  Register the cleanup handler.  */
            at_fatal_signal (&cleanup);
          else
            {
              /* Don't use memcpy() here, because memcpy takes non-volatile
                 arguments and is therefore not guaranteed to complete all
                 memory stores before the next statement.  */
              size_t k;

              for (k = 0; k < old_allocated; k++)
                new_array[k] = old_array[k];
            }

          cleanup_list.tempdir_list = new_array;
          cleanup_list.tempdir_allocated = new_allocated;

          /* Now we can free the old array.  */
          if (old_array != NULL)
            free ((struct tempdir **) old_array);
        }

      tmpdirp = &cleanup_list.tempdir_list[cleanup_list.tempdir_count];
      /* Initialize *tmpdirp before incrementing tempdir_count, so that
         cleanup() will skip this entry before it is fully initialized.  */
      *tmpdirp = NULL;
      cleanup_list.tempdir_count++;
    }

  /* Initialize a 'struct tmpdir'.  */
  tmpdir = (struct tempdir *) xmalloc (sizeof (struct tempdir));
  tmpdir->dirname = NULL;
  tmpdir->subdir = NULL;
  tmpdir->subdir_count = 0;
  tmpdir->subdir_allocated = 0;
  tmpdir->file = NULL;
  tmpdir->file_count = 0;
  tmpdir->file_allocated = 0;

  /* Create the temporary directory.  */
  template = (char *) xallocsa (PATH_MAX);
  if (path_search (template, PATH_MAX, NULL, prefix, true))
    {
      error (0, errno,
             _("cannot find a temporary directory, try setting $TMPDIR"));
      goto quit;
    }
  block_fatal_signals ();
  tmpdirname = mkdtemp (template);
  if (tmpdirname != NULL)
    {
      tmpdir->dirname = tmpdirname;
      *tmpdirp = tmpdir;
    }
  unblock_fatal_signals ();
  if (tmpdirname == NULL)
    {
      error (0, errno,
             _("cannot create a temporary directory using template \"%s\""),
             template);
      goto quit;
    }
  /* Replace tmpdir->dirname with a copy that has indefinite extent.
     We cannot do this inside the block_fatal_signals/unblock_fatal_signals
     block because then the cleanup handler would not remove the directory
     if xstrdup fails.  */
  tmpdir->dirname = xstrdup (tmpdirname);
  freesa (template);
  return (struct temp_dir *) tmpdir;

 quit:
  freesa (template);
  return NULL;
}

/* Register the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
   needs to be removed before DIR can be removed.
   Should be called before the file ABSOLUTE_FILE_NAME is created.  */
void
enqueue_temp_file (struct temp_dir *dir,
                   const char *absolute_file_name)
{
  struct tempdir *tmpdir = (struct tempdir *)dir;
  size_t j;

  /* See whether it can take the slot of an earlier file already dequeued.  */
  for (j = 0; j < tmpdir->file_count; j++)
    if (tmpdir->file[j] == NULL)
      {
        tmpdir->file[j] = xstrdup (absolute_file_name);
        return;
      }
  /* See whether the array needs to be extended.  */
  if (tmpdir->file_count == tmpdir->file_allocated)
    {
      /* Note that we cannot use xrealloc(), because then the cleanup()
         function could access an already deallocated array.  */
      char * volatile * old_array = tmpdir->file;
      size_t old_allocated = tmpdir->file_allocated;
      size_t new_allocated = 2 * tmpdir->file_allocated + 1;
      char * volatile * new_array =
        (char * volatile *) xmalloc (new_allocated * sizeof (char * volatile));
      size_t k;

      /* Don't use memcpy() here, because memcpy takes non-volatile arguments
         and is therefore not guaranteed to complete all memory stores before
         the next statement.  */
      for (k = 0; k < old_allocated; k++)
        new_array[k] = old_array[k];

      tmpdir->file = new_array;
      tmpdir->file_allocated = new_allocated;

      /* Now we can free the old array.  */
      if (old_array != NULL)
        free ((char **) old_array);
    }

  /* Initialize the pointer before incrementing file_count, so that cleanup()
     will not see this entry before it is fully initialized.  */
  tmpdir->file[tmpdir->file_count] = xstrdup (absolute_file_name);
  tmpdir->file_count++;
}

/* Unregister the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
   needs to be removed before DIR can be removed.
   Should be called when the file ABSOLUTE_FILE_NAME could not be created.  */
void
dequeue_temp_file (struct temp_dir *dir,
                   const char *absolute_file_name)
{
  struct tempdir *tmpdir = (struct tempdir *)dir;
  size_t j;

  for (j = 0; j < tmpdir->file_count; j++)
    if (tmpdir->file[j] != NULL
        && strcmp (tmpdir->file[j], absolute_file_name) == 0)
      {
        /* Clear tmpdir->file[j].  */
        char *old_string = tmpdir->file[j];
        if (j + 1 == tmpdir->file_count)
          {
            while (j > 0 && tmpdir->file[j - 1] == NULL)
              j--;
            tmpdir->file_count = j;
          }
        else
          tmpdir->file[j] = NULL;
        /* Now only we can free the old tmpdir->file[j].  */
        free (old_string);
      }
}

/* Register the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
   that needs to be removed before DIR can be removed.
   Should be called before the subdirectory ABSOLUTE_DIR_NAME is created.  */
void
enqueue_temp_subdir (struct temp_dir *dir,
                     const char *absolute_dir_name)
{
  struct tempdir *tmpdir = (struct tempdir *)dir;

  /* Reusing the slot of an earlier subdirectory already dequeued is not
     possible here, because the order of the subdirectories matter.  */
  /* See whether the array needs to be extended.  */
  if (tmpdir->subdir_count == tmpdir->subdir_allocated)
    {
      /* Note that we cannot use xrealloc(), because then the cleanup()
         function could access an already deallocated array.  */
      char * volatile * old_array = tmpdir->subdir;
      size_t old_allocated = tmpdir->subdir_allocated;
      size_t new_allocated = 2 * tmpdir->subdir_allocated + 1;
      char * volatile * new_array =
        (char * volatile *) xmalloc (new_allocated * sizeof (char * volatile));
      size_t k;

      /* Don't use memcpy() here, because memcpy takes non-volatile arguments
         and is therefore not guaranteed to complete all memory stores before
         the next statement.  */
      for (k = 0; k < old_allocated; k++)
        new_array[k] = old_array[k];

      tmpdir->subdir = new_array;
      tmpdir->subdir_allocated = new_allocated;

      /* Now we can free the old array.  */
      if (old_array != NULL)
        free ((char **) old_array);
    }

  /* Initialize the pointer before incrementing subdir_count, so that cleanup()
     will not see this entry before it is fully initialized.  */
  tmpdir->subdir[tmpdir->subdir_count] = xstrdup (absolute_dir_name);
  tmpdir->subdir_count++;
}

/* Unregister the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
   that needs to be removed before DIR can be removed.
   Should be called when the subdirectory ABSOLUTE_DIR_NAME could not be
   created.  */
void
dequeue_temp_subdir (struct temp_dir *dir,
                     const char *absolute_dir_name)
{
  struct tempdir *tmpdir = (struct tempdir *)dir;
  size_t j;

  for (j = 0; j < tmpdir->subdir_count; j++)
    if (tmpdir->subdir[j] != NULL
        && strcmp (tmpdir->subdir[j], absolute_dir_name) == 0)
      {
        /* Clear tmpdir->subdir[j].  */
        char *old_string = tmpdir->subdir[j];
        bool anything_beyond_index_j = false;
        size_t k;

        for (k = j + 1; k < tmpdir->subdir_count; k++)
          if (tmpdir->subdir[k] != NULL)
            {
              anything_beyond_index_j = true;
              break;
            }
        if (anything_beyond_index_j)
          tmpdir->subdir[j] = NULL;
        else
          tmpdir->subdir_count = j;
        /* Now only we can free the old tmpdir->subdir[j].  */
        free (old_string);
      }
}

/* Remove the given ABSOLUTE_FILE_NAME and unregister it.  */
void
cleanup_temp_file (struct temp_dir *dir,
                   const char *absolute_file_name)
{
  unlink (absolute_file_name);
  dequeue_temp_file (dir, absolute_file_name);
}

/* Remove the given ABSOLUTE_DIR_NAME and unregister it.  */
void
cleanup_temp_subdir (struct temp_dir *dir,
                     const char *absolute_dir_name)
{
  rmdir (absolute_dir_name);
  dequeue_temp_subdir (dir, absolute_dir_name);
}

/* Remove all registered files and subdirectories inside DIR.  */
void
cleanup_temp_dir_contents (struct temp_dir *dir)
{
  struct tempdir *tmpdir = (struct tempdir *)dir;
  size_t j;

  /* First cleanup the files in the subdirectories.  */
  for (j = tmpdir->file_count; ; )
    if (j > 0)
      {
        char *file = tmpdir->file[--j];
        if (file != NULL)
          unlink (file);
        tmpdir->file_count = j;
        /* Now only we can free file.  */
        if (file != NULL)
          free (file);
      }
    else
      break;

  /* Then cleanup the subdirectories.  */
  for (j = tmpdir->subdir_count; ; )
    if (j > 0)
      {
        char *subdir = tmpdir->subdir[--j];
        if (subdir != NULL)
          rmdir (subdir);
        tmpdir->subdir_count = j;
        /* Now only we can free subdir.  */
        if (subdir != NULL)
          free (subdir);
      }
    else
      break;
}

/* Remove all registered files and subdirectories inside DIR and DIR itself.
   DIR cannot be used any more after this call.  */
void
cleanup_temp_dir (struct temp_dir *dir)
{
  struct tempdir *tmpdir = (struct tempdir *)dir;
  size_t i;

  cleanup_temp_dir_contents (dir);
  rmdir (tmpdir->dirname);

  for (i = 0; i < cleanup_list.tempdir_count; i++)
    if (cleanup_list.tempdir_list[i] == tmpdir)
      {
        /* Remove cleanup_list.tempdir_list[i].  */
        if (i + 1 == cleanup_list.tempdir_count)
          {
            while (i > 0 && cleanup_list.tempdir_list[i - 1] == NULL)
              i--;
            cleanup_list.tempdir_count = i;
          }
        else
          cleanup_list.tempdir_list[i] = NULL;
        /* Now only we can free the tmpdir->dirname and tmpdir itself.  */
        free (tmpdir->dirname);
        free (tmpdir);
        return;
      }

  /* The user passed an invalid DIR argument.  */
  abort ();
}
=============================== tmpdir.h ===============================
/* Determine a temporary directory.
   Copyright (C) 2001-2002 Free Software Foundation, Inc.

   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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#include <stdbool.h>
#include <stddef.h>

/* Path search algorithm, for tmpnam, tmpfile, etc.  If DIR is
   non-null and exists, uses it; otherwise uses the first of $TMPDIR,
   P_tmpdir, /tmp that exists.  Copies into TMPL a template suitable
   for use with mk[s]temp.  Will fail (-1) if DIR is non-null and
   doesn't exist, none of the searched dirs exists, or there's not
   enough space in TMPL. */
extern int path_search (char *tmpl, size_t tmpl_len, const char *dir, const 
char *pfx, bool try_tmpdir);
=============================== tmpdir.c ===============================
/* Copyright (C) 1999, 2001-2002 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The GNU C Library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the GNU C Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 51 Franklin Street,
   Fifth Floor, Boston, MA 02110-1301, USA.  */

/* Extracted from sysdeps/posix/tempname.c.  */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

/* Specification.  */
#include "tmpdir.h"

#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

#include <errno.h>
#ifndef __set_errno
# define __set_errno(Val) errno = (Val)
#endif

#include <stdio.h>
#ifndef P_tmpdir
# define P_tmpdir "/tmp"
#endif

#include <sys/stat.h>
#if STAT_MACROS_BROKEN
# undef S_ISDIR
#endif
#if !defined S_ISDIR && defined S_IFDIR
# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
#if !S_IRUSR && S_IREAD
# define S_IRUSR S_IREAD
#endif
#if !S_IRUSR
# define S_IRUSR 00400
#endif
#if !S_IWUSR && S_IWRITE
# define S_IWUSR S_IWRITE
#endif
#if !S_IWUSR
# define S_IWUSR 00200
#endif
#if !S_IXUSR && S_IEXEC
# define S_IXUSR S_IEXEC
#endif
#if !S_IXUSR
# define S_IXUSR 00100
#endif

#if _LIBC
# define struct_stat64 struct stat64
#else
# define struct_stat64 struct stat
# define __xstat64(version, path, buf) stat (path, buf)
#endif

#if ! (HAVE___SECURE_GETENV || _LIBC)
# define __secure_getenv getenv
#endif


/* Return nonzero if DIR is an existent directory.  */
static bool
direxists (const char *dir)
{
  struct_stat64 buf;
  return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode);
}

/* Path search algorithm, for tmpnam, tmpfile, etc.  If DIR is
   non-null and exists, uses it; otherwise uses the first of $TMPDIR,
   P_tmpdir, /tmp that exists.  Copies into TMPL a template suitable
   for use with mk[s]temp.  Will fail (-1) if DIR is non-null and
   doesn't exist, none of the searched dirs exists, or there's not
   enough space in TMPL. */
int
path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
             bool try_tmpdir)
{
  const char *d;
  size_t dlen, plen;

  if (!pfx || !pfx[0])
    {
      pfx = "file";
      plen = 4;
    }
  else
    {
      plen = strlen (pfx);
      if (plen > 5)
        plen = 5;
    }

  if (try_tmpdir)
    {
      d = __secure_getenv ("TMPDIR");
      if (d != NULL && direxists (d))
        dir = d;
      else if (dir != NULL && direxists (dir))
        /* nothing */ ;
      else
        dir = NULL;
    }
  if (dir == NULL)
    {
      if (direxists (P_tmpdir))
        dir = P_tmpdir;
      else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
        dir = "/tmp";
      else
        {
          __set_errno (ENOENT);
          return -1;
        }
    }

  dlen = strlen (dir);
  while (dlen > 1 && dir[dlen - 1] == '/')
    dlen--;                     /* remove trailing slashes */

  /* check we have room for "${dir}/${pfx}XXXXXX\0" */
  if (tmpl_len < dlen + 1 + plen + 6 + 1)
    {
      __set_errno (EINVAL);
      return -1;
    }

  sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx);
  return 0;
}
========================================================================




reply via email to

[Prev in Thread] Current Thread [Next in Thread]