Got rid of merge conflict
This commit is contained in:
commit
f6958d7212
6 changed files with 293 additions and 58 deletions
|
@ -8,17 +8,16 @@ include_directories(../ext-src/gtest/fused-src impl)
|
|||
link_directories(${monad_native_BINARY_DIR})
|
||||
|
||||
# source file definitions
|
||||
set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp impl/getcpinfo.cpp)
|
||||
set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp impl/getcomputername.cpp impl/getcpinfo.cpp)
|
||||
set(HOST_COMMON_SOURCE_FILES host/common/coreclrutil.cpp)
|
||||
set(HOST_COMMON_TEST_SOURCE_FILES tests/host/test-hostutil.cpp)
|
||||
set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp tests/test-getcpinfo.cpp tests/test-getusername.cpp ${HOST_COMMON_SOURCE_FILES} ${HOST_COMMON_TEST_SOURCE_FILES})
|
||||
|
||||
set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp tests/test-getusername.cpp tests/test-getcomputername.cpp tests/test-getcpinfo.cpp ${HOST_COMMON_SOURCE_FILES} ${HOST_COMMON_TEST_SOURCE_FILES})
|
||||
set(SOURCE_FILES main.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc)
|
||||
set(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp ${HOST_COMMON_SOURCE_FILES})
|
||||
|
||||
|
||||
# target definitions
|
||||
add_library(ps SHARED ${LIB_SOURCE_FILES})
|
||||
|
||||
add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES})
|
||||
add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES})
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ void printHelp()
|
|||
{
|
||||
std::cerr << "PS CoreCLR host" << std::endl;
|
||||
std::cerr << "Usage: host_cmdline [-c coreclr_path] [-alc load_context_assembly] [-s search_paths]" << std::endl;
|
||||
std::cerr << " [-b base_path] assembly_name type_name function_name [...]" << std::endl;
|
||||
std::cerr << " [-b base_path] assembly [...]" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "What it does:" << std::endl;
|
||||
std::cerr << "- by default the host assumes that CoreCLR is located in the same folder" << std::endl;
|
||||
|
@ -28,8 +28,8 @@ void printHelp()
|
|||
std::cerr << " + a custom assembly containing the PowerShellAssemblyLoadContext can" << std::endl;
|
||||
std::cerr << " be provided with the -alc command line argument" << std::endl;
|
||||
std::cerr << "- all additional parameters at the end of the command line are forwarded" << std::endl;
|
||||
std::cerr << " to the specified entry function in the assembly" << std::endl;
|
||||
std::cerr << "- the host will execute the specified entry function in the specified assembly" << std::endl;
|
||||
std::cerr << " to the Main function in the assembly" << std::endl;
|
||||
std::cerr << "- the host will execute the Main function in the specified assembly" << std::endl;
|
||||
std::cerr << " + this assembly has to be located in the search path" << std::endl;
|
||||
std::cerr << "- by default the host will add the current working directory to the assembly search path" << std::endl;
|
||||
std::cerr << " + this can be overridden with the -s command line argument" << std::endl;
|
||||
|
@ -37,8 +37,8 @@ void printHelp()
|
|||
std::cerr << "- by default the host assumes the PS base path for the assembly load context is the current" << std::endl;
|
||||
std::cerr << " working directory" << std::endl;
|
||||
std::cerr << " + this can be overridden with the -b command line argument" << std::endl;
|
||||
std::cerr << "- the function signature of the function that gets executed must be:" << std::endl;
|
||||
std::cerr << " public static int UnmanagedMain(int argc, [MarshalAs(UnmanagedType.LPArray,ArraySubType=UnmanagedType.LPStr,SizeParamIndex=0)] String[] argv)" << std::endl;
|
||||
std::cerr << "- the function signature of the Main function that gets executed must be:" << std::endl;
|
||||
std::cerr << " static void Main(string[] args)" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "Options:" << std::endl;
|
||||
std::cerr << "-c, --clr-path path to libcoreclr.so and the managed CLR assemblies" << std::endl;
|
||||
|
@ -50,13 +50,10 @@ void printHelp()
|
|||
std::cerr << " separated by :" << std::endl;
|
||||
std::cerr << " unless part of the same folder as CoreCLR, the main assembly referenced with the assembly_name" << std::endl;
|
||||
std::cerr << " argument, must always be added to the TPA list with this parameter" << std::endl;
|
||||
std::cerr << "assembly_name the assembly name of the assembly to execute" << std::endl;
|
||||
std::cerr << " must be available in the search path" << std::endl;
|
||||
std::cerr << "type_name the type name where the function can be found" << std::endl;
|
||||
std::cerr << "function_name the function to execute (must have the function signature described above!)" << std::endl;
|
||||
std::cerr << "assembly the path of the assembly to execute relative to current directory" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "Example:" << std::endl;
|
||||
std::cerr << "./host_cmdline -c /test/coreclr -alc /test/ps/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll -s /test/ps -b /test/ps -tpa /test/ps/powershell-simple.exe 'powershell-simple, version=1.0.0.0, culture=neutral, PublicKeyToken=null' 'ps_hello_world.Program' 'UnmanagedMain' 'get-process'" << std::endl;
|
||||
std::cerr << "./host_cmdline -c /test/coreclr -alc /test/ps/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll -s /test/ps -b /test/ps -tpa /test/ps/powershell-simple.exe 'powershell-simple, version=1.0.0.0, culture=neutral, PublicKeyToken=null' 'get-process'" << std::endl;
|
||||
}
|
||||
|
||||
struct Args
|
||||
|
@ -73,9 +70,7 @@ struct Args
|
|||
std::string searchPaths;
|
||||
std::string basePath;
|
||||
std::string tpaList;
|
||||
std::string entryAssemblyName;
|
||||
std::string entryTypeName;
|
||||
std::string entryFunctionName;
|
||||
std::string entryAssemblyPath;
|
||||
int argc;
|
||||
char** argv;
|
||||
bool verbose;
|
||||
|
@ -88,9 +83,7 @@ struct Args
|
|||
std::cerr << "- searchPaths " << searchPaths << std::endl;
|
||||
std::cerr << "- basePath " << basePath << std::endl;
|
||||
std::cerr << "- tpaList " << tpaList << std::endl;
|
||||
std::cerr << "- entryAssemblyName " << entryAssemblyName << std::endl;
|
||||
std::cerr << "- entryTypeName " << entryTypeName << std::endl;
|
||||
std::cerr << "- entryFunctionName " << entryFunctionName << std::endl;
|
||||
std::cerr << "- entryAssemblyPath " << entryAssemblyPath << std::endl;
|
||||
std::cerr << "- argc " << argc << std::endl;
|
||||
std::cerr << "- verbose " << (verbose ? "true" : "false") << std::endl;
|
||||
}
|
||||
|
@ -141,17 +134,9 @@ bool parseCmdline(const int argc, char** argv, Args& args)
|
|||
{
|
||||
args.verbose = true;
|
||||
}
|
||||
else if (args.entryAssemblyName == "")
|
||||
else if (args.entryAssemblyPath == "")
|
||||
{
|
||||
args.entryAssemblyName = arg;
|
||||
}
|
||||
else if (args.entryTypeName == "")
|
||||
{
|
||||
args.entryTypeName = arg;
|
||||
}
|
||||
else if (args.entryFunctionName == "")
|
||||
{
|
||||
args.entryFunctionName = arg;
|
||||
args.entryAssemblyPath = arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -165,18 +150,10 @@ bool parseCmdline(const int argc, char** argv, Args& args)
|
|||
}
|
||||
|
||||
// check for mandatory parameters
|
||||
if (args.entryAssemblyName == "")
|
||||
if (args.entryAssemblyPath == "")
|
||||
{
|
||||
std::cerr << "error: assembly_name argument missing" << std::endl;
|
||||
}
|
||||
if (args.entryTypeName == "")
|
||||
{
|
||||
std::cerr << "error: type_name argument missing" << std::endl;
|
||||
}
|
||||
if (args.entryFunctionName == "")
|
||||
{
|
||||
std::cerr << "error: function_name argument missing" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -410,23 +387,12 @@ int main(int argc, char** argv)
|
|||
}
|
||||
loaderDelegate(psBasePath16.c_str());
|
||||
|
||||
// call the unmanaged entry point for PowerShell
|
||||
typedef int (*UnmanagedMain)(int argc, char const* const* argv);
|
||||
UnmanagedMain unmanagedMain = nullptr;
|
||||
status = createDelegate(
|
||||
hostHandle,
|
||||
domainId,
|
||||
args.entryAssemblyName.c_str(),
|
||||
args.entryTypeName.c_str(),
|
||||
args.entryFunctionName.c_str(),
|
||||
(void**)&unmanagedMain);
|
||||
if (0 > status)
|
||||
{
|
||||
std::cerr << "could not create delegate for UnmanagedMain - status: " << std::hex << status << std::endl;
|
||||
return 4;
|
||||
}
|
||||
|
||||
int exitCode = unmanagedMain(args.argc,args.argv);
|
||||
// call into Main of powershell-simple.exe
|
||||
unsigned int exitCode;
|
||||
executeAssembly(hostHandle, domainId, args.argc,
|
||||
(const char**)args.argv,
|
||||
(currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(),
|
||||
&exitCode);
|
||||
|
||||
// shutdown CoreCLR
|
||||
status = shutdownCoreCLR(hostHandle,domainId);
|
||||
|
|
127
src/impl/getcomputername.cpp
Normal file
127
src/impl/getcomputername.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
//! @file getcomputername.cpp
|
||||
//! @author Aaron Katz <v-aakatz@microsoft.com>
|
||||
//! @brief Implements GetComputerName Win32 API
|
||||
|
||||
#include <errno.h>
|
||||
#include <langinfo.h>
|
||||
#include <locale.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <unicode/unistr.h>
|
||||
#include "getcomputername.h"
|
||||
|
||||
//! @brief GetComputerName retrieves the name of the host associated with
|
||||
//! the current thread.
|
||||
//!
|
||||
//! GetComputerNameW is the Unicode variation. See [MSDN documentation].
|
||||
//!
|
||||
//! @param[out] lpBuffer
|
||||
//! @parblock
|
||||
//! A pointer to the buffer to receive the hosts's
|
||||
//! name. If this buffer is not large enough to contain the
|
||||
//! entire user hosts 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 TRUE 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 FALSE 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/ms724295%28v=vs.85%29.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 GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize)
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
// Check parameters
|
||||
if (!lpBuffer || !lpnSize)
|
||||
{
|
||||
errno = ERROR_INVALID_PARAMETER;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Select locale from environment
|
||||
setlocale(LC_ALL, "");
|
||||
// Check that locale is UTF-8
|
||||
if (nl_langinfo(CODESET) != std::string("UTF-8"))
|
||||
{
|
||||
errno = ERROR_BAD_ENVIRONMENT;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Get computername from system in a thread-safe manner
|
||||
std::string computername(HOST_NAME_MAX, 0);
|
||||
int err = gethostname(&computername[0], computername.length());
|
||||
// Map errno to Win32 Error Codes
|
||||
if (err != 0)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EFAULT:
|
||||
errno = ERROR_INVALID_ADDRESS;
|
||||
break;
|
||||
case ENAMETOOLONG:
|
||||
errno = ERROR_GEN_FAILURE;
|
||||
break;
|
||||
default:
|
||||
errno = ERROR_INVALID_FUNCTION;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Convert to UnicodeString
|
||||
auto computername16 = icu::UnicodeString::fromUTF8(computername.c_str());
|
||||
// Terminate string with null
|
||||
computername16.append('\0');
|
||||
|
||||
// Size in WCHARs including null
|
||||
const DWORD size = computername16.length();
|
||||
|
||||
//Check if parameters passed enough buffer space
|
||||
if (size > *lpnSize)
|
||||
{
|
||||
errno = ERROR_INSUFFICIENT_BUFFER;
|
||||
// Set lpnSize if buffer is too small to inform user
|
||||
// of necessary size
|
||||
*lpnSize= size;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Extract string as UTF-16LE to buffer
|
||||
computername16.extract(0, size, reinterpret_cast<char*>(lpBuffer), "UTF-16LE");
|
||||
|
||||
*lpnSize = size;
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
9
src/impl/getcomputername.h
Normal file
9
src/impl/getcomputername.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "pal.h"
|
||||
|
||||
PAL_BEGIN_EXTERNC
|
||||
|
||||
BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize);
|
||||
|
||||
PAL_END_EXTERNC
|
|
@ -69,7 +69,6 @@
|
|||
#define INFINITE 0xFFFFFFFF
|
||||
#define WINAPI
|
||||
#define S_OK 0
|
||||
#define ERROR_GEN_FAILURE 31
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define ERROR_INVALID_PARAMETER 87
|
||||
|
@ -81,7 +80,8 @@
|
|||
#define ERROR_NO_SUCH_USER 0x00000525
|
||||
#define ERROR_INVALID_FUNCTION 0x00000001
|
||||
#define MAX_PATH 0x00000104
|
||||
#define ERROR_BAD_ENVIRONMENT 0x0000000A
|
||||
#define ERROR_INVALID_ADDRESS 0x000001e7
|
||||
#define ERROR_GEN_FAILURE 0x0000001F
|
||||
typedef unsigned long long uint64;
|
||||
#endif
|
||||
|
||||
|
|
134
src/tests/test-getcomputername.cpp
Normal file
134
src/tests/test-getcomputername.cpp
Normal file
|
@ -0,0 +1,134 @@
|
|||
//! @file test-getcomputername.cpp
|
||||
//! @author Aaron Katz <v-aakatz@microsoft.com>
|
||||
//! @brief Unit tests for GetComputerNameW
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <unistd.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <unicode/unistr.h>
|
||||
#include "getcomputername.h"
|
||||
|
||||
//! Test fixture for GetComputerNameTest
|
||||
class GetComputerNameTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
DWORD lpnSize;
|
||||
std::vector<WCHAR_T> lpBuffer;
|
||||
BOOL result;
|
||||
std::string expectedComputerName;
|
||||
DWORD expectedSize;
|
||||
|
||||
//Get expected result from using linux call
|
||||
GetComputerNameTest()
|
||||
{
|
||||
expectedComputerName.resize(HOST_NAME_MAX);
|
||||
BOOL ret = gethostname(&expectedComputerName[0], expectedComputerName.length());
|
||||
EXPECT_EQ(0, ret);
|
||||
expectedSize = std::strlen(expectedComputerName.c_str()) + 1;
|
||||
expectedComputerName.resize(expectedSize - 1);
|
||||
}
|
||||
|
||||
//! Invokes GetComputerNameW 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;
|
||||
lpBuffer.assign(lpnSize, 0);
|
||||
result = GetComputerNameW(&lpBuffer[0], &lpnSize);
|
||||
}
|
||||
|
||||
void TestSuccess()
|
||||
{
|
||||
SCOPED_TRACE("");
|
||||
|
||||
//! Returns TRUE on success.
|
||||
EXPECT_EQ(TRUE, result);
|
||||
|
||||
//! Sets lpnSize to number of WCHARs including null.
|
||||
ASSERT_EQ(expectedSize, lpnSize);
|
||||
|
||||
// Read lpBuffer into UnicodeString (without null)
|
||||
const char* begin = reinterpret_cast<char*>(&lpBuffer[0]);
|
||||
icu::UnicodeString computername16(begin, (lpnSize-1)*sizeof(UChar), "UTF-16LE");
|
||||
// Convert to UTF-8 for comparison
|
||||
std::string computername;
|
||||
computername16.toUTF8String(computername);
|
||||
|
||||
ASSERT_EQ(expectedSize, computername.length() + 1);
|
||||
|
||||
//! Returned computername(after conversion) is what was expected.
|
||||
EXPECT_EQ(expectedComputerName, computername);
|
||||
}
|
||||
|
||||
void TestInvalidParameter()
|
||||
{
|
||||
SCOPED_TRACE("");
|
||||
|
||||
// returns FALSE on failure
|
||||
EXPECT_EQ(FALSE, result);
|
||||
|
||||
// sets errno to ERROR_INVALID_PARAMETER when lpBuffer is null
|
||||
EXPECT_EQ(errno, ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
void TestInsufficientBuffer()
|
||||
{
|
||||
SCOPED_TRACE("");
|
||||
|
||||
// returns FALSE on failure
|
||||
EXPECT_EQ(FALSE, result);
|
||||
|
||||
// sets errno to ERROR_INSUFFICIENT_BUFFER
|
||||
EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER);
|
||||
|
||||
// sets lpnSize to length of username + null
|
||||
ASSERT_EQ(expectedSize, lpnSize);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(GetComputerNameTest, BufferAsNullButNotBufferSize)
|
||||
{
|
||||
lpnSize = 1;
|
||||
result = GetComputerNameW(NULL, &lpnSize);
|
||||
TestInvalidParameter();
|
||||
// does not reset lpnSize
|
||||
EXPECT_EQ(1, lpnSize);
|
||||
}
|
||||
|
||||
TEST_F(GetComputerNameTest, BufferSizeAsNullButNotBuffer)
|
||||
{
|
||||
lpBuffer.push_back('\0');
|
||||
result = GetComputerNameW(&lpBuffer[0], NULL);
|
||||
TestInvalidParameter();
|
||||
}
|
||||
|
||||
TEST_F(GetComputerNameTest, BufferSizeAsZero)
|
||||
{
|
||||
TestWithSize(0);
|
||||
EXPECT_EQ(errno, ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(GetComputerNameTest, BufferSizeAsUserNameMinusOne)
|
||||
{
|
||||
// the buffer is also too small
|
||||
TestWithSize(expectedSize-1);
|
||||
TestInsufficientBuffer();
|
||||
}
|
||||
|
||||
TEST_F(GetComputerNameTest, BufferSizeAsUserNamePlusOne)
|
||||
{
|
||||
// the buffer is exactly big enough
|
||||
TestWithSize(expectedSize+1);
|
||||
TestSuccess();
|
||||
}
|
||||
|
||||
TEST_F(GetComputerNameTest, BufferSizeAsLoginNameMax)
|
||||
{
|
||||
// the buffer larger than needed
|
||||
TestWithSize(HOST_NAME_MAX);
|
||||
TestSuccess();
|
||||
}
|
Loading…
Reference in a new issue