chiark / gitweb /
rename backlog_nextscan_periods to until_backlog_nextscan
[innduct.git] / lib / mkstemp.c
1 /*  $Id: mkstemp.c 5329 2002-03-17 07:39:14Z rra $
2 **
3 **  Replacement for a missing mkstemp.
4 **
5 **  Written by Russ Allbery <rra@stanford.edu>
6 **  This work is hereby placed in the public domain by its author.
7 **
8 **  Provides the same functionality as the library function mkstemp for those
9 **  systems that don't have it.
10 */
11
12 #include "config.h"
13 #include "clibrary.h"
14 #include "portable/time.h"
15 #include <errno.h>
16 #include <fcntl.h>
17
18 /* If we're running the test suite, rename mkstemp to avoid conflicts with the
19    system version.  #undef it first because some systems may define it to
20    another name. */
21 #if TESTING
22 # undef mkstemp
23 # define mkstemp test_mkstemp
24 int test_mkstemp(char *);
25 #endif
26
27 /* Pick the longest available integer type. */
28 #if HAVE_LONG_LONG
29 typedef unsigned long long long_int_type;
30 #else
31 typedef unsigned long long_int_type;
32 #endif
33
34 int
35 mkstemp(char *template)
36 {
37     static const char letters[] =
38         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
39     size_t length;
40     char *XXXXXX;
41     struct timeval tv;
42     long_int_type randnum, working;
43     int i, tries, fd;
44
45     /* Make sure we have a valid template and initialize p to point at the
46        beginning of the template portion of the string. */
47     length = strlen(template);
48     if (length < 6) {
49         errno = EINVAL;
50         return -1;
51     }
52     XXXXXX = template + length - 6;
53     if (strcmp(XXXXXX, "XXXXXX") != 0) {
54         errno = EINVAL;
55         return -1;
56     }
57
58     /* Get some more-or-less random information. */
59     gettimeofday(&tv, NULL);
60     randnum = ((long_int_type) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();
61
62     /* Now, try to find a working file name.  We try no more than TMP_MAX file
63        names. */
64     for (tries = 0; tries < TMP_MAX; tries++) {
65         for (working = randnum, i = 0; i < 6; i++) {
66             XXXXXX[i] = letters[working % 62];
67             working /= 62;
68         }
69         fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600);
70         if (fd >= 0 || errno != EEXIST)
71             return fd;
72
73         /* This is a relatively random increment.  Cut off the tail end of
74            tv_usec since it's often predictable. */
75         randnum += (tv.tv_usec >> 10) & 0xfff;
76     }
77     errno = EEXIST;
78     return -1;
79 }