1*150b7e42Smiod /* Copyright (C) 1991, 1992, 1996, 1998, 2004 Free Software Foundation, Inc.
200bf4279Sespie This file is derived from mkstemp.c from the GNU C Library.
300bf4279Sespie
400bf4279Sespie The GNU C Library is free software; you can redistribute it and/or
500bf4279Sespie modify it under the terms of the GNU Library General Public License as
600bf4279Sespie published by the Free Software Foundation; either version 2 of the
700bf4279Sespie License, or (at your option) any later version.
800bf4279Sespie
900bf4279Sespie The GNU C Library is distributed in the hope that it will be useful,
1000bf4279Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of
1100bf4279Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1200bf4279Sespie Library General Public License for more details.
1300bf4279Sespie
1400bf4279Sespie You should have received a copy of the GNU Library General Public
1500bf4279Sespie License along with the GNU C Library; see the file COPYING.LIB. If not,
16*150b7e42Smiod write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
17*150b7e42Smiod Boston, MA 02110-1301, USA. */
1800bf4279Sespie
1900bf4279Sespie #ifdef HAVE_CONFIG_H
2000bf4279Sespie #include "config.h"
2100bf4279Sespie #endif
2200bf4279Sespie
23f5dd06f4Sespie #include <sys/types.h>
2400bf4279Sespie #ifdef HAVE_STDLIB_H
2500bf4279Sespie #include <stdlib.h>
2600bf4279Sespie #endif
2700bf4279Sespie #ifdef HAVE_STRING_H
2800bf4279Sespie #include <string.h>
2900bf4279Sespie #endif
3000bf4279Sespie #include <errno.h>
3100bf4279Sespie #include <stdio.h>
3200bf4279Sespie #include <fcntl.h>
3300bf4279Sespie #ifdef HAVE_UNISTD_H
3400bf4279Sespie #include <unistd.h>
3500bf4279Sespie #endif
3600bf4279Sespie #ifdef HAVE_SYS_TIME_H
3700bf4279Sespie #include <sys/time.h>
3800bf4279Sespie #endif
3900bf4279Sespie #include "ansidecl.h"
4000bf4279Sespie
4100bf4279Sespie /* We need to provide a type for gcc_uint64_t. */
4200bf4279Sespie #ifdef __GNUC__
43f5dd06f4Sespie __extension__ typedef unsigned long long gcc_uint64_t;
4400bf4279Sespie #else
4500bf4279Sespie typedef unsigned long gcc_uint64_t;
4600bf4279Sespie #endif
4700bf4279Sespie
4800bf4279Sespie #ifndef TMP_MAX
4900bf4279Sespie #define TMP_MAX 16384
5000bf4279Sespie #endif
5100bf4279Sespie
5237c53322Sespie /*
5300bf4279Sespie
54*150b7e42Smiod @deftypefn Replacement int mkstemps (char *@var{pattern}, int @var{suffix_len})
5500bf4279Sespie
56*150b7e42Smiod Generate a unique temporary file name from @var{pattern}.
57*150b7e42Smiod @var{pattern} has the form:
5800bf4279Sespie
5937c53322Sespie @example
6037c53322Sespie @var{path}/ccXXXXXX@var{suffix}
6137c53322Sespie @end example
6200bf4279Sespie
6337c53322Sespie @var{suffix_len} tells us how long @var{suffix} is (it can be zero
64*150b7e42Smiod length). The last six characters of @var{pattern} before @var{suffix}
6537c53322Sespie must be @samp{XXXXXX}; they are replaced with a string that makes the
6637c53322Sespie filename unique. Returns a file descriptor open on the file for
6737c53322Sespie reading and writing.
6800bf4279Sespie
6937c53322Sespie @end deftypefn
7037c53322Sespie
7137c53322Sespie */
7237c53322Sespie
7300bf4279Sespie int
mkstemps(char * pattern,int suffix_len)74*150b7e42Smiod mkstemps (char *pattern, int suffix_len)
7500bf4279Sespie {
7600bf4279Sespie static const char letters[]
7700bf4279Sespie = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
7800bf4279Sespie static gcc_uint64_t value;
7900bf4279Sespie #ifdef HAVE_GETTIMEOFDAY
8000bf4279Sespie struct timeval tv;
8100bf4279Sespie #endif
8200bf4279Sespie char *XXXXXX;
8300bf4279Sespie size_t len;
8400bf4279Sespie int count;
8500bf4279Sespie
86*150b7e42Smiod len = strlen (pattern);
8700bf4279Sespie
8800bf4279Sespie if ((int) len < 6 + suffix_len
89*150b7e42Smiod || strncmp (&pattern[len - 6 - suffix_len], "XXXXXX", 6))
9000bf4279Sespie {
9100bf4279Sespie return -1;
9200bf4279Sespie }
9300bf4279Sespie
94*150b7e42Smiod XXXXXX = &pattern[len - 6 - suffix_len];
9500bf4279Sespie
9600bf4279Sespie #ifdef HAVE_GETTIMEOFDAY
9700bf4279Sespie /* Get some more or less random data. */
9800bf4279Sespie gettimeofday (&tv, NULL);
9900bf4279Sespie value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
10000bf4279Sespie #else
10100bf4279Sespie value += getpid ();
10200bf4279Sespie #endif
10300bf4279Sespie
10400bf4279Sespie for (count = 0; count < TMP_MAX; ++count)
10500bf4279Sespie {
10600bf4279Sespie gcc_uint64_t v = value;
10700bf4279Sespie int fd;
10800bf4279Sespie
10900bf4279Sespie /* Fill in the random bits. */
11000bf4279Sespie XXXXXX[0] = letters[v % 62];
11100bf4279Sespie v /= 62;
11200bf4279Sespie XXXXXX[1] = letters[v % 62];
11300bf4279Sespie v /= 62;
11400bf4279Sespie XXXXXX[2] = letters[v % 62];
11500bf4279Sespie v /= 62;
11600bf4279Sespie XXXXXX[3] = letters[v % 62];
11700bf4279Sespie v /= 62;
11800bf4279Sespie XXXXXX[4] = letters[v % 62];
11900bf4279Sespie v /= 62;
12000bf4279Sespie XXXXXX[5] = letters[v % 62];
12100bf4279Sespie
122*150b7e42Smiod fd = open (pattern, O_RDWR|O_CREAT|O_EXCL, 0600);
12300bf4279Sespie if (fd >= 0)
12400bf4279Sespie /* The file does not exist. */
12500bf4279Sespie return fd;
12600bf4279Sespie
12700bf4279Sespie /* This is a random value. It is only necessary that the next
12800bf4279Sespie TMP_MAX values generated by adding 7777 to VALUE are different
12900bf4279Sespie with (module 2^32). */
13000bf4279Sespie value += 7777;
13100bf4279Sespie }
13200bf4279Sespie
13300bf4279Sespie /* We return the null string if we can't find a unique file name. */
134*150b7e42Smiod pattern[0] = '\0';
13500bf4279Sespie return -1;
13600bf4279Sespie }
137