@@ -312,6 +312,43 @@ int statvfs(const wchar_t *p, StatVFS *buf) {
312
312
}
313
313
314
314
wchar_t *getcwd (wchar_t *buff, size_t size) { return _wgetcwd (buff, size); }
315
+
316
+ wchar_t *realpath (const wchar_t *path, wchar_t *resolved_name) {
317
+ // Only expected to be used with us allocating the buffer.
318
+ _LIBCPP_ASSERT (resolved_name == nullptr ,
319
+ " Windows realpath() assumes a null resolved_name" );
320
+
321
+ WinHandle h (path, FILE_READ_ATTRIBUTES, 0 );
322
+ if (!h) {
323
+ set_errno ();
324
+ return nullptr ;
325
+ }
326
+ size_t buff_size = MAX_PATH + 10 ;
327
+ std::unique_ptr<wchar_t , decltype (&::free)> buff (
328
+ static_cast <wchar_t *>(malloc (buff_size * sizeof (wchar_t ))), &::free);
329
+ DWORD retval = GetFinalPathNameByHandleW (
330
+ h, buff.get (), buff_size, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
331
+ if (retval > buff_size) {
332
+ buff_size = retval;
333
+ buff.reset (static_cast <wchar_t *>(malloc (buff_size * sizeof (wchar_t ))));
334
+ retval = GetFinalPathNameByHandleW (h, buff.get (), buff_size,
335
+ FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
336
+ }
337
+ if (!retval) {
338
+ set_errno ();
339
+ return nullptr ;
340
+ }
341
+ wchar_t *ptr = buff.get ();
342
+ if (!wcsncmp (ptr, L" \\\\ ?\\ " , 4 )) {
343
+ if (ptr[5 ] == ' :' ) { // \\?\X: -> X:
344
+ memmove (&ptr[0 ], &ptr[4 ], (wcslen (&ptr[4 ]) + 1 ) * sizeof (wchar_t ));
345
+ } else if (!wcsncmp (&ptr[4 ], L" UNC\\ " , 4 )) { // \\?\UNC\server -> \\server
346
+ wcscpy (&ptr[0 ], L" \\\\ " );
347
+ memmove (&ptr[2 ], &ptr[8 ], (wcslen (&ptr[8 ]) + 1 ) * sizeof (wchar_t ));
348
+ }
349
+ }
350
+ return buff.release ();
351
+ }
315
352
#else
316
353
int symlink_file (const char *oldname, const char *newname) {
317
354
return ::symlink (oldname, newname);
@@ -328,6 +365,7 @@ using ::link;
328
365
using ::lstat;
329
366
using ::mkdir;
330
367
using ::open;
368
+ using ::realpath;
331
369
using ::remove;
332
370
using ::rename;
333
371
using ::stat;
0 commit comments