File: mkdtemp.c

package info (click to toggle)
syrep 0.9-4.2
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 1,112 kB
  • ctags: 523
  • sloc: ansic: 6,023; sh: 3,563; makefile: 156
file content (87 lines) | stat: -rw-r--r-- 2,524 bytes parent folder | download | duplicates (6)
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*/
}