Skip to content

Commit ff08ca3

Browse files
committed
Use Cch API more cleanly, abstract string munging into a computed variable
1 parent 64b66f3 commit ff08ca3

File tree

3 files changed

+76
-32
lines changed

3 files changed

+76
-32
lines changed

Sources/Testing/ExitTests/SpawnProcess.swift

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -297,18 +297,7 @@ func spawnExecutable(
297297
// unlikely to be deleted, one hopes).
298298
//
299299
// SEE: https://devblogs.microsoft.com/oldnewthing/20101109-00/?p=12323
300-
var workingDirectoryPath = UnsafeMutableBufferPointer<wchar_t>.allocate(capacity: Int(MAX_PATH))
301-
defer {
302-
workingDirectoryPath.deallocate()
303-
}
304-
let systemDrive = Environment.variable(named: "SYSTEMDRIVE") ?? "C:"
305-
systemDrive.withCString(encodedAs: UTF16.self) { systemDrive in
306-
wcscpy_s(workingDirectoryPath.baseAddress!, workingDirectoryPath.count, systemDrive)
307-
let rAddBackslash = PathCchAddBackslashEx(workingDirectoryPath.baseAddress!, workingDirectoryPath.count, nil, nil)
308-
guard rAddBackslash == S_OK || rAddBackslash == S_FALSE else {
309-
fatalError("Unexpected error when normalizing system drive path '\(systemDrive)': HRESULT(\(rAddBackslash))")
310-
}
311-
}
300+
let workingDirectoryPath = rootDirectoryPath
312301

313302
var flags = DWORD(CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT)
314303
#if DEBUG
@@ -318,30 +307,32 @@ func spawnExecutable(
318307

319308
return try commandLine.withCString(encodedAs: UTF16.self) { commandLine in
320309
try environ.withCString(encodedAs: UTF16.self) { environ in
321-
var processInfo = PROCESS_INFORMATION()
322-
323-
guard CreateProcessW(
324-
nil,
325-
.init(mutating: commandLine),
326-
nil,
327-
nil,
328-
true, // bInheritHandles
329-
flags,
330-
.init(mutating: environ),
331-
workingDirectoryPath,
332-
startupInfo.pointer(to: \.StartupInfo)!,
333-
&processInfo
334-
) else {
335-
throw Win32Error(rawValue: GetLastError())
336-
}
310+
try workingDirectoryPath.withCString(encodedAs: UTF16.self) { workingDirectoryPath in
311+
var processInfo = PROCESS_INFORMATION()
312+
313+
guard CreateProcessW(
314+
nil,
315+
.init(mutating: commandLine),
316+
nil,
317+
nil,
318+
true, // bInheritHandles
319+
flags,
320+
.init(mutating: environ),
321+
workingDirectoryPath,
322+
startupInfo.pointer(to: \.StartupInfo)!,
323+
&processInfo
324+
) else {
325+
throw Win32Error(rawValue: GetLastError())
326+
}
337327

338328
#if DEBUG
339-
// Resume the process.
340-
_ = ResumeThread(processInfo.hThread!)
329+
// Resume the process.
330+
_ = ResumeThread(processInfo.hThread!)
341331
#endif
342332

343-
_ = CloseHandle(processInfo.hThread)
344-
return processInfo.hProcess!
333+
_ = CloseHandle(processInfo.hThread)
334+
return processInfo.hProcess!
335+
}
345336
}
346337
}
347338
}

Sources/Testing/Support/FileHandle.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,4 +719,37 @@ func setFD_CLOEXEC(_ flag: Bool, onFileDescriptor fd: CInt) throws {
719719
}
720720
}
721721
#endif
722+
723+
/// The path to the root directory of the boot volume.
724+
///
725+
/// On Windows, this string is usually of the form `"C:\"`. On UNIX-like
726+
/// platforms, it is always equal to `"/"`.
727+
let rootDirectoryPath: String = {
728+
#if os(Windows)
729+
if let systemDrive = Environment.variable(named: "SYSTEMDRIVE")?.utf16 {
730+
// Copy the system drive string with room for up to "C:\" and a NUL.
731+
var buffer = UnsafeMutableBufferPointer<wchar_t>.allocate(capacity: systemDrive.count + 4)
732+
defer {
733+
buffer.deallocate()
734+
}
735+
buffer.initialize(fromContentsOf: systemDrive)
736+
buffer[systemDrive.count] = 0
737+
738+
// On the assumption that the value of %SYSTEMDRIVE% is "C:" or similar,
739+
// ensure a trailing slash is added to refer to the root directory. If
740+
// somebody decides to set this environment variable to something
741+
// nonsensical or to a deeper path, we should accept it silently.
742+
let rAddBackslash = PathCchAddBackslashEx(buffer.baseAddress!, buffer.count, nil, nil)
743+
if rAddBackslash == S_OK || rAddBackslash == S_FALSE,
744+
let result = String.decodeCString(buffer.baseAddress!, as: UTF16.self)?.result {
745+
return result
746+
}
747+
}
748+
// We weren't able to get a path, so fall back to "C:\" on the assumption that
749+
// it's the common case and most likely correct.
750+
return #"C:\"#
751+
#else
752+
return "/"
753+
#endif
754+
}()
722755
#endif

Tests/TestingTests/Support/FileHandleTests.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,26 @@ struct FileHandleTests {
201201
#endif
202202
}
203203
#endif
204+
205+
@Test("Root directory path is correct")
206+
func rootDirectoryPathIsCorrect() async {
207+
#if os(Windows)
208+
#if !SWT_NO_EXIT_TESTS
209+
await #expect(processExitsWith: .success) {
210+
#expect(Environment.setVariable(nil, named: "SYSTEMDRIVE"))
211+
#expect(rootDirectoryPath == #"C:\"#)
212+
213+
#expect(Environment.setVariable("Q:", named: "SYSTEMDRIVE"))
214+
#expect(rootDirectoryPath == #"Q:\"#)
215+
216+
#expect(Environment.setVariable("Q:\abc123", named: "SYSTEMDRIVE"))
217+
#expect(rootDirectoryPath == #"Q:\abc123\"#)
218+
}
219+
#endif
220+
#else
221+
#expect(rootDirectoryPath == "/")
222+
#endif
223+
}
204224
}
205225

206226
// MARK: - Fixtures

0 commit comments

Comments
 (0)