@@ -28,6 +28,13 @@ public func realpath(
28
28
fatalError ( " realpath is unimplemented " )
29
29
}
30
30
31
+ private func __randname( _ buffer: UnsafeMutablePointer < CChar > ) {
32
+ let alpha = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
33
+ _ = ( 0 ..< 6 ) . map { index in
34
+ buffer [ index] = CChar ( alpha. shuffled ( ) . randomElement ( ) !. utf8. first!)
35
+ }
36
+ }
37
+
31
38
// char *mkdtemp(char *template);
32
39
// NOTE(compnerd) this is unsafe! This assumes that the template is *ASCII*.
33
40
public func mkdtemp(
@@ -50,17 +57,10 @@ public func mkdtemp(
50
57
return nil
51
58
}
52
59
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
60
// Attempt to create the directory
61
61
var retries : Int = 100
62
62
repeat {
63
- stampSuffix ( template + length - 6 )
63
+ __randname ( template + length - 6 )
64
64
if _mkdir ( template) == 0 {
65
65
return template
66
66
}
@@ -75,24 +75,35 @@ public func mkstemps(
75
75
_ template: UnsafeMutablePointer < CChar > ? ,
76
76
_ suffixlen: Int32
77
77
) -> Int32 {
78
- guard let template = template else { return - EINVAL }
79
- return String ( cString: template) . withCString ( encodedAs: UTF16 . self) {
80
- let capacity : Int = wcslen ( $0) + 1
81
- return $0. withMemoryRebound ( to: wchar_t. self, capacity: capacity) {
82
- guard _wmktemp_s ( UnsafeMutablePointer ( mutating: $0) , capacity) == 0 else {
83
- return - EINVAL
84
- }
85
-
86
- var fd : Int32 = - 1
87
- _wsopen_s ( & fd, $0, _O_RDWR | _O_CREAT | _O_BINARY | _O_NOINHERIT,
88
- _SH_DENYNO, _S_IREAD | _S_IWRITE)
89
-
90
- String ( decodingCString: $0, as: UTF16 . self) . utf8CString. withUnsafeBytes {
91
- template. assign ( from: $0. bindMemory ( to: CChar . self) . baseAddress!,
92
- count: $0. count)
93
- }
78
+ // Although the signature of the function is `char *(*)(char *)`, the C
79
+ // library treats it as `char *(*)(char * _Nonull)`. Most implementations
80
+ // will simply use and trigger a segmentation fault on x86 (and similar faults
81
+ // on other architectures) when the memory is accessed. This roughly emulates
82
+ // that by terminating in the case even though it is possible for us to return
83
+ // an error.
84
+ guard let template = template else { fatalError ( ) }
85
+
86
+ let length : Int = strlen ( template)
87
+
88
+ // Validate the precondition: the template must terminate with 6 `X` which
89
+ // will be filled in to generate a unique directory.
90
+ guard length >= 6 , memcmp ( template + length - Int( suffixlen) - 6 , " XXXXXX " , 6 ) == 0 else {
91
+ _set_errno ( EINVAL)
92
+ return - 1
93
+ }
94
+
95
+ // Attempt to create file
96
+ var retries : Int = 100
97
+ repeat {
98
+ __randname ( template + length - Int( suffixlen) - 6 )
99
+ var fd : CInt = - 1
100
+ if _sopen_s ( & fd, template, _O_RDWR | _O_CREAT | _O_BINARY | _O_NOINHERIT,
101
+ _SH_DENYNO, _S_IREAD | _S_IWRITE) == 0 {
94
102
return fd
95
103
}
96
- }
104
+ retries = retries - 1
105
+ } while retries > 0
106
+
107
+ return - 1
97
108
}
98
109
#endif
0 commit comments