1226586Sdim/* Copyright (C) 1991, 1992, 1996, 1998, 2004 Free Software Foundation, Inc. 2226586Sdim This file is derived from mkstemp.c from the GNU C Library. 3226586Sdim 4226586Sdim The GNU C Library is free software; you can redistribute it and/or 5226586Sdim modify it under the terms of the GNU Library General Public License as 6226586Sdim published by the Free Software Foundation; either version 2 of the 7226586Sdim License, or (at your option) any later version. 8226586Sdim 9226586Sdim The GNU C Library is distributed in the hope that it will be useful, 10226586Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 11226586Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12226586Sdim Library General Public License for more details. 13226586Sdim 14249423Sdim You should have received a copy of the GNU Library General Public 15226586Sdim License along with the GNU C Library; see the file COPYING.LIB. If not, 16239462Sdim write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 17226586Sdim Boston, MA 02110-1301, USA. */ 18226586Sdim 19234353Sdim#ifdef HAVE_CONFIG_H 20226586Sdim#include "config.h" 21226586Sdim#endif 22226586Sdim 23226586Sdim#include <sys/types.h> 24226586Sdim#ifdef HAVE_STDLIB_H 25234353Sdim#include <stdlib.h> 26234353Sdim#endif 27234353Sdim#ifdef HAVE_STRING_H 28234353Sdim#include <string.h> 29234353Sdim#endif 30234353Sdim#include <errno.h> 31234353Sdim#include <stdio.h> 32234353Sdim#include <fcntl.h> 33234353Sdim#ifdef HAVE_UNISTD_H 34234353Sdim#include <unistd.h> 35234353Sdim#endif 36234353Sdim#ifdef HAVE_SYS_TIME_H 37234353Sdim#include <sys/time.h> 38234353Sdim#endif 39234353Sdim#include "ansidecl.h" 40234353Sdim 41234353Sdim/* We need to provide a type for gcc_uint64_t. */ 42234353Sdim#ifdef __GNUC__ 43234353Sdim__extension__ typedef unsigned long long gcc_uint64_t; 44234353Sdim#else 45226586Sdimtypedef unsigned long gcc_uint64_t; 46226586Sdim#endif 47226586Sdim 48226586Sdim#ifndef TMP_MAX 49226586Sdim#define TMP_MAX 16384 50226586Sdim#endif 51226586Sdim 52226586Sdim#ifndef O_BINARY 53226586Sdim# define O_BINARY 0 54226586Sdim#endif 55226586Sdim 56226586Sdim/* 57226586Sdim 58226586Sdim@deftypefn Replacement int mkstemps (char *@var{pattern}, int @var{suffix_len}) 59226586Sdim 60226586SdimGenerate a unique temporary file name from @var{pattern}. 61226586Sdim@var{pattern} has the form: 62226586Sdim 63226586Sdim@example 64226586Sdim @var{path}/ccXXXXXX@var{suffix} 65226586Sdim@end example 66226586Sdim 67226586Sdim@var{suffix_len} tells us how long @var{suffix} is (it can be zero 68226586Sdimlength). The last six characters of @var{pattern} before @var{suffix} 69226586Sdimmust be @samp{XXXXXX}; they are replaced with a string that makes the 70239462Sdimfilename unique. Returns a file descriptor open on the file for 71239462Sdimreading and writing. 72239462Sdim 73239462Sdim@end deftypefn 74243830Sdim 75243830Sdim*/ 76239462Sdim 77239462Sdimint 78239462Sdimmkstemps (char *pattern, int suffix_len) 79239462Sdim{ 80239462Sdim static const char letters[] 81239462Sdim = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 82239462Sdim static gcc_uint64_t value; 83226586Sdim#ifdef HAVE_GETTIMEOFDAY 84226586Sdim struct timeval tv; 85226586Sdim#endif 86226586Sdim char *XXXXXX; 87226586Sdim size_t len; 88226586Sdim int count; 89234353Sdim 90234353Sdim len = strlen (pattern); 91226586Sdim 92226586Sdim if ((int) len < 6 + suffix_len 93226586Sdim || strncmp (&pattern[len - 6 - suffix_len], "XXXXXX", 6)) 94226586Sdim { 95226586Sdim return -1; 96226586Sdim } 97226586Sdim 98226586Sdim XXXXXX = &pattern[len - 6 - suffix_len]; 99226586Sdim 100226586Sdim#ifdef HAVE_GETTIMEOFDAY 101226586Sdim /* Get some more or less random data. */ 102226586Sdim gettimeofday (&tv, NULL); 103226586Sdim value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid (); 104226586Sdim#else 105226586Sdim value += getpid (); 106226586Sdim#endif 107226586Sdim 108226586Sdim for (count = 0; count < TMP_MAX; ++count) 109226586Sdim { 110243830Sdim gcc_uint64_t v = value; 111243830Sdim int fd; 112226586Sdim 113226586Sdim /* Fill in the random bits. */ 114243830Sdim XXXXXX[0] = letters[v % 62]; 115226586Sdim v /= 62; 116234353Sdim XXXXXX[1] = letters[v % 62]; 117226586Sdim v /= 62; 118226586Sdim XXXXXX[2] = letters[v % 62]; 119243830Sdim v /= 62; 120226586Sdim XXXXXX[3] = letters[v % 62]; 121226586Sdim v /= 62; 122226586Sdim XXXXXX[4] = letters[v % 62]; 123226586Sdim v /= 62; 124226586Sdim XXXXXX[5] = letters[v % 62]; 125234353Sdim 126226586Sdim fd = open (pattern, O_BINARY|O_RDWR|O_CREAT|O_EXCL, 0600); 127249423Sdim if (fd >= 0) 128226586Sdim /* The file does not exist. */ 129234353Sdim return fd; 130226586Sdim 131226586Sdim /* This is a random value. It is only necessary that the next 132226586Sdim TMP_MAX values generated by adding 7777 to VALUE are different 133226586Sdim with (module 2^32). */ 134226586Sdim value += 7777; 135249423Sdim } 136249423Sdim 137249423Sdim /* We return the null string if we can't find a unique file name. */ 138234353Sdim pattern[0] = '\0'; 139249423Sdim return -1; 140263508Sdim} 141263508Sdim