@@ -29,10 +29,45 @@ public func realpath(
2929}
3030
3131// char *mkdtemp(char *template);
32+ // NOTE(compnerd) this is unsafe! This assumes that the template is *ASCII*.
3233public func mkdtemp(
3334 _ template: UnsafeMutablePointer < CChar > ?
3435) -> 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
3671}
3772
3873// int mkstemps(char *template, int suffixlen);
0 commit comments