1218822Sdim/* Copyright (C) 1991, 1992, 1996, 1998, 2004 Free Software Foundation, Inc.
260484Sobrien   This file is derived from mkstemp.c from the GNU C Library.
360484Sobrien
460484Sobrien   The GNU C Library is free software; you can redistribute it and/or
560484Sobrien   modify it under the terms of the GNU Library General Public License as
660484Sobrien   published by the Free Software Foundation; either version 2 of the
760484Sobrien   License, or (at your option) any later version.
860484Sobrien
960484Sobrien   The GNU C Library is distributed in the hope that it will be useful,
1060484Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1160484Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1260484Sobrien   Library General Public License for more details.
1360484Sobrien
1460484Sobrien   You should have received a copy of the GNU Library General Public
1560484Sobrien   License along with the GNU C Library; see the file COPYING.LIB.  If not,
16218822Sdim   write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
17218822Sdim   Boston, MA 02110-1301, USA.  */
1860484Sobrien
1960484Sobrien#ifdef HAVE_CONFIG_H
2060484Sobrien#include "config.h"
2160484Sobrien#endif
2260484Sobrien
2377298Sobrien#include <sys/types.h>
2460484Sobrien#ifdef HAVE_STDLIB_H
2560484Sobrien#include <stdlib.h>
2660484Sobrien#endif
2760484Sobrien#ifdef HAVE_STRING_H
2860484Sobrien#include <string.h>
2960484Sobrien#endif
3060484Sobrien#include <errno.h>
3160484Sobrien#include <stdio.h>
3260484Sobrien#include <fcntl.h>
3360484Sobrien#ifdef HAVE_UNISTD_H
3460484Sobrien#include <unistd.h>
3560484Sobrien#endif
3660484Sobrien#ifdef HAVE_SYS_TIME_H
3760484Sobrien#include <sys/time.h>
3860484Sobrien#endif
3960484Sobrien#include "ansidecl.h"
4060484Sobrien
4160484Sobrien/* We need to provide a type for gcc_uint64_t.  */
4260484Sobrien#ifdef __GNUC__
4377298Sobrien__extension__ typedef unsigned long long gcc_uint64_t;
4460484Sobrien#else
4560484Sobrientypedef unsigned long gcc_uint64_t;
4660484Sobrien#endif
4760484Sobrien
4860484Sobrien#ifndef TMP_MAX
4960484Sobrien#define TMP_MAX 16384
5060484Sobrien#endif
5160484Sobrien
52218822Sdim#ifndef O_BINARY
53218822Sdim# define O_BINARY 0
54218822Sdim#endif
55218822Sdim
5689857Sobrien/*
5760484Sobrien
58218822Sdim@deftypefn Replacement int mkstemps (char *@var{pattern}, int @var{suffix_len})
5960484Sobrien
60218822SdimGenerate a unique temporary file name from @var{pattern}.
61218822Sdim@var{pattern} has the form:
6260484Sobrien
6389857Sobrien@example
6489857Sobrien   @var{path}/ccXXXXXX@var{suffix}
6589857Sobrien@end example
6660484Sobrien
6789857Sobrien@var{suffix_len} tells us how long @var{suffix} is (it can be zero
68218822Sdimlength).  The last six characters of @var{pattern} before @var{suffix}
6989857Sobrienmust be @samp{XXXXXX}; they are replaced with a string that makes the
7089857Sobrienfilename unique.  Returns a file descriptor open on the file for
7189857Sobrienreading and writing.
7260484Sobrien
7389857Sobrien@end deftypefn
7489857Sobrien
7589857Sobrien*/
7689857Sobrien
7760484Sobrienint
78218822Sdimmkstemps (char *pattern, int suffix_len)
7960484Sobrien{
8060484Sobrien  static const char letters[]
8160484Sobrien    = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
8260484Sobrien  static gcc_uint64_t value;
8360484Sobrien#ifdef HAVE_GETTIMEOFDAY
8460484Sobrien  struct timeval tv;
8560484Sobrien#endif
8660484Sobrien  char *XXXXXX;
8760484Sobrien  size_t len;
8860484Sobrien  int count;
8960484Sobrien
90218822Sdim  len = strlen (pattern);
9160484Sobrien
9260484Sobrien  if ((int) len < 6 + suffix_len
93218822Sdim      || strncmp (&pattern[len - 6 - suffix_len], "XXXXXX", 6))
9460484Sobrien    {
9560484Sobrien      return -1;
9660484Sobrien    }
9760484Sobrien
98218822Sdim  XXXXXX = &pattern[len - 6 - suffix_len];
9960484Sobrien
10060484Sobrien#ifdef HAVE_GETTIMEOFDAY
10160484Sobrien  /* Get some more or less random data.  */
10260484Sobrien  gettimeofday (&tv, NULL);
10360484Sobrien  value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
10460484Sobrien#else
10560484Sobrien  value += getpid ();
10660484Sobrien#endif
10760484Sobrien
10860484Sobrien  for (count = 0; count < TMP_MAX; ++count)
10960484Sobrien    {
11060484Sobrien      gcc_uint64_t v = value;
11160484Sobrien      int fd;
11260484Sobrien
11360484Sobrien      /* Fill in the random bits.  */
11460484Sobrien      XXXXXX[0] = letters[v % 62];
11560484Sobrien      v /= 62;
11660484Sobrien      XXXXXX[1] = letters[v % 62];
11760484Sobrien      v /= 62;
11860484Sobrien      XXXXXX[2] = letters[v % 62];
11960484Sobrien      v /= 62;
12060484Sobrien      XXXXXX[3] = letters[v % 62];
12160484Sobrien      v /= 62;
12260484Sobrien      XXXXXX[4] = letters[v % 62];
12360484Sobrien      v /= 62;
12460484Sobrien      XXXXXX[5] = letters[v % 62];
12560484Sobrien
126218822Sdim      fd = open (pattern, O_BINARY|O_RDWR|O_CREAT|O_EXCL, 0600);
12760484Sobrien      if (fd >= 0)
12860484Sobrien	/* The file does not exist.  */
12960484Sobrien	return fd;
13060484Sobrien
13160484Sobrien      /* This is a random value.  It is only necessary that the next
13260484Sobrien	 TMP_MAX values generated by adding 7777 to VALUE are different
13360484Sobrien	 with (module 2^32).  */
13460484Sobrien      value += 7777;
13560484Sobrien    }
13660484Sobrien
13760484Sobrien  /* We return the null string if we can't find a unique file name.  */
138218822Sdim  pattern[0] = '\0';
13960484Sobrien  return -1;
14060484Sobrien}
141