@@ -10,7 +10,7 @@ import aws.smithy.kotlin.runtime.time.Clock
1010import aws.smithy.kotlin.runtime.util.PlatformProvider
1111import kotlinx.cinterop.*
1212import kotlinx.coroutines.withContext
13- import platform.posix._wunlink // to delete the temp file afterwards
13+ import platform.posix._wunlink
1414import platform.windows.*
1515
1616@OptIn(ExperimentalForeignApi ::class )
@@ -25,7 +25,7 @@ internal actual suspend fun executeCommand(
2525 clock : Clock ,
2626): Pair <Int , String > = withContext(SdkDispatchers .IO ) {
2727 memScoped {
28- // 1) Make a temp file to capture stdout+stderr
28+ // 1) temp path + file
2929 val tmpDirBuf = allocArray<UShortVar >(MAX_PATH )
3030 val gotTmp = GetTempPathW (MAX_PATH .toUInt(), tmpDirBuf)
3131 if (gotTmp == 0u ) error(" GetTempPathW failed" )
@@ -36,65 +36,62 @@ internal actual suspend fun executeCommand(
3636 if (gotName == 0u ) error(" GetTempFileNameW failed" )
3737 val outPath: String = tmpNameBuf.toKString()
3838
39- // 2) Create the output file (child inherits this handle )
39+ // 2) create output (inherit )
4040 val sa = alloc<SECURITY_ATTRIBUTES >().apply {
4141 nLength = sizeOf<SECURITY_ATTRIBUTES >().toUInt()
4242 bInheritHandle = TRUE
4343 lpSecurityDescriptor = null
4444 }
4545
46- val hOut: HANDLE = CreateFileW (
47- /* lpFileName = */ outPath,
48- /* dwDesiredAccess = */ GENERIC_WRITE .toUInt(),
49- /* dwShareMode = */ (FILE_SHARE_READ or FILE_SHARE_WRITE ),
50- /* lpSecurityAttributes = */ sa.ptr,
46+ // NOTE: CreateFileW returns HANDLE? in Kotlin/Native bindings
47+ val hOut: HANDLE ? = CreateFileW (
48+ /* lpFileName = */ outPath,
49+ /* dwDesiredAccess = */ GENERIC_WRITE .toUInt(),
50+ /* dwShareMode = */ (FILE_SHARE_READ or FILE_SHARE_WRITE ).toUInt(),
51+ /* lpSecurityAttributes = */ sa.ptr,
5152 /* dwCreationDisposition = */ CREATE_ALWAYS ,
5253 /* dwFlagsAndAttributes = */ FILE_ATTRIBUTE_NORMAL .toUInt(),
53- /* hTemplateFile = */ null ,
54+ /* hTemplateFile = */ null ,
5455 )
5556 if (hOut == INVALID_HANDLE_VALUE ) error(" CreateFileW failed for temp output (GetLastError=${GetLastError ()} )" )
5657
5758 try {
58- // 3) Resolve the shell (prefer %ComSpec%)
59+ // 3) resolve shell
5960 val comspecBuf = allocArray<UShortVar >(MAX_PATH )
6061 val comspecLen = GetEnvironmentVariableW (" ComSpec" , comspecBuf, MAX_PATH .toUInt())
61- val cmdExe: String = if (comspecLen > 0u ) {
62- comspecBuf.toKString()
63- } else {
64- " C:\\ Windows\\ System32\\ cmd.exe"
65- }
62+ val cmdExe: String = if (comspecLen > 0u ) comspecBuf.toKString() else " C:\\ Windows\\ System32\\ cmd.exe"
6663
67- // Build mutable command line buffer for CreateProcessW
68- // CreateProcessW expects the *command line* buffer to be mutable (it may write into it)
64+ // mutable command line buffer
6965 val cmdLineStr = " /C $command "
70- val cmdLineBuf = cmdLineStr.wideCString(this ) // writable buffer from MemScope
66+ val cmdLineBuf = cmdLineStr.wideCString(this )
7167
72- // 4) Launch child with redirected stdout/stderr
68+ // 4) launch with redirected stdio
7369 val si = alloc<STARTUPINFOW >().apply {
7470 cb = sizeOf<STARTUPINFOW >().toUInt()
7571 dwFlags = STARTF_USESTDHANDLES .toUInt()
7672 hStdOutput = hOut
7773 hStdError = hOut
78- hStdInput = GetStdHandle (STD_INPUT_HANDLE )
74+ // GetStdHandle expects a DWORD/UInt
75+ hStdInput = GetStdHandle (STD_INPUT_HANDLE .toUInt())
7976 }
8077 val pi = alloc<PROCESS_INFORMATION >()
8178
8279 val created = CreateProcessW (
83- /* lpApplicationName = */ cmdExe,
84- /* lpCommandLine = */ cmdLineBuf, // mutable
85- /* lpProcessAttributes = */ null ,
86- /* lpThreadAttributes = */ null ,
87- /* bInheritHandles = */ TRUE ,
88- /* dwCreationFlags = */ CREATE_NO_WINDOW .toUInt(),
89- /* lpEnvironment = */ null ,
90- /* lpCurrentDirectory = */ null ,
91- /* lpStartupInfo = */ si.ptr,
92- /* lpProcessInformation= */ pi.ptr,
80+ /* lpApplicationName = */ cmdExe,
81+ /* lpCommandLine = */ cmdLineBuf,
82+ /* lpProcessAttributes = */ null ,
83+ /* lpThreadAttributes = */ null ,
84+ /* bInheritHandles = */ TRUE ,
85+ /* dwCreationFlags = */ CREATE_NO_WINDOW .toUInt(),
86+ /* lpEnvironment = */ null ,
87+ /* lpCurrentDirectory = */ null ,
88+ /* lpStartupInfo = */ si.ptr,
89+ /* lpProcessInformation = */ pi.ptr,
9390 )
9491 if (created == 0 ) error(" CreateProcessW failed (GetLastError=${GetLastError ()} )" )
9592
9693 try {
97- // 5) Wait up to timeout; if it times out, terminate
94+ // 5) wait + timeout
9895 val waitRc: UInt = WaitForSingleObject (pi.hProcess, timeoutMillis.toUInt())
9996 if (waitRc == WAIT_TIMEOUT .toUInt()) {
10097 TerminateProcess (pi.hProcess, 124u )
@@ -105,24 +102,22 @@ internal actual suspend fun executeCommand(
105102 error(" Process timed out after ${timeoutMillis} ms" )
106103 }
107104
108- // 6) Get exit code
105+ // 6) exit code
109106 val exitCodeVar = alloc<DWORDVar >()
110107 if (GetExitCodeProcess (pi.hProcess, exitCodeVar.ptr) == 0 ) {
111- // If this fails, propagate a generic error but still try to read output
112- // (fall through with exitCode = -1)
113108 exitCodeVar.value = 0xFFFFFFFFu
114109 }
115110 val exitCode = exitCodeVar.value.toInt()
116111
117- // 7) Read back the temp file ( bounded)
118- val hIn: HANDLE = CreateFileW (
119- /* lpFileName = */ outPath,
120- /* dwDesiredAccess = */ GENERIC_READ .toUInt(),
121- /* dwShareMode = */ (FILE_SHARE_READ or FILE_SHARE_WRITE ),
122- /* lpSecurityAttributes = */ null ,
112+ // 7) read back bounded
113+ val hIn: HANDLE ? = CreateFileW (
114+ /* lpFileName = */ outPath,
115+ /* dwDesiredAccess = */ GENERIC_READ .toUInt(),
116+ /* dwShareMode = */ (FILE_SHARE_READ or FILE_SHARE_WRITE ).toUInt( ),
117+ /* lpSecurityAttributes = */ null ,
123118 /* dwCreationDisposition = */ OPEN_EXISTING ,
124119 /* dwFlagsAndAttributes = */ FILE_ATTRIBUTE_NORMAL .toUInt(),
125- /* hTemplateFile = */ null ,
120+ /* hTemplateFile = */ null ,
126121 )
127122 if (hIn == INVALID_HANDLE_VALUE ) {
128123 _wunlink (outPath.wideCString(this ))
@@ -139,7 +134,6 @@ internal actual suspend fun executeCommand(
139134 while (true ) {
140135 val toRead = minOf(buf.size.toLong(), maxOutputLengthBytes - total).toInt()
141136 if (toRead <= 0 ) {
142- // ensure cleanup before throwing
143137 CloseHandle (hIn)
144138 _wunlink (outPath.wideCString(this ))
145139 throw CredentialsProviderException (" Process output exceeded limit of $maxOutputLengthBytes bytes" )
0 commit comments