@@ -146,6 +146,81 @@ _swift_initRootPath(void *)
146
146
}
147
147
}
148
148
149
+ #if _WIN32
150
+ // / Map an NT-style filename to a Win32 filename.
151
+ // /
152
+ // / We can't use GetFinalPathNameByHandle() because there's no way to obtain
153
+ // / a handle (at least, not without using the internal NtCreateFile() API, which
154
+ // / we aren't supposed to be using). Additionally, that function would resolve
155
+ // / symlinks, which we don't want to do here.
156
+ // /
157
+ // / As a result, we use the approach demonstrated here:
158
+ // /
159
+ // / https://learn.microsoft.com/en-us/windows/win32/memory/obtaining-a-file-name-from-a-file-handle
160
+ // /
161
+ // / @param pszFilename The NT-style filename to convert.
162
+ // /
163
+ // / @result A string, allocated using std::malloc(), containing the Win32-style
164
+ // / filename.
165
+ LPWSTR
166
+ _swift_win32NameFromNTName (LPWSTR pszFilename) {
167
+ DWORD dwLen = GetLogicalDriveStringsW (0 , NULL );
168
+ if (!dwLen)
169
+ return NULL ;
170
+
171
+ LPWSTR lpDriveStrings = (LPWSTR)std::malloc (dwLen * sizeof (WCHAR));
172
+ if (!lpDriveStrings)
173
+ return NULL ;
174
+
175
+ DWORD dwRet = GetLogicalDriveStringsW (dwLen, lpDriveStrings);
176
+ if (!dwRet)
177
+ return NULL ;
178
+
179
+ LPWSTR pszDrive = lpDriveStrings;
180
+ while (*pszDrive) {
181
+ size_t len = wcslen (pszDrive);
182
+ if (len && pszDrive[len - 1 ] == ' \\ ' )
183
+ pszDrive[len - 1 ] = 0 ;
184
+
185
+ WCHAR ntPath[4096 ];
186
+ dwRet = QueryDosDeviceW (pszDrive, ntPath, 4096 );
187
+ if (dwRet) {
188
+ size_t ntLen = wcslen (ntPath);
189
+
190
+ if (_wcsnicmp (pszFilename, ntPath, ntLen) == 0
191
+ && pszFilename[ntLen] == ' \\ ' ) {
192
+ size_t fnLen = wcslen (pszFilename);
193
+ size_t driveLen = wcslen (pszDrive);
194
+ size_t pathLen = fnLen - ntLen;
195
+ size_t newLen = driveLen + pathLen + 1 ;
196
+ LPWSTR pszWin32Name = (LPWSTR)std::malloc (newLen * sizeof (WCHAR));
197
+ if (!pszWin32Name) {
198
+ std::free (lpDriveStrings);
199
+ return NULL ;
200
+ }
201
+
202
+ LPWSTR ptr = pszWin32Name;
203
+ memcpy (ptr, pszDrive, driveLen * sizeof (WCHAR));
204
+ ptr += driveLen;
205
+ memcpy (ptr, pszFilename + ntLen, pathLen * sizeof (WCHAR));
206
+ ptr += pathLen;
207
+ *ptr = 0 ;
208
+
209
+ std::free (lpDriveStrings);
210
+
211
+ return pszWin32Name;
212
+ }
213
+ }
214
+
215
+ pszDrive += len + 1 ;
216
+ }
217
+
218
+ std::free (lpDriveStrings);
219
+
220
+ return _wcsdup (pszFilename);
221
+ }
222
+ #endif
223
+
149
224
}
150
225
151
226
SWIFT_RUNTIME_EXPORT
@@ -241,22 +316,32 @@ _swift_initRuntimePath(void *) {
241
316
LPWSTR lpFilename = (LPWSTR)std::malloc (dwBufSize * sizeof (WCHAR));
242
317
243
318
DWORD dwRet = GetMappedFileNameW (GetCurrentProcess (),
244
- _swift_initRuntimePath,
319
+ ( void *) _swift_initRuntimePath,
245
320
lpFilename,
246
321
dwBufSize);
247
322
if (!dwRet) {
248
323
swift::fatalError (/* flags = */ 0 ,
249
324
" Unable to obtain Swift runtime path\n " );
250
325
}
251
326
252
- runtimePath = swift::win32::copyUTF8FromWide (lpFilename);
327
+ // GetMappedFileNameW() returns an NT-style path, not a Win32 path; that is,
328
+ // it starts with \Device\DeviceName rather than a drive letter.
329
+ LPWSTR lpWin32Filename = _swift_win32NameFromNTName (lpFilename);
330
+ if (!lpWin32Filename) {
331
+ swift::fatalError (/* flags = */ 0 ,
332
+ " Unable to obtain Win32 path for Swift runtime\n " );
333
+ }
334
+
335
+ std::free (lpFilename);
336
+
337
+ runtimePath = swift::win32::copyUTF8FromWide (lpWin32Filename);
253
338
if (!runtimePath) {
254
339
swift::fatalError (/* flags = */ 0 ,
255
340
" Unable to convert Swift runtime path to UTF-8: %lx, %d\n " ,
256
341
::GetLastError (), errno);
257
342
}
258
343
259
- free (lpFilename );
344
+ std:: free (lpWin32Filename );
260
345
}
261
346
#endif
262
347
0 commit comments