diff options
Diffstat (limited to 'source/Host/windows/Windows.cpp')
-rw-r--r-- | source/Host/windows/Windows.cpp | 157 |
1 files changed, 106 insertions, 51 deletions
diff --git a/source/Host/windows/Windows.cpp b/source/Host/windows/Windows.cpp index 71bff7a9d2e2..2aebb10bcdd9 100644 --- a/source/Host/windows/Windows.cpp +++ b/source/Host/windows/Windows.cpp @@ -12,6 +12,9 @@ #include "lldb/Host/windows/windows.h" #include "lldb/Host/windows/win32.h" +#include "llvm/Support/ConvertUTF.h" + +#include <assert.h> #include <stdio.h> #include <stdarg.h> #include <string.h> @@ -27,6 +30,29 @@ extern "C" int _chdir(const char *path); } +namespace +{ +bool +utf8ToWide(const char *utf8, wchar_t *buf, size_t bufSize) +{ + const UTF8 *sourceStart = reinterpret_cast<const UTF8 *>(utf8); + size_t sourceLen = strlen(utf8) + 1 /* convert null too */; + UTF16 *target = reinterpret_cast<UTF16 *>(buf); + ConversionFlags flags = strictConversion; + return ConvertUTF8toUTF16(&sourceStart, sourceStart + sourceLen, &target, target + bufSize, flags) == conversionOK; +} + +bool +wideToUtf8(const wchar_t *wide, char *buf, size_t bufSize) +{ + const UTF16 *sourceStart = reinterpret_cast<const UTF16 *>(wide); + size_t sourceLen = wcslen(wide) + 1 /* convert null too */; + UTF8 *target = reinterpret_cast<UTF8 *>(buf); + ConversionFlags flags = strictConversion; + return ConvertUTF16toUTF8(&sourceStart, sourceStart + sourceLen, &target, target + bufSize, flags) == conversionOK; +} +} + int vasprintf(char **ret, const char *fmt, va_list ap) { char *buf; @@ -75,81 +101,90 @@ char* strcasestr(const char *s, const char* find) char* realpath(const char * name, char * resolved) { - char *retname = NULL; /* we will return this, if we fail */ + char *retname = NULL; /* SUSv3 says we must set `errno = EINVAL', and return NULL, * if `name' is passed as a NULL pointer. */ - if (name == NULL) + { errno = EINVAL; + return NULL; + } /* Otherwise, `name' must refer to a readable filesystem object, * if we are going to resolve its absolute path name. */ - - else if (access(name, 4) == 0) + wchar_t wideNameBuffer[PATH_MAX]; + wchar_t *wideName = wideNameBuffer; + if (!utf8ToWide(name, wideName, PATH_MAX)) { - /* If `name' didn't point to an existing entity, - * then we don't get to here; we simply fall past this block, - * returning NULL, with `errno' appropriately set by `access'. - * - * When we _do_ get to here, then we can use `_fullpath' to - * resolve the full path for `name' into `resolved', but first, - * check that we have a suitable buffer, in which to return it. - */ + errno = EINVAL; + return NULL; + } - if ((retname = resolved) == NULL) - { - /* Caller didn't give us a buffer, so we'll exercise the - * option granted by SUSv3, and allocate one. - * - * `_fullpath' would do this for us, but it uses `malloc', and - * Microsoft's implementation doesn't set `errno' on failure. - * If we don't do this explicitly ourselves, then we will not - * know if `_fullpath' fails on `malloc' failure, or for some - * other reason, and we want to set `errno = ENOMEM' for the - * `malloc' failure case. - */ - - retname = (char*) malloc(_MAX_PATH); - } + if (_waccess(wideName, 4) != 0) + return NULL; + + /* If `name' didn't point to an existing entity, + * then we don't get to here; we simply fall past this block, + * returning NULL, with `errno' appropriately set by `access'. + * + * When we _do_ get to here, then we can use `_fullpath' to + * resolve the full path for `name' into `resolved', but first, + * check that we have a suitable buffer, in which to return it. + */ - /* By now, we should have a valid buffer. - * If we don't, then we know that `malloc' failed, - * so we can set `errno = ENOMEM' appropriately. + if ((retname = resolved) == NULL) + { + /* Caller didn't give us a buffer, so we'll exercise the + * option granted by SUSv3, and allocate one. + * + * `_fullpath' would do this for us, but it uses `malloc', and + * Microsoft's implementation doesn't set `errno' on failure. + * If we don't do this explicitly ourselves, then we will not + * know if `_fullpath' fails on `malloc' failure, or for some + * other reason, and we want to set `errno = ENOMEM' for the + * `malloc' failure case. */ + retname = (char *)malloc(PATH_MAX); if (retname == NULL) + { errno = ENOMEM; + return NULL; + } + } - /* Otherwise, when we do have a valid buffer, - * `_fullpath' should only fail if the path name is too long. - */ + /* Otherwise, when we do have a valid buffer, + * `_fullpath' should only fail if the path name is too long. + */ - else if ((retname = _fullpath(retname, name, _MAX_PATH)) == NULL) - errno = ENAMETOOLONG; + wchar_t wideFullPathBuffer[PATH_MAX]; + wchar_t *wideFullPath; + if ((wideFullPath = _wfullpath(wideFullPathBuffer, wideName, PATH_MAX)) == NULL) + { + errno = ENAMETOOLONG; + return NULL; } - /* By the time we get to here, - * `retname' either points to the required resolved path name, - * or it is NULL, with `errno' set appropriately, either of which - * is our required return condition. - */ + // Do a LongPath<->ShortPath roundtrip so that case is resolved by OS + // FIXME: Check for failure + size_t initialLength = wcslen(wideFullPath); + GetShortPathNameW(wideFullPath, wideNameBuffer, PATH_MAX); + GetLongPathNameW(wideNameBuffer, wideFullPathBuffer, initialLength + 1); - if (retname != NULL) + // Convert back to UTF-8 + if (!wideToUtf8(wideFullPathBuffer, retname, PATH_MAX)) { - // Do a LongPath<->ShortPath roundtrip so that case is resolved by OS - int initialLength = strlen(retname); - TCHAR buffer[MAX_PATH]; - GetShortPathName(retname, buffer, MAX_PATH); - GetLongPathName(buffer, retname, initialLength + 1); - - // Force drive to be upper case - if (retname[1] == ':') - retname[0] = toupper(retname[0]); + errno = EINVAL; + return NULL; } + // Force drive to be upper case + if (retname[1] == ':') + retname[0] = toupper(retname[0]); + return retname; } @@ -167,7 +202,27 @@ char* basename(char *path) // use _getcwd() instead of GetCurrentDirectory() because it updates errno char* getcwd(char* path, int max) { - return _getcwd(path, max); + assert(path == NULL || max <= PATH_MAX); + wchar_t wpath[PATH_MAX]; + if (wchar_t *wresult = _wgetcwd(wpath, PATH_MAX)) + { + // Caller is allowed to pass in NULL for `path`. + // In that case, we're supposed to allocate a + // buffer on the caller's behalf. + if (path == NULL) + { + max = UNI_MAX_UTF8_BYTES_PER_CODE_POINT * wcslen(wresult) + 1; + path = (char *)malloc(max); + if (path == NULL) + { + errno = ENOMEM; + return NULL; + } + } + if (wideToUtf8(wresult, path, max)) + return path; + } + return NULL; } // use _chdir() instead of SetCurrentDirectory() because it updates errno |