1169695Skan/* Copyright (C) 1991, 1992, 1996, 1998, 2004 Free Software Foundation, Inc.
2169695Skan   This file is derived from mkstemp.c from the GNU C Library.
3169695Skan
4169695Skan   The GNU C Library is free software; you can redistribute it and/or
5169695Skan   modify it under the terms of the GNU Library General Public License as
6169695Skan   published by the Free Software Foundation; either version 2 of the
7169695Skan   License, or (at your option) any later version.
8169695Skan
9169695Skan   The GNU C Library is distributed in the hope that it will be useful,
10169695Skan   but WITHOUT ANY WARRANTY; without even the implied warranty of
11169695Skan   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12169695Skan   Library General Public License for more details.
13169695Skan
14169695Skan   You should have received a copy of the GNU Library General Public
15169695Skan   License along with the GNU C Library; see the file COPYING.LIB.  If not,
16169695Skan   write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
17169695Skan   Boston, MA 02110-1301, USA.  */
18169695Skan
19169695Skan#ifdef HAVE_CONFIG_H
20169695Skan#include "config.h"
21169695Skan#endif
22169695Skan
23169695Skan#include <sys/types.h>
24169695Skan#ifdef HAVE_STDLIB_H
25169695Skan#include <stdlib.h>
26169695Skan#endif
27169695Skan#ifdef HAVE_STRING_H
28169695Skan#include <string.h>
29169695Skan#endif
30169695Skan#include <errno.h>
31169695Skan#include <stdio.h>
32169695Skan#include <fcntl.h>
33169695Skan#ifdef HAVE_UNISTD_H
34169695Skan#include <unistd.h>
35169695Skan#endif
36169695Skan#ifdef HAVE_SYS_TIME_H
37169695Skan#include <sys/time.h>
38169695Skan#endif
39169695Skan#include "ansidecl.h"
40169695Skan
41169695Skan/* We need to provide a type for gcc_uint64_t.  */
42169695Skan#ifdef __GNUC__
43169695Skan__extension__ typedef unsigned long long gcc_uint64_t;
44169695Skan#else
45169695Skantypedef unsigned long gcc_uint64_t;
46169695Skan#endif
47169695Skan
48169695Skan#ifndef TMP_MAX
49169695Skan#define TMP_MAX 16384
50169695Skan#endif
51169695Skan
52169695Skan#ifndef O_BINARY
53169695Skan# define O_BINARY 0
54169695Skan#endif
55169695Skan
56169695Skan/*
57169695Skan
58169695Skan@deftypefn Replacement int mkstemps (char *@var{pattern}, int @var{suffix_len})
59169695Skan
60169695SkanGenerate a unique temporary file name from @var{pattern}.
61169695Skan@var{pattern} has the form:
62169695Skan
63169695Skan@example
64169695Skan   @var{path}/ccXXXXXX@var{suffix}
65169695Skan@end example
66169695Skan
67169695Skan@var{suffix_len} tells us how long @var{suffix} is (it can be zero
68169695Skanlength).  The last six characters of @var{pattern} before @var{suffix}
69169695Skanmust be @samp{XXXXXX}; they are replaced with a string that makes the
70169695Skanfilename unique.  Returns a file descriptor open on the file for
71169695Skanreading and writing.
72169695Skan
73169695Skan@end deftypefn
74169695Skan
75169695Skan*/
76169695Skan
77169695Skanint
78169695Skanmkstemps (char *pattern, int suffix_len)
79169695Skan{
80169695Skan  static const char letters[]
81169695Skan    = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
82169695Skan  static gcc_uint64_t value;
83169695Skan#ifdef HAVE_GETTIMEOFDAY
84169695Skan  struct timeval tv;
85169695Skan#endif
86169695Skan  char *XXXXXX;
87169695Skan  size_t len;
88169695Skan  int count;
89169695Skan
90169695Skan  len = strlen (pattern);
91169695Skan
92169695Skan  if ((int) len < 6 + suffix_len
93169695Skan      || strncmp (&pattern[len - 6 - suffix_len], "XXXXXX", 6))
94169695Skan    {
95169695Skan      return -1;
96169695Skan    }
97169695Skan
98169695Skan  XXXXXX = &pattern[len - 6 - suffix_len];
99169695Skan
100169695Skan#ifdef HAVE_GETTIMEOFDAY
101169695Skan  /* Get some more or less random data.  */
102169695Skan  gettimeofday (&tv, NULL);
103169695Skan  value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
104169695Skan#else
105169695Skan  value += getpid ();
106169695Skan#endif
107169695Skan
108169695Skan  for (count = 0; count < TMP_MAX; ++count)
109169695Skan    {
110169695Skan      gcc_uint64_t v = value;
111169695Skan      int fd;
112169695Skan
113169695Skan      /* Fill in the random bits.  */
114169695Skan      XXXXXX[0] = letters[v % 62];
115169695Skan      v /= 62;
116169695Skan      XXXXXX[1] = letters[v % 62];
117169695Skan      v /= 62;
118169695Skan      XXXXXX[2] = letters[v % 62];
119169695Skan      v /= 62;
120169695Skan      XXXXXX[3] = letters[v % 62];
121169695Skan      v /= 62;
122169695Skan      XXXXXX[4] = letters[v % 62];
123169695Skan      v /= 62;
124169695Skan      XXXXXX[5] = letters[v % 62];
125169695Skan
126169695Skan      fd = open (pattern, O_BINARY|O_RDWR|O_CREAT|O_EXCL, 0600);
127169695Skan      if (fd >= 0)
128169695Skan	/* The file does not exist.  */
129169695Skan	return fd;
130169695Skan
131169695Skan      /* This is a random value.  It is only necessary that the next
132169695Skan	 TMP_MAX values generated by adding 7777 to VALUE are different
133169695Skan	 with (module 2^32).  */
134169695Skan      value += 7777;
135169695Skan    }
136169695Skan
137169695Skan  /* We return the null string if we can't find a unique file name.  */
138169695Skan  pattern[0] = '\0';
139169695Skan  return -1;
140169695Skan}
141