diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index ba6f64ad8..eb35137bd 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -1,4 +1,7 @@ -#include "getusername.h" +//! @file getusername.cpp +//! @author Andrew Schwartzmeyer +//! @brief Implements GetUserName Win32 API + #include #include #include @@ -8,66 +11,62 @@ #include #include #include +#include "getusername.h" -/* - GetUserNameW function - - https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx - - Retrieves the name of the user associated with the current thread. - - Parameters - - lpBuffer [out] - - A pointer to the buffer to receive the user's logon name. If this - buffer is not large enough to contain the entire user name, the - function fails. A buffer size of (UNLEN + 1) characters will hold - the maximum length user name including the terminating null - character. UNLEN is defined in Lmcons.h. - - lpnSize [in, out] - - On input, this variable specifies the size of the lpBuffer buffer, - in TCHARs. On output, the variable receives the number of TCHARs - copied to the buffer, including the terminating null character. - - Note that TCHAR is WCHAR here because UNICODE is defined, and so a - TCHAR is a byte. - - https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx#CHAR - - If lpBuffer is too small, the function fails and GetLastError - returns ERROR_INSUFFICIENT_BUFFER. This parameter receives the - required buffer size, including the terminating null character. - - - Sets errno to: - ERROR_INVALID_PARAMETER - parameter is not valid - ERROR_BAD_ENVIRONMENT - locale is not UTF-8 - ERROR_TOO_MANY_OPEN_FILES - already have the maximum allowed number of open files - ERROR_NO_ASSOCIATION - calling process has no controlling terminal - ERROR_INSUFFICIENT_BUFFER - buffer not large enough to hold username string - ERROR_NO_SUCH_USER - there was no corresponding entry in the utmp-file - ERROR_OUTOFMEMORY - insufficient memory to allocate passwd structure - ERROR_NO_ASSOCIATION - standard input didn't refer to a terminal - ERROR_INVALID_FUNCTION - getlogin_r() returned an unrecognized error code - - Return value - - If the function succeeds, the return value is a nonzero value, and - the variable pointed to by lpnSize contains the number of TCHARs - copied to the buffer specified by lpBuffer, including the - terminating null character. - - If the function fails, the return value is zero. To get extended - error information, call GetLastError. -*/ -BOOL GetUserNameW(WCHAR_T *lpBuffer, LPDWORD lpnSize) +//! @brief GetUserName retrieves the name of the user associated with +//! the current thread. +//! +//! GetUserNameW is the Unicode variation. See [MSDN documentation]. +//! +//! @param[out] lpBuffer +//! @parblock +//! A pointer to the buffer to receive the user's +//! logon name. If this buffer is not large enough to contain the +//! entire user name, the function fails. +//! +//! WCHAR_T* is a Unicode [LPTSTR]. +//! @endparblock +//! +//! @param[in, out] lpnSize +//! @parblock +//! On input, this variable specifies the size of the lpBuffer buffer, +//! in TCHARs. On output, the variable receives the number of TCHARs +//! copied to the buffer, including the terminating null character. +//! +//! TCHAR is a Unicode 16-bit [WCHAR]. +//! +//! If lpBuffer is too small, the function fails and GetLastError +//! returns ERROR_INSUFFICIENT_BUFFER. This parameter receives the +//! required buffer size, including the terminating null character. +//! @endparblock +//! +//! @exception errno Passes these errors via errno to GetLastError: +//! - ERROR_INVALID_PARAMETER: parameter is not valid +//! - ERROR_BAD_ENVIRONMENT: locale is not UTF-8 +//! - ERROR_TOO_MANY_OPEN_FILES: already have the maximum allowed number of open files +//! - ERROR_NO_ASSOCIATION: calling process has no controlling terminal +//! - ERROR_INSUFFICIENT_BUFFER: buffer not large enough to hold username string +//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file +//! - ERROR_OUTOFMEMORY: insufficient memory to allocate passwd structure +//! - ERROR_NO_ASSOCIATION: standard input didn't refer to a terminal +//! - ERROR_INVALID_FUNCTION: getlogin_r() returned an unrecognized error code +//! +//! @retval 1 If the function succeeds, the return value is a nonzero +//! value, and the variable pointed to by lpnSize contains the number +//! of TCHARs copied to the buffer specified by lpBuffer, including +//! the terminating null character. +//! +//! @retval 0 If the function fails, the return value is zero. To get +//! extended error information, call GetLastError. +//! +//! [MSDN documentation]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx +//! [WCHAR]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx#WCHAR +//! [LPTSTR]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx#LPTSTR +BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) { const std::string utf8 = "UTF-8"; - errno = 0; + errno = FALSE; // Check parameters if (!lpBuffer || !lpnSize) { @@ -80,14 +79,14 @@ BOOL GetUserNameW(WCHAR_T *lpBuffer, LPDWORD lpnSize) // Check that locale is UTF-8 if (nl_langinfo(CODESET) != utf8) { errno = ERROR_BAD_ENVIRONMENT; - return 0; + return FALSE; } // Get username from system in a thread-safe manner std::string username(LOGIN_NAME_MAX, '\0'); - int err = getlogin_r(&username[0], username.size()); + int ret = getlogin_r(&username[0], username.size()); // Map errno to Win32 Error Codes - if (err != 0) { + if (ret) { switch (errno) { case EMFILE: case ENFILE: @@ -111,14 +110,14 @@ BOOL GetUserNameW(WCHAR_T *lpBuffer, LPDWORD lpnSize) default: errno = ERROR_INVALID_FUNCTION; } - return 0; + return FALSE; } - // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) + // Convert to char* to WCHAR_T* (UTF-8 to UTF-16 LE w/o BOM) std::basic_string username16(LOGIN_NAME_MAX+1, 0); icu::UnicodeString username8(username.c_str(), "UTF-8"); int32_t targetSize = username8.extract(0, username8.length(), - reinterpret_cast(&username16[0]), + reinterpret_cast(&username16[0]), (username16.size()-1)*sizeof(char16_t), "UTF-16LE"); // Number of characters including null @@ -138,5 +137,5 @@ BOOL GetUserNameW(WCHAR_T *lpBuffer, LPDWORD lpnSize) memcpy(lpBuffer, &username16[0], size*sizeof(char16_t)); *lpnSize = size; - return 1; + return TRUE; } diff --git a/src/impl/getusername.h b/src/impl/getusername.h index ad6099c4b..6083078bc 100644 --- a/src/impl/getusername.h +++ b/src/impl/getusername.h @@ -4,8 +4,6 @@ PAL_BEGIN_EXTERNC -// WCHAR_T * is a Unicode LPTSTR -// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx#LPTSTR -BOOL GetUserNameW(WCHAR_T *lpBuffer, LPDWORD lpnSize); +BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize); PAL_END_EXTERNC diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index 5a6a8535c..d00acdf30 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -1,3 +1,7 @@ +//! @file test-getusername.cpp +//! @author Andrew Schwartzmeyer +//! @brief Unit tests for GetUserName + #include #include #include @@ -8,7 +12,9 @@ #include #include "getusername.h" -class GetUserNameTest : public ::testing::Test { +//! Test fixture for GetUserNameW +class GetUserNameTest : public ::testing::Test +{ protected: DWORD lpnSize; std::vector lpBuffer; @@ -20,24 +26,31 @@ protected: expectedSize(expectedUsername.length()+1) {} - void TestWithSize(DWORD size) { + //! Invokes GetUserNameW with lpnSize and lpBuffer, saves result. + //! + //! @param size Assigns to lpnSize and allocates lpBuffer with + //! size number of null characters. + void TestWithSize(DWORD size) + { lpnSize = size; // allocate a WCHAR_T buffer to receive username lpBuffer.assign(lpnSize, '\0'); result = GetUserNameW(&lpBuffer[0], &lpnSize); } - void TestSuccess() { + //! Checks the effects of GetUserNameW for success. + void TestSuccess() + { SCOPED_TRACE(""); - // returns 1 on success - EXPECT_EQ(1, result); + //! Returns TRUE on success. + EXPECT_EQ(TRUE, result); - // sets lpnSize to number of WCHARs including null + //! Sets lpnSize to number of WCHARs including null. ASSERT_EQ(expectedSize, lpnSize); // setup for conversion from UTF-16LE - const char *begin = reinterpret_cast(&lpBuffer[0]); + const char* begin = reinterpret_cast(&lpBuffer[0]); // multiply to get number of bytes icu::UnicodeString username16(begin, lpnSize*sizeof(char16_t), "UTF-16LE"); // username16 length includes null and is number of characters @@ -46,38 +59,44 @@ protected: // convert (minus null) to UTF-8 for comparison std::string username(lpnSize-1, 0); ASSERT_EQ(expectedUsername.length(), username.length()); - int32_t targetSize = username16.extract(0, username.length(), - reinterpret_cast(&username[0]), "UTF-8"); + username16.extract(0, username.length(), + reinterpret_cast(&username[0]), "UTF-8"); + //! Returned username (after conversion) is what was expected. EXPECT_EQ(expectedUsername, username); } - void TestInvalidParameter() { + //! Checks the effects of GetUserNameW on failure with invalid parameters. + void TestInvalidParameter() + { SCOPED_TRACE(""); - // returns 0 on failure - EXPECT_EQ(0, result); + //! Returns FALSE on failure. + EXPECT_EQ(FALSE, result); - // sets errno to ERROR_INVALID_PARAMETER when lpBuffer is null - // (which is the case for an empty vector) + //! Sets errno to ERROR_INVALID_PARAMETER when lpBuffer is null + //! (which is the case for an empty vector). EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); } - void TestInsufficientBuffer() { + //! Checks the effects of GetUserNameW on failure with a buffer that is too small. + void TestInsufficientBuffer() + { SCOPED_TRACE(""); - // returns 0 on failure - EXPECT_EQ(0, result); + //! Returns FALSE on failure. + EXPECT_EQ(FALSE, result); - // sets errno to ERROR_INSUFFICIENT_BUFFER + //! Sets errno to ERROR_INSUFFICIENT_BUFFER. EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); - // sets lpnSize to length of username + null + //! Sets lpnSize to length of username plus null. EXPECT_EQ(expectedSize, lpnSize); } }; -TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) { +TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) +{ lpnSize = 1; result = GetUserNameW(NULL, &lpnSize); @@ -86,47 +105,54 @@ TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) { EXPECT_EQ(1, lpnSize); } -TEST_F(GetUserNameTest, BufferSizeAsNullButNotBuffer) { +TEST_F(GetUserNameTest, BufferSizeAsNullButNotBuffer) +{ lpBuffer.push_back('\0'); result = GetUserNameW(&lpBuffer[0], NULL); TestInvalidParameter(); } -TEST_F(GetUserNameTest, BufferSizeAsZero) { +TEST_F(GetUserNameTest, BufferSizeAsZero) +{ TestWithSize(0); TestInvalidParameter(); // does not reset lpnSize EXPECT_EQ(0, lpnSize); } -TEST_F(GetUserNameTest, BufferSizeAsOne) { +TEST_F(GetUserNameTest, BufferSizeAsOne) +{ // theoretically this should never fail because any non-empty // username length will be >1 with trailing null TestWithSize(1); TestInsufficientBuffer(); } -TEST_F(GetUserNameTest, BufferSizeAsUsername) { - // the buffer is too small because this is a UTF-8 size +TEST_F(GetUserNameTest, BufferSizeAsUsername) +{ + // the buffer is too small because it does not account for null TestWithSize(expectedUsername.length()); TestInsufficientBuffer(); } -TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOne) { +TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOne) +{ // includes null and so should be sufficient TestWithSize(expectedUsername.length()+1); TestSuccess(); } -TEST_F(GetUserNameTest, BufferSizeAsExpectedSize) { +TEST_F(GetUserNameTest, BufferSizeAsExpectedSize) +{ // expectedSize is the same as username.size()+1 TestWithSize(expectedSize); TestSuccess(); } -TEST_F(GetUserNameTest, BufferSizeAsLoginNameMax) { - // LoginNameMax is big enough to hold any username +TEST_F(GetUserNameTest, BufferSizeAsLoginNameMax) +{ + // LoginNameMax is big enough to hold any username, including null TestWithSize(LOGIN_NAME_MAX); TestSuccess(); }