]> eyrie.org Git - kerberos/krb5-strength.git/blob - portable/mkstemp.c
Add NEWS entry for spec file
[kerberos/krb5-strength.git] / portable / mkstemp.c
1 /*
2  * Replacement for a missing mkstemp.
3  *
4  * Provides the same functionality as the library function mkstemp for those
5  * systems that don't have it.
6  *
7  * The canonical version of this file is maintained in the rra-c-util package,
8  * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
9  *
10  * Written by Russ Allbery <eagle@eyrie.org>
11  * Copyright 2009, 2011, 2014
12  *     The Board of Trustees of the Leland Stanford Junior University
13  *
14  * Copying and distribution of this file, with or without modification, are
15  * permitted in any medium without royalty provided the copyright notice and
16  * this notice are preserved.  This file is offered as-is, without any
17  * warranty.
18  *
19  * SPDX-License-Identifier: FSFAP
20  */
21
22 #include <config.h>
23 #include <portable/system.h>
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #ifdef HAVE_SYS_TIME_H
28 #    include <sys/time.h>
29 #endif
30 #include <time.h>
31
32 /*
33  * If we're running the test suite, rename mkstemp to avoid conflicts with the
34  * system version.  #undef it first because some systems may define it to
35  * another name.
36  */
37 #if TESTING
38 #    undef mkstemp
39 #    define mkstemp test_mkstemp
40 int test_mkstemp(char *);
41 #endif
42
43 /* Pick the longest available integer type. */
44 #if HAVE_LONG_LONG_INT
45 typedef unsigned long long long_int_type;
46 #else
47 typedef unsigned long long_int_type;
48 #endif
49
50 int
51 mkstemp(char *template)
52 {
53     static const char letters[] =
54         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
55     size_t length;
56     char *XXXXXX;
57     struct timeval tv;
58     long_int_type randnum, working;
59     int i, tries, fd;
60
61     /*
62      * Make sure we have a valid template and initialize p to point at the
63      * beginning of the template portion of the string.
64      */
65     length = strlen(template);
66     if (length < 6) {
67         errno = EINVAL;
68         return -1;
69     }
70     XXXXXX = template + length - 6;
71     if (strcmp(XXXXXX, "XXXXXX") != 0) {
72         errno = EINVAL;
73         return -1;
74     }
75
76     /* Get some more-or-less random information. */
77     gettimeofday(&tv, NULL);
78     randnum = ((long_int_type) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();
79
80     /*
81      * Now, try to find a working file name.  We try no more than TMP_MAX file
82      * names.
83      */
84     for (tries = 0; tries < TMP_MAX; tries++) {
85         for (working = randnum, i = 0; i < 6; i++) {
86             XXXXXX[i] = letters[working % 62];
87             working /= 62;
88         }
89         fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600);
90         if (fd >= 0 || (errno != EEXIST && errno != EISDIR))
91             return fd;
92
93         /*
94          * This is a relatively random increment.  Cut off the tail end of
95          * tv_usec since it's often predictable.
96          */
97         randnum += (tv.tv_usec >> 10) & 0xfff;
98     }
99     errno = EEXIST;
100     return -1;
101 }