1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
|
/*
* This has been derived from the implementation in the FreeBSD libc.
*
* 2000-12-28 Ha*vard Kva*len <havardk@xmms.org>:
* Stripped down to only mkdtemp() and made more portable
*
*/
#include <sys/stat.h>
#include <sys/time.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static const unsigned char padchar[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char * mkdtemp(char *path)
{
register char *start, *trv, *suffp;
char *pad;
struct stat sbuf;
int rval;
for (trv = path; *trv; ++trv)
;
suffp = trv;
--trv;
if (trv < path) {
errno = EINVAL;
return NULL;
}
/* Fill space with random characters */
/*
* I hope this is random enough. The orginal implementation
* uses arc4random(3) which is not available everywhere.
*/
while (*trv == 'X') {
int randv = random() % (sizeof(padchar) - 1);
*trv-- = padchar[randv];
}
start = trv + 1;
/*
* check the target directory.
*/
for (;; --trv) {
if (trv <= path)
break;
if (*trv == '/') {
*trv = '\0';
rval = stat(path, &sbuf);
*trv = '/';
if (rval != 0)
return NULL;
if (!S_ISDIR(sbuf.st_mode)) {
errno = ENOTDIR;
return NULL;
}
break;
}
}
for (;;) {
if (mkdir(path, 0700) == 0)
return path;
if (errno != EEXIST)
return NULL;
/* If we have a collision, cycle through the space of filenames */
for (trv = start;;) {
if (*trv == '\0' || trv == suffp)
return NULL;
pad = strchr(padchar, *trv);
if (pad == NULL || !*++pad)
*trv++ = padchar[0];
else {
*trv++ = *pad;
break;
}
}
}
/*NOTREACHED*/
}
|