Skip to content

Commit d74a13d

Browse files
committed
TSCLibc: add an implementation of mkdtemp for Windows
This adds an implementation of `mkdtemp` for Windows to accommodate swift-package-manager which uses this rather than Foundation.
1 parent 154af99 commit d74a13d

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed

Sources/TSCLibc/libc.swift

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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*.
3233
public 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

Comments
 (0)