Skip to content

Commit d92486a

Browse files
committed
Implement realpath & mkdtemp on Windows
1 parent 9261988 commit d92486a

File tree

1 file changed

+64
-17
lines changed

1 file changed

+64
-17
lines changed

Sources/TSCLibc/libc.swift

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,72 @@
2020
@_exported import TSCclibc
2121

2222
#if os(Windows)
23+
private extension String {
24+
func withCStringW<Result>(_ body: (UnsafePointer<wchar_t>, Int) throws -> Result) rethrows -> Result {
25+
return try withCString(encodedAs: UTF16.self) {
26+
let capacity: Int = wcslen($0) + 1
27+
return try $0.withMemoryRebound(to: wchar_t.self, capacity: capacity) {
28+
try body($0, capacity)
29+
}
30+
}
31+
}
32+
}
33+
34+
private extension UnsafeMutablePointer where Pointee == CChar {
35+
func assign(from source: UnsafePointer<wchar_t>) {
36+
String(decodingCString: source, as: UTF16.self).utf8CString.withUnsafeBytes {
37+
assign(from: $0.bindMemory(to: CChar.self).baseAddress!,
38+
count: $0.count)
39+
}
40+
}
41+
}
42+
2343
// char *realpath(const char *path, char *resolved_path);
2444
public func realpath(
2545
_ path: String,
2646
_ resolvedPath: UnsafeMutablePointer<CChar>?
2747
) -> UnsafeMutablePointer<CChar>? {
28-
fatalError("realpath is unimplemented")
48+
let result: UnsafeMutablePointer<CChar>
49+
if let resolvedPath = resolvedPath {
50+
result = resolvedPath
51+
} else {
52+
result = UnsafeMutablePointer<CChar>.allocate(capacity: Int(MAX_PATH))
53+
}
54+
return String(cString: result).withCStringW { resultW, capacity in
55+
return path.withCStringW { pathW, _ in
56+
guard _wfullpath(UnsafeMutablePointer(mutating: resultW), pathW, capacity) != nil else {
57+
return nil
58+
}
59+
result.assign(from: resultW)
60+
return result
61+
}
62+
}
2963
}
3064

3165
// char *mkdtemp(char *template);
3266
public func mkdtemp(
3367
_ template: UnsafeMutablePointer<CChar>?
3468
) -> UnsafeMutablePointer<CChar>? {
35-
fatalError("mkdtemp is unimplemented")
69+
guard let template = template else { return nil }
70+
71+
func createDirectory() -> UnsafeMutablePointer<CChar>? {
72+
let path = String(String(cString: template).dropLast(6) +
73+
String(Int.random(in: 1..<1000000)))
74+
return path.withCStringW { pathW, _ in
75+
guard CreateDirectoryW(pathW, nil) else {
76+
return nil
77+
}
78+
template.assign(from: pathW)
79+
return template
80+
}
81+
}
82+
83+
var result: UnsafeMutablePointer<CChar>?
84+
repeat {
85+
result = createDirectory()
86+
} while result == nil && Int32(GetLastError()) == ERROR_ALREADY_EXISTS
87+
88+
return result
3689
}
3790

3891
// int mkstemps(char *template, int suffixlen);
@@ -41,23 +94,17 @@ public func mkstemps(
4194
_ suffixlen: Int32
4295
) -> Int32 {
4396
guard let template = template else { return -EINVAL }
44-
return String(cString: template).withCString(encodedAs: UTF16.self) {
45-
let capacity: Int = wcslen($0) + 1
46-
return $0.withMemoryRebound(to: wchar_t.self, capacity: capacity) {
47-
guard _wmktemp_s(UnsafeMutablePointer(mutating: $0), capacity) == 0 else {
48-
return -EINVAL
49-
}
97+
return String(cString: template).withCStringW { templateW, capacity in
98+
guard _wmktemp_s(UnsafeMutablePointer(mutating: templateW), capacity) == 0 else {
99+
return -EINVAL
100+
}
50101

51-
var fd: Int32 = -1
52-
_wsopen_s(&fd, $0, _O_RDWR | _O_CREAT | _O_BINARY | _O_NOINHERIT,
53-
_SH_DENYNO, _S_IREAD | _S_IWRITE)
102+
var fd: Int32 = -1
103+
_wsopen_s(&fd, templateW, _O_RDWR | _O_CREAT | _O_BINARY | _O_NOINHERIT,
104+
_SH_DENYNO, _S_IREAD | _S_IWRITE)
54105

55-
String(decodingCString: $0, as: UTF16.self).utf8CString.withUnsafeBytes {
56-
template.assign(from: $0.bindMemory(to: CChar.self).baseAddress!,
57-
count: $0.count)
58-
}
59-
return fd
60-
}
106+
template.assign(from: templateW)
107+
return fd
61108
}
62109
}
63110
#endif

0 commit comments

Comments
 (0)