1*f22f0ef4Schristos /* Copyright (C) 1991-2022 Free Software Foundation, Inc.
22a6b7db3Sskrll    This file is derived from mkstemp.c from the GNU C Library.
32a6b7db3Sskrll 
42a6b7db3Sskrll    The GNU C Library is free software; you can redistribute it and/or
52a6b7db3Sskrll    modify it under the terms of the GNU Library General Public License as
62a6b7db3Sskrll    published by the Free Software Foundation; either version 2 of the
72a6b7db3Sskrll    License, or (at your option) any later version.
82a6b7db3Sskrll 
92a6b7db3Sskrll    The GNU C Library is distributed in the hope that it will be useful,
102a6b7db3Sskrll    but WITHOUT ANY WARRANTY; without even the implied warranty of
112a6b7db3Sskrll    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
122a6b7db3Sskrll    Library General Public License for more details.
132a6b7db3Sskrll 
142a6b7db3Sskrll    You should have received a copy of the GNU Library General Public
152a6b7db3Sskrll    License along with the GNU C Library; see the file COPYING.LIB.  If not,
162a6b7db3Sskrll    write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
172a6b7db3Sskrll    Boston, MA 02110-1301, USA.  */
182a6b7db3Sskrll 
192a6b7db3Sskrll #ifdef HAVE_CONFIG_H
202a6b7db3Sskrll #include "config.h"
212a6b7db3Sskrll #endif
222a6b7db3Sskrll 
232a6b7db3Sskrll #include <sys/types.h>
242a6b7db3Sskrll #ifdef HAVE_STDLIB_H
252a6b7db3Sskrll #include <stdlib.h>
262a6b7db3Sskrll #endif
272a6b7db3Sskrll #ifdef HAVE_STRING_H
282a6b7db3Sskrll #include <string.h>
292a6b7db3Sskrll #endif
302a6b7db3Sskrll #include <errno.h>
312a6b7db3Sskrll #include <stdio.h>
322a6b7db3Sskrll #include <fcntl.h>
332a6b7db3Sskrll #ifdef HAVE_UNISTD_H
342a6b7db3Sskrll #include <unistd.h>
352a6b7db3Sskrll #endif
362a6b7db3Sskrll #ifdef HAVE_SYS_TIME_H
372a6b7db3Sskrll #include <sys/time.h>
385ba6b03cSchristos #elif HAVE_TIME_H
395ba6b03cSchristos #include <time.h>
402a6b7db3Sskrll #endif
412a6b7db3Sskrll #include "ansidecl.h"
422a6b7db3Sskrll 
432a6b7db3Sskrll /* We need to provide a type for gcc_uint64_t.  */
442a6b7db3Sskrll #ifdef __GNUC__
452a6b7db3Sskrll __extension__ typedef unsigned long long gcc_uint64_t;
462a6b7db3Sskrll #else
472a6b7db3Sskrll typedef unsigned long gcc_uint64_t;
482a6b7db3Sskrll #endif
492a6b7db3Sskrll 
502a6b7db3Sskrll #ifndef TMP_MAX
512a6b7db3Sskrll #define TMP_MAX 16384
522a6b7db3Sskrll #endif
532a6b7db3Sskrll 
542a6b7db3Sskrll #ifndef O_BINARY
552a6b7db3Sskrll # define O_BINARY 0
562a6b7db3Sskrll #endif
572a6b7db3Sskrll 
582a6b7db3Sskrll /*
592a6b7db3Sskrll 
602a6b7db3Sskrll @deftypefn Replacement int mkstemps (char *@var{pattern}, int @var{suffix_len})
612a6b7db3Sskrll 
622a6b7db3Sskrll Generate a unique temporary file name from @var{pattern}.
632a6b7db3Sskrll @var{pattern} has the form:
642a6b7db3Sskrll 
652a6b7db3Sskrll @example
662a6b7db3Sskrll    @var{path}/ccXXXXXX@var{suffix}
672a6b7db3Sskrll @end example
682a6b7db3Sskrll 
692a6b7db3Sskrll @var{suffix_len} tells us how long @var{suffix} is (it can be zero
702a6b7db3Sskrll length).  The last six characters of @var{pattern} before @var{suffix}
712a6b7db3Sskrll must be @samp{XXXXXX}; they are replaced with a string that makes the
722a6b7db3Sskrll filename unique.  Returns a file descriptor open on the file for
732a6b7db3Sskrll reading and writing.
742a6b7db3Sskrll 
752a6b7db3Sskrll @end deftypefn
762a6b7db3Sskrll 
772a6b7db3Sskrll */
782a6b7db3Sskrll 
792a6b7db3Sskrll int
mkstemps(char * pattern,int suffix_len)802a6b7db3Sskrll mkstemps (char *pattern, int suffix_len)
812a6b7db3Sskrll {
822a6b7db3Sskrll   static const char letters[]
832a6b7db3Sskrll     = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
842a6b7db3Sskrll   static gcc_uint64_t value;
852a6b7db3Sskrll #ifdef HAVE_GETTIMEOFDAY
862a6b7db3Sskrll   struct timeval tv;
872a6b7db3Sskrll #endif
882a6b7db3Sskrll   char *XXXXXX;
892a6b7db3Sskrll   size_t len;
902a6b7db3Sskrll   int count;
912a6b7db3Sskrll 
922a6b7db3Sskrll   len = strlen (pattern);
932a6b7db3Sskrll 
942a6b7db3Sskrll   if ((int) len < 6 + suffix_len
952a6b7db3Sskrll       || strncmp (&pattern[len - 6 - suffix_len], "XXXXXX", 6))
962a6b7db3Sskrll     {
972a6b7db3Sskrll       return -1;
982a6b7db3Sskrll     }
992a6b7db3Sskrll 
1002a6b7db3Sskrll   XXXXXX = &pattern[len - 6 - suffix_len];
1012a6b7db3Sskrll 
1022a6b7db3Sskrll #ifdef HAVE_GETTIMEOFDAY
1032a6b7db3Sskrll   /* Get some more or less random data.  */
1042a6b7db3Sskrll   gettimeofday (&tv, NULL);
1052a6b7db3Sskrll   value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
1062a6b7db3Sskrll #else
1072a6b7db3Sskrll   value += getpid ();
1082a6b7db3Sskrll #endif
1092a6b7db3Sskrll 
1102a6b7db3Sskrll   for (count = 0; count < TMP_MAX; ++count)
1112a6b7db3Sskrll     {
1122a6b7db3Sskrll       gcc_uint64_t v = value;
1132a6b7db3Sskrll       int fd;
1142a6b7db3Sskrll 
1152a6b7db3Sskrll       /* Fill in the random bits.  */
1162a6b7db3Sskrll       XXXXXX[0] = letters[v % 62];
1172a6b7db3Sskrll       v /= 62;
1182a6b7db3Sskrll       XXXXXX[1] = letters[v % 62];
1192a6b7db3Sskrll       v /= 62;
1202a6b7db3Sskrll       XXXXXX[2] = letters[v % 62];
1212a6b7db3Sskrll       v /= 62;
1222a6b7db3Sskrll       XXXXXX[3] = letters[v % 62];
1232a6b7db3Sskrll       v /= 62;
1242a6b7db3Sskrll       XXXXXX[4] = letters[v % 62];
1252a6b7db3Sskrll       v /= 62;
1262a6b7db3Sskrll       XXXXXX[5] = letters[v % 62];
1272a6b7db3Sskrll 
1282a6b7db3Sskrll       fd = open (pattern, O_BINARY|O_RDWR|O_CREAT|O_EXCL, 0600);
1292a6b7db3Sskrll       if (fd >= 0)
1302a6b7db3Sskrll 	/* The file does not exist.  */
1312a6b7db3Sskrll 	return fd;
1322a6b7db3Sskrll       if (errno != EEXIST
1332a6b7db3Sskrll #ifdef EISDIR
1342a6b7db3Sskrll 	  && errno != EISDIR
1352a6b7db3Sskrll #endif
1362a6b7db3Sskrll 	 )
1372a6b7db3Sskrll 	/* Fatal error (EPERM, ENOSPC etc).  Doesn't make sense to loop.  */
1382a6b7db3Sskrll 	break;
1392a6b7db3Sskrll 
1402a6b7db3Sskrll       /* This is a random value.  It is only necessary that the next
1412a6b7db3Sskrll 	 TMP_MAX values generated by adding 7777 to VALUE are different
1422a6b7db3Sskrll 	 with (module 2^32).  */
1432a6b7db3Sskrll       value += 7777;
1442a6b7db3Sskrll     }
1452a6b7db3Sskrll 
1462a6b7db3Sskrll   /* We return the null string if we can't find a unique file name.  */
1472a6b7db3Sskrll   pattern[0] = '\0';
1482a6b7db3Sskrll   return -1;
1492a6b7db3Sskrll }
150