@@ -28,6 +28,13 @@ public func realpath(
2828 fatalError ( " realpath is unimplemented " )
2929}
3030
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+
3138// char *mkdtemp(char *template);
3239// NOTE(compnerd) this is unsafe! This assumes that the template is *ASCII*.
3340public func mkdtemp(
@@ -50,17 +57,10 @@ public func mkdtemp(
5057 return nil
5158 }
5259
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-
6060 // Attempt to create the directory
6161 var retries : Int = 100
6262 repeat {
63- stampSuffix ( template + length - 6 )
63+ __randname ( template + length - 6 )
6464 if _mkdir ( template) == 0 {
6565 return template
6666 }
@@ -75,24 +75,35 @@ public func mkstemps(
7575 _ template: UnsafeMutablePointer < CChar > ? ,
7676 _ suffixlen: Int32
7777) -> 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 {
94102 return fd
95103 }
96- }
104+ retries = retries - 1
105+ } while retries > 0
106+
107+ return - 1
97108}
98109#endif
0 commit comments