]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libc/misc/internals/tempname.c
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libc / misc / internals / tempname.c
1 /* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with the GNU C Library; see the file COPYING.LIB.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 /* March 11, 2002       Manuel Novoa III
20  *
21  * Modify code to remove dependency on libgcc long long arith support funcs.
22  */
23
24 /* June 6, 2004       Erik Andersen
25  *
26  * Don't use brain damaged getpid() based randomness.
27  */
28
29 /* April 15, 2005     Mike Frysinger
30  *
31  * Use brain damaged getpid() if real random fails.
32  */
33
34 #include <stddef.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <assert.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/time.h>
46 #include "tempname.h"
47
48 /* Return nonzero if DIR is an existent directory.  */
49 static int direxists (const char *dir)
50 {
51     struct stat buf;
52     return stat(dir, &buf) == 0 && S_ISDIR (buf.st_mode);
53 }
54
55 /* Path search algorithm, for tmpnam, tmpfile, etc.  If DIR is
56    non-null and exists, uses it; otherwise uses the first of $TMPDIR,
57    P_tmpdir, /tmp that exists.  Copies into TMPL a template suitable
58    for use with mk[s]temp.  Will fail (-1) if DIR is non-null and
59    doesn't exist, none of the searched dirs exists, or there's not
60    enough space in TMPL. */
61 int attribute_hidden ___path_search (char *tmpl, size_t tmpl_len, const char *dir,
62         const char *pfx /*, int try_tmpdir*/)
63 {
64     /*const char *d; */
65     size_t dlen, plen;
66
67     if (!pfx || !pfx[0])
68     {
69         pfx = "file";
70         plen = 4;
71     }
72     else
73     {
74         plen = strlen (pfx);
75         if (plen > 5)
76             plen = 5;
77     }
78
79     /* Disable support for $TMPDIR */
80 #if 0
81     if (try_tmpdir)
82     {
83         d = __secure_getenv ("TMPDIR");
84         if (d != NULL && direxists (d))
85             dir = d;
86         else if (dir != NULL && direxists (dir))
87             /* nothing */ ;
88         else
89             dir = NULL;
90     }
91 #endif
92     if (dir == NULL)
93     {
94         if (direxists (P_tmpdir))
95             dir = P_tmpdir;
96         else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
97             dir = "/tmp";
98         else
99         {
100             __set_errno (ENOENT);
101             return -1;
102         }
103     }
104
105     dlen = strlen (dir);
106     while (dlen > 1 && dir[dlen - 1] == '/')
107         dlen--;                 /* remove trailing slashes */
108
109     /* check we have room for "${dir}/${pfx}XXXXXX\0" */
110     if (tmpl_len < dlen + 1 + plen + 6 + 1)
111     {
112         __set_errno (EINVAL);
113         return -1;
114     }
115
116     sprintf (tmpl, "%.*s/%.*sXXXXXX", (int)dlen, dir, (int)plen, pfx);
117     return 0;
118 }
119
120 /* These are the characters used in temporary filenames.  */
121 static const char letters[] =
122 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
123 #define NUM_LETTERS (62)
124
125 static unsigned int fillrand(unsigned char *buf, unsigned int len)
126 {
127     int fd;
128     unsigned int result = -1;
129     fd = open("/dev/urandom", O_RDONLY);
130     if (fd < 0) {
131         fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
132     }
133     if (fd >= 0) {
134         result = read(fd, buf, len);
135         close(fd);
136     }
137     return result;
138 }
139
140 static void brain_damaged_fillrand(unsigned char *buf, unsigned int len)
141 {
142         unsigned int i, k;
143         struct timeval tv;
144         uint32_t high, low, rh;
145         static uint64_t value;
146         gettimeofday(&tv, NULL);
147         value += ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();
148         low = value & UINT32_MAX;
149         high = value >> 32;
150         for (i = 0; i < len; ++i) {
151                 rh = high % NUM_LETTERS;
152                 high /= NUM_LETTERS;
153 #define L ((UINT32_MAX % NUM_LETTERS + 1) % NUM_LETTERS)
154                 k = (low % NUM_LETTERS) + (L * rh);
155 #undef L
156 #define H ((UINT32_MAX / NUM_LETTERS) + ((UINT32_MAX % NUM_LETTERS + 1) / NUM_LETTERS))
157                 low = (low / NUM_LETTERS) + (H * rh) + (k / NUM_LETTERS);
158 #undef H
159                 k %= NUM_LETTERS;
160                 buf[i] = letters[k];
161         }
162 }
163
164 /* Generate a temporary file name based on TMPL.  TMPL must match the
165    rules for mk[s]temp (i.e. end in "XXXXXX").  The name constructed
166    does not exist at the time of the call to __gen_tempname.  TMPL is
167    overwritten with the result.
168
169    KIND may be one of:
170    __GT_NOCREATE:       simply verify that the name does not exist
171                         at the time of the call. mode argument is ignored.
172    __GT_FILE:           create the file using open(O_CREAT|O_EXCL)
173                         and return a read-write fd with given mode.
174    __GT_BIGFILE:        same as __GT_FILE but use open64().
175    __GT_DIR:            create a directory with given mode.
176
177 */
178 int __gen_tempname (char *tmpl, int kind, mode_t mode)
179 {
180     char *XXXXXX;
181     unsigned int i;
182     int fd, save_errno = errno;
183     unsigned char randomness[6];
184     size_t len;
185
186     len = strlen (tmpl);
187     /* This is where the Xs start.  */
188     XXXXXX = tmpl + len - 6;
189     if (len < 6 || strcmp (XXXXXX, "XXXXXX"))
190     {
191         __set_errno (EINVAL);
192         return -1;
193     }
194
195     for (i = 0; i < TMP_MAX; ++i) {
196         int j;
197         /* Get some random data.  */
198         if (fillrand(randomness, sizeof(randomness)) != sizeof(randomness)) {
199             /* if random device nodes failed us, lets use the braindamaged ver */
200             brain_damaged_fillrand(randomness, sizeof(randomness));
201         }
202         for (j = 0; j < sizeof(randomness); ++j)
203             XXXXXX[j] = letters[randomness[j] % NUM_LETTERS];
204
205         switch (kind) {
206             case __GT_NOCREATE:
207                 {
208                     struct stat st;
209                     if (stat (tmpl, &st) < 0) {
210                         if (errno == ENOENT) {
211                             fd = 0;
212                             goto restore_and_ret;
213                         } else
214                             /* Give up now. */
215                             return -1;
216                     } else
217                         fd = 0;
218                 }
219             case __GT_FILE:
220                 fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, mode);
221                 break;
222 #if defined __UCLIBC_HAS_LFS__
223             case __GT_BIGFILE:
224                 fd = open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, mode);
225                 break;
226 #endif
227             case __GT_DIR:
228                 fd = mkdir (tmpl, mode);
229                 break;
230             default:
231                 fd = -1;
232                 assert (! "invalid KIND in __gen_tempname");
233         }
234
235         if (fd >= 0) {
236 restore_and_ret:
237             __set_errno (save_errno);
238             return fd;
239         }
240         else if (errno != EEXIST)
241             /* Any other error will apply also to other names we might
242                try, and there are 2^32 or so of them, so give up now. */
243             return -1;
244     }
245
246     /* We got out of the loop because we ran out of combinations to try.  */
247     __set_errno (EEXIST);
248     return -1;
249 }