xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/mkstemps.c (revision 5173eb0a33e5d83890ba976253e703be4c92557c)
1*5173eb0aSchristos /* Copyright (C) 1991-2024 Free Software Foundation, Inc.
298b9484cSchristos    This file is derived from mkstemp.c from the GNU C Library.
398b9484cSchristos 
498b9484cSchristos    The GNU C Library is free software; you can redistribute it and/or
598b9484cSchristos    modify it under the terms of the GNU Library General Public License as
698b9484cSchristos    published by the Free Software Foundation; either version 2 of the
798b9484cSchristos    License, or (at your option) any later version.
898b9484cSchristos 
998b9484cSchristos    The GNU C Library is distributed in the hope that it will be useful,
1098b9484cSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1198b9484cSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1298b9484cSchristos    Library General Public License for more details.
1398b9484cSchristos 
1498b9484cSchristos    You should have received a copy of the GNU Library General Public
1598b9484cSchristos    License along with the GNU C Library; see the file COPYING.LIB.  If not,
1698b9484cSchristos    write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
1798b9484cSchristos    Boston, MA 02110-1301, USA.  */
1898b9484cSchristos 
1998b9484cSchristos #ifdef HAVE_CONFIG_H
2098b9484cSchristos #include "config.h"
2198b9484cSchristos #endif
2298b9484cSchristos 
2398b9484cSchristos #include <sys/types.h>
2498b9484cSchristos #ifdef HAVE_STDLIB_H
2598b9484cSchristos #include <stdlib.h>
2698b9484cSchristos #endif
2798b9484cSchristos #ifdef HAVE_STRING_H
2898b9484cSchristos #include <string.h>
2998b9484cSchristos #endif
3098b9484cSchristos #include <errno.h>
3198b9484cSchristos #include <stdio.h>
3298b9484cSchristos #include <fcntl.h>
3398b9484cSchristos #ifdef HAVE_UNISTD_H
3498b9484cSchristos #include <unistd.h>
3598b9484cSchristos #endif
3698b9484cSchristos #ifdef HAVE_SYS_TIME_H
3798b9484cSchristos #include <sys/time.h>
38212397c6Schristos #elif HAVE_TIME_H
39212397c6Schristos #include <time.h>
4098b9484cSchristos #endif
4198b9484cSchristos #include "ansidecl.h"
4298b9484cSchristos 
4398b9484cSchristos /* We need to provide a type for gcc_uint64_t.  */
4498b9484cSchristos #ifdef __GNUC__
4598b9484cSchristos __extension__ typedef unsigned long long gcc_uint64_t;
4698b9484cSchristos #else
4798b9484cSchristos typedef unsigned long gcc_uint64_t;
4898b9484cSchristos #endif
4998b9484cSchristos 
5098b9484cSchristos #ifndef TMP_MAX
5198b9484cSchristos #define TMP_MAX 16384
5298b9484cSchristos #endif
5398b9484cSchristos 
5498b9484cSchristos #ifndef O_BINARY
5598b9484cSchristos # define O_BINARY 0
5698b9484cSchristos #endif
5798b9484cSchristos 
5898b9484cSchristos /*
5998b9484cSchristos 
6098b9484cSchristos @deftypefn Replacement int mkstemps (char *@var{pattern}, int @var{suffix_len})
6198b9484cSchristos 
6298b9484cSchristos Generate a unique temporary file name from @var{pattern}.
6398b9484cSchristos @var{pattern} has the form:
6498b9484cSchristos 
6598b9484cSchristos @example
6698b9484cSchristos    @var{path}/ccXXXXXX@var{suffix}
6798b9484cSchristos @end example
6898b9484cSchristos 
6998b9484cSchristos @var{suffix_len} tells us how long @var{suffix} is (it can be zero
7098b9484cSchristos length).  The last six characters of @var{pattern} before @var{suffix}
7198b9484cSchristos must be @samp{XXXXXX}; they are replaced with a string that makes the
7298b9484cSchristos filename unique.  Returns a file descriptor open on the file for
7398b9484cSchristos reading and writing.
7498b9484cSchristos 
7598b9484cSchristos @end deftypefn
7698b9484cSchristos 
7798b9484cSchristos */
7898b9484cSchristos 
7998b9484cSchristos int
8098b9484cSchristos mkstemps (char *pattern, int suffix_len)
8198b9484cSchristos {
8298b9484cSchristos   static const char letters[]
8398b9484cSchristos     = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
8498b9484cSchristos   static gcc_uint64_t value;
8598b9484cSchristos #ifdef HAVE_GETTIMEOFDAY
8698b9484cSchristos   struct timeval tv;
8798b9484cSchristos #endif
8898b9484cSchristos   char *XXXXXX;
8998b9484cSchristos   size_t len;
9098b9484cSchristos   int count;
9198b9484cSchristos 
9298b9484cSchristos   len = strlen (pattern);
9398b9484cSchristos 
9498b9484cSchristos   if ((int) len < 6 + suffix_len
9598b9484cSchristos       || strncmp (&pattern[len - 6 - suffix_len], "XXXXXX", 6))
9698b9484cSchristos     {
9798b9484cSchristos       return -1;
9898b9484cSchristos     }
9998b9484cSchristos 
10098b9484cSchristos   XXXXXX = &pattern[len - 6 - suffix_len];
10198b9484cSchristos 
10298b9484cSchristos #ifdef HAVE_GETTIMEOFDAY
10398b9484cSchristos   /* Get some more or less random data.  */
10498b9484cSchristos   gettimeofday (&tv, NULL);
10598b9484cSchristos   value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
10698b9484cSchristos #else
10798b9484cSchristos   value += getpid ();
10898b9484cSchristos #endif
10998b9484cSchristos 
11098b9484cSchristos   for (count = 0; count < TMP_MAX; ++count)
11198b9484cSchristos     {
11298b9484cSchristos       gcc_uint64_t v = value;
11398b9484cSchristos       int fd;
11498b9484cSchristos 
11598b9484cSchristos       /* Fill in the random bits.  */
11698b9484cSchristos       XXXXXX[0] = letters[v % 62];
11798b9484cSchristos       v /= 62;
11898b9484cSchristos       XXXXXX[1] = letters[v % 62];
11998b9484cSchristos       v /= 62;
12098b9484cSchristos       XXXXXX[2] = letters[v % 62];
12198b9484cSchristos       v /= 62;
12298b9484cSchristos       XXXXXX[3] = letters[v % 62];
12398b9484cSchristos       v /= 62;
12498b9484cSchristos       XXXXXX[4] = letters[v % 62];
12598b9484cSchristos       v /= 62;
12698b9484cSchristos       XXXXXX[5] = letters[v % 62];
12798b9484cSchristos 
12898b9484cSchristos       fd = open (pattern, O_BINARY|O_RDWR|O_CREAT|O_EXCL, 0600);
12998b9484cSchristos       if (fd >= 0)
13098b9484cSchristos 	/* The file does not exist.  */
13198b9484cSchristos 	return fd;
13298b9484cSchristos       if (errno != EEXIST
13398b9484cSchristos #ifdef EISDIR
13498b9484cSchristos 	  && errno != EISDIR
13598b9484cSchristos #endif
13698b9484cSchristos 	 )
13798b9484cSchristos 	/* Fatal error (EPERM, ENOSPC etc).  Doesn't make sense to loop.  */
13898b9484cSchristos 	break;
13998b9484cSchristos 
14098b9484cSchristos       /* This is a random value.  It is only necessary that the next
14198b9484cSchristos 	 TMP_MAX values generated by adding 7777 to VALUE are different
14298b9484cSchristos 	 with (module 2^32).  */
14398b9484cSchristos       value += 7777;
14498b9484cSchristos     }
14598b9484cSchristos 
14698b9484cSchristos   /* We return the null string if we can't find a unique file name.  */
14798b9484cSchristos   pattern[0] = '\0';
14898b9484cSchristos   return -1;
14998b9484cSchristos }
150