@@ -29,10 +29,45 @@ public func realpath(
29
29
}
30
30
31
31
// char *mkdtemp(char *template);
32
+ // NOTE(compnerd) this is unsafe! This assumes that the template is *ASCII*.
32
33
public func mkdtemp(
33
34
_ template: UnsafeMutablePointer < CChar > ?
34
35
) -> UnsafeMutablePointer < CChar > ? {
35
- fatalError ( " mkdtemp is unimplemented " )
36
+ // Although the signature of the function is `char *(*)(char *)`, the C
37
+ // library treats it as `char *(*)(char * _Nonull)`. Most implementations
38
+ // will simply use and trigger a segmentation fault on x86 (and similar faults
39
+ // on other architectures) when the memory is accessed. This roughly emulates
40
+ // that by terminating in the case even though it is possible for us to return
41
+ // an error.
42
+ guard let template = template else { fatalError ( ) }
43
+
44
+ let length : Int = strlen ( template)
45
+
46
+ // Validate the precondition: the template must terminate with 6 `X` which
47
+ // will be filled in to generate a unique directory.
48
+ guard length >= 6 , memcmp ( template + length - 6 , " XXXXXX " , 6 ) == 0 else {
49
+ _set_errno ( EINVAL)
50
+ return nil
51
+ }
52
+
53
+ let stampSuffix = { ( buffer: UnsafeMutablePointer < CChar > ) in
54
+ let alpha = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
55
+ _ = ( 0 ..< 6 ) . map { index in
56
+ buffer [ index] = CChar ( alpha. shuffled ( ) . randomElement ( ) !. utf8. first!)
57
+ }
58
+ }
59
+
60
+ // Attempt to create the directory
61
+ var retries : Int = 100
62
+ repeat {
63
+ stampSuffix ( template + length - 6 )
64
+ if _mkdir ( template) == 0 {
65
+ return template
66
+ }
67
+ retries = retries - 1
68
+ } while retries > 0
69
+
70
+ return nil
36
71
}
37
72
38
73
// int mkstemps(char *template, int suffixlen);
0 commit comments