OSDN Git Service

Rename cygWFMO to cygwait throughout and use the magic of polymorphism to "wait
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / mktemp.cc
1 /* mktemp.cc: mktemp functions
2
3 This file is adapted for Cygwin from FreeBSD and newlib.
4
5 See the copyright at the bottom of this file. */
6
7 #include "winsup.h"
8 #include "cygerrno.h"
9 #include <fcntl.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12
13 static int _gettemp(char *, int *, int, size_t, int);
14 static uint32_t arc4random ();
15
16 static const char padchar[] =
17 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
18
19 extern "C" int
20 mkstemp(char *path)
21 {
22   int fd;
23   return _gettemp(path, &fd, 0, 0, O_BINARY) ? fd : -1;
24 }
25
26 extern "C" char *
27 mkdtemp(char *path)
28 {
29   return _gettemp(path, NULL, 1, 0, 0) ? path : NULL;
30 }
31
32 extern "C" int
33 mkstemps(char *path, int len)
34 {
35   int fd;
36   return _gettemp(path, &fd, 0, len, O_BINARY) ? fd : -1;
37 }
38
39 extern "C" int
40 mkostemp(char *path, int flags)
41 {
42   int fd;
43   return _gettemp(path, &fd, 0, 0, flags & ~O_ACCMODE) ? fd : -1;
44 }
45
46 extern "C" int
47 mkostemps(char *path, int len, int flags)
48 {
49   int fd;
50   return _gettemp(path, &fd, 0, len, flags & ~O_ACCMODE) ? fd : -1;
51 }
52
53 extern "C" char *
54 mktemp(char *path)
55 {
56   return _gettemp(path, NULL, 0, 0, 0) ? path : (char *) NULL;
57 }
58
59 static int
60 _gettemp(char *path, int *doopen, int domkdir, size_t suffixlen, int flags)
61 {
62   char *start, *trv, *suffp;
63   char *pad;
64
65   if (doopen && domkdir)
66     {
67       set_errno (EINVAL);
68       return 0;
69     }
70
71   trv = strchr (path, '\0');
72   if ((size_t) (trv - path) < suffixlen)
73     {
74       set_errno (EINVAL);
75       return 0;
76     }
77   trv -= suffixlen;
78   suffp = trv--;
79
80   /* Fill space with random characters */
81   while (trv >= path && *trv == 'X')
82     {
83       uint32_t rand = arc4random () % (sizeof (padchar) - 1);
84       *trv-- = padchar[rand];
85     }
86   if (suffp - trv < 6)
87     {
88       set_errno (EINVAL);
89       return 0;
90     }
91   start = trv + 1;
92
93   /*
94    * check the target directory.
95    */
96   struct __stat64 sbuf;
97   if (doopen != NULL || domkdir)
98     {
99       for (; trv > path; trv--)
100         {
101           if (*trv == '/')
102             {
103               *trv = '\0';
104               int rval = stat64 (path, &sbuf);
105               *trv = '/';
106               if (rval != 0)
107                 return 0;
108               if (!S_ISDIR (sbuf.st_mode))
109                 {
110                   set_errno (ENOTDIR);
111                   return 0;
112                 }
113               break;
114             }
115         }
116     }
117
118   for (;;)
119     {
120       if (doopen)
121         {
122           if ((*doopen = open (path, O_CREAT | O_EXCL | O_RDWR | flags,
123                                S_IRUSR | S_IWUSR)) >= 0)
124             return 1;
125           if (errno != EEXIST)
126             return 0;
127         }
128       else if (domkdir)
129         {
130           if (mkdir (path, 0700) == 0)
131             return 1;
132           if (errno != EEXIST)
133             return 0;
134           }
135       else if (lstat64 (path, &sbuf))
136         return errno == ENOENT;
137
138       /* If we have a collision, cycle through the space of filenames */
139       for (trv = start;;)
140         {
141           if (*trv == '\0' || trv == suffp)
142             return 0;
143           pad = strchr (padchar, *trv);
144           if (pad == NULL || *++pad == '\0')
145             *trv++ = padchar[0];
146           else
147             {
148               *trv++ = *pad;
149               break;
150             }
151         }
152     }
153   /*NOTREACHED*/
154 }
155
156 static uint32_t
157 arc4random ()
158 {
159   union
160   {
161     uint32_t rand;
162     char buf[sizeof (int) / 8];
163   } r;
164   int fd = open ("/dev/urandom", O_RDONLY);
165   read (fd, r.buf, 4);
166   close (fd);
167   return r.rand;
168 }
169
170 /*
171 * Copyright (c) 1987, 1993
172 *       The Regents of the University of California.  All rights reserved.
173 *
174 * Redistribution and use in source and binary forms, with or without
175 * modification, are permitted provided that the following conditions
176 * are met:
177 * 1. Redistributions of source code must retain the above copyright
178 *    notice, this list of conditions and the following disclaimer.
179 * 2. Redistributions in binary form must reproduce the above copyright
180 *    notice, this list of conditions and the following disclaimer in the
181 *    documentation and/or other materials provided with the distribution.
182 * 4. Neither the name of the University nor the names of its contributors
183 *    may be used to endorse or promote products derived from this software
184 *    without specific prior written permission.
185 *
186 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
187 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
188 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
189 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
190 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
192 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
193 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
194 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
195 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
196 * SUCH DAMAGE.
197 */