PostgreSQL Source Code git master
mkdtemp.c File Reference
#include "c.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
Include dependency graph for mkdtemp.c:

Go to the source code of this file.

Macros

#define _DIAGASSERT(x)   do {} while (0)
 

Functions

static int GETTEMP (char *path, int *doopen, int domkdir)
 
char * mkdtemp (char *path)
 

Macro Definition Documentation

◆ _DIAGASSERT

#define _DIAGASSERT (   x)    do {} while (0)

Definition at line 21 of file mkdtemp.c.

Function Documentation

◆ GETTEMP()

static int GETTEMP ( char *  path,
int *  doopen,
int  domkdir 
)
static

Definition at line 94 of file mkdtemp.c.

95{
96 char *start,
97 *trv;
98 struct stat sbuf;
99 u_int pid;
100
101 /*
102 * To guarantee multiple calls generate unique names even if the file is
103 * not created. 676 different possibilities with 7 or more X's, 26 with 6
104 * or less.
105 */
106 static char xtra[2] = "aa";
107 int xcnt = 0;
108
109 _DIAGASSERT(path != NULL);
110 /* doopen may be NULL */
111
112 pid = getpid();
113
114 /* Move to end of path and count trailing X's. */
115 for (trv = path; *trv; ++trv)
116 if (*trv == 'X')
117 xcnt++;
118 else
119 xcnt = 0;
120
121 /* Use at least one from xtra. Use 2 if more than 6 X's. */
122 if (xcnt > 0)
123 {
124 *--trv = xtra[0];
125 xcnt--;
126 }
127 if (xcnt > 5)
128 {
129 *--trv = xtra[1];
130 xcnt--;
131 }
132
133 /* Set remaining X's to pid digits with 0's to the left. */
134 for (; xcnt > 0; xcnt--)
135 {
136 *--trv = (pid % 10) + '0';
137 pid /= 10;
138 }
139
140 /* update xtra for next call. */
141 if (xtra[0] != 'z')
142 xtra[0]++;
143 else
144 {
145 xtra[0] = 'a';
146 if (xtra[1] != 'z')
147 xtra[1]++;
148 else
149 xtra[1] = 'a';
150 }
151
152 /*
153 * check the target directory; if you have six X's and it doesn't exist
154 * this runs for a *very* long time.
155 */
156 for (start = trv + 1;; --trv)
157 {
158 if (trv <= path)
159 break;
160 if (*trv == '/')
161 {
162 int e;
163
164 *trv = '\0';
165 e = stat(path, &sbuf);
166 *trv = '/';
167 if (e == -1)
168 return doopen == NULL && !domkdir;
169 if (!S_ISDIR(sbuf.st_mode))
170 {
171 errno = ENOTDIR;
172 return doopen == NULL && !domkdir;
173 }
174 break;
175 }
176 }
177
178 for (;;)
179 {
180 if (doopen)
181 {
182 if ((*doopen =
183 open(path, O_CREAT | O_EXCL | O_RDWR, 0600)) >= 0)
184 return 1;
185 if (errno != EEXIST)
186 return 0;
187 }
188 else if (domkdir)
189 {
190 if (mkdir(path, 0700) >= 0)
191 return 1;
192 if (errno != EEXIST)
193 return 0;
194 }
195 else if (lstat(path, &sbuf))
196 return errno == ENOENT ? 1 : 0;
197
198 /* tricky little algorithm for backward compatibility */
199 for (trv = start;;)
200 {
201 if (!*trv)
202 return 0;
203 if (*trv == 'z')
204 *trv++ = 'a';
205 else
206 {
207 if (isdigit((unsigned char) *trv))
208 *trv = 'a';
209 else
210 ++*trv;
211 break;
212 }
213 }
214 }
215 /* NOTREACHED */
216}
return str start
#define _DIAGASSERT(x)
Definition: mkdtemp.c:21
e
Definition: preproc-init.c:82
#define stat
Definition: win32_port.h:274
#define lstat(path, sb)
Definition: win32_port.h:275
#define S_ISDIR(m)
Definition: win32_port.h:315
#define mkdir(a, b)
Definition: win32_port.h:80

References _DIAGASSERT, lstat, mkdir, S_ISDIR, stat::st_mode, start, and stat.

Referenced by mkdtemp().

◆ mkdtemp()

char * mkdtemp ( char *  path)

Definition at line 286 of file mkdtemp.c.

287{
288 _DIAGASSERT(path != NULL);
289
290 return GETTEMP(path, NULL, 1) ? path : NULL;
291}
static int GETTEMP(char *path, int *doopen, int domkdir)
Definition: mkdtemp.c:94

References _DIAGASSERT, and GETTEMP().

Referenced by make_temp_sockdir().