From c0bc9a2a67015b1cad8d87dac5b6e111843f086b Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Thu, 5 Mar 2015 14:58:25 -0800 Subject: [PATCH 001/342] initial commit --- .gitmodules | 3 + ext-src/gtest | 1 + src/CMakeLists.txt | 17 + src/impl/getcurrentprocessorid.cpp | 9 + src/impl/getcurrentprocessorid.h | 10 + src/impl/pal.h | 587 +++++++++++++++++++++++++ src/main.cpp | 7 + src/tests/test-getcurrentprocessid.cpp | 16 + 8 files changed, 650 insertions(+) create mode 100644 .gitmodules create mode 160000 ext-src/gtest create mode 100644 src/CMakeLists.txt create mode 100644 src/impl/getcurrentprocessorid.cpp create mode 100644 src/impl/getcurrentprocessorid.h create mode 100644 src/impl/pal.h create mode 100644 src/main.cpp create mode 100644 src/tests/test-getcurrentprocessid.cpp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..63ba77f86 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ext-src/gtest"] + path = ext-src/gtest + url = https://msostc.visualstudio.com/DefaultCollection/PS/_git/ext-gtest diff --git a/ext-src/gtest b/ext-src/gtest new file mode 160000 index 000000000..2196edcdb --- /dev/null +++ b/ext-src/gtest @@ -0,0 +1 @@ +Subproject commit 2196edcdb71dc8ff99f693e9e43332c143fe59d3 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..4355f98d0 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.4) +project(monad_native) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + +#include gtest +include_directories(../ext-src/gtest/fused-src impl) + +set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) +add_executable(monad_native ${SOURCE_FILES}) + +# add pthread +find_package(Threads) +target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT}) + + + diff --git a/src/impl/getcurrentprocessorid.cpp b/src/impl/getcurrentprocessorid.cpp new file mode 100644 index 000000000..409f2c258 --- /dev/null +++ b/src/impl/getcurrentprocessorid.cpp @@ -0,0 +1,9 @@ +#include "getcurrentprocessorid.h" +#include + +HANDLE GetCurrentProcessId() +{ + pid_t pid = getpid(); + return reinterpret_cast(pid); +} + diff --git a/src/impl/getcurrentprocessorid.h b/src/impl/getcurrentprocessorid.h new file mode 100644 index 000000000..fa3f35534 --- /dev/null +++ b/src/impl/getcurrentprocessorid.h @@ -0,0 +1,10 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +HANDLE GetCurrentProcessId(); + +PAL_END_EXTERNC + diff --git a/src/impl/pal.h b/src/impl/pal.h new file mode 100644 index 000000000..659afd4f6 --- /dev/null +++ b/src/impl/pal.h @@ -0,0 +1,587 @@ +/* +**============================================================================== +** +** Open Management Infrastructure (OMI) +** +** Copyright (c) Microsoft Corporation +** +** Licensed under the Apache License, Version 2.0 (the "License"); you may not +** use this file except in compliance with the License. You may obtain a copy +** of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +** MERCHANTABLITY OR NON-INFRINGEMENT. +** +** See the Apache 2 License for the specific language governing permissions +** and limitations under the License. +** +**============================================================================== +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#ifndef NAME_MAX +# define NAME_MAX 255 +#endif + +/* +**============================================================================== +** +** Windows-specific types. Defined here for PAL on Non-Windows platforms. +** +**============================================================================== +*/ + +#ifdef _MSC_VER + #ifndef WIN32_FROM_HRESULT + #define WIN32_FROM_HRESULT(hr) (HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : hr) + #endif +#else + #define WIN32_FROM_HRESULT(hr) hr + #define HRESULT_FROM_WIN32(error) error + typedef unsigned long DWORD, *LPDWORD; + typedef int BOOL; + typedef unsigned long HRESULT; + typedef const wchar_t *PCWSTR; + typedef wchar_t *PWSTR; + typedef const char *PCSTR; + typedef char *PSTR; + typedef void *PVOID; + typedef PVOID HANDLE; + #define NO_ERROR 0 + #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 + #define ERROR_OUTOFMEMORY 14 + #define MAX_PATH 0x00000104 + typedef unsigned long long uint64; +#endif + +/* +**============================================================================== +** +** __FUNCTION__ +** +**============================================================================== +*/ + +#if !defined(CONFIG_HAVE_FUNCTION_MACRO) +# if !defined(_MSC_VER) && !defined(__FUNCTION__) +# define __FUNCTION__ "" +# endif +#endif + +/* +**============================================================================== +** +** PAL_32BIT +** PAL_64BIT +** +**============================================================================== +*/ +#if defined(__GNUC__) +# if defined(__i386__) +# define PAL_32BIT +# elif defined(__x86_64__) +# define PAL_64BIT +# elif defined(__ppc__) +# define PAL_32BIT +# elif defined(__ppc64__) +# define PAL_64BIT +# elif ((ULONG_MAX) == (UINT_MAX) && (ULONG_MAX == 0xFFFFFFFF)) +# define PAL_32BIT +# else +# define PAL_64BIT +# endif +#elif defined(_MSC_VER) +# if defined(_WIN64) +# define PAL_64BIT +# else +# define PAL_32BIT +# endif +#elif ((ULONG_MAX) == (UINT_MAX) && (ULONG_MAX == 0xFFFFFFFF)) +# define PAL_32BIT +#else +# define PAL_64BIT +#endif + +/* +**============================================================================== +** +** PAL_CALL macro +** +**============================================================================== +*/ +#ifdef _MSC_VER +# define PAL_CALL __stdcall +#else +# define PAL_CALL +#endif + +/* +**============================================================================== +** +** PAL_EXPORT_API, PAL_IMPORT_API macros +** +**============================================================================== +*/ + +#if defined(_MSC_VER) +# define PAL_EXPORT_API __declspec(dllexport) +# define PAL_IMPORT_API __declspec(dllimport) +#elif defined(__GNUC__) +# define PAL_EXPORT_API __attribute__((visibility("default"))) +# define PAL_IMPORT_API /* empty */ +#elif defined(sun) +# define PAL_EXPORT_API __global +# define PAL_IMPORT_API /* empty */ +#else +# define PAL_EXPORT_API /* empty */ +# define PAL_IMPORT_API /* empty */ +#endif + +/* +**============================================================================== +** +** PAL_BEGIN_EXTERNC +** PAL_END_EXTERNC +** +**============================================================================== +*/ + +#if defined(__cplusplus) +# define PAL_BEGIN_EXTERNC extern "C" { +# define PAL_END_EXTERNC } +#else +# define PAL_BEGIN_EXTERNC +# define PAL_END_EXTERNC +#endif + +/* +**============================================================================== +** +** PAL_EXTERN_C +** +**============================================================================== +*/ +#ifdef __cplusplus +# define PAL_EXTERN_C extern "C" +#else +# define PAL_EXTERN_C extern +#endif /* __cplusplus */ + +/* +**============================================================================== +** +** PAL_INLINE macro +** +**============================================================================== +*/ + +#if defined(_MSC_VER) +# define PAL_INLINE static __inline +#elif defined(__GNUC__) +# define PAL_INLINE static __inline +#elif defined(sun) +# define PAL_INLINE static inline +#elif defined(__PPC) +# define PAL_INLINE __inline__ +#else +# define PAL_INLINE static __inline +#endif + +/* +**============================================================================== +** +** PAL string +** +**============================================================================== +*/ + +#if defined(CONFIG_ENABLE_WCHAR) +typedef wchar_t PAL_Char; +#else +typedef char PAL_Char; +#endif + +typedef PAL_Char TChar; + +/* +**============================================================================== +** +** PAL_T() +** +**============================================================================== +*/ + +#if defined(CONFIG_ENABLE_WCHAR) +# define __PAL_T(STR) L ## STR +# define PAL_T(STR) __PAL_T(STR) +#else +# define PAL_T(STR) STR +#endif + +/* +**============================================================================== +** +** PAL_UNUSED +** +**============================================================================== +*/ + +#define PAL_UNUSED(X) ((void)X) + +/* +**============================================================================== +** +** PAL_HAVE_POSIX +** +**============================================================================== +*/ + +#if defined(linux) || defined(sun) || defined(hpux) || defined(aix) +# define PAL_HAVE_POSIX +#endif + +/* +**============================================================================== +** +** PAL_HAVE_PTHREADS +** +**============================================================================== +*/ + +#if defined(linux) | defined(sun) | defined(hpux) | defined(aix) +# define PAL_HAVE_PTHREADS +#endif + +/* +**============================================================================== +** +** Basic types +** +**============================================================================== +*/ + +typedef unsigned char PAL_Uint8; +#define PAL_UINT8_MAX (UCHAR_MAX) + +typedef signed char PAL_Sint8; +#define PAL_SINT8_MIN (SCHAR_MIN) +#define PAL_SINT8_MAX (SCHAR_MAX) + +typedef unsigned short PAL_Uint16; +#define PAL_UINT16_MAX (USHRT_MAX) + +typedef signed short PAL_Sint16; +#define PAL_SINT16_MIN (SHRT_MIN) +#define PAL_SINT16_MAX (SHRT_MAX) + +typedef unsigned int PAL_Uint32; +#define PAL_UINT32_MAX (UINT_MAX) + +typedef signed int PAL_Sint32; +#define PAL_SINT32_MIN (INT_MIN) +#define PAL_SINT32_MAX (INT_MAX) + +#if defined(_MSC_VER) +typedef unsigned __int64 PAL_Uint64; +typedef signed __int64 PAL_Sint64; +#else +typedef unsigned long long PAL_Uint64; +typedef signed long long PAL_Sint64; +#endif +#define PAL_UINT64_MIN ((PAL_Uint64) 0ULL) +#define PAL_UINT64_MAX ((PAL_Uint64) 18446744073709551615ULL) +#define PAL_SINT64_MIN ((PAL_Sint64) (-9223372036854775807LL - 1LL)) +#define PAL_SINT64_MAX ((PAL_Sint64) 9223372036854775807LL ) + +typedef unsigned char PAL_Boolean; + +#define PAL_TRUE ((PAL_Boolean)1) +#define PAL_FALSE ((PAL_Boolean)0) + +/* +**============================================================================== +** +** Function calling conventions +** +**============================================================================== +*/ + +#ifdef _MSC_VER +# define PAL_CDECLAPI __cdecl +#else +# define PAL_CDECLAPI +#endif + +#define ATEXIT_API PAL_CDECLAPI + +/* +**============================================================================== +** +** SAL Notation for non-Windows platforms +** +**============================================================================== +*/ + +#if !defined(_MSC_VER) + +# ifndef _In_ +# define _In_ +# endif + +# ifndef _Out_ +# define _Out_ +# endif + +# ifndef _Inout_ +# define _Inout_ +# endif + +# ifndef _Return_type_success_ +# define _Return_type_success_(x) +# endif + +# ifndef _Acquires_lock_ +# define _Acquires_lock_(x) +# endif + +# ifndef _Releases_lock_ +# define _Releases_lock_(x) +# endif + +# ifndef _In_z_ +# define _In_z_ +# endif + +# ifndef _Post_z_ +# define _Post_z_ +# endif + +# ifndef _Out_writes_ +# define _Out_writes_(size) +# endif + +# ifndef _Out_writes_z_ +# define _Out_writes_z_(size) +# endif + +# ifndef _Null_terminated_ +# define _Null_terminated_ +# endif + +# ifndef _Use_decl_annotations_ +# define _Use_decl_annotations_ +# endif + +# ifndef _Out_opt_ +# define _Out_opt_ +# endif + +# ifndef _Deref_post_z_ +# define _Deref_post_z_ +# endif + +# ifndef _Inout_updates_z_ +# define _Inout_updates_z_(count) +# endif + +# ifndef _Inout_opt_z_ +# define _Inout_opt_z_ +# endif + +# ifndef _Deref_prepost_opt_z_ +# define _Deref_prepost_opt_z_ +# endif + +# ifndef _In_opt_ +# define _In_opt_ +# endif + +# ifndef _In_opt_z_ +# define _In_opt_z_ +# endif + +# ifndef _Ret_maybenull_ +# define _Ret_maybenull_ +# endif + +# ifndef _Check_return_ +# define _Check_return_ +# endif + +# ifndef _Must_inspect_result_ +# define _Must_inspect_result_ +# endif + +# ifndef _Frees_ptr_opt_ +# define _Frees_ptr_opt_ +# endif + +# ifndef _Frees_ptr_ +# define _Frees_ptr_ +# endif + +# ifndef _Const_ +# define _Const_ +# endif + +# ifndef _Post_writable_byte_size +# define _Post_writable_byte_size(size) +# endif + +# ifndef _Analysis_assume_ +# define _Analysis_assume_(expr) +# endif + +# ifndef _Always_ +# define _Always_(expr) +# endif + +# ifndef _Outptr_ +# define _Outptr_ +# endif + +# ifndef _Outptr_result_buffer_ +# define _Outptr_result_buffer_(size) +# endif + +# ifndef _Outptr_result_nullonfailure_ +# define _Outptr_result_nullonfailure_ +# endif + +# ifndef _Maybenull_ +# define _Maybenull_ +# endif + +# ifndef _Notnull_ +# define _Notnull_ +# endif + +# ifndef _Valid_ +# define _Valid_ +# endif + +# ifndef _Analysis_noreturn_ +# define _Analysis_noreturn_ +# endif + +# ifndef _Ret_writes_maybenull_z_ +# define _Ret_writes_maybenull_z_(count) +# endif + +# ifndef _String_length_ +# define _String_length_(str) +# endif + +# ifndef _Success_ +# define _Success_ +# endif + +# ifndef _Field_range_ +# define _Field_range_(min, max) +# endif + +# ifndef _In_range_ +# define _In_range_(min, max) +# endif + +# ifndef _Field_size_ +# define _Field_size_(count) +# endif + +# ifndef _Field_size_opt_ +# define _Field_size_opt_(count) +# endif + +# ifndef _Field_size_full_opt_ +# define _Field_size_full_opt_(count) +# endif + +# ifndef _Field_size_bytes_opt_ +# define _Field_size_bytes_opt_(size) +# endif + +# ifndef _Readable_elements_ +# define _Readable_elements_(count) +# endif + +# ifndef _Writable_elements_ +# define _Writable_elements_(count) +# endif + +# ifndef _Struct_size_bytes_ +# define _Struct_size_bytes_(size) +# endif + +# ifndef _At_ +# define _At_(target, annotation) +# endif + +# ifndef _Pre_satisfies_ +# define _Pre_satisfies_(expr) +# endif + +# ifndef _On_failure_ +# define _On_failure_(expr) +# endif + +# ifndef _In_bytecount_ +# define _In_bytecount_(size) +# endif + +# ifndef _Out_writes_bytes_to_opt_ +# define _Out_writes_bytes_to_opt_(buffLen, bufferNeeded) +# endif + +# ifndef _When_ +# define _When_(expr, annotation) +# endif + +# ifndef _Analysis_assume_nullterminated_ +# define _Analysis_assume_nullterminated_(expr) +# endif + + +#endif /* !defined(_MSC_VER) */ + +/* +**============================================================================== +** +** PAL_MAX_PATH_SIZE +** +**============================================================================== +*/ + +#define PAL_MAX_PATH_SIZE 1024 + +/* +**============================================================================== +** +** PAL_COUNT +** +**============================================================================== +*/ + +#ifdef _MSC_VER +# define PAL_COUNT(ARR) _countof(ARR) +#else +# define PAL_COUNT(ARR) (sizeof(ARR) / sizeof(ARR[0])) +#endif + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 000000000..e59bea057 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,7 @@ +#include + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/src/tests/test-getcurrentprocessid.cpp b/src/tests/test-getcurrentprocessid.cpp new file mode 100644 index 000000000..9803b6612 --- /dev/null +++ b/src/tests/test-getcurrentprocessid.cpp @@ -0,0 +1,16 @@ +#include +#include "getcurrentprocessorid.h" + +// This is a very simple test case to show how tests can be written +TEST(GetCurrentProcessId,simple) +{ + const HANDLE currentProcessId = GetCurrentProcessId(); + const pid_t pid = getpid(); + + // first make sure that on this platform those types are of the same size + ASSERT_TRUE(sizeof(HANDLE) >= sizeof(pid_t)); + + // now compare the actual values + ASSERT_EQ(currentProcessId,reinterpret_cast(pid)); +} + From beb5be9ffaac1ee032fb091a83f9e28ddb6d1110 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Thu, 5 Mar 2015 14:58:25 -0800 Subject: [PATCH 002/342] initial commit --- CMakeLists.txt | 17 + impl/getcurrentprocessorid.cpp | 9 + impl/getcurrentprocessorid.h | 10 + impl/pal.h | 587 +++++++++++++++++++++++++++++ main.cpp | 7 + tests/test-getcurrentprocessid.cpp | 16 + 6 files changed, 646 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 impl/getcurrentprocessorid.cpp create mode 100644 impl/getcurrentprocessorid.h create mode 100644 impl/pal.h create mode 100644 main.cpp create mode 100644 tests/test-getcurrentprocessid.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..4355f98d0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.4) +project(monad_native) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + +#include gtest +include_directories(../ext-src/gtest/fused-src impl) + +set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) +add_executable(monad_native ${SOURCE_FILES}) + +# add pthread +find_package(Threads) +target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT}) + + + diff --git a/impl/getcurrentprocessorid.cpp b/impl/getcurrentprocessorid.cpp new file mode 100644 index 000000000..409f2c258 --- /dev/null +++ b/impl/getcurrentprocessorid.cpp @@ -0,0 +1,9 @@ +#include "getcurrentprocessorid.h" +#include + +HANDLE GetCurrentProcessId() +{ + pid_t pid = getpid(); + return reinterpret_cast(pid); +} + diff --git a/impl/getcurrentprocessorid.h b/impl/getcurrentprocessorid.h new file mode 100644 index 000000000..fa3f35534 --- /dev/null +++ b/impl/getcurrentprocessorid.h @@ -0,0 +1,10 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +HANDLE GetCurrentProcessId(); + +PAL_END_EXTERNC + diff --git a/impl/pal.h b/impl/pal.h new file mode 100644 index 000000000..659afd4f6 --- /dev/null +++ b/impl/pal.h @@ -0,0 +1,587 @@ +/* +**============================================================================== +** +** Open Management Infrastructure (OMI) +** +** Copyright (c) Microsoft Corporation +** +** Licensed under the Apache License, Version 2.0 (the "License"); you may not +** use this file except in compliance with the License. You may obtain a copy +** of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +** MERCHANTABLITY OR NON-INFRINGEMENT. +** +** See the Apache 2 License for the specific language governing permissions +** and limitations under the License. +** +**============================================================================== +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#ifndef NAME_MAX +# define NAME_MAX 255 +#endif + +/* +**============================================================================== +** +** Windows-specific types. Defined here for PAL on Non-Windows platforms. +** +**============================================================================== +*/ + +#ifdef _MSC_VER + #ifndef WIN32_FROM_HRESULT + #define WIN32_FROM_HRESULT(hr) (HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : hr) + #endif +#else + #define WIN32_FROM_HRESULT(hr) hr + #define HRESULT_FROM_WIN32(error) error + typedef unsigned long DWORD, *LPDWORD; + typedef int BOOL; + typedef unsigned long HRESULT; + typedef const wchar_t *PCWSTR; + typedef wchar_t *PWSTR; + typedef const char *PCSTR; + typedef char *PSTR; + typedef void *PVOID; + typedef PVOID HANDLE; + #define NO_ERROR 0 + #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 + #define ERROR_OUTOFMEMORY 14 + #define MAX_PATH 0x00000104 + typedef unsigned long long uint64; +#endif + +/* +**============================================================================== +** +** __FUNCTION__ +** +**============================================================================== +*/ + +#if !defined(CONFIG_HAVE_FUNCTION_MACRO) +# if !defined(_MSC_VER) && !defined(__FUNCTION__) +# define __FUNCTION__ "" +# endif +#endif + +/* +**============================================================================== +** +** PAL_32BIT +** PAL_64BIT +** +**============================================================================== +*/ +#if defined(__GNUC__) +# if defined(__i386__) +# define PAL_32BIT +# elif defined(__x86_64__) +# define PAL_64BIT +# elif defined(__ppc__) +# define PAL_32BIT +# elif defined(__ppc64__) +# define PAL_64BIT +# elif ((ULONG_MAX) == (UINT_MAX) && (ULONG_MAX == 0xFFFFFFFF)) +# define PAL_32BIT +# else +# define PAL_64BIT +# endif +#elif defined(_MSC_VER) +# if defined(_WIN64) +# define PAL_64BIT +# else +# define PAL_32BIT +# endif +#elif ((ULONG_MAX) == (UINT_MAX) && (ULONG_MAX == 0xFFFFFFFF)) +# define PAL_32BIT +#else +# define PAL_64BIT +#endif + +/* +**============================================================================== +** +** PAL_CALL macro +** +**============================================================================== +*/ +#ifdef _MSC_VER +# define PAL_CALL __stdcall +#else +# define PAL_CALL +#endif + +/* +**============================================================================== +** +** PAL_EXPORT_API, PAL_IMPORT_API macros +** +**============================================================================== +*/ + +#if defined(_MSC_VER) +# define PAL_EXPORT_API __declspec(dllexport) +# define PAL_IMPORT_API __declspec(dllimport) +#elif defined(__GNUC__) +# define PAL_EXPORT_API __attribute__((visibility("default"))) +# define PAL_IMPORT_API /* empty */ +#elif defined(sun) +# define PAL_EXPORT_API __global +# define PAL_IMPORT_API /* empty */ +#else +# define PAL_EXPORT_API /* empty */ +# define PAL_IMPORT_API /* empty */ +#endif + +/* +**============================================================================== +** +** PAL_BEGIN_EXTERNC +** PAL_END_EXTERNC +** +**============================================================================== +*/ + +#if defined(__cplusplus) +# define PAL_BEGIN_EXTERNC extern "C" { +# define PAL_END_EXTERNC } +#else +# define PAL_BEGIN_EXTERNC +# define PAL_END_EXTERNC +#endif + +/* +**============================================================================== +** +** PAL_EXTERN_C +** +**============================================================================== +*/ +#ifdef __cplusplus +# define PAL_EXTERN_C extern "C" +#else +# define PAL_EXTERN_C extern +#endif /* __cplusplus */ + +/* +**============================================================================== +** +** PAL_INLINE macro +** +**============================================================================== +*/ + +#if defined(_MSC_VER) +# define PAL_INLINE static __inline +#elif defined(__GNUC__) +# define PAL_INLINE static __inline +#elif defined(sun) +# define PAL_INLINE static inline +#elif defined(__PPC) +# define PAL_INLINE __inline__ +#else +# define PAL_INLINE static __inline +#endif + +/* +**============================================================================== +** +** PAL string +** +**============================================================================== +*/ + +#if defined(CONFIG_ENABLE_WCHAR) +typedef wchar_t PAL_Char; +#else +typedef char PAL_Char; +#endif + +typedef PAL_Char TChar; + +/* +**============================================================================== +** +** PAL_T() +** +**============================================================================== +*/ + +#if defined(CONFIG_ENABLE_WCHAR) +# define __PAL_T(STR) L ## STR +# define PAL_T(STR) __PAL_T(STR) +#else +# define PAL_T(STR) STR +#endif + +/* +**============================================================================== +** +** PAL_UNUSED +** +**============================================================================== +*/ + +#define PAL_UNUSED(X) ((void)X) + +/* +**============================================================================== +** +** PAL_HAVE_POSIX +** +**============================================================================== +*/ + +#if defined(linux) || defined(sun) || defined(hpux) || defined(aix) +# define PAL_HAVE_POSIX +#endif + +/* +**============================================================================== +** +** PAL_HAVE_PTHREADS +** +**============================================================================== +*/ + +#if defined(linux) | defined(sun) | defined(hpux) | defined(aix) +# define PAL_HAVE_PTHREADS +#endif + +/* +**============================================================================== +** +** Basic types +** +**============================================================================== +*/ + +typedef unsigned char PAL_Uint8; +#define PAL_UINT8_MAX (UCHAR_MAX) + +typedef signed char PAL_Sint8; +#define PAL_SINT8_MIN (SCHAR_MIN) +#define PAL_SINT8_MAX (SCHAR_MAX) + +typedef unsigned short PAL_Uint16; +#define PAL_UINT16_MAX (USHRT_MAX) + +typedef signed short PAL_Sint16; +#define PAL_SINT16_MIN (SHRT_MIN) +#define PAL_SINT16_MAX (SHRT_MAX) + +typedef unsigned int PAL_Uint32; +#define PAL_UINT32_MAX (UINT_MAX) + +typedef signed int PAL_Sint32; +#define PAL_SINT32_MIN (INT_MIN) +#define PAL_SINT32_MAX (INT_MAX) + +#if defined(_MSC_VER) +typedef unsigned __int64 PAL_Uint64; +typedef signed __int64 PAL_Sint64; +#else +typedef unsigned long long PAL_Uint64; +typedef signed long long PAL_Sint64; +#endif +#define PAL_UINT64_MIN ((PAL_Uint64) 0ULL) +#define PAL_UINT64_MAX ((PAL_Uint64) 18446744073709551615ULL) +#define PAL_SINT64_MIN ((PAL_Sint64) (-9223372036854775807LL - 1LL)) +#define PAL_SINT64_MAX ((PAL_Sint64) 9223372036854775807LL ) + +typedef unsigned char PAL_Boolean; + +#define PAL_TRUE ((PAL_Boolean)1) +#define PAL_FALSE ((PAL_Boolean)0) + +/* +**============================================================================== +** +** Function calling conventions +** +**============================================================================== +*/ + +#ifdef _MSC_VER +# define PAL_CDECLAPI __cdecl +#else +# define PAL_CDECLAPI +#endif + +#define ATEXIT_API PAL_CDECLAPI + +/* +**============================================================================== +** +** SAL Notation for non-Windows platforms +** +**============================================================================== +*/ + +#if !defined(_MSC_VER) + +# ifndef _In_ +# define _In_ +# endif + +# ifndef _Out_ +# define _Out_ +# endif + +# ifndef _Inout_ +# define _Inout_ +# endif + +# ifndef _Return_type_success_ +# define _Return_type_success_(x) +# endif + +# ifndef _Acquires_lock_ +# define _Acquires_lock_(x) +# endif + +# ifndef _Releases_lock_ +# define _Releases_lock_(x) +# endif + +# ifndef _In_z_ +# define _In_z_ +# endif + +# ifndef _Post_z_ +# define _Post_z_ +# endif + +# ifndef _Out_writes_ +# define _Out_writes_(size) +# endif + +# ifndef _Out_writes_z_ +# define _Out_writes_z_(size) +# endif + +# ifndef _Null_terminated_ +# define _Null_terminated_ +# endif + +# ifndef _Use_decl_annotations_ +# define _Use_decl_annotations_ +# endif + +# ifndef _Out_opt_ +# define _Out_opt_ +# endif + +# ifndef _Deref_post_z_ +# define _Deref_post_z_ +# endif + +# ifndef _Inout_updates_z_ +# define _Inout_updates_z_(count) +# endif + +# ifndef _Inout_opt_z_ +# define _Inout_opt_z_ +# endif + +# ifndef _Deref_prepost_opt_z_ +# define _Deref_prepost_opt_z_ +# endif + +# ifndef _In_opt_ +# define _In_opt_ +# endif + +# ifndef _In_opt_z_ +# define _In_opt_z_ +# endif + +# ifndef _Ret_maybenull_ +# define _Ret_maybenull_ +# endif + +# ifndef _Check_return_ +# define _Check_return_ +# endif + +# ifndef _Must_inspect_result_ +# define _Must_inspect_result_ +# endif + +# ifndef _Frees_ptr_opt_ +# define _Frees_ptr_opt_ +# endif + +# ifndef _Frees_ptr_ +# define _Frees_ptr_ +# endif + +# ifndef _Const_ +# define _Const_ +# endif + +# ifndef _Post_writable_byte_size +# define _Post_writable_byte_size(size) +# endif + +# ifndef _Analysis_assume_ +# define _Analysis_assume_(expr) +# endif + +# ifndef _Always_ +# define _Always_(expr) +# endif + +# ifndef _Outptr_ +# define _Outptr_ +# endif + +# ifndef _Outptr_result_buffer_ +# define _Outptr_result_buffer_(size) +# endif + +# ifndef _Outptr_result_nullonfailure_ +# define _Outptr_result_nullonfailure_ +# endif + +# ifndef _Maybenull_ +# define _Maybenull_ +# endif + +# ifndef _Notnull_ +# define _Notnull_ +# endif + +# ifndef _Valid_ +# define _Valid_ +# endif + +# ifndef _Analysis_noreturn_ +# define _Analysis_noreturn_ +# endif + +# ifndef _Ret_writes_maybenull_z_ +# define _Ret_writes_maybenull_z_(count) +# endif + +# ifndef _String_length_ +# define _String_length_(str) +# endif + +# ifndef _Success_ +# define _Success_ +# endif + +# ifndef _Field_range_ +# define _Field_range_(min, max) +# endif + +# ifndef _In_range_ +# define _In_range_(min, max) +# endif + +# ifndef _Field_size_ +# define _Field_size_(count) +# endif + +# ifndef _Field_size_opt_ +# define _Field_size_opt_(count) +# endif + +# ifndef _Field_size_full_opt_ +# define _Field_size_full_opt_(count) +# endif + +# ifndef _Field_size_bytes_opt_ +# define _Field_size_bytes_opt_(size) +# endif + +# ifndef _Readable_elements_ +# define _Readable_elements_(count) +# endif + +# ifndef _Writable_elements_ +# define _Writable_elements_(count) +# endif + +# ifndef _Struct_size_bytes_ +# define _Struct_size_bytes_(size) +# endif + +# ifndef _At_ +# define _At_(target, annotation) +# endif + +# ifndef _Pre_satisfies_ +# define _Pre_satisfies_(expr) +# endif + +# ifndef _On_failure_ +# define _On_failure_(expr) +# endif + +# ifndef _In_bytecount_ +# define _In_bytecount_(size) +# endif + +# ifndef _Out_writes_bytes_to_opt_ +# define _Out_writes_bytes_to_opt_(buffLen, bufferNeeded) +# endif + +# ifndef _When_ +# define _When_(expr, annotation) +# endif + +# ifndef _Analysis_assume_nullterminated_ +# define _Analysis_assume_nullterminated_(expr) +# endif + + +#endif /* !defined(_MSC_VER) */ + +/* +**============================================================================== +** +** PAL_MAX_PATH_SIZE +** +**============================================================================== +*/ + +#define PAL_MAX_PATH_SIZE 1024 + +/* +**============================================================================== +** +** PAL_COUNT +** +**============================================================================== +*/ + +#ifdef _MSC_VER +# define PAL_COUNT(ARR) _countof(ARR) +#else +# define PAL_COUNT(ARR) (sizeof(ARR) / sizeof(ARR[0])) +#endif + diff --git a/main.cpp b/main.cpp new file mode 100644 index 000000000..e59bea057 --- /dev/null +++ b/main.cpp @@ -0,0 +1,7 @@ +#include + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/tests/test-getcurrentprocessid.cpp b/tests/test-getcurrentprocessid.cpp new file mode 100644 index 000000000..9803b6612 --- /dev/null +++ b/tests/test-getcurrentprocessid.cpp @@ -0,0 +1,16 @@ +#include +#include "getcurrentprocessorid.h" + +// This is a very simple test case to show how tests can be written +TEST(GetCurrentProcessId,simple) +{ + const HANDLE currentProcessId = GetCurrentProcessId(); + const pid_t pid = getpid(); + + // first make sure that on this platform those types are of the same size + ASSERT_TRUE(sizeof(HANDLE) >= sizeof(pid_t)); + + // now compare the actual values + ASSERT_EQ(currentProcessId,reinterpret_cast(pid)); +} + From 7acaf3a0930adb4d6f019ded1986d3f30c502cc6 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Thu, 5 Mar 2015 14:59:16 -0800 Subject: [PATCH 003/342] added .idea to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..485dee64b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea From 8c27f6eb801b1c8923422c301749590aaeb7d3c1 Mon Sep 17 00:00:00 2001 From: Pete Baker Date: Thu, 19 Mar 2015 13:09:36 -0700 Subject: [PATCH 004/342] built and tested - pass --- src/impl/getcurrentthreadid.cpp | 9 +++++++++ src/impl/getcurrentthreadid.h | 10 ++++++++++ src/tests/test-getcurrentthreadid.cpp | 16 ++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 src/impl/getcurrentthreadid.cpp create mode 100644 src/impl/getcurrentthreadid.h create mode 100644 src/tests/test-getcurrentthreadid.cpp diff --git a/src/impl/getcurrentthreadid.cpp b/src/impl/getcurrentthreadid.cpp new file mode 100644 index 000000000..efd7a3136 --- /dev/null +++ b/src/impl/getcurrentthreadid.cpp @@ -0,0 +1,9 @@ +#include "getcurrentthreadid.h" +#include +#include + +HANDLE GetCurrentThreadId() +{ + pid_t tid = pthread_self(); + return reinterpret_cast(tid); +} diff --git a/src/impl/getcurrentthreadid.h b/src/impl/getcurrentthreadid.h new file mode 100644 index 000000000..258c3c397 --- /dev/null +++ b/src/impl/getcurrentthreadid.h @@ -0,0 +1,10 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +HANDLE GetCurrentThreadId(); + +PAL_END_EXTERNC + diff --git a/src/tests/test-getcurrentthreadid.cpp b/src/tests/test-getcurrentthreadid.cpp new file mode 100644 index 000000000..7488d192d --- /dev/null +++ b/src/tests/test-getcurrentthreadid.cpp @@ -0,0 +1,16 @@ +#include +#include "getcurrentthreadid.h" +#include + +TEST(GetCurrentThreadId,simple) +{ + const HANDLE currentThreadId = GetCurrentThreadId(); + const pid_t tid = pthread_self(); + + // first make sure that on this platform those types are of the same size + ASSERT_TRUE(sizeof(HANDLE) >= sizeof(pid_t)); + + // now compare the actual values + ASSERT_EQ(currentThreadId,reinterpret_cast(tid)); +} + From 0c5f78a223210371576a5c5ec7cda2ae035196bc Mon Sep 17 00:00:00 2001 From: Pete Baker Date: Thu, 19 Mar 2015 13:09:36 -0700 Subject: [PATCH 005/342] built and tested - pass --- impl/getcurrentthreadid.cpp | 9 +++++++++ impl/getcurrentthreadid.h | 10 ++++++++++ tests/test-getcurrentthreadid.cpp | 16 ++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 impl/getcurrentthreadid.cpp create mode 100644 impl/getcurrentthreadid.h create mode 100644 tests/test-getcurrentthreadid.cpp diff --git a/impl/getcurrentthreadid.cpp b/impl/getcurrentthreadid.cpp new file mode 100644 index 000000000..efd7a3136 --- /dev/null +++ b/impl/getcurrentthreadid.cpp @@ -0,0 +1,9 @@ +#include "getcurrentthreadid.h" +#include +#include + +HANDLE GetCurrentThreadId() +{ + pid_t tid = pthread_self(); + return reinterpret_cast(tid); +} diff --git a/impl/getcurrentthreadid.h b/impl/getcurrentthreadid.h new file mode 100644 index 000000000..258c3c397 --- /dev/null +++ b/impl/getcurrentthreadid.h @@ -0,0 +1,10 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +HANDLE GetCurrentThreadId(); + +PAL_END_EXTERNC + diff --git a/tests/test-getcurrentthreadid.cpp b/tests/test-getcurrentthreadid.cpp new file mode 100644 index 000000000..7488d192d --- /dev/null +++ b/tests/test-getcurrentthreadid.cpp @@ -0,0 +1,16 @@ +#include +#include "getcurrentthreadid.h" +#include + +TEST(GetCurrentThreadId,simple) +{ + const HANDLE currentThreadId = GetCurrentThreadId(); + const pid_t tid = pthread_self(); + + // first make sure that on this platform those types are of the same size + ASSERT_TRUE(sizeof(HANDLE) >= sizeof(pid_t)); + + // now compare the actual values + ASSERT_EQ(currentThreadId,reinterpret_cast(tid)); +} + From ac95206250ac27740a9b91fdde8d6afe682bdb57 Mon Sep 17 00:00:00 2001 From: Aaron Katz Date: Fri, 20 Mar 2015 10:07:06 -0700 Subject: [PATCH 006/342] code for cpinfo --- src/CMakeLists.txt | 3 ++- src/impl/getcpinfo.cpp | 27 ++++++++++++++++++++++++ src/impl/getcpinfo.h | 22 ++++++++++++++++++++ src/tests/test-getcpinfo.cpp | 40 ++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/impl/getcpinfo.cpp create mode 100644 src/impl/getcpinfo.h create mode 100644 src/tests/test-getcpinfo.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4355f98d0..018b963fc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,7 +6,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest include_directories(../ext-src/gtest/fused-src impl) -set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) +set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp tests/test-getcpinfo.cpp impl/getcpinfo.cpp +../ext-src/gtest/fused-src/gtest/gtest-all.cc) add_executable(monad_native ${SOURCE_FILES}) # add pthread diff --git a/src/impl/getcpinfo.cpp b/src/impl/getcpinfo.cpp new file mode 100644 index 000000000..1392f7970 --- /dev/null +++ b/src/impl/getcpinfo.cpp @@ -0,0 +1,27 @@ +#include "getcpinfo.h" +#include + +bool GetCPInfo(unsigned int codepage, LPCPINFO cpinfo) +{ + switch(codepage) + { + case 65000: + cpinfo->DefaultChar[0]= '?'; + cpinfo->DefaultChar[1]= '0'; + cpinfo->LeadByte[0] = cpinfo->LeadByte[1] = '0'; + cpinfo->MaxCharSize = 5; + return true; + break; + case 65001: + cpinfo->DefaultChar[0]= '?'; + cpinfo->DefaultChar[1]= '0'; + cpinfo->LeadByte[0] = cpinfo->LeadByte[1] = '0'; + cpinfo->MaxCharSize = 4; + return true; + break; + default: + return false; + } + +} + diff --git a/src/impl/getcpinfo.h b/src/impl/getcpinfo.h new file mode 100644 index 000000000..2e11196bd --- /dev/null +++ b/src/impl/getcpinfo.h @@ -0,0 +1,22 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + + + const int MAX_DEFAULTCHAR = 2; + + const int MAX_LEADBYTES = 12; + + +typedef struct _cpinfo { + unsigned int MaxCharSize; + char DefaultChar[MAX_DEFAULTCHAR]; + char LeadByte[MAX_LEADBYTES]; +} CPINFO, *LPCPINFO; + + +bool GetCPInfo(unsigned int codepage, LPCPINFO cpinfo); + +PAL_END_EXTERNC diff --git a/src/tests/test-getcpinfo.cpp b/src/tests/test-getcpinfo.cpp new file mode 100644 index 000000000..2a23121ec --- /dev/null +++ b/src/tests/test-getcpinfo.cpp @@ -0,0 +1,40 @@ +#include +#include "getcpinfo.h" + +// This is a very simple test case to show how tests can be written +TEST(GetCPInfo,utf8) +{ + + LPCPINFO cpinfo = new CPINFO(); + bool utf8 = GetCPInfo(65001, cpinfo); + + + // first make sure that on this platform those types are of the same size + ASSERT_TRUE(utf8 == 1); + + // now compare the actual values + ASSERT_EQ(cpinfo->DefaultChar[0],'?'); + ASSERT_EQ(cpinfo->DefaultChar[1],'0'); + ASSERT_EQ(cpinfo->LeadByte[0] ,'0'); + ASSERT_EQ(cpinfo->LeadByte[1] ,'0'); + ASSERT_EQ(cpinfo->MaxCharSize ,4); + +} + + +TEST(GetCPInfo,utf7) +{ + LPCPINFO cpinfo = new CPINFO(); + bool utf7 = GetCPInfo(65000, cpinfo); + + + // first make sure that on this platform those types are of the same size + ASSERT_TRUE(utf7 == 1); + + // now compare the actual values + ASSERT_EQ(cpinfo->DefaultChar[0],'?'); + ASSERT_EQ(cpinfo->DefaultChar[1],'0'); + ASSERT_EQ(cpinfo->LeadByte[0] ,'0'); + ASSERT_EQ(cpinfo->LeadByte[1] ,'0'); + ASSERT_EQ(cpinfo->MaxCharSize ,5); +} \ No newline at end of file From 82c111c6c248bb08fded0ec079c3de919c5c30a4 Mon Sep 17 00:00:00 2001 From: Aaron Katz Date: Fri, 20 Mar 2015 10:07:06 -0700 Subject: [PATCH 007/342] code for cpinfo --- CMakeLists.txt | 3 ++- impl/getcpinfo.cpp | 27 +++++++++++++++++++++++++++ impl/getcpinfo.h | 22 ++++++++++++++++++++++ tests/test-getcpinfo.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 impl/getcpinfo.cpp create mode 100644 impl/getcpinfo.h create mode 100644 tests/test-getcpinfo.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4355f98d0..018b963fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest include_directories(../ext-src/gtest/fused-src impl) -set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) +set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp tests/test-getcpinfo.cpp impl/getcpinfo.cpp +../ext-src/gtest/fused-src/gtest/gtest-all.cc) add_executable(monad_native ${SOURCE_FILES}) # add pthread diff --git a/impl/getcpinfo.cpp b/impl/getcpinfo.cpp new file mode 100644 index 000000000..1392f7970 --- /dev/null +++ b/impl/getcpinfo.cpp @@ -0,0 +1,27 @@ +#include "getcpinfo.h" +#include + +bool GetCPInfo(unsigned int codepage, LPCPINFO cpinfo) +{ + switch(codepage) + { + case 65000: + cpinfo->DefaultChar[0]= '?'; + cpinfo->DefaultChar[1]= '0'; + cpinfo->LeadByte[0] = cpinfo->LeadByte[1] = '0'; + cpinfo->MaxCharSize = 5; + return true; + break; + case 65001: + cpinfo->DefaultChar[0]= '?'; + cpinfo->DefaultChar[1]= '0'; + cpinfo->LeadByte[0] = cpinfo->LeadByte[1] = '0'; + cpinfo->MaxCharSize = 4; + return true; + break; + default: + return false; + } + +} + diff --git a/impl/getcpinfo.h b/impl/getcpinfo.h new file mode 100644 index 000000000..2e11196bd --- /dev/null +++ b/impl/getcpinfo.h @@ -0,0 +1,22 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + + + const int MAX_DEFAULTCHAR = 2; + + const int MAX_LEADBYTES = 12; + + +typedef struct _cpinfo { + unsigned int MaxCharSize; + char DefaultChar[MAX_DEFAULTCHAR]; + char LeadByte[MAX_LEADBYTES]; +} CPINFO, *LPCPINFO; + + +bool GetCPInfo(unsigned int codepage, LPCPINFO cpinfo); + +PAL_END_EXTERNC diff --git a/tests/test-getcpinfo.cpp b/tests/test-getcpinfo.cpp new file mode 100644 index 000000000..2a23121ec --- /dev/null +++ b/tests/test-getcpinfo.cpp @@ -0,0 +1,40 @@ +#include +#include "getcpinfo.h" + +// This is a very simple test case to show how tests can be written +TEST(GetCPInfo,utf8) +{ + + LPCPINFO cpinfo = new CPINFO(); + bool utf8 = GetCPInfo(65001, cpinfo); + + + // first make sure that on this platform those types are of the same size + ASSERT_TRUE(utf8 == 1); + + // now compare the actual values + ASSERT_EQ(cpinfo->DefaultChar[0],'?'); + ASSERT_EQ(cpinfo->DefaultChar[1],'0'); + ASSERT_EQ(cpinfo->LeadByte[0] ,'0'); + ASSERT_EQ(cpinfo->LeadByte[1] ,'0'); + ASSERT_EQ(cpinfo->MaxCharSize ,4); + +} + + +TEST(GetCPInfo,utf7) +{ + LPCPINFO cpinfo = new CPINFO(); + bool utf7 = GetCPInfo(65000, cpinfo); + + + // first make sure that on this platform those types are of the same size + ASSERT_TRUE(utf7 == 1); + + // now compare the actual values + ASSERT_EQ(cpinfo->DefaultChar[0],'?'); + ASSERT_EQ(cpinfo->DefaultChar[1],'0'); + ASSERT_EQ(cpinfo->LeadByte[0] ,'0'); + ASSERT_EQ(cpinfo->LeadByte[1] ,'0'); + ASSERT_EQ(cpinfo->MaxCharSize ,5); +} \ No newline at end of file From 9f4c6d3e02313f84e6878b6266b0d11a43d9d431 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Fri, 3 Apr 2015 10:19:17 -0700 Subject: [PATCH 008/342] added build files and folders to gitignore --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 485dee64b..45c8b7d40 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,7 @@ .idea +src/.kdev4/ +src/CMakeFiles/ +src/build/ +src/monad_native +src/src.kdev4 + From 70645d5bc1f8d039a240f3753b656a1cdfc7ca70 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Fri, 3 Apr 2015 10:22:05 -0700 Subject: [PATCH 009/342] fetched changes from branch feature/GetComputerName --- CMakeLists.txt | 3 ++- impl/getcomputername.cpp | 8 ++++++++ impl/getcomputername.h | 9 +++++++++ tests/test-getcomputername.cpp | 23 +++++++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 impl/getcomputername.cpp create mode 100644 impl/getcomputername.h create mode 100644 tests/test-getcomputername.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4355f98d0..868a006fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest include_directories(../ext-src/gtest/fused-src impl) -set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) +set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp tests/test-getcomputername.cpp impl/getcomputername.cpp +../ext-src/gtest/fused-src/gtest/gtest-all.cc) add_executable(monad_native ${SOURCE_FILES}) # add pthread diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp new file mode 100644 index 000000000..f67adab0b --- /dev/null +++ b/impl/getcomputername.cpp @@ -0,0 +1,8 @@ +#include "getcomputername.h" +#include + +int GetComputerName(char *name, size_t len) +{ + int host = gethostname(name, len); + return host; +} diff --git a/impl/getcomputername.h b/impl/getcomputername.h new file mode 100644 index 000000000..a1d6cefe2 --- /dev/null +++ b/impl/getcomputername.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +int GetComputerName(char * name, size_t len); + +PAL_END_EXTERNC \ No newline at end of file diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp new file mode 100644 index 000000000..c2c152ed5 --- /dev/null +++ b/tests/test-getcomputername.cpp @@ -0,0 +1,23 @@ +#include +#include "getcomputername.h" + +TEST(GetComputerName,simple) +{ + + char hostname[128]; + char hostnameFunctionTest[128]; + + int getComputerName = GetComputerName(hostnameFunctionTest, sizeof hostnameFunctionTest); + int host = gethostname(hostname, sizeof hostname); + + // first make sure that on this platform those types are of the same size + + ASSERT_TRUE(getComputerName == 0); + ASSERT_TRUE(host == 0); + + // now compare the actual values + for(int i =0; hostname[i] != '\0'; i++) + { + ASSERT_EQ(hostnameFunctionTest[i],hostname[i]); + } +} \ No newline at end of file From e46e44d701fcc0de19d3c30e2cd26a516ed25fb4 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Fri, 3 Apr 2015 10:22:05 -0700 Subject: [PATCH 010/342] fetched changes from branch feature/GetComputerName --- src/CMakeLists.txt | 3 ++- src/impl/getcomputername.cpp | 8 ++++++++ src/impl/getcomputername.h | 9 +++++++++ src/tests/test-getcomputername.cpp | 23 +++++++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/impl/getcomputername.cpp create mode 100644 src/impl/getcomputername.h create mode 100644 src/tests/test-getcomputername.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4355f98d0..868a006fa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,7 +6,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest include_directories(../ext-src/gtest/fused-src impl) -set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) +set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp tests/test-getcomputername.cpp impl/getcomputername.cpp +../ext-src/gtest/fused-src/gtest/gtest-all.cc) add_executable(monad_native ${SOURCE_FILES}) # add pthread diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp new file mode 100644 index 000000000..f67adab0b --- /dev/null +++ b/src/impl/getcomputername.cpp @@ -0,0 +1,8 @@ +#include "getcomputername.h" +#include + +int GetComputerName(char *name, size_t len) +{ + int host = gethostname(name, len); + return host; +} diff --git a/src/impl/getcomputername.h b/src/impl/getcomputername.h new file mode 100644 index 000000000..a1d6cefe2 --- /dev/null +++ b/src/impl/getcomputername.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +int GetComputerName(char * name, size_t len); + +PAL_END_EXTERNC \ No newline at end of file diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp new file mode 100644 index 000000000..c2c152ed5 --- /dev/null +++ b/src/tests/test-getcomputername.cpp @@ -0,0 +1,23 @@ +#include +#include "getcomputername.h" + +TEST(GetComputerName,simple) +{ + + char hostname[128]; + char hostnameFunctionTest[128]; + + int getComputerName = GetComputerName(hostnameFunctionTest, sizeof hostnameFunctionTest); + int host = gethostname(hostname, sizeof hostname); + + // first make sure that on this platform those types are of the same size + + ASSERT_TRUE(getComputerName == 0); + ASSERT_TRUE(host == 0); + + // now compare the actual values + for(int i =0; hostname[i] != '\0'; i++) + { + ASSERT_EQ(hostnameFunctionTest[i],hostname[i]); + } +} \ No newline at end of file From 6194094244805ddd7950c256b7e5ccd486712787 Mon Sep 17 00:00:00 2001 From: Aaron Katz Date: Fri, 3 Apr 2015 11:06:30 -0700 Subject: [PATCH 011/342] Changes from notes --- src/impl/getcpinfo.cpp | 31 +++++++++++++++--------------- src/impl/getcpinfo.h | 15 +-------------- src/impl/pal.h | 29 ++++++++++++++++++++++++++++ src/tests/test-getcpinfo.cpp | 37 ++++++++++++++++++------------------ 4 files changed, 64 insertions(+), 48 deletions(-) diff --git a/src/impl/getcpinfo.cpp b/src/impl/getcpinfo.cpp index 1392f7970..0ad41c0a2 100644 --- a/src/impl/getcpinfo.cpp +++ b/src/impl/getcpinfo.cpp @@ -1,27 +1,28 @@ #include "getcpinfo.h" #include +#include -bool GetCPInfo(unsigned int codepage, LPCPINFO cpinfo) +BOOL GetCPInfo(UINT codepage, CPINFO &cpinfo) { + std::string test; switch(codepage) { case 65000: - cpinfo->DefaultChar[0]= '?'; - cpinfo->DefaultChar[1]= '0'; - cpinfo->LeadByte[0] = cpinfo->LeadByte[1] = '0'; - cpinfo->MaxCharSize = 5; - return true; - break; + cpinfo.DefaultChar[0]= '?'; + cpinfo.DefaultChar[1]= '0'; + cpinfo.LeadByte[0] = '0'; + cpinfo.LeadByte[1] = '0'; + cpinfo.MaxCharSize = 5; + return TRUE; case 65001: - cpinfo->DefaultChar[0]= '?'; - cpinfo->DefaultChar[1]= '0'; - cpinfo->LeadByte[0] = cpinfo->LeadByte[1] = '0'; - cpinfo->MaxCharSize = 4; - return true; - break; + cpinfo.DefaultChar[0]= '?'; + cpinfo.DefaultChar[1]= '0'; + cpinfo.LeadByte[0] = '0'; + cpinfo.LeadByte[1] = '0'; + cpinfo.MaxCharSize = 4; + return TRUE; default: - return false; + return FALSE; } - } diff --git a/src/impl/getcpinfo.h b/src/impl/getcpinfo.h index 2e11196bd..0e5d57462 100644 --- a/src/impl/getcpinfo.h +++ b/src/impl/getcpinfo.h @@ -4,19 +4,6 @@ PAL_BEGIN_EXTERNC - - const int MAX_DEFAULTCHAR = 2; - - const int MAX_LEADBYTES = 12; - - -typedef struct _cpinfo { - unsigned int MaxCharSize; - char DefaultChar[MAX_DEFAULTCHAR]; - char LeadByte[MAX_LEADBYTES]; -} CPINFO, *LPCPINFO; - - -bool GetCPInfo(unsigned int codepage, LPCPINFO cpinfo); +BOOL GetCPInfo(UINT codepage, CPINFO &cpinfo); PAL_END_EXTERNC diff --git a/src/impl/pal.h b/src/impl/pal.h index 659afd4f6..c86ba79b0 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -30,6 +30,7 @@ #include #include #include +#include #ifndef NAME_MAX # define NAME_MAX 255 @@ -59,6 +60,8 @@ typedef char *PSTR; typedef void *PVOID; typedef PVOID HANDLE; + typedef uint32_t UINT; + typedef char BYTE; #define NO_ERROR 0 #define INFINITE 0xFFFFFFFF #define WINAPI @@ -585,3 +588,29 @@ typedef unsigned char PAL_Boolean; # define PAL_COUNT(ARR) (sizeof(ARR) / sizeof(ARR[0])) #endif +/* +**============================================================================== +** +** NameSpace +** +**============================================================================== +*/ + +namespace const_cpinfo{ + constexpr int MAX_DEFAULTCHAR = 2; + constexpr int MAX_LEADBYTES = 12; +} + +/* +**============================================================================== +** +** Structs +** +**============================================================================== +*/ + +typedef struct _cpinfo { + UINT MaxCharSize; + BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; + BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; +} CPINFO; \ No newline at end of file diff --git a/src/tests/test-getcpinfo.cpp b/src/tests/test-getcpinfo.cpp index 2a23121ec..428261f20 100644 --- a/src/tests/test-getcpinfo.cpp +++ b/src/tests/test-getcpinfo.cpp @@ -4,37 +4,36 @@ // This is a very simple test case to show how tests can be written TEST(GetCPInfo,utf8) { - - LPCPINFO cpinfo = new CPINFO(); - bool utf8 = GetCPInfo(65001, cpinfo); + CPINFO cpinfo; + BOOL utf8 = GetCPInfo(65001, cpinfo); - // first make sure that on this platform those types are of the same size - ASSERT_TRUE(utf8 == 1); + // first make sure that the function worked + ASSERT_TRUE(utf8 == TRUE); // now compare the actual values - ASSERT_EQ(cpinfo->DefaultChar[0],'?'); - ASSERT_EQ(cpinfo->DefaultChar[1],'0'); - ASSERT_EQ(cpinfo->LeadByte[0] ,'0'); - ASSERT_EQ(cpinfo->LeadByte[1] ,'0'); - ASSERT_EQ(cpinfo->MaxCharSize ,4); + ASSERT_EQ(cpinfo.DefaultChar[0],'?'); + ASSERT_EQ(cpinfo.DefaultChar[1],'0'); + ASSERT_EQ(cpinfo.LeadByte[0] ,'0'); + ASSERT_EQ(cpinfo.LeadByte[1] ,'0'); + ASSERT_EQ(cpinfo.MaxCharSize ,4); } TEST(GetCPInfo,utf7) { - LPCPINFO cpinfo = new CPINFO(); - bool utf7 = GetCPInfo(65000, cpinfo); + CPINFO cpinfo; + BOOL utf7 = GetCPInfo(65000, cpinfo); - // first make sure that on this platform those types are of the same size - ASSERT_TRUE(utf7 == 1); + // first make sure that the function worked + ASSERT_TRUE(utf7 == TRUE); // now compare the actual values - ASSERT_EQ(cpinfo->DefaultChar[0],'?'); - ASSERT_EQ(cpinfo->DefaultChar[1],'0'); - ASSERT_EQ(cpinfo->LeadByte[0] ,'0'); - ASSERT_EQ(cpinfo->LeadByte[1] ,'0'); - ASSERT_EQ(cpinfo->MaxCharSize ,5); + ASSERT_EQ(cpinfo.DefaultChar[0],'?'); + ASSERT_EQ(cpinfo.DefaultChar[1],'0'); + ASSERT_EQ(cpinfo.LeadByte[0] ,'0'); + ASSERT_EQ(cpinfo.LeadByte[1] ,'0'); + ASSERT_EQ(cpinfo.MaxCharSize ,5); } \ No newline at end of file From c84dfa9b63056325345d303d22de631c79a13584 Mon Sep 17 00:00:00 2001 From: Aaron Katz Date: Fri, 3 Apr 2015 11:06:30 -0700 Subject: [PATCH 012/342] Changes from notes --- impl/getcpinfo.cpp | 31 ++++++++++++++++--------------- impl/getcpinfo.h | 15 +-------------- impl/pal.h | 29 +++++++++++++++++++++++++++++ tests/test-getcpinfo.cpp | 37 ++++++++++++++++++------------------- 4 files changed, 64 insertions(+), 48 deletions(-) diff --git a/impl/getcpinfo.cpp b/impl/getcpinfo.cpp index 1392f7970..0ad41c0a2 100644 --- a/impl/getcpinfo.cpp +++ b/impl/getcpinfo.cpp @@ -1,27 +1,28 @@ #include "getcpinfo.h" #include +#include -bool GetCPInfo(unsigned int codepage, LPCPINFO cpinfo) +BOOL GetCPInfo(UINT codepage, CPINFO &cpinfo) { + std::string test; switch(codepage) { case 65000: - cpinfo->DefaultChar[0]= '?'; - cpinfo->DefaultChar[1]= '0'; - cpinfo->LeadByte[0] = cpinfo->LeadByte[1] = '0'; - cpinfo->MaxCharSize = 5; - return true; - break; + cpinfo.DefaultChar[0]= '?'; + cpinfo.DefaultChar[1]= '0'; + cpinfo.LeadByte[0] = '0'; + cpinfo.LeadByte[1] = '0'; + cpinfo.MaxCharSize = 5; + return TRUE; case 65001: - cpinfo->DefaultChar[0]= '?'; - cpinfo->DefaultChar[1]= '0'; - cpinfo->LeadByte[0] = cpinfo->LeadByte[1] = '0'; - cpinfo->MaxCharSize = 4; - return true; - break; + cpinfo.DefaultChar[0]= '?'; + cpinfo.DefaultChar[1]= '0'; + cpinfo.LeadByte[0] = '0'; + cpinfo.LeadByte[1] = '0'; + cpinfo.MaxCharSize = 4; + return TRUE; default: - return false; + return FALSE; } - } diff --git a/impl/getcpinfo.h b/impl/getcpinfo.h index 2e11196bd..0e5d57462 100644 --- a/impl/getcpinfo.h +++ b/impl/getcpinfo.h @@ -4,19 +4,6 @@ PAL_BEGIN_EXTERNC - - const int MAX_DEFAULTCHAR = 2; - - const int MAX_LEADBYTES = 12; - - -typedef struct _cpinfo { - unsigned int MaxCharSize; - char DefaultChar[MAX_DEFAULTCHAR]; - char LeadByte[MAX_LEADBYTES]; -} CPINFO, *LPCPINFO; - - -bool GetCPInfo(unsigned int codepage, LPCPINFO cpinfo); +BOOL GetCPInfo(UINT codepage, CPINFO &cpinfo); PAL_END_EXTERNC diff --git a/impl/pal.h b/impl/pal.h index 659afd4f6..c86ba79b0 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -30,6 +30,7 @@ #include #include #include +#include #ifndef NAME_MAX # define NAME_MAX 255 @@ -59,6 +60,8 @@ typedef char *PSTR; typedef void *PVOID; typedef PVOID HANDLE; + typedef uint32_t UINT; + typedef char BYTE; #define NO_ERROR 0 #define INFINITE 0xFFFFFFFF #define WINAPI @@ -585,3 +588,29 @@ typedef unsigned char PAL_Boolean; # define PAL_COUNT(ARR) (sizeof(ARR) / sizeof(ARR[0])) #endif +/* +**============================================================================== +** +** NameSpace +** +**============================================================================== +*/ + +namespace const_cpinfo{ + constexpr int MAX_DEFAULTCHAR = 2; + constexpr int MAX_LEADBYTES = 12; +} + +/* +**============================================================================== +** +** Structs +** +**============================================================================== +*/ + +typedef struct _cpinfo { + UINT MaxCharSize; + BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; + BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; +} CPINFO; \ No newline at end of file diff --git a/tests/test-getcpinfo.cpp b/tests/test-getcpinfo.cpp index 2a23121ec..428261f20 100644 --- a/tests/test-getcpinfo.cpp +++ b/tests/test-getcpinfo.cpp @@ -4,37 +4,36 @@ // This is a very simple test case to show how tests can be written TEST(GetCPInfo,utf8) { - - LPCPINFO cpinfo = new CPINFO(); - bool utf8 = GetCPInfo(65001, cpinfo); + CPINFO cpinfo; + BOOL utf8 = GetCPInfo(65001, cpinfo); - // first make sure that on this platform those types are of the same size - ASSERT_TRUE(utf8 == 1); + // first make sure that the function worked + ASSERT_TRUE(utf8 == TRUE); // now compare the actual values - ASSERT_EQ(cpinfo->DefaultChar[0],'?'); - ASSERT_EQ(cpinfo->DefaultChar[1],'0'); - ASSERT_EQ(cpinfo->LeadByte[0] ,'0'); - ASSERT_EQ(cpinfo->LeadByte[1] ,'0'); - ASSERT_EQ(cpinfo->MaxCharSize ,4); + ASSERT_EQ(cpinfo.DefaultChar[0],'?'); + ASSERT_EQ(cpinfo.DefaultChar[1],'0'); + ASSERT_EQ(cpinfo.LeadByte[0] ,'0'); + ASSERT_EQ(cpinfo.LeadByte[1] ,'0'); + ASSERT_EQ(cpinfo.MaxCharSize ,4); } TEST(GetCPInfo,utf7) { - LPCPINFO cpinfo = new CPINFO(); - bool utf7 = GetCPInfo(65000, cpinfo); + CPINFO cpinfo; + BOOL utf7 = GetCPInfo(65000, cpinfo); - // first make sure that on this platform those types are of the same size - ASSERT_TRUE(utf7 == 1); + // first make sure that the function worked + ASSERT_TRUE(utf7 == TRUE); // now compare the actual values - ASSERT_EQ(cpinfo->DefaultChar[0],'?'); - ASSERT_EQ(cpinfo->DefaultChar[1],'0'); - ASSERT_EQ(cpinfo->LeadByte[0] ,'0'); - ASSERT_EQ(cpinfo->LeadByte[1] ,'0'); - ASSERT_EQ(cpinfo->MaxCharSize ,5); + ASSERT_EQ(cpinfo.DefaultChar[0],'?'); + ASSERT_EQ(cpinfo.DefaultChar[1],'0'); + ASSERT_EQ(cpinfo.LeadByte[0] ,'0'); + ASSERT_EQ(cpinfo.LeadByte[1] ,'0'); + ASSERT_EQ(cpinfo.MaxCharSize ,5); } \ No newline at end of file From ea7b78ef1c00106b03a1cfd2bf4b4aa049415e27 Mon Sep 17 00:00:00 2001 From: Aaron Katz Date: Mon, 6 Apr 2015 09:57:16 -0700 Subject: [PATCH 013/342] changes based on comments --- impl/getcomputername.cpp | 10 ++++++--- impl/getcomputername.h | 2 +- impl/pal.h | 3 +++ tests/test-getcomputername.cpp | 37 +++++++++++++++++++--------------- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp index f67adab0b..66a34e67e 100644 --- a/impl/getcomputername.cpp +++ b/impl/getcomputername.cpp @@ -1,8 +1,12 @@ #include "getcomputername.h" #include -int GetComputerName(char *name, size_t len) +BOOL GetComputerName(LPTSTR name, LPDWORD len) { - int host = gethostname(name, len); - return host; + int host = gethostname(name, HOST_NAME_MAX); + if(host == 0) + { + return TRUE; + } + return FALSE; } diff --git a/impl/getcomputername.h b/impl/getcomputername.h index a1d6cefe2..7f8dd8eb5 100644 --- a/impl/getcomputername.h +++ b/impl/getcomputername.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -int GetComputerName(char * name, size_t len); +BOOL GetComputerName(LPTSTR name, LPDWORD len); PAL_END_EXTERNC \ No newline at end of file diff --git a/impl/pal.h b/impl/pal.h index 659afd4f6..defde3b1f 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -59,6 +59,9 @@ typedef char *PSTR; typedef void *PVOID; typedef PVOID HANDLE; + typedef char TCHAR; + typedef TCHAR *LPTSTR; + typedef DWORD *LPDWORD; #define NO_ERROR 0 #define INFINITE 0xFFFFFFFF #define WINAPI diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index c2c152ed5..f4ce811fc 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -2,22 +2,27 @@ #include "getcomputername.h" TEST(GetComputerName,simple) -{ - - char hostname[128]; - char hostnameFunctionTest[128]; +{ + char hostname[HOST_NAME_MAX]; + TCHAR hostnameFunctionTest[HOST_NAME_MAX]; + DWORD hostSize = HOST_NAME_MAX; - int getComputerName = GetComputerName(hostnameFunctionTest, sizeof hostnameFunctionTest); - int host = gethostname(hostname, sizeof hostname); + BOOL getComputerName = GetComputerName(hostnameFunctionTest, &hostSize); + BOOL host = gethostname(hostname, sizeof hostname); - // first make sure that on this platform those types are of the same size - - ASSERT_TRUE(getComputerName == 0); - ASSERT_TRUE(host == 0); - - // now compare the actual values - for(int i =0; hostname[i] != '\0'; i++) - { - ASSERT_EQ(hostnameFunctionTest[i],hostname[i]); - } + if(host == 0) + { + host = TRUE; + } + else + { + host = FALSE; + } + + std::string hostnameSting(hostname); + std::string hostnameStingTest(hostnameFunctionTest); + + ASSERT_TRUE(getComputerName == TRUE); + ASSERT_EQ(host,TRUE); + ASSERT_EQ(hostnameSting,hostnameFunctionTest); } \ No newline at end of file From 03eae4653ad64151ef5d978a630e322de699f4ce Mon Sep 17 00:00:00 2001 From: Aaron Katz Date: Mon, 6 Apr 2015 09:57:16 -0700 Subject: [PATCH 014/342] changes based on comments --- src/impl/getcomputername.cpp | 10 +++++--- src/impl/getcomputername.h | 2 +- src/impl/pal.h | 3 +++ src/tests/test-getcomputername.cpp | 37 +++++++++++++++++------------- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp index f67adab0b..66a34e67e 100644 --- a/src/impl/getcomputername.cpp +++ b/src/impl/getcomputername.cpp @@ -1,8 +1,12 @@ #include "getcomputername.h" #include -int GetComputerName(char *name, size_t len) +BOOL GetComputerName(LPTSTR name, LPDWORD len) { - int host = gethostname(name, len); - return host; + int host = gethostname(name, HOST_NAME_MAX); + if(host == 0) + { + return TRUE; + } + return FALSE; } diff --git a/src/impl/getcomputername.h b/src/impl/getcomputername.h index a1d6cefe2..7f8dd8eb5 100644 --- a/src/impl/getcomputername.h +++ b/src/impl/getcomputername.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -int GetComputerName(char * name, size_t len); +BOOL GetComputerName(LPTSTR name, LPDWORD len); PAL_END_EXTERNC \ No newline at end of file diff --git a/src/impl/pal.h b/src/impl/pal.h index 659afd4f6..defde3b1f 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -59,6 +59,9 @@ typedef char *PSTR; typedef void *PVOID; typedef PVOID HANDLE; + typedef char TCHAR; + typedef TCHAR *LPTSTR; + typedef DWORD *LPDWORD; #define NO_ERROR 0 #define INFINITE 0xFFFFFFFF #define WINAPI diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp index c2c152ed5..f4ce811fc 100644 --- a/src/tests/test-getcomputername.cpp +++ b/src/tests/test-getcomputername.cpp @@ -2,22 +2,27 @@ #include "getcomputername.h" TEST(GetComputerName,simple) -{ - - char hostname[128]; - char hostnameFunctionTest[128]; +{ + char hostname[HOST_NAME_MAX]; + TCHAR hostnameFunctionTest[HOST_NAME_MAX]; + DWORD hostSize = HOST_NAME_MAX; - int getComputerName = GetComputerName(hostnameFunctionTest, sizeof hostnameFunctionTest); - int host = gethostname(hostname, sizeof hostname); + BOOL getComputerName = GetComputerName(hostnameFunctionTest, &hostSize); + BOOL host = gethostname(hostname, sizeof hostname); - // first make sure that on this platform those types are of the same size - - ASSERT_TRUE(getComputerName == 0); - ASSERT_TRUE(host == 0); - - // now compare the actual values - for(int i =0; hostname[i] != '\0'; i++) - { - ASSERT_EQ(hostnameFunctionTest[i],hostname[i]); - } + if(host == 0) + { + host = TRUE; + } + else + { + host = FALSE; + } + + std::string hostnameSting(hostname); + std::string hostnameStingTest(hostnameFunctionTest); + + ASSERT_TRUE(getComputerName == TRUE); + ASSERT_EQ(host,TRUE); + ASSERT_EQ(hostnameSting,hostnameFunctionTest); } \ No newline at end of file From a0f238906bb9a964e8c7af8367bf375d1a5d1d30 Mon Sep 17 00:00:00 2001 From: Aaron Katz Date: Thu, 9 Apr 2015 14:51:10 -0700 Subject: [PATCH 015/342] Changes to spacing --- src/impl/.getcpinfo.cpp.kate-swp | Bin 0 -> 1435 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/impl/.getcpinfo.cpp.kate-swp diff --git a/src/impl/.getcpinfo.cpp.kate-swp b/src/impl/.getcpinfo.cpp.kate-swp new file mode 100644 index 0000000000000000000000000000000000000000..91e90a6f3b104a0b2f013e4b582b5deea2b7eeba GIT binary patch literal 1435 zcmZ9LIZgvX5JlU&0q+~m7$8R$5=Sr+B7y-qHj)D*0sD zC6(;w{`KcicRQstx?aC*vV6OK&MqIHHre^vBBeA~y?(xbKYZ-ny?xzW{QPe7EBUo4 zU6rn6%YUu~Zk5*IxZWfumGWs9pR7$q$JI~d~}xiNfgv9l@_`{ANLjw2<{QW_5|!KFg0`KO zUBMAE(zekcWi}(VVfIvQTu`zZGb3#_AZ0dVwPDt5Tu`!^Fe7a?AZ0cawPE&H)3~5y zGi65FY(UCvrfS2i*|?x&GZRHP9xxma7>)-F#{-54AY~C|8iD891$IFx!dw&~0vIBI bAp#g8fFS}%S%kSpIFw)Hugwi{K@s5(Su1(; literal 0 HcmV?d00001 From 6c716b6fa03b4999a5fb587faf317c609c939ad0 Mon Sep 17 00:00:00 2001 From: Aaron Katz Date: Thu, 9 Apr 2015 14:51:10 -0700 Subject: [PATCH 016/342] Changes to spacing --- impl/.getcpinfo.cpp.kate-swp | Bin 0 -> 1435 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 impl/.getcpinfo.cpp.kate-swp diff --git a/impl/.getcpinfo.cpp.kate-swp b/impl/.getcpinfo.cpp.kate-swp new file mode 100644 index 0000000000000000000000000000000000000000..91e90a6f3b104a0b2f013e4b582b5deea2b7eeba GIT binary patch literal 1435 zcmZ9LIZgvX5JlU&0q+~m7$8R$5=Sr+B7y-qHj)D*0sD zC6(;w{`KcicRQstx?aC*vV6OK&MqIHHre^vBBeA~y?(xbKYZ-ny?xzW{QPe7EBUo4 zU6rn6%YUu~Zk5*IxZWfumGWs9pR7$q$JI~d~}xiNfgv9l@_`{ANLjw2<{QW_5|!KFg0`KO zUBMAE(zekcWi}(VVfIvQTu`zZGb3#_AZ0dVwPDt5Tu`!^Fe7a?AZ0cawPE&H)3~5y zGi65FY(UCvrfS2i*|?x&GZRHP9xxma7>)-F#{-54AY~C|8iD891$IFx!dw&~0vIBI bAp#g8fFS}%S%kSpIFw)Hugwi{K@s5(Su1(; literal 0 HcmV?d00001 From 299e362d112d6c6a403e91e44754c21ec04e3591 Mon Sep 17 00:00:00 2001 From: Aaron Katz Date: Thu, 9 Apr 2015 15:16:37 -0700 Subject: [PATCH 017/342] changed spacing and using std::string instead of TCHAR --- impl/getcomputername.cpp | 12 ++++++------ tests/test-getcomputername.cpp | 15 +++++++-------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp index 66a34e67e..1ec69110c 100644 --- a/impl/getcomputername.cpp +++ b/impl/getcomputername.cpp @@ -3,10 +3,10 @@ BOOL GetComputerName(LPTSTR name, LPDWORD len) { - int host = gethostname(name, HOST_NAME_MAX); - if(host == 0) - { - return TRUE; - } - return FALSE; + int host = gethostname(name, HOST_NAME_MAX); + if(host == 0) + { + return TRUE; + } + return FALSE; } diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index f4ce811fc..8b0f19f5d 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -4,25 +4,24 @@ TEST(GetComputerName,simple) { char hostname[HOST_NAME_MAX]; - TCHAR hostnameFunctionTest[HOST_NAME_MAX]; + std::string hostnameFunctionTest; DWORD hostSize = HOST_NAME_MAX; - - BOOL getComputerName = GetComputerName(hostnameFunctionTest, &hostSize); + BOOL getComputerName = GetComputerName(&hostnameFunctionTest[0], &hostSize); BOOL host = gethostname(hostname, sizeof hostname); if(host == 0) { - host = TRUE; + host = TRUE; } else { - host = FALSE; + host = FALSE; } - std::string hostnameSting(hostname); - std::string hostnameStingTest(hostnameFunctionTest); + std::string hostnameString(hostname); + std::string hostnameStringTest(&hostnameFunctionTest[0]); ASSERT_TRUE(getComputerName == TRUE); ASSERT_EQ(host,TRUE); - ASSERT_EQ(hostnameSting,hostnameFunctionTest); + ASSERT_EQ(hostnameString,hostnameStringTest); } \ No newline at end of file From 0245ab771ee6d460e859ed59acc05095bbbc6e05 Mon Sep 17 00:00:00 2001 From: Aaron Katz Date: Thu, 9 Apr 2015 15:16:37 -0700 Subject: [PATCH 018/342] changed spacing and using std::string instead of TCHAR --- src/impl/getcomputername.cpp | 12 ++++++------ src/tests/test-getcomputername.cpp | 15 +++++++-------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp index 66a34e67e..1ec69110c 100644 --- a/src/impl/getcomputername.cpp +++ b/src/impl/getcomputername.cpp @@ -3,10 +3,10 @@ BOOL GetComputerName(LPTSTR name, LPDWORD len) { - int host = gethostname(name, HOST_NAME_MAX); - if(host == 0) - { - return TRUE; - } - return FALSE; + int host = gethostname(name, HOST_NAME_MAX); + if(host == 0) + { + return TRUE; + } + return FALSE; } diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp index f4ce811fc..8b0f19f5d 100644 --- a/src/tests/test-getcomputername.cpp +++ b/src/tests/test-getcomputername.cpp @@ -4,25 +4,24 @@ TEST(GetComputerName,simple) { char hostname[HOST_NAME_MAX]; - TCHAR hostnameFunctionTest[HOST_NAME_MAX]; + std::string hostnameFunctionTest; DWORD hostSize = HOST_NAME_MAX; - - BOOL getComputerName = GetComputerName(hostnameFunctionTest, &hostSize); + BOOL getComputerName = GetComputerName(&hostnameFunctionTest[0], &hostSize); BOOL host = gethostname(hostname, sizeof hostname); if(host == 0) { - host = TRUE; + host = TRUE; } else { - host = FALSE; + host = FALSE; } - std::string hostnameSting(hostname); - std::string hostnameStingTest(hostnameFunctionTest); + std::string hostnameString(hostname); + std::string hostnameStringTest(&hostnameFunctionTest[0]); ASSERT_TRUE(getComputerName == TRUE); ASSERT_EQ(host,TRUE); - ASSERT_EQ(hostnameSting,hostnameFunctionTest); + ASSERT_EQ(hostnameString,hostnameStringTest); } \ No newline at end of file From e9a2a2d8a237c5b67bffa824045cfcd1cf991699 Mon Sep 17 00:00:00 2001 From: Aaron Katz Date: Thu, 9 Apr 2015 15:23:57 -0700 Subject: [PATCH 019/342] changed spacing --- src/impl/getcpinfo.cpp | 32 ++++++++++++------------ src/tests/test-getcpinfo.cpp | 48 +++++++++++++++++------------------- 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/src/impl/getcpinfo.cpp b/src/impl/getcpinfo.cpp index 0ad41c0a2..857b00de7 100644 --- a/src/impl/getcpinfo.cpp +++ b/src/impl/getcpinfo.cpp @@ -4,25 +4,25 @@ BOOL GetCPInfo(UINT codepage, CPINFO &cpinfo) { - std::string test; - switch(codepage) - { + std::string test; + switch(codepage) + { case 65000: - cpinfo.DefaultChar[0]= '?'; - cpinfo.DefaultChar[1]= '0'; - cpinfo.LeadByte[0] = '0'; - cpinfo.LeadByte[1] = '0'; - cpinfo.MaxCharSize = 5; - return TRUE; + cpinfo.DefaultChar[0] = '?'; + cpinfo.DefaultChar[1] = '0'; + cpinfo.LeadByte[0] = '0'; + cpinfo.LeadByte[1] = '0'; + cpinfo.MaxCharSize = 5; + return TRUE; case 65001: - cpinfo.DefaultChar[0]= '?'; - cpinfo.DefaultChar[1]= '0'; - cpinfo.LeadByte[0] = '0'; - cpinfo.LeadByte[1] = '0'; - cpinfo.MaxCharSize = 4; - return TRUE; + cpinfo.DefaultChar[0] = '?'; + cpinfo.DefaultChar[1] = '0'; + cpinfo.LeadByte[0] = '0'; + cpinfo.LeadByte[1] = '0'; + cpinfo.MaxCharSize = 4; + return TRUE; default: - return FALSE; + return FALSE; } } diff --git a/src/tests/test-getcpinfo.cpp b/src/tests/test-getcpinfo.cpp index 428261f20..0a8d110e9 100644 --- a/src/tests/test-getcpinfo.cpp +++ b/src/tests/test-getcpinfo.cpp @@ -4,36 +4,32 @@ // This is a very simple test case to show how tests can be written TEST(GetCPInfo,utf8) { - CPINFO cpinfo; - BOOL utf8 = GetCPInfo(65001, cpinfo); - + CPINFO cpinfo; + BOOL utf8 = GetCPInfo(65001, cpinfo); - // first make sure that the function worked - ASSERT_TRUE(utf8 == TRUE); - - // now compare the actual values - ASSERT_EQ(cpinfo.DefaultChar[0],'?'); - ASSERT_EQ(cpinfo.DefaultChar[1],'0'); - ASSERT_EQ(cpinfo.LeadByte[0] ,'0'); - ASSERT_EQ(cpinfo.LeadByte[1] ,'0'); - ASSERT_EQ(cpinfo.MaxCharSize ,4); - + // first make sure that the function worked + ASSERT_TRUE(utf8 == TRUE); + + // now compare the actual values + ASSERT_EQ(cpinfo.DefaultChar[0],'?'); + ASSERT_EQ(cpinfo.DefaultChar[1],'0'); + ASSERT_EQ(cpinfo.LeadByte[0],'0'); + ASSERT_EQ(cpinfo.LeadByte[1],'0'); + ASSERT_EQ(cpinfo.MaxCharSize,4); } - TEST(GetCPInfo,utf7) { - CPINFO cpinfo; - BOOL utf7 = GetCPInfo(65000, cpinfo); - + CPINFO cpinfo; + BOOL utf7 = GetCPInfo(65000, cpinfo); + + // first make sure that the function worked + ASSERT_TRUE(utf7 == TRUE); - // first make sure that the function worked - ASSERT_TRUE(utf7 == TRUE); - - // now compare the actual values - ASSERT_EQ(cpinfo.DefaultChar[0],'?'); - ASSERT_EQ(cpinfo.DefaultChar[1],'0'); - ASSERT_EQ(cpinfo.LeadByte[0] ,'0'); - ASSERT_EQ(cpinfo.LeadByte[1] ,'0'); - ASSERT_EQ(cpinfo.MaxCharSize ,5); + // now compare the actual values + ASSERT_EQ(cpinfo.DefaultChar[0],'?'); + ASSERT_EQ(cpinfo.DefaultChar[1],'0'); + ASSERT_EQ(cpinfo.LeadByte[0],'0'); + ASSERT_EQ(cpinfo.LeadByte[1],'0'); + ASSERT_EQ(cpinfo.MaxCharSize,5); } \ No newline at end of file From 439381cbf6710893da4809efcae0848af6f62828 Mon Sep 17 00:00:00 2001 From: Aaron Katz Date: Thu, 9 Apr 2015 15:23:57 -0700 Subject: [PATCH 020/342] changed spacing --- impl/getcpinfo.cpp | 32 +++++++++++++-------------- tests/test-getcpinfo.cpp | 48 ++++++++++++++++++---------------------- 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/impl/getcpinfo.cpp b/impl/getcpinfo.cpp index 0ad41c0a2..857b00de7 100644 --- a/impl/getcpinfo.cpp +++ b/impl/getcpinfo.cpp @@ -4,25 +4,25 @@ BOOL GetCPInfo(UINT codepage, CPINFO &cpinfo) { - std::string test; - switch(codepage) - { + std::string test; + switch(codepage) + { case 65000: - cpinfo.DefaultChar[0]= '?'; - cpinfo.DefaultChar[1]= '0'; - cpinfo.LeadByte[0] = '0'; - cpinfo.LeadByte[1] = '0'; - cpinfo.MaxCharSize = 5; - return TRUE; + cpinfo.DefaultChar[0] = '?'; + cpinfo.DefaultChar[1] = '0'; + cpinfo.LeadByte[0] = '0'; + cpinfo.LeadByte[1] = '0'; + cpinfo.MaxCharSize = 5; + return TRUE; case 65001: - cpinfo.DefaultChar[0]= '?'; - cpinfo.DefaultChar[1]= '0'; - cpinfo.LeadByte[0] = '0'; - cpinfo.LeadByte[1] = '0'; - cpinfo.MaxCharSize = 4; - return TRUE; + cpinfo.DefaultChar[0] = '?'; + cpinfo.DefaultChar[1] = '0'; + cpinfo.LeadByte[0] = '0'; + cpinfo.LeadByte[1] = '0'; + cpinfo.MaxCharSize = 4; + return TRUE; default: - return FALSE; + return FALSE; } } diff --git a/tests/test-getcpinfo.cpp b/tests/test-getcpinfo.cpp index 428261f20..0a8d110e9 100644 --- a/tests/test-getcpinfo.cpp +++ b/tests/test-getcpinfo.cpp @@ -4,36 +4,32 @@ // This is a very simple test case to show how tests can be written TEST(GetCPInfo,utf8) { - CPINFO cpinfo; - BOOL utf8 = GetCPInfo(65001, cpinfo); - + CPINFO cpinfo; + BOOL utf8 = GetCPInfo(65001, cpinfo); - // first make sure that the function worked - ASSERT_TRUE(utf8 == TRUE); - - // now compare the actual values - ASSERT_EQ(cpinfo.DefaultChar[0],'?'); - ASSERT_EQ(cpinfo.DefaultChar[1],'0'); - ASSERT_EQ(cpinfo.LeadByte[0] ,'0'); - ASSERT_EQ(cpinfo.LeadByte[1] ,'0'); - ASSERT_EQ(cpinfo.MaxCharSize ,4); - + // first make sure that the function worked + ASSERT_TRUE(utf8 == TRUE); + + // now compare the actual values + ASSERT_EQ(cpinfo.DefaultChar[0],'?'); + ASSERT_EQ(cpinfo.DefaultChar[1],'0'); + ASSERT_EQ(cpinfo.LeadByte[0],'0'); + ASSERT_EQ(cpinfo.LeadByte[1],'0'); + ASSERT_EQ(cpinfo.MaxCharSize,4); } - TEST(GetCPInfo,utf7) { - CPINFO cpinfo; - BOOL utf7 = GetCPInfo(65000, cpinfo); - + CPINFO cpinfo; + BOOL utf7 = GetCPInfo(65000, cpinfo); + + // first make sure that the function worked + ASSERT_TRUE(utf7 == TRUE); - // first make sure that the function worked - ASSERT_TRUE(utf7 == TRUE); - - // now compare the actual values - ASSERT_EQ(cpinfo.DefaultChar[0],'?'); - ASSERT_EQ(cpinfo.DefaultChar[1],'0'); - ASSERT_EQ(cpinfo.LeadByte[0] ,'0'); - ASSERT_EQ(cpinfo.LeadByte[1] ,'0'); - ASSERT_EQ(cpinfo.MaxCharSize ,5); + // now compare the actual values + ASSERT_EQ(cpinfo.DefaultChar[0],'?'); + ASSERT_EQ(cpinfo.DefaultChar[1],'0'); + ASSERT_EQ(cpinfo.LeadByte[0],'0'); + ASSERT_EQ(cpinfo.LeadByte[1],'0'); + ASSERT_EQ(cpinfo.MaxCharSize,5); } \ No newline at end of file From 95450a16ed4eede74fa20b7d975094a2709f2d73 Mon Sep 17 00:00:00 2001 From: Aditya Mandaleeka Date: Tue, 21 Apr 2015 23:47:33 -0700 Subject: [PATCH 021/342] Add Unix version of coreconsole. Created a Unix version of coreconsole which, like the Windows version, is similar to corerun but runs the managed binary with the same name as the executable (but with the DLL extension). Moved code that is common between corerun and coreconsole to coreruncommon. Remove the workaround for the XCode 6.3 SDK issue wherein some of the system headers that we reference try to include a __debug header which does not exist. The 6.3.1 update fixed that issue so the workaround is no longer required. Fix #747 --- .gitmirror | 1 + coreruncommon.cpp | 311 ++++++++++++++++++++++++++++++++++++++++++++++ coreruncommon.h | 46 +++++++ 3 files changed, 358 insertions(+) create mode 100644 .gitmirror create mode 100644 coreruncommon.cpp create mode 100644 coreruncommon.h diff --git a/.gitmirror b/.gitmirror new file mode 100644 index 000000000..f507630f9 --- /dev/null +++ b/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file diff --git a/coreruncommon.cpp b/coreruncommon.cpp new file mode 100644 index 000000000..129403866 --- /dev/null +++ b/coreruncommon.cpp @@ -0,0 +1,311 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// +// Code that is used by both the Unix corerun and coreconsole. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +// The name of the CoreCLR native runtime DLL +#if defined(__APPLE__) +static const char * const coreClrDll = "libcoreclr.dylib"; +#else +static const char * const coreClrDll = "libcoreclr.so"; +#endif + +// Windows types used by the ExecuteAssembly function +typedef unsigned int DWORD; +typedef const char16_t* LPCWSTR; +typedef const char* LPCSTR; +typedef int32_t HRESULT; + +#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0) + +// Prototype of the ExecuteAssembly function from the libcoreclr.do +typedef HRESULT (*ExecuteAssemblyFunction)( + LPCSTR exePath, + LPCSTR coreClrPath, + LPCSTR appDomainFriendlyName, + int propertyCount, + LPCSTR* propertyKeys, + LPCSTR* propertyValues, + int argc, + LPCSTR* argv, + LPCSTR managedAssemblyPath, + LPCSTR entryPointAssemblyName, + LPCSTR entryPointTypeName, + LPCSTR entryPointMethodsName, + DWORD* exitCode); + +bool GetAbsolutePath(const char* path, std::string& absolutePath) +{ + bool result = false; + + char realPath[PATH_MAX]; + if (realpath(path, realPath) != nullptr && realPath[0] != '\0') + { + absolutePath.assign(realPath); + // realpath should return canonicalized path without the trailing slash + assert(absolutePath.back() != '/'); + + result = true; + } + + return result; +} + +bool GetDirectory(const char* absolutePath, std::string& directory) +{ + directory.assign(absolutePath); + size_t lastSlash = directory.rfind('/'); + if (lastSlash != std::string::npos) + { + directory.erase(lastSlash); + return true; + } + + return false; +} + +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) +{ + std::string clrFilesRelativePath; + const char* clrFilesPathLocal = clrFilesPath; + if (clrFilesPathLocal == nullptr) + { + // There was no CLR files path specified, use the folder of the corerun/coreconsole + if (!GetDirectory(currentExePath, clrFilesRelativePath)) + { + perror("Failed to get directory from argv[0]"); + return false; + } + + clrFilesPathLocal = clrFilesRelativePath.c_str(); + + // TODO: consider using an env variable (if defined) as a fall-back. + // The windows version of the corerun uses core_root env variable + } + + if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) + { + perror("Failed to convert CLR files path to absolute path"); + return false; + } + + return true; +} + +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) +{ + const char * const tpaExtensions[] = { + ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir + ".dll", + ".ni.exe", + ".exe", + }; + + DIR* dir = opendir(directory); + if (dir == nullptr) + { + return; + } + + std::set addedAssemblies; + + // Walk the directory for each extension separately so that we first get files with .ni.dll extension, + // then files with .dll extension, etc. + for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + { + const char* ext = tpaExtensions[extIndex]; + int extLength = strlen(ext); + + struct dirent* entry; + + // For all entries in the directory + while ((entry = readdir(dir)) != nullptr) + { + // We are interested in files only + switch (entry->d_type) + { + case DT_REG: + break; + + // Handle symlinks and file systems that do not support d_type + case DT_LNK: + case DT_UNKNOWN: + { + std::string fullFilename; + + fullFilename.append(directory); + fullFilename.append("/"); + fullFilename.append(entry->d_name); + + struct stat sb; + if (stat(fullFilename.c_str(), &sb) == -1) + { + continue; + } + + if (!S_ISREG(sb.st_mode)) + { + continue; + } + } + break; + + default: + continue; + } + + std::string filename(entry->d_name); + + // Check if the extension matches the one we are looking for + int extPos = filename.length() - extLength; + if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) + { + continue; + } + + std::string filenameWithoutExt(filename.substr(0, extPos)); + + // Make sure if we have an assembly with multiple extensions present, + // we insert only one version of it. + if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) + { + addedAssemblies.insert(filenameWithoutExt); + + tpaList.append(directory); + tpaList.append("/"); + tpaList.append(filename); + tpaList.append(":"); + } + } + + // Rewind the directory stream to be able to iterate over it for the next extension + rewinddir(dir); + } + + closedir(dir); +} + +int ExecuteManagedAssembly( + const char* currentExeAbsolutePath, + const char* clrFilesAbsolutePath, + const char* managedAssemblyAbsolutePath, + int managedAssemblyArgc, + const char** managedAssemblyArgv) +{ + // Indicates failure + int exitCode = -1; + + std::string coreClrDllPath(clrFilesAbsolutePath); + coreClrDllPath.append("/"); + coreClrDllPath.append(coreClrDll); + + if (coreClrDllPath.length() >= PATH_MAX) + { + fprintf(stderr, "Absolute path to libcoreclr.so too long\n"); + return -1; + } + + // Get just the path component of the managed assembly path + std::string appPath; + GetDirectory(managedAssemblyAbsolutePath, appPath); + + std::string nativeDllSearchDirs(appPath); + nativeDllSearchDirs.append(":"); + nativeDllSearchDirs.append(clrFilesAbsolutePath); + + std::string tpaList; + AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath, tpaList); + + void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW | RTLD_LOCAL); + if (coreclrLib != nullptr) + { + ExecuteAssemblyFunction executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib, "ExecuteAssembly"); + if (executeAssembly != nullptr) + { + // Allowed property names: + // APPBASE + // - The base path of the application from which the exe and other assemblies will be loaded + // + // TRUSTED_PLATFORM_ASSEMBLIES + // - The list of complete paths to each of the fully trusted assemblies + // + // APP_PATHS + // - The list of paths which will be probed by the assembly loader + // + // APP_NI_PATHS + // - The list of additional paths that the assembly loader will probe for ngen images + // + // NATIVE_DLL_SEARCH_DIRECTORIES + // - The list of paths that will be probed for native DLLs called by PInvoke + // + const char *propertyKeys[] = { + "TRUSTED_PLATFORM_ASSEMBLIES", + "APP_PATHS", + "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", + "AppDomainCompatSwitch" + }; + const char *propertyValues[] = { + // TRUSTED_PLATFORM_ASSEMBLIES + tpaList.c_str(), + // APP_PATHS + appPath.c_str(), + // APP_NI_PATHS + appPath.c_str(), + // NATIVE_DLL_SEARCH_DIRECTORIES + nativeDllSearchDirs.c_str(), + // AppDomainCompatSwitch + "UseLatestBehaviorWhenTFMNotSpecified" + }; + + HRESULT st = executeAssembly( + currentExeAbsolutePath, + coreClrDllPath.c_str(), + "unixcorerun", + sizeof(propertyKeys) / sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + managedAssemblyArgc, + managedAssemblyArgv, + managedAssemblyAbsolutePath, + NULL, + NULL, + NULL, + (DWORD*)&exitCode); + + if (!SUCCEEDED(st)) + { + fprintf(stderr, "ExecuteAssembly failed - status: 0x%08x\n", st); + } + } + else + { + fprintf(stderr, "Function ExecuteAssembly not found in the libcoreclr.so\n"); + } + + if (dlclose(coreclrLib) != 0) + { + fprintf(stderr, "Warning - dlclose failed\n"); + } + } + else + { + char* error = dlerror(); + fprintf(stderr, "dlopen failed to open the libcoreclr.so with error %s\n", error); + } + + return exitCode; +} diff --git a/coreruncommon.h b/coreruncommon.h new file mode 100644 index 000000000..b587e407f --- /dev/null +++ b/coreruncommon.h @@ -0,0 +1,46 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include + +// Get absolute path from the specified path. +// Return true in case of a success, false otherwise. +bool GetAbsolutePath(const char* path, std::string& absolutePath); + +// Get directory of the specified path. +// Return true in case of a success, false otherwise. +bool GetDirectory(const char* absolutePath, std::string& directory); + +// +// Get the absolute path to use to locate libcoreclr.so and the CLR assemblies are stored. If clrFilesPath is provided, +// this function will return the absolute path to it. Otherwise, the directory of the current executable is used. +// +// Return true in case of a success, false otherwise. +// +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); + +// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); + +// +// Execute the specified managed assembly. +// +// Parameters: +// currentExePath - Path to the current executable +// clrFilesAbsolutePath - Absolute path to the folder where the libcoreclr.so and CLR managed assemblies are stored +// managedAssemblyPath - Path to the managed assembly to execute +// managedAssemblyArgc - Number of arguments passed to the executed assembly +// managedAssemblyArgv - Array of arguments passed to the executed assembly +// +// Returns: +// ExitCode of the assembly +// +int ExecuteManagedAssembly( + const char* currentExeAbsolutePath, + const char* clrFilesAbsolutePath, + const char* managedAssemblyAbsolutePath, + int managedAssemblyArgc, + const char** managedAssemblyArgv); + From accac3138edc494b1466b4c4642b2b820755dcba Mon Sep 17 00:00:00 2001 From: Anders Jensen-Waud Date: Fri, 1 May 2015 11:16:53 +1000 Subject: [PATCH 022/342] Fix unixcoreruncommon build error on FreeBSD Needed cstdlib to build properly --- coreruncommon.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/coreruncommon.cpp b/coreruncommon.cpp index 129403866..e7323c177 100644 --- a/coreruncommon.cpp +++ b/coreruncommon.cpp @@ -7,6 +7,7 @@ // Code that is used by both the Unix corerun and coreconsole. // +#include #include #include #include From 1c6cd1d37e89e22169535e1c65edb7d7b0f1eabc Mon Sep 17 00:00:00 2001 From: stephentoub Date: Thu, 28 May 2015 15:02:40 -0400 Subject: [PATCH 023/342] Fix exitCode from ExecuteAssembly ExecuteAssembly is initializing exitCode to 0 on entrance to the function. If it then fails prior to exitCode being set when invoking the entry point, the exitCode remains 0 even though there was a failure, and corerun ends up returning a successful exit code. --- coreruncommon.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/coreruncommon.cpp b/coreruncommon.cpp index e7323c177..4f6ffa033 100644 --- a/coreruncommon.cpp +++ b/coreruncommon.cpp @@ -290,6 +290,7 @@ int ExecuteManagedAssembly( if (!SUCCEEDED(st)) { fprintf(stderr, "ExecuteAssembly failed - status: 0x%08x\n", st); + exitCode = -1; } } else From f8f4b5e380a222332793c1005d425de02bf1817e Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Tue, 16 Jun 2015 14:02:19 -0700 Subject: [PATCH 024/342] added libps.so, added stub for GetUserName --- src/CMakeLists.txt | 13 +++++++++---- src/impl/getusername.cpp | 8 ++++++++ src/impl/getusername.h | 10 ++++++++++ src/impl/pal.h | 4 +++- 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 src/impl/getusername.cpp create mode 100644 src/impl/getusername.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4355f98d0..967a6f004 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,13 +5,18 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest include_directories(../ext-src/gtest/fused-src impl) +link_directories(${monad_native_BINARY_DIR}) -set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) -add_executable(monad_native ${SOURCE_FILES}) +set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp) +set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp) +set(SOURCE_FILES main.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) -# add pthread +add_library(ps SHARED ${LIB_SOURCE_FILES}) +add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) + +# add pthread and other libs find_package(Threads) -target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp new file mode 100644 index 000000000..b37b1cffc --- /dev/null +++ b/src/impl/getusername.cpp @@ -0,0 +1,8 @@ +#include "getusername.h" +#include + +BOOL GetUserName(WCHAR_T* userName, UINT32* maxLength) +{ + return 0; +} + diff --git a/src/impl/getusername.h b/src/impl/getusername.h new file mode 100644 index 000000000..922a4e96a --- /dev/null +++ b/src/impl/getusername.h @@ -0,0 +1,10 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +BOOL GetUserName(WCHAR_T* userName, UINT32* maxLength); + +PAL_END_EXTERNC + diff --git a/src/impl/pal.h b/src/impl/pal.h index 659afd4f6..1cfc77630 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -51,7 +51,9 @@ #define WIN32_FROM_HRESULT(hr) hr #define HRESULT_FROM_WIN32(error) error typedef unsigned long DWORD, *LPDWORD; - typedef int BOOL; + typedef char BOOL; + typedef unsigned short WCHAR_T; + typedef unsigned int UINT32; typedef unsigned long HRESULT; typedef const wchar_t *PCWSTR; typedef wchar_t *PWSTR; From 1b02619b2d513916106c8a0e1a827c92fcdd2bc3 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Tue, 16 Jun 2015 14:02:19 -0700 Subject: [PATCH 025/342] added libps.so, added stub for GetUserName --- CMakeLists.txt | 13 +++++++++---- impl/getusername.cpp | 8 ++++++++ impl/getusername.h | 10 ++++++++++ impl/pal.h | 4 +++- 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 impl/getusername.cpp create mode 100644 impl/getusername.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4355f98d0..967a6f004 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,13 +5,18 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest include_directories(../ext-src/gtest/fused-src impl) +link_directories(${monad_native_BINARY_DIR}) -set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) -add_executable(monad_native ${SOURCE_FILES}) +set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp) +set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp) +set(SOURCE_FILES main.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) -# add pthread +add_library(ps SHARED ${LIB_SOURCE_FILES}) +add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) + +# add pthread and other libs find_package(Threads) -target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) diff --git a/impl/getusername.cpp b/impl/getusername.cpp new file mode 100644 index 000000000..b37b1cffc --- /dev/null +++ b/impl/getusername.cpp @@ -0,0 +1,8 @@ +#include "getusername.h" +#include + +BOOL GetUserName(WCHAR_T* userName, UINT32* maxLength) +{ + return 0; +} + diff --git a/impl/getusername.h b/impl/getusername.h new file mode 100644 index 000000000..922a4e96a --- /dev/null +++ b/impl/getusername.h @@ -0,0 +1,10 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +BOOL GetUserName(WCHAR_T* userName, UINT32* maxLength); + +PAL_END_EXTERNC + diff --git a/impl/pal.h b/impl/pal.h index 659afd4f6..1cfc77630 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -51,7 +51,9 @@ #define WIN32_FROM_HRESULT(hr) hr #define HRESULT_FROM_WIN32(error) error typedef unsigned long DWORD, *LPDWORD; - typedef int BOOL; + typedef char BOOL; + typedef unsigned short WCHAR_T; + typedef unsigned int UINT32; typedef unsigned long HRESULT; typedef const wchar_t *PCWSTR; typedef wchar_t *PWSTR; From a756ecaadfa486b77032e7cefeb75ac0f479b403 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Tue, 7 Jul 2015 18:04:23 -0700 Subject: [PATCH 026/342] added pinvoke functions to query terminal size --- src/CMakeLists.txt | 2 +- src/impl/pal.h | 1 + src/impl/terminal.cpp | 21 +++++++++++++++++++++ src/impl/terminal.h | 11 +++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/impl/terminal.cpp create mode 100644 src/impl/terminal.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 967a6f004..f23a2b711 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") include_directories(../ext-src/gtest/fused-src impl) link_directories(${monad_native_BINARY_DIR}) -set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp) +set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp) set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp) set(SOURCE_FILES main.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) diff --git a/src/impl/pal.h b/src/impl/pal.h index 1cfc77630..f98108884 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -54,6 +54,7 @@ typedef char BOOL; typedef unsigned short WCHAR_T; typedef unsigned int UINT32; + typedef int INT32; typedef unsigned long HRESULT; typedef const wchar_t *PCWSTR; typedef wchar_t *PWSTR; diff --git a/src/impl/terminal.cpp b/src/impl/terminal.cpp new file mode 100644 index 000000000..c32192802 --- /dev/null +++ b/src/impl/terminal.cpp @@ -0,0 +1,21 @@ +#include "terminal.h" +#include + +INT32 GetTerminalWidth() +{ + struct winsize ws; + if (-1 == ioctl(0,TIOCGWINSZ,&ws)) + return -1; + + return ws.ws_col; +} + +INT32 GetTerminalHeight() +{ + struct winsize ws; + if (-1 == ioctl(0,TIOCGWINSZ,&ws)) + return -1; + + return ws.ws_row; +} + diff --git a/src/impl/terminal.h b/src/impl/terminal.h new file mode 100644 index 000000000..00332e9bf --- /dev/null +++ b/src/impl/terminal.h @@ -0,0 +1,11 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +INT32 GetTerminalWidth(); +INT32 GetTerminalHeight(); + +PAL_END_EXTERNC + From 39e939ce0f7bfd1c90e949cd447ad71dc91fa8b1 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Tue, 7 Jul 2015 18:04:23 -0700 Subject: [PATCH 027/342] added pinvoke functions to query terminal size --- CMakeLists.txt | 2 +- impl/pal.h | 1 + impl/terminal.cpp | 21 +++++++++++++++++++++ impl/terminal.h | 11 +++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 impl/terminal.cpp create mode 100644 impl/terminal.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 967a6f004..f23a2b711 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") include_directories(../ext-src/gtest/fused-src impl) link_directories(${monad_native_BINARY_DIR}) -set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp) +set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp) set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp) set(SOURCE_FILES main.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) diff --git a/impl/pal.h b/impl/pal.h index 1cfc77630..f98108884 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -54,6 +54,7 @@ typedef char BOOL; typedef unsigned short WCHAR_T; typedef unsigned int UINT32; + typedef int INT32; typedef unsigned long HRESULT; typedef const wchar_t *PCWSTR; typedef wchar_t *PWSTR; diff --git a/impl/terminal.cpp b/impl/terminal.cpp new file mode 100644 index 000000000..c32192802 --- /dev/null +++ b/impl/terminal.cpp @@ -0,0 +1,21 @@ +#include "terminal.h" +#include + +INT32 GetTerminalWidth() +{ + struct winsize ws; + if (-1 == ioctl(0,TIOCGWINSZ,&ws)) + return -1; + + return ws.ws_col; +} + +INT32 GetTerminalHeight() +{ + struct winsize ws; + if (-1 == ioctl(0,TIOCGWINSZ,&ws)) + return -1; + + return ws.ws_row; +} + diff --git a/impl/terminal.h b/impl/terminal.h new file mode 100644 index 000000000..00332e9bf --- /dev/null +++ b/impl/terminal.h @@ -0,0 +1,11 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +INT32 GetTerminalWidth(); +INT32 GetTerminalHeight(); + +PAL_END_EXTERNC + From a566a181a076f4fa49f4874934c080309424bd6c Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Wed, 15 Jul 2015 23:08:09 +0200 Subject: [PATCH 028/342] Extend the Unix hosting API This change modifies the Unix hosting API so that the hosting app can create as many managed delegates as it needs and execute them as many times it wants. The new API contains separate functions to initialize and shutdown CoreCLR and a function to create a delegate. The current ExecuteAssembly function behavior stays unmodified for now to ensure that dnx that uses that API and that pulls the binary libcoreclr is not broken. After the dnx is updated to use the new coreclr_create_delegate API, I'll remove the ExecuteAssembly. Also done: 1) Added support for comments and skipping empty lines in the mscorwks_unixexports.src. 2) Restructured the mscorwks_unixexports.src 3) Added coreclr_execute_assembly to the unixinterface.cpp / exports 4) Modified coreruncommon.cpp to use the new hosting API --- coreruncommon.cpp | 117 +++++++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 42 deletions(-) diff --git a/coreruncommon.cpp b/coreruncommon.cpp index 4f6ffa033..ecbbf3929 100644 --- a/coreruncommon.cpp +++ b/coreruncommon.cpp @@ -24,29 +24,31 @@ static const char * const coreClrDll = "libcoreclr.dylib"; static const char * const coreClrDll = "libcoreclr.so"; #endif -// Windows types used by the ExecuteAssembly function -typedef unsigned int DWORD; -typedef const char16_t* LPCWSTR; -typedef const char* LPCSTR; -typedef int32_t HRESULT; +#define SUCCEEDED(Status) ((Status) >= 0) -#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0) +// Prototype of the coreclr_initialize function from the libcoreclr.so +typedef int (*InitializeCoreCLRFunction)( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); -// Prototype of the ExecuteAssembly function from the libcoreclr.do -typedef HRESULT (*ExecuteAssemblyFunction)( - LPCSTR exePath, - LPCSTR coreClrPath, - LPCSTR appDomainFriendlyName, - int propertyCount, - LPCSTR* propertyKeys, - LPCSTR* propertyValues, - int argc, - LPCSTR* argv, - LPCSTR managedAssemblyPath, - LPCSTR entryPointAssemblyName, - LPCSTR entryPointTypeName, - LPCSTR entryPointMethodsName, - DWORD* exitCode); +// Prototype of the coreclr_shutdown function from the libcoreclr.so +typedef int (*ShutdownCoreCLRFunction)( + void* hostHandle, + unsigned int domainId); + +// Prototype of the coreclr_execute_assembly function from the libcoreclr.so +typedef int (*ExecuteAssemblyFunction)( + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); bool GetAbsolutePath(const char* path, std::string& absolutePath) { @@ -233,8 +235,23 @@ int ExecuteManagedAssembly( void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW | RTLD_LOCAL); if (coreclrLib != nullptr) { - ExecuteAssemblyFunction executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib, "ExecuteAssembly"); - if (executeAssembly != nullptr) + InitializeCoreCLRFunction initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib, "coreclr_initialize"); + ExecuteAssemblyFunction executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib, "coreclr_execute_assembly"); + ShutdownCoreCLRFunction shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib, "coreclr_shutdown"); + + if (initializeCoreCLR == nullptr) + { + fprintf(stderr, "Function coreclr_initialize not found in the libcoreclr.so\n"); + } + else if (executeAssembly == nullptr) + { + fprintf(stderr, "Function coreclr_execute_assembly not found in the libcoreclr.so\n"); + } + else if (shutdownCoreCLR == nullptr) + { + fprintf(stderr, "Function coreclr_shutdown not found in the libcoreclr.so\n"); + } + else { // Allowed property names: // APPBASE @@ -272,30 +289,46 @@ int ExecuteManagedAssembly( "UseLatestBehaviorWhenTFMNotSpecified" }; - HRESULT st = executeAssembly( - currentExeAbsolutePath, - coreClrDllPath.c_str(), - "unixcorerun", - sizeof(propertyKeys) / sizeof(propertyKeys[0]), - propertyKeys, - propertyValues, - managedAssemblyArgc, - managedAssemblyArgv, - managedAssemblyAbsolutePath, - NULL, - NULL, - NULL, - (DWORD*)&exitCode); + void* hostHandle; + unsigned int domainId; + + int st = initializeCoreCLR( + currentExeAbsolutePath, + "unixcorerun", + sizeof(propertyKeys) / sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + &hostHandle, + &domainId); if (!SUCCEEDED(st)) { - fprintf(stderr, "ExecuteAssembly failed - status: 0x%08x\n", st); + fprintf(stderr, "coreclr_initialize failed - status: 0x%08x\n", st); exitCode = -1; } - } - else - { - fprintf(stderr, "Function ExecuteAssembly not found in the libcoreclr.so\n"); + else + { + st = executeAssembly( + hostHandle, + domainId, + managedAssemblyArgc, + managedAssemblyArgv, + managedAssemblyAbsolutePath, + (unsigned int*)&exitCode); + + if (!SUCCEEDED(st)) + { + fprintf(stderr, "coreclr_execute_assembly failed - status: 0x%08x\n", st); + exitCode = -1; + } + + st = shutdownCoreCLR(hostHandle, domainId); + if (!SUCCEEDED(st)) + { + fprintf(stderr, "coreclr_shutdown failed - status: 0x%08x\n", st); + exitCode = -1; + } + } } if (dlclose(coreclrLib) != 0) From 371115999686e0580a9faf35b4c008223ae602ea Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Mon, 27 Jul 2015 17:38:11 +0200 Subject: [PATCH 029/342] added first version of custom PS hosting code --- src/CMakeLists.txt | 5 + src/host/cmdline/coreclrutil.cpp | 163 ++++++++++++++++++++++++++ src/host/cmdline/coreclrutil.h | 63 ++++++++++ src/host/cmdline/main.cpp | 194 +++++++++++++++++++++++++++++++ 4 files changed, 425 insertions(+) create mode 100644 src/host/cmdline/coreclrutil.cpp create mode 100644 src/host/cmdline/coreclrutil.h create mode 100644 src/host/cmdline/main.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f23a2b711..98053e3cc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,16 +7,21 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 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) set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp) set(SOURCE_FILES main.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) +SET(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp host/cmdline/coreclrutil.cpp) +# 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}) # add pthread and other libs find_package(Threads) target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) +target_link_libraries(host_cmdline dl) diff --git a/src/host/cmdline/coreclrutil.cpp b/src/host/cmdline/coreclrutil.cpp new file mode 100644 index 000000000..d67a1057f --- /dev/null +++ b/src/host/cmdline/coreclrutil.cpp @@ -0,0 +1,163 @@ +#include "coreclrutil.h" +#include +#include +#include +#include +#include + +namespace CoreCLRUtil +{ + +bool GetAbsolutePath(const char* path, std::string& absolutePath) +{ + bool result = false; + + char realPath[PATH_MAX]; + if (realpath(path, realPath) != nullptr && realPath[0] != '\0') + { + absolutePath.assign(realPath); + // realpath should return canonicalized path without the trailing slash + assert(absolutePath.back() != '/'); + + result = true; + } + + return result; +} + +bool GetDirectory(const char* absolutePath, std::string& directory) +{ + directory.assign(absolutePath); + size_t lastSlash = directory.rfind('/'); + if (lastSlash != std::string::npos) + { + directory.erase(lastSlash); + return true; + } + + return false; +} + +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) +{ + std::string clrFilesRelativePath; + const char* clrFilesPathLocal = clrFilesPath; + if (clrFilesPathLocal == nullptr) + { + // There was no CLR files path specified, use the folder of the corerun/coreconsole + if (!GetDirectory(currentExePath, clrFilesRelativePath)) + { + perror("Failed to get directory from argv[0]"); + return false; + } + + clrFilesPathLocal = clrFilesRelativePath.c_str(); + + // TODO: consider using an env variable (if defined) as a fall-back. + // The windows version of the corerun uses core_root env variable + } + + if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) + { + perror("Failed to convert CLR files path to absolute path"); + return false; + } + + return true; +} + +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) +{ + const char * const tpaExtensions[] = { + ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir + ".dll", + ".ni.exe", + ".exe", + }; + + DIR* dir = opendir(directory); + if (dir == nullptr) + { + return; + } + + std::set addedAssemblies; + + // Walk the directory for each extension separately so that we first get files with .ni.dll extension, + // then files with .dll extension, etc. + for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + { + const char* ext = tpaExtensions[extIndex]; + int extLength = strlen(ext); + + struct dirent* entry; + + // For all entries in the directory + while ((entry = readdir(dir)) != nullptr) + { + // We are interested in files only + switch (entry->d_type) + { + case DT_REG: + break; + + // Handle symlinks and file systems that do not support d_type + case DT_LNK: + case DT_UNKNOWN: + { + std::string fullFilename; + + fullFilename.append(directory); + fullFilename.append("/"); + fullFilename.append(entry->d_name); + + struct stat sb; + if (stat(fullFilename.c_str(), &sb) == -1) + { + continue; + } + + if (!S_ISREG(sb.st_mode)) + { + continue; + } + } + break; + + default: + continue; + } + + std::string filename(entry->d_name); + + // Check if the extension matches the one we are looking for + int extPos = filename.length() - extLength; + if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) + { + continue; + } + + std::string filenameWithoutExt(filename.substr(0, extPos)); + + // Make sure if we have an assembly with multiple extensions present, + // we insert only one version of it. + if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) + { + addedAssemblies.insert(filenameWithoutExt); + + tpaList.append(directory); + tpaList.append("/"); + tpaList.append(filename); + tpaList.append(":"); + } + } + + // Rewind the directory stream to be able to iterate over it for the next extension + rewinddir(dir); + } + + closedir(dir); +} + +} // namespace CoreCLRUtil + diff --git a/src/host/cmdline/coreclrutil.h b/src/host/cmdline/coreclrutil.h new file mode 100644 index 000000000..49a45ab6e --- /dev/null +++ b/src/host/cmdline/coreclrutil.h @@ -0,0 +1,63 @@ +#pragma once + +#include + +namespace CoreCLRUtil +{ + +// +// This code is mostly copied and modified from original CoreCLR project's +// code on github: https://github.com/dotnet/coreclr +// + +// +// these function signatures are the entry point API for CoreCLR +// + +// Prototype of the coreclr_initialize function from the libcoreclr.so +typedef int (*InitializeCoreCLRFunction)( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); + +// Prototype of the coreclr_shutdown function from the libcoreclr.so +typedef int (*ShutdownCoreCLRFunction)( + void* hostHandle, + unsigned int domainId); + +// Prototype of the coreclr_execute_assembly function from the libcoreclr.so +typedef int (*ExecuteAssemblyFunction)( + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); + +// Prototype of coreclr_create_delegate function from the libcoreclr.so +typedef int (*CreateDelegateFunction)( + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate); + +// The name of the CoreCLR native runtime DLL +#if defined(__APPLE__) +constexpr char coreClrDll[] = "libcoreclr.dylib"; +#else +constexpr char coreClrDll[] = "libcoreclr.so"; +#endif + +bool GetAbsolutePath(const char* path, std::string& absolutePath); +bool GetDirectory(const char* absolutePath, std::string& directory); +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); + +} // namespace CoreCLRUtil + diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp new file mode 100644 index 000000000..29fbfb938 --- /dev/null +++ b/src/host/cmdline/main.cpp @@ -0,0 +1,194 @@ +#include +#include +#include "coreclrutil.h" +#include +#include + +int main(int argc, char** argv) +{ + // TODO: read from command line args + std::string clrAbsolutePath = "/home/peter/gitwd/monad-linux/scripts/exec_env/app_base"; + + // managed assembly arguments + int managedAssemblyArgc = 0; + const char* managedAssemblyArgv[] = { "" }; + + // there are two assemblies involved in hosting PowerShell: + // - Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll + // + this assembly has to be listed as platform assembly + // - System.Management.Automation.dll + std::string powershellBaseAbsolutePath = "/home/peter/gitwd/monad-linux/scripts/exec_env/app_base"; + std::string assemblyLoadContextAssemblyName = "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext"; + std::string assemblyLoadContextAbsolutePath = powershellBaseAbsolutePath + "/" + assemblyLoadContextAssemblyName + ".dll"; + std::string systemManagementAutomationAssemblyName = "System.Management.Automation"; + std::string systemManagementAutomationAbsolutePath = powershellBaseAbsolutePath + "/" + systemManagementAutomationAssemblyName + ".dll"; + + std::string coreClrDllPath = clrAbsolutePath + "/" + CoreCLRUtil::coreClrDll; + if (coreClrDllPath.size() >= PATH_MAX) + { + std::cerr << "Absolute path to CoreCLR library too long" << std::endl; + return 1; + } + std::cout << "coreClrDllPath: " << coreClrDllPath << std::endl; + + // TPA list + // + // The list of platform assemblies must include all CoreCLR assemblies + // and the Microsoft.PowerShell.CoreCLR.AssemblyLoadContext + // + // TODO: move CLR assemblies to separate path during build&run make steps + // TODO: only add assembly load context to TPA list, not any other PS dll + + std::string tpaList; + CoreCLRUtil::AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); + std::cout << "tpaList: " << tpaList << std::endl; + + // assembly load paths + // + // All PowerShell assemblies are assumed to be in the same path + + std::string appPath; + if (!CoreCLRUtil::GetDirectory(assemblyLoadContextAbsolutePath.c_str(),appPath)) + { + std::cerr << "failed to get assembly search directory from assembly absolute path" << std::endl; + return 1; + } + std::cout << "appPath: " << appPath << std::endl; + + // search paths for native dlls + // + // Add both the CoreCLR directory and the PowerShell directory to this list + std::string nativeDllSearchDirs = appPath + ":" + clrAbsolutePath; + + // get the absolute path of the current executable + std::string currentExeAbsolutePath; + if (!CoreCLRUtil::GetAbsolutePath(argv[0],currentExeAbsolutePath)) + { + std::cerr << "could not get absolute path of current executable" << std::endl; + return 1; + } + + // open the shared library + void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); + if (coreclrLib == nullptr) + { + char* error = dlerror(); + std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; + return 2; + } + + // query the function pointers + CoreCLRUtil::InitializeCoreCLRFunction initializeCoreCLR = (CoreCLRUtil::InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); + CoreCLRUtil::ExecuteAssemblyFunction executeAssembly = (CoreCLRUtil::ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); + CoreCLRUtil::ShutdownCoreCLRFunction shutdownCoreCLR = (CoreCLRUtil::ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); + CoreCLRUtil::CreateDelegateFunction createDelegate = (CoreCLRUtil::CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); + + if (initializeCoreCLR == nullptr) + { + std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; + return 3; + } + if (executeAssembly == nullptr) + { + std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; + return 3; + } + if (shutdownCoreCLR == nullptr) + { + std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; + return 3; + } + if (createDelegate == nullptr) + { + std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; + return 3; + } + + // create list of properties to initialize CoreCLR + const char* propertyKeys[] = { + "TRUSTED_PLATFORM_ASSEMBLIES", + "APP_PATHS", + "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", + "AppDomainCompatSwitch" + }; + + const char* propertyValues[] = { + tpaList.c_str(), + appPath.c_str(), + appPath.c_str(), + nativeDllSearchDirs.c_str(), + "UseLatestBehaviorWhenTFMNotSpecified" + }; + + + // initialize CoreCLR + void* hostHandle; + unsigned int domainId; + int status = initializeCoreCLR( + currentExeAbsolutePath.c_str(), + "ps_cmdline_host", + sizeof(propertyKeys)/sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + &hostHandle, + &domainId); + + if (0 > status) + { + std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; + return 4; + } + + // initialize the PS's custom assembly load context + typedef void (*LoaderRunHelperFp)(const char16_t* appPath); + LoaderRunHelperFp loaderDelegate = nullptr; + status = createDelegate( + hostHandle, + domainId, + "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", + "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", + "SetPowerShellAssemblyLoadContext", + (void**)&loaderDelegate); + if (0 > status) + { + std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; + return 4; + } + + loaderDelegate(u"/home/peter/gitwd/monad-linux/scripts/exec_env/app_base"); + + + typedef int (*TestDelegate)(); + TestDelegate testDelegate = nullptr; + status = createDelegate( + hostHandle, + domainId, + "System.Management.Automation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", + "System.Management.Automation.Platform", + "IsLinux", + (void**)&testDelegate); + int returnValue = testDelegate(); + std::cout << "returnValue=" << returnValue << std::endl; + + + typedef void (*UnmanagedEntry)(); + UnmanagedEntry unmanagedEntry = nullptr; + status = createDelegate( + hostHandle, + domainId, + "powershell-simple, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", + "ps_hello_world.Program", + "UnmanagedEntry", + (void**)&unmanagedEntry); + if (0 > status) + { + std::cerr << "could not create delegate for UnmanagedEntry - status: " << std::hex << status << std::endl; + return 4; + } + + unmanagedEntry(); + + return 0; +} + From b9784906f4d71d4d4a4f36f6667d6ed8e1d2aff9 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Mon, 27 Jul 2015 17:38:11 +0200 Subject: [PATCH 030/342] added first version of custom PS hosting code --- CMakeLists.txt | 5 + host/cmdline/coreclrutil.cpp | 163 +++++++++++++++++++++++++++++ host/cmdline/coreclrutil.h | 63 ++++++++++++ host/cmdline/main.cpp | 194 +++++++++++++++++++++++++++++++++++ 4 files changed, 425 insertions(+) create mode 100644 host/cmdline/coreclrutil.cpp create mode 100644 host/cmdline/coreclrutil.h create mode 100644 host/cmdline/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f23a2b711..98053e3cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,16 +7,21 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 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) set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp) set(SOURCE_FILES main.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) +SET(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp host/cmdline/coreclrutil.cpp) +# 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}) # add pthread and other libs find_package(Threads) target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) +target_link_libraries(host_cmdline dl) diff --git a/host/cmdline/coreclrutil.cpp b/host/cmdline/coreclrutil.cpp new file mode 100644 index 000000000..d67a1057f --- /dev/null +++ b/host/cmdline/coreclrutil.cpp @@ -0,0 +1,163 @@ +#include "coreclrutil.h" +#include +#include +#include +#include +#include + +namespace CoreCLRUtil +{ + +bool GetAbsolutePath(const char* path, std::string& absolutePath) +{ + bool result = false; + + char realPath[PATH_MAX]; + if (realpath(path, realPath) != nullptr && realPath[0] != '\0') + { + absolutePath.assign(realPath); + // realpath should return canonicalized path without the trailing slash + assert(absolutePath.back() != '/'); + + result = true; + } + + return result; +} + +bool GetDirectory(const char* absolutePath, std::string& directory) +{ + directory.assign(absolutePath); + size_t lastSlash = directory.rfind('/'); + if (lastSlash != std::string::npos) + { + directory.erase(lastSlash); + return true; + } + + return false; +} + +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) +{ + std::string clrFilesRelativePath; + const char* clrFilesPathLocal = clrFilesPath; + if (clrFilesPathLocal == nullptr) + { + // There was no CLR files path specified, use the folder of the corerun/coreconsole + if (!GetDirectory(currentExePath, clrFilesRelativePath)) + { + perror("Failed to get directory from argv[0]"); + return false; + } + + clrFilesPathLocal = clrFilesRelativePath.c_str(); + + // TODO: consider using an env variable (if defined) as a fall-back. + // The windows version of the corerun uses core_root env variable + } + + if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) + { + perror("Failed to convert CLR files path to absolute path"); + return false; + } + + return true; +} + +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) +{ + const char * const tpaExtensions[] = { + ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir + ".dll", + ".ni.exe", + ".exe", + }; + + DIR* dir = opendir(directory); + if (dir == nullptr) + { + return; + } + + std::set addedAssemblies; + + // Walk the directory for each extension separately so that we first get files with .ni.dll extension, + // then files with .dll extension, etc. + for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + { + const char* ext = tpaExtensions[extIndex]; + int extLength = strlen(ext); + + struct dirent* entry; + + // For all entries in the directory + while ((entry = readdir(dir)) != nullptr) + { + // We are interested in files only + switch (entry->d_type) + { + case DT_REG: + break; + + // Handle symlinks and file systems that do not support d_type + case DT_LNK: + case DT_UNKNOWN: + { + std::string fullFilename; + + fullFilename.append(directory); + fullFilename.append("/"); + fullFilename.append(entry->d_name); + + struct stat sb; + if (stat(fullFilename.c_str(), &sb) == -1) + { + continue; + } + + if (!S_ISREG(sb.st_mode)) + { + continue; + } + } + break; + + default: + continue; + } + + std::string filename(entry->d_name); + + // Check if the extension matches the one we are looking for + int extPos = filename.length() - extLength; + if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) + { + continue; + } + + std::string filenameWithoutExt(filename.substr(0, extPos)); + + // Make sure if we have an assembly with multiple extensions present, + // we insert only one version of it. + if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) + { + addedAssemblies.insert(filenameWithoutExt); + + tpaList.append(directory); + tpaList.append("/"); + tpaList.append(filename); + tpaList.append(":"); + } + } + + // Rewind the directory stream to be able to iterate over it for the next extension + rewinddir(dir); + } + + closedir(dir); +} + +} // namespace CoreCLRUtil + diff --git a/host/cmdline/coreclrutil.h b/host/cmdline/coreclrutil.h new file mode 100644 index 000000000..49a45ab6e --- /dev/null +++ b/host/cmdline/coreclrutil.h @@ -0,0 +1,63 @@ +#pragma once + +#include + +namespace CoreCLRUtil +{ + +// +// This code is mostly copied and modified from original CoreCLR project's +// code on github: https://github.com/dotnet/coreclr +// + +// +// these function signatures are the entry point API for CoreCLR +// + +// Prototype of the coreclr_initialize function from the libcoreclr.so +typedef int (*InitializeCoreCLRFunction)( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); + +// Prototype of the coreclr_shutdown function from the libcoreclr.so +typedef int (*ShutdownCoreCLRFunction)( + void* hostHandle, + unsigned int domainId); + +// Prototype of the coreclr_execute_assembly function from the libcoreclr.so +typedef int (*ExecuteAssemblyFunction)( + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); + +// Prototype of coreclr_create_delegate function from the libcoreclr.so +typedef int (*CreateDelegateFunction)( + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate); + +// The name of the CoreCLR native runtime DLL +#if defined(__APPLE__) +constexpr char coreClrDll[] = "libcoreclr.dylib"; +#else +constexpr char coreClrDll[] = "libcoreclr.so"; +#endif + +bool GetAbsolutePath(const char* path, std::string& absolutePath); +bool GetDirectory(const char* absolutePath, std::string& directory); +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); + +} // namespace CoreCLRUtil + diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp new file mode 100644 index 000000000..29fbfb938 --- /dev/null +++ b/host/cmdline/main.cpp @@ -0,0 +1,194 @@ +#include +#include +#include "coreclrutil.h" +#include +#include + +int main(int argc, char** argv) +{ + // TODO: read from command line args + std::string clrAbsolutePath = "/home/peter/gitwd/monad-linux/scripts/exec_env/app_base"; + + // managed assembly arguments + int managedAssemblyArgc = 0; + const char* managedAssemblyArgv[] = { "" }; + + // there are two assemblies involved in hosting PowerShell: + // - Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll + // + this assembly has to be listed as platform assembly + // - System.Management.Automation.dll + std::string powershellBaseAbsolutePath = "/home/peter/gitwd/monad-linux/scripts/exec_env/app_base"; + std::string assemblyLoadContextAssemblyName = "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext"; + std::string assemblyLoadContextAbsolutePath = powershellBaseAbsolutePath + "/" + assemblyLoadContextAssemblyName + ".dll"; + std::string systemManagementAutomationAssemblyName = "System.Management.Automation"; + std::string systemManagementAutomationAbsolutePath = powershellBaseAbsolutePath + "/" + systemManagementAutomationAssemblyName + ".dll"; + + std::string coreClrDllPath = clrAbsolutePath + "/" + CoreCLRUtil::coreClrDll; + if (coreClrDllPath.size() >= PATH_MAX) + { + std::cerr << "Absolute path to CoreCLR library too long" << std::endl; + return 1; + } + std::cout << "coreClrDllPath: " << coreClrDllPath << std::endl; + + // TPA list + // + // The list of platform assemblies must include all CoreCLR assemblies + // and the Microsoft.PowerShell.CoreCLR.AssemblyLoadContext + // + // TODO: move CLR assemblies to separate path during build&run make steps + // TODO: only add assembly load context to TPA list, not any other PS dll + + std::string tpaList; + CoreCLRUtil::AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); + std::cout << "tpaList: " << tpaList << std::endl; + + // assembly load paths + // + // All PowerShell assemblies are assumed to be in the same path + + std::string appPath; + if (!CoreCLRUtil::GetDirectory(assemblyLoadContextAbsolutePath.c_str(),appPath)) + { + std::cerr << "failed to get assembly search directory from assembly absolute path" << std::endl; + return 1; + } + std::cout << "appPath: " << appPath << std::endl; + + // search paths for native dlls + // + // Add both the CoreCLR directory and the PowerShell directory to this list + std::string nativeDllSearchDirs = appPath + ":" + clrAbsolutePath; + + // get the absolute path of the current executable + std::string currentExeAbsolutePath; + if (!CoreCLRUtil::GetAbsolutePath(argv[0],currentExeAbsolutePath)) + { + std::cerr << "could not get absolute path of current executable" << std::endl; + return 1; + } + + // open the shared library + void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); + if (coreclrLib == nullptr) + { + char* error = dlerror(); + std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; + return 2; + } + + // query the function pointers + CoreCLRUtil::InitializeCoreCLRFunction initializeCoreCLR = (CoreCLRUtil::InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); + CoreCLRUtil::ExecuteAssemblyFunction executeAssembly = (CoreCLRUtil::ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); + CoreCLRUtil::ShutdownCoreCLRFunction shutdownCoreCLR = (CoreCLRUtil::ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); + CoreCLRUtil::CreateDelegateFunction createDelegate = (CoreCLRUtil::CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); + + if (initializeCoreCLR == nullptr) + { + std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; + return 3; + } + if (executeAssembly == nullptr) + { + std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; + return 3; + } + if (shutdownCoreCLR == nullptr) + { + std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; + return 3; + } + if (createDelegate == nullptr) + { + std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; + return 3; + } + + // create list of properties to initialize CoreCLR + const char* propertyKeys[] = { + "TRUSTED_PLATFORM_ASSEMBLIES", + "APP_PATHS", + "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", + "AppDomainCompatSwitch" + }; + + const char* propertyValues[] = { + tpaList.c_str(), + appPath.c_str(), + appPath.c_str(), + nativeDllSearchDirs.c_str(), + "UseLatestBehaviorWhenTFMNotSpecified" + }; + + + // initialize CoreCLR + void* hostHandle; + unsigned int domainId; + int status = initializeCoreCLR( + currentExeAbsolutePath.c_str(), + "ps_cmdline_host", + sizeof(propertyKeys)/sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + &hostHandle, + &domainId); + + if (0 > status) + { + std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; + return 4; + } + + // initialize the PS's custom assembly load context + typedef void (*LoaderRunHelperFp)(const char16_t* appPath); + LoaderRunHelperFp loaderDelegate = nullptr; + status = createDelegate( + hostHandle, + domainId, + "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", + "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", + "SetPowerShellAssemblyLoadContext", + (void**)&loaderDelegate); + if (0 > status) + { + std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; + return 4; + } + + loaderDelegate(u"/home/peter/gitwd/monad-linux/scripts/exec_env/app_base"); + + + typedef int (*TestDelegate)(); + TestDelegate testDelegate = nullptr; + status = createDelegate( + hostHandle, + domainId, + "System.Management.Automation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", + "System.Management.Automation.Platform", + "IsLinux", + (void**)&testDelegate); + int returnValue = testDelegate(); + std::cout << "returnValue=" << returnValue << std::endl; + + + typedef void (*UnmanagedEntry)(); + UnmanagedEntry unmanagedEntry = nullptr; + status = createDelegate( + hostHandle, + domainId, + "powershell-simple, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", + "ps_hello_world.Program", + "UnmanagedEntry", + (void**)&unmanagedEntry); + if (0 > status) + { + std::cerr << "could not create delegate for UnmanagedEntry - status: " << std::hex << status << std::endl; + return 4; + } + + unmanagedEntry(); + + return 0; +} + From f7396c956114223403f5d59a201eede3b0194fc0 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Mon, 27 Jul 2015 18:40:33 +0200 Subject: [PATCH 031/342] renamed function pointer type, changed code to call UnmanagedMain --- src/host/cmdline/main.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 29fbfb938..485ba56e9 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -172,22 +172,23 @@ int main(int argc, char** argv) std::cout << "returnValue=" << returnValue << std::endl; - typedef void (*UnmanagedEntry)(); - UnmanagedEntry unmanagedEntry = nullptr; + typedef void (*UnmanagedMain)(int argc, const char** argv); + UnmanagedMain unmanagedMain = nullptr; status = createDelegate( hostHandle, domainId, "powershell-simple, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "ps_hello_world.Program", - "UnmanagedEntry", - (void**)&unmanagedEntry); + "UnmanagedMain", + (void**)&unmanagedMain); if (0 > status) { - std::cerr << "could not create delegate for UnmanagedEntry - status: " << std::hex << status << std::endl; + std::cerr << "could not create delegate for UnmanagedMain - status: " << std::hex << status << std::endl; return 4; } - unmanagedEntry(); + const char* testargs[] = { "get-process | out-host", "get-module" }; + unmanagedMain(2,testargs); return 0; } From ba45c8f07600158c9439de2bd93e675bad0588df Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Mon, 27 Jul 2015 18:40:33 +0200 Subject: [PATCH 032/342] renamed function pointer type, changed code to call UnmanagedMain --- host/cmdline/main.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 29fbfb938..485ba56e9 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -172,22 +172,23 @@ int main(int argc, char** argv) std::cout << "returnValue=" << returnValue << std::endl; - typedef void (*UnmanagedEntry)(); - UnmanagedEntry unmanagedEntry = nullptr; + typedef void (*UnmanagedMain)(int argc, const char** argv); + UnmanagedMain unmanagedMain = nullptr; status = createDelegate( hostHandle, domainId, "powershell-simple, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "ps_hello_world.Program", - "UnmanagedEntry", - (void**)&unmanagedEntry); + "UnmanagedMain", + (void**)&unmanagedMain); if (0 > status) { - std::cerr << "could not create delegate for UnmanagedEntry - status: " << std::hex << status << std::endl; + std::cerr << "could not create delegate for UnmanagedMain - status: " << std::hex << status << std::endl; return 4; } - unmanagedEntry(); + const char* testargs[] = { "get-process | out-host", "get-module" }; + unmanagedMain(2,testargs); return 0; } From 0a316592717abbcf9e11aeaeac205a8692c1e2f6 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Tue, 28 Jul 2015 18:28:09 +0200 Subject: [PATCH 033/342] cleaned up implementation, added command line parsing and standardized managed interface for cmdline hosts --- src/CMakeLists.txt | 2 +- src/host/cmdline/main.cpp | 339 ++++++++++++++++++++++++++++++-------- 2 files changed, 267 insertions(+), 74 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 98053e3cc..3a7c35b54 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,7 +21,7 @@ add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) # add pthread and other libs find_package(Threads) target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) -target_link_libraries(host_cmdline dl) +target_link_libraries(host_cmdline dl icuuc) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 485ba56e9..678d8ccc3 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -3,62 +3,172 @@ #include "coreclrutil.h" #include #include +#include +#include +#include +#include + +namespace Cmdline +{ + +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 << 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; + std::cerr << " as host_cmdline" << std::endl; + std::cerr << " + this behavior can be overridden with the -c command line argument" << std::endl; + std::cerr << "- by default the host assumes that the assembly named" << std::endl; + std::cerr << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl; + std::cerr << " platform assemblies" << std::endl; + 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 << " + 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; + 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 << std::endl; + std::cerr << "Options:" << std::endl; + std::cerr << "-c, --clr-path path to libcoreclr.so and the managed CLR assemblies" << std::endl; + std::cerr << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl; + std::cerr << "-s a list of assembly search paths, separated by :" << std::endl; + std::cerr << "-b the powershell assembly base path" << 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 << 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 'powershell-simple, version=1.0.0.0, culture=neutral, PublicKeyToken=null' 'ps_hello_world.Program' 'UnmanagedMain' 'get-process'" << std::endl; +} + +struct Args +{ + Args() : + argc(0), + argv(nullptr) + { + } + + std::string clrPath; + std::string assemblyLoadContextFilePath; + std::string searchPaths; + std::string basePath; + std::string entryAssemblyName; + std::string entryTypeName; + std::string entryFunctionName; + int argc; + char** argv; + + void debugPrint() const + { + std::cerr << "Args:" << std::endl; + std::cerr << "- clrPath " << clrPath << std::endl; + std::cerr << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl; + std::cerr << "- searchPaths " << searchPaths << std::endl; + std::cerr << "- basePath " << basePath << std::endl; + std::cerr << "- entryAssemblyName " << entryAssemblyName << std::endl; + std::cerr << "- entryTypeName " << entryTypeName << std::endl; + std::cerr << "- entryFunctionName " << entryFunctionName << std::endl; + std::cerr << "- argc " << argc << std::endl; + } +}; + +// this is implemented without any 3rd party lib to keep the list +// of dependencies low +bool parseCmdline(const int argc, char** argv, Args& args) +{ + if (argc <= 1) + { + std::cerr << "error: missing arguments" << std::endl; + return false; + } + + for (int i = 1; i < argc; ++i) + { + const std::string arg = argv[i]; + const bool hasNextArg = i+1 < argc; + const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); + + if (hasNextArg && (arg == "-c" || arg == "--clr-path")) + { + args.clrPath = nextArg; + ++i; + } + else if (hasNextArg && arg == "-alc") + { + args.assemblyLoadContextFilePath = nextArg; + ++i; + } + else if (hasNextArg && arg == "-s") + { + args.searchPaths = nextArg; + ++i; + } + else if (hasNextArg && arg == "-b") + { + args.basePath = nextArg; + ++i; + } + else if (args.entryAssemblyName == "") + { + args.entryAssemblyName = arg; + } + else if (args.entryTypeName == "") + { + args.entryTypeName = arg; + } + else if (args.entryFunctionName == "") + { + args.entryFunctionName = arg; + } + else + { + // forward command line parameters + args.argc = argc-i; + args.argv = &argv[i]; + } + } + + // check for mandatory parameters + if (args.entryAssemblyName == "") + { + 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; +} + +} int main(int argc, char** argv) { - // TODO: read from command line args - std::string clrAbsolutePath = "/home/peter/gitwd/monad-linux/scripts/exec_env/app_base"; - - // managed assembly arguments - int managedAssemblyArgc = 0; - const char* managedAssemblyArgv[] = { "" }; - - // there are two assemblies involved in hosting PowerShell: - // - Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll - // + this assembly has to be listed as platform assembly - // - System.Management.Automation.dll - std::string powershellBaseAbsolutePath = "/home/peter/gitwd/monad-linux/scripts/exec_env/app_base"; - std::string assemblyLoadContextAssemblyName = "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext"; - std::string assemblyLoadContextAbsolutePath = powershellBaseAbsolutePath + "/" + assemblyLoadContextAssemblyName + ".dll"; - std::string systemManagementAutomationAssemblyName = "System.Management.Automation"; - std::string systemManagementAutomationAbsolutePath = powershellBaseAbsolutePath + "/" + systemManagementAutomationAssemblyName + ".dll"; - - std::string coreClrDllPath = clrAbsolutePath + "/" + CoreCLRUtil::coreClrDll; - if (coreClrDllPath.size() >= PATH_MAX) + // parse the command line arguments + Cmdline::Args args; + if (!Cmdline::parseCmdline(argc,argv,args)) { - std::cerr << "Absolute path to CoreCLR library too long" << std::endl; + Cmdline::printHelp(); return 1; } - std::cout << "coreClrDllPath: " << coreClrDllPath << std::endl; - - // TPA list - // - // The list of platform assemblies must include all CoreCLR assemblies - // and the Microsoft.PowerShell.CoreCLR.AssemblyLoadContext - // - // TODO: move CLR assemblies to separate path during build&run make steps - // TODO: only add assembly load context to TPA list, not any other PS dll - - std::string tpaList; - CoreCLRUtil::AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); - std::cout << "tpaList: " << tpaList << std::endl; - - // assembly load paths - // - // All PowerShell assemblies are assumed to be in the same path - - std::string appPath; - if (!CoreCLRUtil::GetDirectory(assemblyLoadContextAbsolutePath.c_str(),appPath)) - { - std::cerr << "failed to get assembly search directory from assembly absolute path" << std::endl; - return 1; - } - std::cout << "appPath: " << appPath << std::endl; - - // search paths for native dlls - // - // Add both the CoreCLR directory and the PowerShell directory to this list - std::string nativeDllSearchDirs = appPath + ":" + clrAbsolutePath; + args.debugPrint(); // get the absolute path of the current executable std::string currentExeAbsolutePath; @@ -67,6 +177,91 @@ int main(int argc, char** argv) std::cerr << "could not get absolute path of current executable" << std::endl; return 1; } + std::cerr << "currentExeAbsolutePath=" << currentExeAbsolutePath << std::endl; + + // CLR absolute folder path + // + // This path is created from the location of this executable or a path + // specified with the -c command line argument + std::string clrAbsolutePath; + const char* clrPathArg = args.clrPath == "" ? nullptr : args.clrPath.c_str(); + if (!CoreCLRUtil::GetClrFilesAbsolutePath(currentExeAbsolutePath.c_str(),clrPathArg,clrAbsolutePath)) + { + std::cerr << "could not find absolute CLR path" << std::endl; + return 1; + } + + // the path to the CoreCLR library + // + // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac + + std::string coreClrDllPath = clrAbsolutePath + "/" + CoreCLRUtil::coreClrDll; + if (coreClrDllPath.size() >= PATH_MAX) + { + std::cerr << "Absolute path to CoreCLR library too long" << std::endl; + return 1; + } + std::cerr << "coreClrDllPath: " << coreClrDllPath << std::endl; + + // TPA list + // + // The list of platform assemblies must include all CoreCLR assemblies + // and the Microsoft.PowerShell.CoreCLR.AssemblyLoadContext + // + // if the -alc parameter was specified, add it to the TPA list here + + std::string tpaList; + CoreCLRUtil::AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); + + if (args.assemblyLoadContextFilePath != "") + tpaList += ":" + args.assemblyLoadContextFilePath; + + std::cerr << "tpaList: " << tpaList << std::endl; + + // get the absolute path of the current directory + + std::string currentDirAbsolutePath; + if (!CoreCLRUtil::GetAbsolutePath(".",currentDirAbsolutePath)) + { + std::cerr << "failed to get the absolute path from current working directory" << std::endl; + return 1; + } + + // assembly search paths + // + // add the current directory and anything specified with the -s option + + std::string appPath = currentDirAbsolutePath; + if (args.searchPaths != "") + appPath += ":" + args.searchPaths; + std::cerr << "appPath: " << appPath << std::endl; + + // search paths for native dlls + // + // Add both the CoreCLR directory and the regular search paths to this list + std::string nativeDllSearchDirs = appPath + ":" + clrAbsolutePath; + + // convert the app base to utf-16 + // + // this is needed as a utf-16 LE string by CoreCLR/PS's assembly load context interface + // it is either: + // - the current dir's absolute path + // - the path specified through the -b argument + std::string psBasePath = currentDirAbsolutePath; + if (args.basePath != "") + { + if (!CoreCLRUtil::GetAbsolutePath(args.basePath.c_str(),psBasePath)) + { + std::cerr << "failed to get the absolute path from the base_path argument" << std::endl; + return 1; + } + } + std::basic_string psBasePath16(PATH_MAX,0); + + UnicodeString u8str = UnicodeString(psBasePath.c_str(),"UTF-8"); + int32_t targetSize = u8str.extract(0,u8str.length(),(char*)&psBasePath16[0],psBasePath16.size()*sizeof(char16_t),"UTF-16LE"); + psBasePath16.resize(targetSize/sizeof(char16_t)+1); + std::cerr << "targetSize=" << targetSize << std::endl; // open the shared library void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); @@ -155,31 +350,17 @@ int main(int argc, char** argv) std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; return 4; } + loaderDelegate(psBasePath16.c_str()); - loaderDelegate(u"/home/peter/gitwd/monad-linux/scripts/exec_env/app_base"); - - - typedef int (*TestDelegate)(); - TestDelegate testDelegate = nullptr; - status = createDelegate( - hostHandle, - domainId, - "System.Management.Automation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", - "System.Management.Automation.Platform", - "IsLinux", - (void**)&testDelegate); - int returnValue = testDelegate(); - std::cout << "returnValue=" << returnValue << std::endl; - - - typedef void (*UnmanagedMain)(int argc, const char** argv); + // call the unmanaged entry point for PowerShell + typedef int (*UnmanagedMain)(int argc, char const* const* argv); UnmanagedMain unmanagedMain = nullptr; status = createDelegate( hostHandle, domainId, - "powershell-simple, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", - "ps_hello_world.Program", - "UnmanagedMain", + args.entryAssemblyName.c_str(), + args.entryTypeName.c_str(), + args.entryFunctionName.c_str(), (void**)&unmanagedMain); if (0 > status) { @@ -187,9 +368,21 @@ int main(int argc, char** argv) return 4; } - const char* testargs[] = { "get-process | out-host", "get-module" }; - unmanagedMain(2,testargs); + int exitCode = unmanagedMain(args.argc,args.argv); - return 0; + // shutdown CoreCLR + status = shutdownCoreCLR(hostHandle,domainId); + if (0 > status) + { + std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; + } + + // close the dynamic library + if (0 != dlclose(coreclrLib)) + { + std::cerr << "failed to close CoreCLR library" << std::endl; + } + + return exitCode; } From c0414f8fc460f2acca28675310ae3ff63f8903c2 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Tue, 28 Jul 2015 18:28:09 +0200 Subject: [PATCH 034/342] cleaned up implementation, added command line parsing and standardized managed interface for cmdline hosts --- CMakeLists.txt | 2 +- host/cmdline/main.cpp | 339 +++++++++++++++++++++++++++++++++--------- 2 files changed, 267 insertions(+), 74 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 98053e3cc..3a7c35b54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) # add pthread and other libs find_package(Threads) target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) -target_link_libraries(host_cmdline dl) +target_link_libraries(host_cmdline dl icuuc) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 485ba56e9..678d8ccc3 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -3,62 +3,172 @@ #include "coreclrutil.h" #include #include +#include +#include +#include +#include + +namespace Cmdline +{ + +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 << 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; + std::cerr << " as host_cmdline" << std::endl; + std::cerr << " + this behavior can be overridden with the -c command line argument" << std::endl; + std::cerr << "- by default the host assumes that the assembly named" << std::endl; + std::cerr << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl; + std::cerr << " platform assemblies" << std::endl; + 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 << " + 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; + 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 << std::endl; + std::cerr << "Options:" << std::endl; + std::cerr << "-c, --clr-path path to libcoreclr.so and the managed CLR assemblies" << std::endl; + std::cerr << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl; + std::cerr << "-s a list of assembly search paths, separated by :" << std::endl; + std::cerr << "-b the powershell assembly base path" << 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 << 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 'powershell-simple, version=1.0.0.0, culture=neutral, PublicKeyToken=null' 'ps_hello_world.Program' 'UnmanagedMain' 'get-process'" << std::endl; +} + +struct Args +{ + Args() : + argc(0), + argv(nullptr) + { + } + + std::string clrPath; + std::string assemblyLoadContextFilePath; + std::string searchPaths; + std::string basePath; + std::string entryAssemblyName; + std::string entryTypeName; + std::string entryFunctionName; + int argc; + char** argv; + + void debugPrint() const + { + std::cerr << "Args:" << std::endl; + std::cerr << "- clrPath " << clrPath << std::endl; + std::cerr << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl; + std::cerr << "- searchPaths " << searchPaths << std::endl; + std::cerr << "- basePath " << basePath << std::endl; + std::cerr << "- entryAssemblyName " << entryAssemblyName << std::endl; + std::cerr << "- entryTypeName " << entryTypeName << std::endl; + std::cerr << "- entryFunctionName " << entryFunctionName << std::endl; + std::cerr << "- argc " << argc << std::endl; + } +}; + +// this is implemented without any 3rd party lib to keep the list +// of dependencies low +bool parseCmdline(const int argc, char** argv, Args& args) +{ + if (argc <= 1) + { + std::cerr << "error: missing arguments" << std::endl; + return false; + } + + for (int i = 1; i < argc; ++i) + { + const std::string arg = argv[i]; + const bool hasNextArg = i+1 < argc; + const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); + + if (hasNextArg && (arg == "-c" || arg == "--clr-path")) + { + args.clrPath = nextArg; + ++i; + } + else if (hasNextArg && arg == "-alc") + { + args.assemblyLoadContextFilePath = nextArg; + ++i; + } + else if (hasNextArg && arg == "-s") + { + args.searchPaths = nextArg; + ++i; + } + else if (hasNextArg && arg == "-b") + { + args.basePath = nextArg; + ++i; + } + else if (args.entryAssemblyName == "") + { + args.entryAssemblyName = arg; + } + else if (args.entryTypeName == "") + { + args.entryTypeName = arg; + } + else if (args.entryFunctionName == "") + { + args.entryFunctionName = arg; + } + else + { + // forward command line parameters + args.argc = argc-i; + args.argv = &argv[i]; + } + } + + // check for mandatory parameters + if (args.entryAssemblyName == "") + { + 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; +} + +} int main(int argc, char** argv) { - // TODO: read from command line args - std::string clrAbsolutePath = "/home/peter/gitwd/monad-linux/scripts/exec_env/app_base"; - - // managed assembly arguments - int managedAssemblyArgc = 0; - const char* managedAssemblyArgv[] = { "" }; - - // there are two assemblies involved in hosting PowerShell: - // - Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll - // + this assembly has to be listed as platform assembly - // - System.Management.Automation.dll - std::string powershellBaseAbsolutePath = "/home/peter/gitwd/monad-linux/scripts/exec_env/app_base"; - std::string assemblyLoadContextAssemblyName = "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext"; - std::string assemblyLoadContextAbsolutePath = powershellBaseAbsolutePath + "/" + assemblyLoadContextAssemblyName + ".dll"; - std::string systemManagementAutomationAssemblyName = "System.Management.Automation"; - std::string systemManagementAutomationAbsolutePath = powershellBaseAbsolutePath + "/" + systemManagementAutomationAssemblyName + ".dll"; - - std::string coreClrDllPath = clrAbsolutePath + "/" + CoreCLRUtil::coreClrDll; - if (coreClrDllPath.size() >= PATH_MAX) + // parse the command line arguments + Cmdline::Args args; + if (!Cmdline::parseCmdline(argc,argv,args)) { - std::cerr << "Absolute path to CoreCLR library too long" << std::endl; + Cmdline::printHelp(); return 1; } - std::cout << "coreClrDllPath: " << coreClrDllPath << std::endl; - - // TPA list - // - // The list of platform assemblies must include all CoreCLR assemblies - // and the Microsoft.PowerShell.CoreCLR.AssemblyLoadContext - // - // TODO: move CLR assemblies to separate path during build&run make steps - // TODO: only add assembly load context to TPA list, not any other PS dll - - std::string tpaList; - CoreCLRUtil::AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); - std::cout << "tpaList: " << tpaList << std::endl; - - // assembly load paths - // - // All PowerShell assemblies are assumed to be in the same path - - std::string appPath; - if (!CoreCLRUtil::GetDirectory(assemblyLoadContextAbsolutePath.c_str(),appPath)) - { - std::cerr << "failed to get assembly search directory from assembly absolute path" << std::endl; - return 1; - } - std::cout << "appPath: " << appPath << std::endl; - - // search paths for native dlls - // - // Add both the CoreCLR directory and the PowerShell directory to this list - std::string nativeDllSearchDirs = appPath + ":" + clrAbsolutePath; + args.debugPrint(); // get the absolute path of the current executable std::string currentExeAbsolutePath; @@ -67,6 +177,91 @@ int main(int argc, char** argv) std::cerr << "could not get absolute path of current executable" << std::endl; return 1; } + std::cerr << "currentExeAbsolutePath=" << currentExeAbsolutePath << std::endl; + + // CLR absolute folder path + // + // This path is created from the location of this executable or a path + // specified with the -c command line argument + std::string clrAbsolutePath; + const char* clrPathArg = args.clrPath == "" ? nullptr : args.clrPath.c_str(); + if (!CoreCLRUtil::GetClrFilesAbsolutePath(currentExeAbsolutePath.c_str(),clrPathArg,clrAbsolutePath)) + { + std::cerr << "could not find absolute CLR path" << std::endl; + return 1; + } + + // the path to the CoreCLR library + // + // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac + + std::string coreClrDllPath = clrAbsolutePath + "/" + CoreCLRUtil::coreClrDll; + if (coreClrDllPath.size() >= PATH_MAX) + { + std::cerr << "Absolute path to CoreCLR library too long" << std::endl; + return 1; + } + std::cerr << "coreClrDllPath: " << coreClrDllPath << std::endl; + + // TPA list + // + // The list of platform assemblies must include all CoreCLR assemblies + // and the Microsoft.PowerShell.CoreCLR.AssemblyLoadContext + // + // if the -alc parameter was specified, add it to the TPA list here + + std::string tpaList; + CoreCLRUtil::AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); + + if (args.assemblyLoadContextFilePath != "") + tpaList += ":" + args.assemblyLoadContextFilePath; + + std::cerr << "tpaList: " << tpaList << std::endl; + + // get the absolute path of the current directory + + std::string currentDirAbsolutePath; + if (!CoreCLRUtil::GetAbsolutePath(".",currentDirAbsolutePath)) + { + std::cerr << "failed to get the absolute path from current working directory" << std::endl; + return 1; + } + + // assembly search paths + // + // add the current directory and anything specified with the -s option + + std::string appPath = currentDirAbsolutePath; + if (args.searchPaths != "") + appPath += ":" + args.searchPaths; + std::cerr << "appPath: " << appPath << std::endl; + + // search paths for native dlls + // + // Add both the CoreCLR directory and the regular search paths to this list + std::string nativeDllSearchDirs = appPath + ":" + clrAbsolutePath; + + // convert the app base to utf-16 + // + // this is needed as a utf-16 LE string by CoreCLR/PS's assembly load context interface + // it is either: + // - the current dir's absolute path + // - the path specified through the -b argument + std::string psBasePath = currentDirAbsolutePath; + if (args.basePath != "") + { + if (!CoreCLRUtil::GetAbsolutePath(args.basePath.c_str(),psBasePath)) + { + std::cerr << "failed to get the absolute path from the base_path argument" << std::endl; + return 1; + } + } + std::basic_string psBasePath16(PATH_MAX,0); + + UnicodeString u8str = UnicodeString(psBasePath.c_str(),"UTF-8"); + int32_t targetSize = u8str.extract(0,u8str.length(),(char*)&psBasePath16[0],psBasePath16.size()*sizeof(char16_t),"UTF-16LE"); + psBasePath16.resize(targetSize/sizeof(char16_t)+1); + std::cerr << "targetSize=" << targetSize << std::endl; // open the shared library void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); @@ -155,31 +350,17 @@ int main(int argc, char** argv) std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; return 4; } + loaderDelegate(psBasePath16.c_str()); - loaderDelegate(u"/home/peter/gitwd/monad-linux/scripts/exec_env/app_base"); - - - typedef int (*TestDelegate)(); - TestDelegate testDelegate = nullptr; - status = createDelegate( - hostHandle, - domainId, - "System.Management.Automation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", - "System.Management.Automation.Platform", - "IsLinux", - (void**)&testDelegate); - int returnValue = testDelegate(); - std::cout << "returnValue=" << returnValue << std::endl; - - - typedef void (*UnmanagedMain)(int argc, const char** argv); + // call the unmanaged entry point for PowerShell + typedef int (*UnmanagedMain)(int argc, char const* const* argv); UnmanagedMain unmanagedMain = nullptr; status = createDelegate( hostHandle, domainId, - "powershell-simple, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", - "ps_hello_world.Program", - "UnmanagedMain", + args.entryAssemblyName.c_str(), + args.entryTypeName.c_str(), + args.entryFunctionName.c_str(), (void**)&unmanagedMain); if (0 > status) { @@ -187,9 +368,21 @@ int main(int argc, char** argv) return 4; } - const char* testargs[] = { "get-process | out-host", "get-module" }; - unmanagedMain(2,testargs); + int exitCode = unmanagedMain(args.argc,args.argv); - return 0; + // shutdown CoreCLR + status = shutdownCoreCLR(hostHandle,domainId); + if (0 > status) + { + std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; + } + + // close the dynamic library + if (0 != dlclose(coreclrLib)) + { + std::cerr << "failed to close CoreCLR library" << std::endl; + } + + return exitCode; } From d09ac28b738a93d686220b432340ae40e66136c5 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Tue, 28 Jul 2015 18:49:32 +0200 Subject: [PATCH 035/342] fixed string termination issue, added verbose mode --- src/host/cmdline/main.cpp | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 678d8ccc3..11c933367 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -43,6 +43,7 @@ void printHelp() std::cerr << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl; std::cerr << "-s a list of assembly search paths, separated by :" << std::endl; std::cerr << "-b the powershell assembly base path" << std::endl; + std::cerr << "-v verbose output, show paths" << 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; @@ -56,7 +57,8 @@ struct Args { Args() : argc(0), - argv(nullptr) + argv(nullptr), + verbose(false) { } @@ -69,6 +71,7 @@ struct Args std::string entryFunctionName; int argc; char** argv; + bool verbose; void debugPrint() const { @@ -81,6 +84,7 @@ struct Args std::cerr << "- entryTypeName " << entryTypeName << std::endl; std::cerr << "- entryFunctionName " << entryFunctionName << std::endl; std::cerr << "- argc " << argc << std::endl; + std::cerr << "- verbose " << (verbose ? "true" : "false") << std::endl; } }; @@ -168,7 +172,8 @@ int main(int argc, char** argv) Cmdline::printHelp(); return 1; } - args.debugPrint(); + if (args.verbose) + args.debugPrint(); // get the absolute path of the current executable std::string currentExeAbsolutePath; @@ -177,7 +182,8 @@ int main(int argc, char** argv) std::cerr << "could not get absolute path of current executable" << std::endl; return 1; } - std::cerr << "currentExeAbsolutePath=" << currentExeAbsolutePath << std::endl; + if (args.verbose) + std::cerr << "currentExeAbsolutePath=" << currentExeAbsolutePath << std::endl; // CLR absolute folder path // @@ -201,7 +207,8 @@ int main(int argc, char** argv) std::cerr << "Absolute path to CoreCLR library too long" << std::endl; return 1; } - std::cerr << "coreClrDllPath: " << coreClrDllPath << std::endl; + if (args.verbose) + std::cerr << "coreClrDllPath: " << coreClrDllPath << std::endl; // TPA list // @@ -216,7 +223,8 @@ int main(int argc, char** argv) if (args.assemblyLoadContextFilePath != "") tpaList += ":" + args.assemblyLoadContextFilePath; - std::cerr << "tpaList: " << tpaList << std::endl; + if (args.verbose) + std::cerr << "tpaList: " << tpaList << std::endl; // get the absolute path of the current directory @@ -234,7 +242,9 @@ int main(int argc, char** argv) std::string appPath = currentDirAbsolutePath; if (args.searchPaths != "") appPath += ":" + args.searchPaths; - std::cerr << "appPath: " << appPath << std::endl; + + if (args.verbose) + std::cerr << "appPath: " << appPath << std::endl; // search paths for native dlls // @@ -256,12 +266,13 @@ int main(int argc, char** argv) return 1; } } - std::basic_string psBasePath16(PATH_MAX,0); + + // make sure to leave 1 byte at the end for null termination + std::basic_string psBasePath16(PATH_MAX+1,0); UnicodeString u8str = UnicodeString(psBasePath.c_str(),"UTF-8"); - int32_t targetSize = u8str.extract(0,u8str.length(),(char*)&psBasePath16[0],psBasePath16.size()*sizeof(char16_t),"UTF-16LE"); + int32_t targetSize = u8str.extract(0,u8str.length(),(char*)&psBasePath16[0],(psBasePath16.size()-1)*sizeof(char16_t),"UTF-16LE"); psBasePath16.resize(targetSize/sizeof(char16_t)+1); - std::cerr << "targetSize=" << targetSize << std::endl; // open the shared library void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); From ea76b7e8fdc269ffd8f571efa88930010b57d75c Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Tue, 28 Jul 2015 18:49:32 +0200 Subject: [PATCH 036/342] fixed string termination issue, added verbose mode --- host/cmdline/main.cpp | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 678d8ccc3..11c933367 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -43,6 +43,7 @@ void printHelp() std::cerr << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl; std::cerr << "-s a list of assembly search paths, separated by :" << std::endl; std::cerr << "-b the powershell assembly base path" << std::endl; + std::cerr << "-v verbose output, show paths" << 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; @@ -56,7 +57,8 @@ struct Args { Args() : argc(0), - argv(nullptr) + argv(nullptr), + verbose(false) { } @@ -69,6 +71,7 @@ struct Args std::string entryFunctionName; int argc; char** argv; + bool verbose; void debugPrint() const { @@ -81,6 +84,7 @@ struct Args std::cerr << "- entryTypeName " << entryTypeName << std::endl; std::cerr << "- entryFunctionName " << entryFunctionName << std::endl; std::cerr << "- argc " << argc << std::endl; + std::cerr << "- verbose " << (verbose ? "true" : "false") << std::endl; } }; @@ -168,7 +172,8 @@ int main(int argc, char** argv) Cmdline::printHelp(); return 1; } - args.debugPrint(); + if (args.verbose) + args.debugPrint(); // get the absolute path of the current executable std::string currentExeAbsolutePath; @@ -177,7 +182,8 @@ int main(int argc, char** argv) std::cerr << "could not get absolute path of current executable" << std::endl; return 1; } - std::cerr << "currentExeAbsolutePath=" << currentExeAbsolutePath << std::endl; + if (args.verbose) + std::cerr << "currentExeAbsolutePath=" << currentExeAbsolutePath << std::endl; // CLR absolute folder path // @@ -201,7 +207,8 @@ int main(int argc, char** argv) std::cerr << "Absolute path to CoreCLR library too long" << std::endl; return 1; } - std::cerr << "coreClrDllPath: " << coreClrDllPath << std::endl; + if (args.verbose) + std::cerr << "coreClrDllPath: " << coreClrDllPath << std::endl; // TPA list // @@ -216,7 +223,8 @@ int main(int argc, char** argv) if (args.assemblyLoadContextFilePath != "") tpaList += ":" + args.assemblyLoadContextFilePath; - std::cerr << "tpaList: " << tpaList << std::endl; + if (args.verbose) + std::cerr << "tpaList: " << tpaList << std::endl; // get the absolute path of the current directory @@ -234,7 +242,9 @@ int main(int argc, char** argv) std::string appPath = currentDirAbsolutePath; if (args.searchPaths != "") appPath += ":" + args.searchPaths; - std::cerr << "appPath: " << appPath << std::endl; + + if (args.verbose) + std::cerr << "appPath: " << appPath << std::endl; // search paths for native dlls // @@ -256,12 +266,13 @@ int main(int argc, char** argv) return 1; } } - std::basic_string psBasePath16(PATH_MAX,0); + + // make sure to leave 1 byte at the end for null termination + std::basic_string psBasePath16(PATH_MAX+1,0); UnicodeString u8str = UnicodeString(psBasePath.c_str(),"UTF-8"); - int32_t targetSize = u8str.extract(0,u8str.length(),(char*)&psBasePath16[0],psBasePath16.size()*sizeof(char16_t),"UTF-16LE"); + int32_t targetSize = u8str.extract(0,u8str.length(),(char*)&psBasePath16[0],(psBasePath16.size()-1)*sizeof(char16_t),"UTF-16LE"); psBasePath16.resize(targetSize/sizeof(char16_t)+1); - std::cerr << "targetSize=" << targetSize << std::endl; // open the shared library void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); From 8e18abaf3103fe5c061334403066fdb79fcd3c6a Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Wed, 29 Jul 2015 18:12:31 +0200 Subject: [PATCH 037/342] added interpreting the verbose option --- src/host/cmdline/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 11c933367..7793bf143 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -124,6 +124,10 @@ bool parseCmdline(const int argc, char** argv, Args& args) args.basePath = nextArg; ++i; } + else if (arg == "-v") + { + args.verbose = true; + } else if (args.entryAssemblyName == "") { args.entryAssemblyName = arg; From ff2ceeceb758cba907a18ab3bd7132cf36bc15e8 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Wed, 29 Jul 2015 18:12:31 +0200 Subject: [PATCH 038/342] added interpreting the verbose option --- host/cmdline/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 11c933367..7793bf143 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -124,6 +124,10 @@ bool parseCmdline(const int argc, char** argv, Args& args) args.basePath = nextArg; ++i; } + else if (arg == "-v") + { + args.verbose = true; + } else if (args.entryAssemblyName == "") { args.entryAssemblyName = arg; From c1c9a992699229cf69ef22a346b95137ab9f7a15 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Thu, 30 Jul 2015 16:53:35 +0200 Subject: [PATCH 039/342] added hostutil.h, added tests for hostutil, added more cmdline options to PS host --- src/CMakeLists.txt | 9 +++- src/host/cmdline/main.cpp | 53 ++++++++++++++++++-- src/host/{cmdline => common}/coreclrutil.cpp | 4 ++ src/host/{cmdline => common}/coreclrutil.h | 0 src/host/common/hostutil.h | 48 ++++++++++++++++++ src/tests/host/test-hostutil.cpp | 35 +++++++++++++ 6 files changed, 142 insertions(+), 7 deletions(-) rename src/host/{cmdline => common}/coreclrutil.cpp (96%) rename src/host/{cmdline => common}/coreclrutil.h (100%) create mode 100644 src/host/common/hostutil.h create mode 100644 src/tests/host/test-hostutil.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3a7c35b54..a5d27e7bf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,9 +9,11 @@ link_directories(${monad_native_BINARY_DIR}) # source file definitions set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp) -set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.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 ${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/cmdline/coreclrutil.cpp) +SET(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp ${HOST_COMMON_SOURCE_FILES}) # target definitions add_library(ps SHARED ${LIB_SOURCE_FILES}) @@ -23,5 +25,8 @@ find_package(Threads) target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) target_link_libraries(host_cmdline dl icuuc) +# target specific include directories +target_include_directories(monad_native PRIVATE host) +target_include_directories(host_cmdline PRIVATE host) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 7793bf143..740d99185 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -1,6 +1,7 @@ #include #include -#include "coreclrutil.h" +#include "common/coreclrutil.h" +#include "common/hostutil.h" #include #include #include @@ -32,6 +33,7 @@ void printHelp() 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; + std::cerr << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl; 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; @@ -44,13 +46,17 @@ void printHelp() std::cerr << "-s a list of assembly search paths, separated by :" << std::endl; std::cerr << "-b the powershell assembly base path" << std::endl; std::cerr << "-v verbose output, show paths" << std::endl; + std::cerr << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl; + 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 << 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 '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' 'ps_hello_world.Program' 'UnmanagedMain' 'get-process'" << std::endl; } struct Args @@ -66,6 +72,7 @@ struct Args std::string assemblyLoadContextFilePath; std::string searchPaths; std::string basePath; + std::string tpaList; std::string entryAssemblyName; std::string entryTypeName; std::string entryFunctionName; @@ -80,6 +87,7 @@ struct Args std::cerr << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl; 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; @@ -124,6 +132,11 @@ bool parseCmdline(const int argc, char** argv, Args& args) args.basePath = nextArg; ++i; } + else if (hasNextArg && arg == "-tpa") + { + args.tpaList = nextArg; + ++i; + } else if (arg == "-v") { args.verbose = true; @@ -145,6 +158,9 @@ bool parseCmdline(const int argc, char** argv, Args& args) // forward command line parameters args.argc = argc-i; args.argv = &argv[i]; + + // explicitly break here because the lines above consume all remaining arguments + break; } } @@ -200,6 +216,8 @@ int main(int argc, char** argv) std::cerr << "could not find absolute CLR path" << std::endl; return 1; } + if (args.verbose) + std::cerr << "clrAbsolutePath=" << clrAbsolutePath << std::endl; // the path to the CoreCLR library // @@ -225,7 +243,23 @@ int main(int argc, char** argv) CoreCLRUtil::AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); if (args.assemblyLoadContextFilePath != "") - tpaList += ":" + args.assemblyLoadContextFilePath; + { + std::string assemblyLoadContextAbsoluteFilePath; + if (!CoreCLRUtil::GetAbsolutePath(args.assemblyLoadContextFilePath.c_str(),assemblyLoadContextAbsoluteFilePath)) + { + std::cerr << "Failed to get absolute file path for assembly load context" << std::endl; + return 1; + } + tpaList += ":" + assemblyLoadContextAbsoluteFilePath; + } + + // add the -tpa command line argument + if (args.tpaList != "") + { + std::string tpaAbsolutePathList = HostUtil::getAbsolutePathList(args.tpaList); + if (tpaAbsolutePathList != "") + tpaList += ":" + tpaAbsolutePathList; + } if (args.verbose) std::cerr << "tpaList: " << tpaList << std::endl; @@ -241,11 +275,18 @@ int main(int argc, char** argv) // assembly search paths // - // add the current directory and anything specified with the -s option + // add the current directory, and optionally the CoreCLR directory if -c was specified + // and anything specified with the -s option std::string appPath = currentDirAbsolutePath; + if (args.clrPath != "") + appPath += ":" + clrAbsolutePath; if (args.searchPaths != "") - appPath += ":" + args.searchPaths; + { + std::string searchAbsolutePathList = HostUtil::getAbsolutePathList(args.searchPaths); + if (searchAbsolutePathList != "") + appPath += ":" + searchAbsolutePathList; + } if (args.verbose) std::cerr << "appPath: " << appPath << std::endl; @@ -270,6 +311,8 @@ int main(int argc, char** argv) return 1; } } + if (args.verbose) + std::cerr << "psBasePath=" << psBasePath << std::endl; // make sure to leave 1 byte at the end for null termination std::basic_string psBasePath16(PATH_MAX+1,0); diff --git a/src/host/cmdline/coreclrutil.cpp b/src/host/common/coreclrutil.cpp similarity index 96% rename from src/host/cmdline/coreclrutil.cpp rename to src/host/common/coreclrutil.cpp index d67a1057f..6aa8b9896 100644 --- a/src/host/cmdline/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -157,6 +157,10 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) } closedir(dir); + + // strip any trailing : from the tpaList + if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':') + tpaList.resize(tpaList.size()-1); } } // namespace CoreCLRUtil diff --git a/src/host/cmdline/coreclrutil.h b/src/host/common/coreclrutil.h similarity index 100% rename from src/host/cmdline/coreclrutil.h rename to src/host/common/coreclrutil.h diff --git a/src/host/common/hostutil.h b/src/host/common/hostutil.h new file mode 100644 index 000000000..a8c9a208d --- /dev/null +++ b/src/host/common/hostutil.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include "common/coreclrutil.h" + +namespace HostUtil +{ + +//!\brief get a list of absolute paths separated by : from a list of relative/absolute paths separated by : +std::string getAbsolutePathList(const std::string& paths) +{ + //std::cerr << "getAbsolutePathList: paths=" << paths << std::endl; + std::string result; + + // split by : + size_t lastPos = 0; + size_t curPos = paths.find(':',lastPos); + do + { + const std::string token = paths.substr(lastPos,curPos-lastPos); + //std::cerr << "curPos=" << curPos << " lastPos=" << lastPos << " token=" << token << std::endl; + + // skip empty tokens + if (token != "") + { + std::string absolutePath; + if (CoreCLRUtil::GetAbsolutePath(token.c_str(),absolutePath)) + { + // add colons correctly + if (result.size() == 0) + result += absolutePath; + else + result += ":" + absolutePath; + } + } + + // increment lastPos to skip the : + lastPos += token.size() + 1; + curPos = paths.find(':',lastPos); + } + while (lastPos < paths.size()); + + return result; +} + +} + + diff --git a/src/tests/host/test-hostutil.cpp b/src/tests/host/test-hostutil.cpp new file mode 100644 index 000000000..7a8b6b473 --- /dev/null +++ b/src/tests/host/test-hostutil.cpp @@ -0,0 +1,35 @@ +#include +#include "common/hostutil.h" + +TEST(HostUtilTest,simple) +{ + // syntactical corner cases + ASSERT_EQ("",HostUtil::getAbsolutePathList("")); + ASSERT_EQ("",HostUtil::getAbsolutePathList(":")); + ASSERT_EQ("",HostUtil::getAbsolutePathList("::")); + ASSERT_EQ("",HostUtil::getAbsolutePathList(":::::")); + + // current directory + char* cwd = get_current_dir_name(); + ASSERT_EQ(std::string(cwd),HostUtil::getAbsolutePathList(".")); + + // relative and absolute paths that don't exist + ASSERT_EQ("",HostUtil::getAbsolutePathList("/something/that/does/not/exist")); + ASSERT_EQ("",HostUtil::getAbsolutePathList(":/something/that/does/not/exist:")); + ASSERT_EQ("",HostUtil::getAbsolutePathList("something/relative/that/does/not/exist")); + ASSERT_EQ("",HostUtil::getAbsolutePathList(":something/relative/that/does/not/exist:")); + + // absolute existing paths + ASSERT_EQ("/tmp",HostUtil::getAbsolutePathList("/tmp")); + ASSERT_EQ("/tmp:/tmp",HostUtil::getAbsolutePathList("/tmp:/tmp")); + + // relative paths + chdir("/"); + ASSERT_EQ("/tmp",HostUtil::getAbsolutePathList("tmp")); + ASSERT_EQ("/tmp:/tmp",HostUtil::getAbsolutePathList("/tmp:tmp:")); + chdir(cwd); + + // cleanup + free(cwd); +} + From 8eeb24ece919d11fcfc41144d27743a97c0b0791 Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Thu, 30 Jul 2015 16:53:35 +0200 Subject: [PATCH 040/342] added hostutil.h, added tests for hostutil, added more cmdline options to PS host --- CMakeLists.txt | 9 +++- host/cmdline/main.cpp | 53 +++++++++++++++++++++--- host/{cmdline => common}/coreclrutil.cpp | 4 ++ host/{cmdline => common}/coreclrutil.h | 0 host/common/hostutil.h | 48 +++++++++++++++++++++ tests/host/test-hostutil.cpp | 35 ++++++++++++++++ 6 files changed, 142 insertions(+), 7 deletions(-) rename host/{cmdline => common}/coreclrutil.cpp (96%) rename host/{cmdline => common}/coreclrutil.h (100%) create mode 100644 host/common/hostutil.h create mode 100644 tests/host/test-hostutil.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a7c35b54..a5d27e7bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,9 +9,11 @@ link_directories(${monad_native_BINARY_DIR}) # source file definitions set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp) -set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.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 ${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/cmdline/coreclrutil.cpp) +SET(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp ${HOST_COMMON_SOURCE_FILES}) # target definitions add_library(ps SHARED ${LIB_SOURCE_FILES}) @@ -23,5 +25,8 @@ find_package(Threads) target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) target_link_libraries(host_cmdline dl icuuc) +# target specific include directories +target_include_directories(monad_native PRIVATE host) +target_include_directories(host_cmdline PRIVATE host) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 7793bf143..740d99185 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -1,6 +1,7 @@ #include #include -#include "coreclrutil.h" +#include "common/coreclrutil.h" +#include "common/hostutil.h" #include #include #include @@ -32,6 +33,7 @@ void printHelp() 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; + std::cerr << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl; 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; @@ -44,13 +46,17 @@ void printHelp() std::cerr << "-s a list of assembly search paths, separated by :" << std::endl; std::cerr << "-b the powershell assembly base path" << std::endl; std::cerr << "-v verbose output, show paths" << std::endl; + std::cerr << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl; + 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 << 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 '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' 'ps_hello_world.Program' 'UnmanagedMain' 'get-process'" << std::endl; } struct Args @@ -66,6 +72,7 @@ struct Args std::string assemblyLoadContextFilePath; std::string searchPaths; std::string basePath; + std::string tpaList; std::string entryAssemblyName; std::string entryTypeName; std::string entryFunctionName; @@ -80,6 +87,7 @@ struct Args std::cerr << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl; 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; @@ -124,6 +132,11 @@ bool parseCmdline(const int argc, char** argv, Args& args) args.basePath = nextArg; ++i; } + else if (hasNextArg && arg == "-tpa") + { + args.tpaList = nextArg; + ++i; + } else if (arg == "-v") { args.verbose = true; @@ -145,6 +158,9 @@ bool parseCmdline(const int argc, char** argv, Args& args) // forward command line parameters args.argc = argc-i; args.argv = &argv[i]; + + // explicitly break here because the lines above consume all remaining arguments + break; } } @@ -200,6 +216,8 @@ int main(int argc, char** argv) std::cerr << "could not find absolute CLR path" << std::endl; return 1; } + if (args.verbose) + std::cerr << "clrAbsolutePath=" << clrAbsolutePath << std::endl; // the path to the CoreCLR library // @@ -225,7 +243,23 @@ int main(int argc, char** argv) CoreCLRUtil::AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); if (args.assemblyLoadContextFilePath != "") - tpaList += ":" + args.assemblyLoadContextFilePath; + { + std::string assemblyLoadContextAbsoluteFilePath; + if (!CoreCLRUtil::GetAbsolutePath(args.assemblyLoadContextFilePath.c_str(),assemblyLoadContextAbsoluteFilePath)) + { + std::cerr << "Failed to get absolute file path for assembly load context" << std::endl; + return 1; + } + tpaList += ":" + assemblyLoadContextAbsoluteFilePath; + } + + // add the -tpa command line argument + if (args.tpaList != "") + { + std::string tpaAbsolutePathList = HostUtil::getAbsolutePathList(args.tpaList); + if (tpaAbsolutePathList != "") + tpaList += ":" + tpaAbsolutePathList; + } if (args.verbose) std::cerr << "tpaList: " << tpaList << std::endl; @@ -241,11 +275,18 @@ int main(int argc, char** argv) // assembly search paths // - // add the current directory and anything specified with the -s option + // add the current directory, and optionally the CoreCLR directory if -c was specified + // and anything specified with the -s option std::string appPath = currentDirAbsolutePath; + if (args.clrPath != "") + appPath += ":" + clrAbsolutePath; if (args.searchPaths != "") - appPath += ":" + args.searchPaths; + { + std::string searchAbsolutePathList = HostUtil::getAbsolutePathList(args.searchPaths); + if (searchAbsolutePathList != "") + appPath += ":" + searchAbsolutePathList; + } if (args.verbose) std::cerr << "appPath: " << appPath << std::endl; @@ -270,6 +311,8 @@ int main(int argc, char** argv) return 1; } } + if (args.verbose) + std::cerr << "psBasePath=" << psBasePath << std::endl; // make sure to leave 1 byte at the end for null termination std::basic_string psBasePath16(PATH_MAX+1,0); diff --git a/host/cmdline/coreclrutil.cpp b/host/common/coreclrutil.cpp similarity index 96% rename from host/cmdline/coreclrutil.cpp rename to host/common/coreclrutil.cpp index d67a1057f..6aa8b9896 100644 --- a/host/cmdline/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -157,6 +157,10 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) } closedir(dir); + + // strip any trailing : from the tpaList + if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':') + tpaList.resize(tpaList.size()-1); } } // namespace CoreCLRUtil diff --git a/host/cmdline/coreclrutil.h b/host/common/coreclrutil.h similarity index 100% rename from host/cmdline/coreclrutil.h rename to host/common/coreclrutil.h diff --git a/host/common/hostutil.h b/host/common/hostutil.h new file mode 100644 index 000000000..a8c9a208d --- /dev/null +++ b/host/common/hostutil.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include "common/coreclrutil.h" + +namespace HostUtil +{ + +//!\brief get a list of absolute paths separated by : from a list of relative/absolute paths separated by : +std::string getAbsolutePathList(const std::string& paths) +{ + //std::cerr << "getAbsolutePathList: paths=" << paths << std::endl; + std::string result; + + // split by : + size_t lastPos = 0; + size_t curPos = paths.find(':',lastPos); + do + { + const std::string token = paths.substr(lastPos,curPos-lastPos); + //std::cerr << "curPos=" << curPos << " lastPos=" << lastPos << " token=" << token << std::endl; + + // skip empty tokens + if (token != "") + { + std::string absolutePath; + if (CoreCLRUtil::GetAbsolutePath(token.c_str(),absolutePath)) + { + // add colons correctly + if (result.size() == 0) + result += absolutePath; + else + result += ":" + absolutePath; + } + } + + // increment lastPos to skip the : + lastPos += token.size() + 1; + curPos = paths.find(':',lastPos); + } + while (lastPos < paths.size()); + + return result; +} + +} + + diff --git a/tests/host/test-hostutil.cpp b/tests/host/test-hostutil.cpp new file mode 100644 index 000000000..7a8b6b473 --- /dev/null +++ b/tests/host/test-hostutil.cpp @@ -0,0 +1,35 @@ +#include +#include "common/hostutil.h" + +TEST(HostUtilTest,simple) +{ + // syntactical corner cases + ASSERT_EQ("",HostUtil::getAbsolutePathList("")); + ASSERT_EQ("",HostUtil::getAbsolutePathList(":")); + ASSERT_EQ("",HostUtil::getAbsolutePathList("::")); + ASSERT_EQ("",HostUtil::getAbsolutePathList(":::::")); + + // current directory + char* cwd = get_current_dir_name(); + ASSERT_EQ(std::string(cwd),HostUtil::getAbsolutePathList(".")); + + // relative and absolute paths that don't exist + ASSERT_EQ("",HostUtil::getAbsolutePathList("/something/that/does/not/exist")); + ASSERT_EQ("",HostUtil::getAbsolutePathList(":/something/that/does/not/exist:")); + ASSERT_EQ("",HostUtil::getAbsolutePathList("something/relative/that/does/not/exist")); + ASSERT_EQ("",HostUtil::getAbsolutePathList(":something/relative/that/does/not/exist:")); + + // absolute existing paths + ASSERT_EQ("/tmp",HostUtil::getAbsolutePathList("/tmp")); + ASSERT_EQ("/tmp:/tmp",HostUtil::getAbsolutePathList("/tmp:/tmp")); + + // relative paths + chdir("/"); + ASSERT_EQ("/tmp",HostUtil::getAbsolutePathList("tmp")); + ASSERT_EQ("/tmp:/tmp",HostUtil::getAbsolutePathList("/tmp:tmp:")); + chdir(cwd); + + // cleanup + free(cwd); +} + From 84f5b079ec6fefcf0c8c14310b42d80053c68e46 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 30 Jul 2015 12:44:48 -0700 Subject: [PATCH 041/342] Added ERROR_BUFFER_OVERFLOW --- impl/pal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/impl/pal.h b/impl/pal.h index defde3b1f..d693f778c 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -71,6 +71,7 @@ #define FALSE 0 #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 + #define ERROR_BUFFER_OVERFLOW 111 #define MAX_PATH 0x00000104 typedef unsigned long long uint64; #endif From 920322c8095d59897626982d1b3c72d21b5ee092 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 30 Jul 2015 12:44:48 -0700 Subject: [PATCH 042/342] Added ERROR_BUFFER_OVERFLOW --- src/impl/pal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/impl/pal.h b/src/impl/pal.h index defde3b1f..d693f778c 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -71,6 +71,7 @@ #define FALSE 0 #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 + #define ERROR_BUFFER_OVERFLOW 111 #define MAX_PATH 0x00000104 typedef unsigned long long uint64; #endif From 8797ebb127f42163df06786d40842f46a7edcdd0 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 30 Jul 2015 12:46:28 -0700 Subject: [PATCH 043/342] Added case for failure --- impl/getcomputername.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp index 1ec69110c..6b3d348ae 100644 --- a/impl/getcomputername.cpp +++ b/impl/getcomputername.cpp @@ -1,12 +1,19 @@ #include "getcomputername.h" #include +#include BOOL GetComputerName(LPTSTR name, LPDWORD len) { + errno = 0; + int host = gethostname(name, HOST_NAME_MAX); if(host == 0) { return TRUE; - } - return FALSE; + } + else + { + errno = ERROR_BUFFER_OVERFLOW; + return FALSE; + } } From bf92f710e87bd5663fd7375dd4ac0d63ff0fd3c1 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 30 Jul 2015 12:46:28 -0700 Subject: [PATCH 044/342] Added case for failure --- src/impl/getcomputername.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp index 1ec69110c..6b3d348ae 100644 --- a/src/impl/getcomputername.cpp +++ b/src/impl/getcomputername.cpp @@ -1,12 +1,19 @@ #include "getcomputername.h" #include +#include BOOL GetComputerName(LPTSTR name, LPDWORD len) { + errno = 0; + int host = gethostname(name, HOST_NAME_MAX); if(host == 0) { return TRUE; - } - return FALSE; + } + else + { + errno = ERROR_BUFFER_OVERFLOW; + return FALSE; + } } From b8ae6d13a9eff0c7ff6acdf1e9a2d99292ae07c7 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 30 Jul 2015 12:47:10 -0700 Subject: [PATCH 045/342] Added failure casex --- tests/test-getcomputername.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index 8b0f19f5d..207f96421 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -24,4 +24,13 @@ TEST(GetComputerName,simple) ASSERT_TRUE(getComputerName == TRUE); ASSERT_EQ(host,TRUE); ASSERT_EQ(hostnameString,hostnameStringTest); +} + +TEST(GetComputerName,buffertosmall) +{ + char hostname[HOST_NAME_MAX]; + std::string hostnameFunctionTest; + DWORD hostSize = 0; + BOOL getComputerName = GetComputerName(&hostnameFunctionTest[0], &hostSize); + ASSERT_TRUE(getComputerName != 0); } \ No newline at end of file From 385fb20cdf4275a2675e7702d02c015a5d33d032 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 30 Jul 2015 12:47:10 -0700 Subject: [PATCH 046/342] Added failure casex --- src/tests/test-getcomputername.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp index 8b0f19f5d..207f96421 100644 --- a/src/tests/test-getcomputername.cpp +++ b/src/tests/test-getcomputername.cpp @@ -24,4 +24,13 @@ TEST(GetComputerName,simple) ASSERT_TRUE(getComputerName == TRUE); ASSERT_EQ(host,TRUE); ASSERT_EQ(hostnameString,hostnameStringTest); +} + +TEST(GetComputerName,buffertosmall) +{ + char hostname[HOST_NAME_MAX]; + std::string hostnameFunctionTest; + DWORD hostSize = 0; + BOOL getComputerName = GetComputerName(&hostnameFunctionTest[0], &hostSize); + ASSERT_TRUE(getComputerName != 0); } \ No newline at end of file From 4661081c7dc1c0d7849bb5cbe869ee8d96e9935b Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 30 Jul 2015 13:47:31 -0700 Subject: [PATCH 047/342] Added test for buffer not having enough space to write computer name --- impl/getcomputername.cpp | 4 ++-- tests/test-getcomputername.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp index 6b3d348ae..c8a7c9719 100644 --- a/impl/getcomputername.cpp +++ b/impl/getcomputername.cpp @@ -5,8 +5,8 @@ BOOL GetComputerName(LPTSTR name, LPDWORD len) { errno = 0; - - int host = gethostname(name, HOST_NAME_MAX); + size_t len2 = *len; + int host = gethostname(name, len2); if(host == 0) { return TRUE; diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index 207f96421..ffce53881 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -1,5 +1,6 @@ #include #include "getcomputername.h" +#include TEST(GetComputerName,simple) { @@ -26,11 +27,13 @@ TEST(GetComputerName,simple) ASSERT_EQ(hostnameString,hostnameStringTest); } -TEST(GetComputerName,buffertosmall) +TEST(GetComputerName,bufferttoosmall) { char hostname[HOST_NAME_MAX]; std::string hostnameFunctionTest; DWORD hostSize = 0; BOOL getComputerName = GetComputerName(&hostnameFunctionTest[0], &hostSize); - ASSERT_TRUE(getComputerName != 0); + ASSERT_TRUE(getComputerName == 0); + char buffer[ 256 ]; + EXPECT_EQ(errno, ERROR_BUFFER_OVERFLOW); } \ No newline at end of file From da4d4d7a21cc4c29b67a61d13dff4417ff6ecc11 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 30 Jul 2015 13:47:31 -0700 Subject: [PATCH 048/342] Added test for buffer not having enough space to write computer name --- src/impl/getcomputername.cpp | 4 ++-- src/tests/test-getcomputername.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp index 6b3d348ae..c8a7c9719 100644 --- a/src/impl/getcomputername.cpp +++ b/src/impl/getcomputername.cpp @@ -5,8 +5,8 @@ BOOL GetComputerName(LPTSTR name, LPDWORD len) { errno = 0; - - int host = gethostname(name, HOST_NAME_MAX); + size_t len2 = *len; + int host = gethostname(name, len2); if(host == 0) { return TRUE; diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp index 207f96421..ffce53881 100644 --- a/src/tests/test-getcomputername.cpp +++ b/src/tests/test-getcomputername.cpp @@ -1,5 +1,6 @@ #include #include "getcomputername.h" +#include TEST(GetComputerName,simple) { @@ -26,11 +27,13 @@ TEST(GetComputerName,simple) ASSERT_EQ(hostnameString,hostnameStringTest); } -TEST(GetComputerName,buffertosmall) +TEST(GetComputerName,bufferttoosmall) { char hostname[HOST_NAME_MAX]; std::string hostnameFunctionTest; DWORD hostSize = 0; BOOL getComputerName = GetComputerName(&hostnameFunctionTest[0], &hostSize); - ASSERT_TRUE(getComputerName != 0); + ASSERT_TRUE(getComputerName == 0); + char buffer[ 256 ]; + EXPECT_EQ(errno, ERROR_BUFFER_OVERFLOW); } \ No newline at end of file From 7a85d035c071f09882275499aa17ed0bce9f1ab4 Mon Sep 17 00:00:00 2001 From: Aaron Date: Mon, 3 Aug 2015 10:48:46 -0700 Subject: [PATCH 049/342] Add error handing for bad enivronment and bad parameter --- CMakeLists.txt | 4 ++-- impl/getcomputername.cpp | 21 ++++++++++++++++++++- impl/getcomputername.h | 2 +- impl/pal.h | 4 ++-- tests/test-getcomputername.cpp | 21 +++++---------------- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05be91e26..97b14a942 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,10 +8,10 @@ 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) +set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp impl/getcomputername.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 ${HOST_COMMON_SOURCE_FILES} ${HOST_COMMON_TEST_SOURCE_FILES}) +set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp tests/test-getcomputername ${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}) diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp index c8a7c9719..5946851b2 100644 --- a/impl/getcomputername.cpp +++ b/impl/getcomputername.cpp @@ -1,10 +1,28 @@ #include "getcomputername.h" #include #include +#include +#include -BOOL GetComputerName(LPTSTR name, LPDWORD len) +BOOL GetComputerNameW(LPTSTR name, LPDWORD len) { + const std::string utf8 = "UTF-8"; errno = 0; + + // Check parameters + if (!name || !len) { + errno = ERROR_INVALID_PARAMETER; + return 0; + } + + // Select locale from environment + setlocale(LC_ALL, ""); + // Check that locale is UTF-8 + if (nl_langinfo(CODESET) != utf8) { + errno = ERROR_BAD_ENVIRONMENT; + return 0; + } + size_t len2 = *len; int host = gethostname(name, len2); if(host == 0) @@ -17,3 +35,4 @@ BOOL GetComputerName(LPTSTR name, LPDWORD len) return FALSE; } } + diff --git a/impl/getcomputername.h b/impl/getcomputername.h index 7f8dd8eb5..3c83030df 100644 --- a/impl/getcomputername.h +++ b/impl/getcomputername.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetComputerName(LPTSTR name, LPDWORD len); +BOOL GetComputerNameW(LPTSTR name, LPDWORD len); PAL_END_EXTERNC \ No newline at end of file diff --git a/impl/pal.h b/impl/pal.h index 645974e33..196e0314a 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -63,8 +63,7 @@ typedef void *PVOID; typedef PVOID HANDLE; typedef char TCHAR; - typedef TCHAR *LPTSTR; - typedef DWORD *LPDWORD; + typedef char *LPTSTR; #define NO_ERROR 0 #define INFINITE 0xFFFFFFFF #define WINAPI @@ -74,6 +73,7 @@ #define FALSE 0 #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 + #define ERROR_BAD_ENVIRONMENT 10; #define ERROR_BUFFER_OVERFLOW 111 #define MAX_PATH 0x00000104 typedef unsigned long long uint64; diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index ffce53881..e76e88df4 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -3,37 +3,26 @@ #include TEST(GetComputerName,simple) -{ +{ char hostname[HOST_NAME_MAX]; - std::string hostnameFunctionTest; + std::string hostnameFunctionTest(LOGIN_NAME_MAX, '\0');; DWORD hostSize = HOST_NAME_MAX; - BOOL getComputerName = GetComputerName(&hostnameFunctionTest[0], &hostSize); + BOOL getComputerName = GetComputerNameW(&hostnameFunctionTest[0], &hostSize); BOOL host = gethostname(hostname, sizeof hostname); - if(host == 0) - { - host = TRUE; - } - else - { - host = FALSE; - } - std::string hostnameString(hostname); std::string hostnameStringTest(&hostnameFunctionTest[0]); ASSERT_TRUE(getComputerName == TRUE); - ASSERT_EQ(host,TRUE); + ASSERT_EQ(host,0); ASSERT_EQ(hostnameString,hostnameStringTest); } TEST(GetComputerName,bufferttoosmall) { - char hostname[HOST_NAME_MAX]; std::string hostnameFunctionTest; DWORD hostSize = 0; - BOOL getComputerName = GetComputerName(&hostnameFunctionTest[0], &hostSize); + BOOL getComputerName = GetComputerNameW(&hostnameFunctionTest[0], &hostSize); ASSERT_TRUE(getComputerName == 0); - char buffer[ 256 ]; EXPECT_EQ(errno, ERROR_BUFFER_OVERFLOW); } \ No newline at end of file From 530c6883f86f6b3dedf73e1b8c3f9aa795d3fd60 Mon Sep 17 00:00:00 2001 From: Aaron Date: Mon, 3 Aug 2015 10:48:46 -0700 Subject: [PATCH 050/342] Add error handing for bad enivronment and bad parameter --- src/CMakeLists.txt | 4 ++-- src/impl/getcomputername.cpp | 21 ++++++++++++++++++++- src/impl/getcomputername.h | 2 +- src/impl/pal.h | 4 ++-- src/tests/test-getcomputername.cpp | 21 +++++---------------- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 05be91e26..97b14a942 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,10 +8,10 @@ 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) +set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp impl/getcomputername.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 ${HOST_COMMON_SOURCE_FILES} ${HOST_COMMON_TEST_SOURCE_FILES}) +set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp tests/test-getcomputername ${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}) diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp index c8a7c9719..5946851b2 100644 --- a/src/impl/getcomputername.cpp +++ b/src/impl/getcomputername.cpp @@ -1,10 +1,28 @@ #include "getcomputername.h" #include #include +#include +#include -BOOL GetComputerName(LPTSTR name, LPDWORD len) +BOOL GetComputerNameW(LPTSTR name, LPDWORD len) { + const std::string utf8 = "UTF-8"; errno = 0; + + // Check parameters + if (!name || !len) { + errno = ERROR_INVALID_PARAMETER; + return 0; + } + + // Select locale from environment + setlocale(LC_ALL, ""); + // Check that locale is UTF-8 + if (nl_langinfo(CODESET) != utf8) { + errno = ERROR_BAD_ENVIRONMENT; + return 0; + } + size_t len2 = *len; int host = gethostname(name, len2); if(host == 0) @@ -17,3 +35,4 @@ BOOL GetComputerName(LPTSTR name, LPDWORD len) return FALSE; } } + diff --git a/src/impl/getcomputername.h b/src/impl/getcomputername.h index 7f8dd8eb5..3c83030df 100644 --- a/src/impl/getcomputername.h +++ b/src/impl/getcomputername.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetComputerName(LPTSTR name, LPDWORD len); +BOOL GetComputerNameW(LPTSTR name, LPDWORD len); PAL_END_EXTERNC \ No newline at end of file diff --git a/src/impl/pal.h b/src/impl/pal.h index 645974e33..196e0314a 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -63,8 +63,7 @@ typedef void *PVOID; typedef PVOID HANDLE; typedef char TCHAR; - typedef TCHAR *LPTSTR; - typedef DWORD *LPDWORD; + typedef char *LPTSTR; #define NO_ERROR 0 #define INFINITE 0xFFFFFFFF #define WINAPI @@ -74,6 +73,7 @@ #define FALSE 0 #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 + #define ERROR_BAD_ENVIRONMENT 10; #define ERROR_BUFFER_OVERFLOW 111 #define MAX_PATH 0x00000104 typedef unsigned long long uint64; diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp index ffce53881..e76e88df4 100644 --- a/src/tests/test-getcomputername.cpp +++ b/src/tests/test-getcomputername.cpp @@ -3,37 +3,26 @@ #include TEST(GetComputerName,simple) -{ +{ char hostname[HOST_NAME_MAX]; - std::string hostnameFunctionTest; + std::string hostnameFunctionTest(LOGIN_NAME_MAX, '\0');; DWORD hostSize = HOST_NAME_MAX; - BOOL getComputerName = GetComputerName(&hostnameFunctionTest[0], &hostSize); + BOOL getComputerName = GetComputerNameW(&hostnameFunctionTest[0], &hostSize); BOOL host = gethostname(hostname, sizeof hostname); - if(host == 0) - { - host = TRUE; - } - else - { - host = FALSE; - } - std::string hostnameString(hostname); std::string hostnameStringTest(&hostnameFunctionTest[0]); ASSERT_TRUE(getComputerName == TRUE); - ASSERT_EQ(host,TRUE); + ASSERT_EQ(host,0); ASSERT_EQ(hostnameString,hostnameStringTest); } TEST(GetComputerName,bufferttoosmall) { - char hostname[HOST_NAME_MAX]; std::string hostnameFunctionTest; DWORD hostSize = 0; - BOOL getComputerName = GetComputerName(&hostnameFunctionTest[0], &hostSize); + BOOL getComputerName = GetComputerNameW(&hostnameFunctionTest[0], &hostSize); ASSERT_TRUE(getComputerName == 0); - char buffer[ 256 ]; EXPECT_EQ(errno, ERROR_BUFFER_OVERFLOW); } \ No newline at end of file From 61b4e5513a433cd8b2d884006b5d195384601ca6 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 1 Jul 2015 16:21:52 -0700 Subject: [PATCH 051/342] Update GetUserName signature --- src/impl/getusername.cpp | 2 +- src/impl/getusername.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index b37b1cffc..e911da41b 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -1,7 +1,7 @@ #include "getusername.h" #include -BOOL GetUserName(WCHAR_T* userName, UINT32* maxLength) +BOOL GetUserName(WCHAR_T* lpBuffer, LPDWORD lpnSize) { return 0; } diff --git a/src/impl/getusername.h b/src/impl/getusername.h index 922a4e96a..7650b94cc 100644 --- a/src/impl/getusername.h +++ b/src/impl/getusername.h @@ -4,7 +4,7 @@ PAL_BEGIN_EXTERNC -BOOL GetUserName(WCHAR_T* userName, UINT32* maxLength); +BOOL GetUserName(WCHAR_T* lpBuffer, LPDWORD lpnSize); PAL_END_EXTERNC From 4404e0361368b6d4fc9c2585ec0086799912c3fc Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 1 Jul 2015 16:21:52 -0700 Subject: [PATCH 052/342] Update GetUserName signature --- impl/getusername.cpp | 2 +- impl/getusername.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index b37b1cffc..e911da41b 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -1,7 +1,7 @@ #include "getusername.h" #include -BOOL GetUserName(WCHAR_T* userName, UINT32* maxLength) +BOOL GetUserName(WCHAR_T* lpBuffer, LPDWORD lpnSize) { return 0; } diff --git a/impl/getusername.h b/impl/getusername.h index 922a4e96a..7650b94cc 100644 --- a/impl/getusername.h +++ b/impl/getusername.h @@ -4,7 +4,7 @@ PAL_BEGIN_EXTERNC -BOOL GetUserName(WCHAR_T* userName, UINT32* maxLength); +BOOL GetUserName(WCHAR_T* lpBuffer, LPDWORD lpnSize); PAL_END_EXTERNC From 197938c6a64475cd4bb153de9cc151d47472342f Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 1 Jul 2015 16:24:36 -0700 Subject: [PATCH 053/342] Check locale in GetUserName --- src/impl/getusername.cpp | 27 ++++++++++++++++++++++++++- src/impl/pal.h | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index e911da41b..839e85c47 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -1,8 +1,33 @@ #include "getusername.h" +#include +#include +#include #include +#include +using namespace std; + +const string utf8 = "UTF-8"; + +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx +// Sets errno to: +// ERROR_BAD_ENVIRONMENT - locale is not UTF-8 +// +// Returns: +// 1 - succeeded +// 0 - failed BOOL GetUserName(WCHAR_T* lpBuffer, LPDWORD lpnSize) { - return 0; + errno = 0; + + // Select locale from environment + setlocale(LC_ALL, ""); + // Check that locale is UTF-8 + if (nl_langinfo(CODESET) != utf8) { + errno = ERROR_BAD_ENVIRONMENT; + return 0; + } + + return 1; } diff --git a/src/impl/pal.h b/src/impl/pal.h index f98108884..06ff5602c 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -71,6 +71,7 @@ #define FALSE 0 #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 + #define ERROR_BAD_ENVIRONMENT 0x0000000A #define MAX_PATH 0x00000104 typedef unsigned long long uint64; #endif From f676c77a8e94ff8ba02d1aad18716598ae28587e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 1 Jul 2015 16:24:36 -0700 Subject: [PATCH 054/342] Check locale in GetUserName --- impl/getusername.cpp | 27 ++++++++++++++++++++++++++- impl/pal.h | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index e911da41b..839e85c47 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -1,8 +1,33 @@ #include "getusername.h" +#include +#include +#include #include +#include +using namespace std; + +const string utf8 = "UTF-8"; + +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx +// Sets errno to: +// ERROR_BAD_ENVIRONMENT - locale is not UTF-8 +// +// Returns: +// 1 - succeeded +// 0 - failed BOOL GetUserName(WCHAR_T* lpBuffer, LPDWORD lpnSize) { - return 0; + errno = 0; + + // Select locale from environment + setlocale(LC_ALL, ""); + // Check that locale is UTF-8 + if (nl_langinfo(CODESET) != utf8) { + errno = ERROR_BAD_ENVIRONMENT; + return 0; + } + + return 1; } diff --git a/impl/pal.h b/impl/pal.h index f98108884..06ff5602c 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -71,6 +71,7 @@ #define FALSE 0 #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 + #define ERROR_BAD_ENVIRONMENT 0x0000000A #define MAX_PATH 0x00000104 typedef unsigned long long uint64; #endif From 83d2162dc16a525145d3e3c6ebc7ff9bde6eb9e5 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 1 Jul 2015 16:24:58 -0700 Subject: [PATCH 055/342] Use getlogin_r() in GetUserName and map errno --- src/impl/getusername.cpp | 47 ++++++++++++++++++++++++++++++++++++++++ src/impl/pal.h | 5 +++++ 2 files changed, 52 insertions(+) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 839e85c47..55ca9c93c 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -12,6 +12,13 @@ const string utf8 = "UTF-8"; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx // Sets errno to: // 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 // // Returns: // 1 - succeeded @@ -28,6 +35,46 @@ BOOL GetUserName(WCHAR_T* lpBuffer, LPDWORD lpnSize) return 0; } + // Get username from system in a thread-safe manner + char userName[*lpnSize]; + int err = getlogin_r(userName, *lpnSize); + // Map errno to Win32 Error Codes + if (err != 0) { + switch (errno) { + case EMFILE: + case ENFILE: + errno = ERROR_TOO_MANY_OPEN_FILES; + break; + case ENXIO: + errno = ERROR_NO_ASSOCIATION; + break; + case ERANGE: + errno = ERROR_INSUFFICIENT_BUFFER; + break; + case ENOENT: + errno = ERROR_NO_SUCH_USER; + break; + case ENOMEM: + errno = ERROR_OUTOFMEMORY; + break; + case ENOTTY: + errno = ERROR_NO_ASSOCIATION; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return 0; + } + + // TODO: Convert to char* to wchar* (UTF-8 to UTF-16 LE w/o BOM) + + // Unfortunately codecvt is not yet supported by G++, othwerise: + // wstring_convert,char16_t> conversion; + + // TODO: Use PAL's Unicode converters + + // TODO: set the lpnSize to the userName length (see msdn) + return 1; } diff --git a/src/impl/pal.h b/src/impl/pal.h index 06ff5602c..f30903a2f 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -72,6 +72,11 @@ #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 #define ERROR_BAD_ENVIRONMENT 0x0000000A + #define ERROR_TOO_MANY_OPEN_FILES 0x00000004 + #define ERROR_INSUFFICIENT_BUFFER 0x0000007A + #define ERROR_NO_ASSOCIATION 0x00000483 + #define ERROR_NO_SUCH_USER 0x00000525 + #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 typedef unsigned long long uint64; #endif From b80da9ab4d8d98a28ea97f75eaafa393bec67a06 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 1 Jul 2015 16:24:58 -0700 Subject: [PATCH 056/342] Use getlogin_r() in GetUserName and map errno --- impl/getusername.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++ impl/pal.h | 5 +++++ 2 files changed, 52 insertions(+) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 839e85c47..55ca9c93c 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -12,6 +12,13 @@ const string utf8 = "UTF-8"; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx // Sets errno to: // 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 // // Returns: // 1 - succeeded @@ -28,6 +35,46 @@ BOOL GetUserName(WCHAR_T* lpBuffer, LPDWORD lpnSize) return 0; } + // Get username from system in a thread-safe manner + char userName[*lpnSize]; + int err = getlogin_r(userName, *lpnSize); + // Map errno to Win32 Error Codes + if (err != 0) { + switch (errno) { + case EMFILE: + case ENFILE: + errno = ERROR_TOO_MANY_OPEN_FILES; + break; + case ENXIO: + errno = ERROR_NO_ASSOCIATION; + break; + case ERANGE: + errno = ERROR_INSUFFICIENT_BUFFER; + break; + case ENOENT: + errno = ERROR_NO_SUCH_USER; + break; + case ENOMEM: + errno = ERROR_OUTOFMEMORY; + break; + case ENOTTY: + errno = ERROR_NO_ASSOCIATION; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return 0; + } + + // TODO: Convert to char* to wchar* (UTF-8 to UTF-16 LE w/o BOM) + + // Unfortunately codecvt is not yet supported by G++, othwerise: + // wstring_convert,char16_t> conversion; + + // TODO: Use PAL's Unicode converters + + // TODO: set the lpnSize to the userName length (see msdn) + return 1; } diff --git a/impl/pal.h b/impl/pal.h index 06ff5602c..f30903a2f 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -72,6 +72,11 @@ #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 #define ERROR_BAD_ENVIRONMENT 0x0000000A + #define ERROR_TOO_MANY_OPEN_FILES 0x00000004 + #define ERROR_INSUFFICIENT_BUFFER 0x0000007A + #define ERROR_NO_ASSOCIATION 0x00000483 + #define ERROR_NO_SUCH_USER 0x00000525 + #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 typedef unsigned long long uint64; #endif From 95c6658178bda60883342084d973d16fd9eeec27 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 20 Jul 2015 11:24:31 -0700 Subject: [PATCH 057/342] Add unit test for GetUserName --- src/CMakeLists.txt | 2 +- src/tests/test-getusername.cpp | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/tests/test-getusername.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a5d27e7bf..c350c6db0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,7 +11,7 @@ link_directories(${monad_native_BINARY_DIR}) set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.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 ${HOST_COMMON_SOURCE_FILES} ${HOST_COMMON_TEST_SOURCE_FILES}) +set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp tests/test-getusername.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}) diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp new file mode 100644 index 000000000..1b15cc2d6 --- /dev/null +++ b/src/tests/test-getusername.cpp @@ -0,0 +1,23 @@ +#include +#include +#include "getusername.h" + +TEST(GetUserName,simple) +{ + // allocate a WCHAR_T buffer to receive username + DWORD lpnSize = 64; + WCHAR_T lpBuffer[lpnSize]; + + BOOL result = GetUserName(lpBuffer, &lpnSize); + + // GetUserName returns 1 on success + ASSERT_EQ(1, result); + + // get expected username + const char *username = getlogin(); + + // GetUserName sets lpnSize to length of username including null + ASSERT_EQ(strlen(username)+1, lpnSize); + + // TODO: ASSERT_STREQ(username, Utf16leToUtf8(lpBuffer)) +} From c8fa2152619286e2dc716c8c137a20061c4e0a2d Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 10:06:31 -0700 Subject: [PATCH 058/342] Add ext-pal dependency Static library and header pulled from a build of the PAL on Ubuntu 14.04. Ugly workaround, but much easier than incorporating that entire project's build system, or even just a part of it. --- .gitmodules | 3 +++ ext-src/pal | 1 + 2 files changed, 4 insertions(+) create mode 160000 ext-src/pal diff --git a/.gitmodules b/.gitmodules index 63ba77f86..d01dc9065 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "ext-src/gtest"] path = ext-src/gtest url = https://msostc.visualstudio.com/DefaultCollection/PS/_git/ext-gtest +[submodule "ext-src/pal"] + path = ext-src/pal + url = https://msostc.visualstudio.com/DefaultCollection/PS/_git/ext-pal diff --git a/ext-src/pal b/ext-src/pal new file mode 160000 index 000000000..56765ad5b --- /dev/null +++ b/ext-src/pal @@ -0,0 +1 @@ +Subproject commit 56765ad5b11e3b061b5af45b74519ce5eda99127 From f8eedc7210df2fec1bc1f7da87b884c56ad5047a Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 20 Jul 2015 11:24:31 -0700 Subject: [PATCH 059/342] Add unit test for GetUserName --- CMakeLists.txt | 2 +- tests/test-getusername.cpp | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tests/test-getusername.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a5d27e7bf..c350c6db0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ link_directories(${monad_native_BINARY_DIR}) set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.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 ${HOST_COMMON_SOURCE_FILES} ${HOST_COMMON_TEST_SOURCE_FILES}) +set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp tests/test-getusername.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}) diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp new file mode 100644 index 000000000..1b15cc2d6 --- /dev/null +++ b/tests/test-getusername.cpp @@ -0,0 +1,23 @@ +#include +#include +#include "getusername.h" + +TEST(GetUserName,simple) +{ + // allocate a WCHAR_T buffer to receive username + DWORD lpnSize = 64; + WCHAR_T lpBuffer[lpnSize]; + + BOOL result = GetUserName(lpBuffer, &lpnSize); + + // GetUserName returns 1 on success + ASSERT_EQ(1, result); + + // get expected username + const char *username = getlogin(); + + // GetUserName sets lpnSize to length of username including null + ASSERT_EQ(strlen(username)+1, lpnSize); + + // TODO: ASSERT_STREQ(username, Utf16leToUtf8(lpBuffer)) +} From 0d9d31d5bdf4c3bcc63dba3baca41361a1078152 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 10:08:26 -0700 Subject: [PATCH 060/342] Link scxcore to ps and include headers --- src/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c350c6db0..382bf3970 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ project(monad_native) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest -include_directories(../ext-src/gtest/fused-src impl) +include_directories(../ext-src/gtest/fused-src ../ext-src/pal/include impl) link_directories(${monad_native_BINARY_DIR}) # source file definitions @@ -17,6 +17,10 @@ SET(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp ${HOST_COMMON_SOURCE_FILES}) # target definitions add_library(ps SHARED ${LIB_SOURCE_FILES}) +add_library(scxcore STATIC IMPORTED GLOBAL) +set_property(TARGET scxcore PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../ext-src/pal/lib/libscxcore.a) +target_link_libraries(ps scxcore) + add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) @@ -28,5 +32,3 @@ target_link_libraries(host_cmdline dl icuuc) # target specific include directories target_include_directories(monad_native PRIVATE host) target_include_directories(host_cmdline PRIVATE host) - - From 8dbe788284fa94c603ce08cc4c36b96a00bbd655 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 10:08:26 -0700 Subject: [PATCH 061/342] Link scxcore to ps and include headers --- CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c350c6db0..382bf3970 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(monad_native) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest -include_directories(../ext-src/gtest/fused-src impl) +include_directories(../ext-src/gtest/fused-src ../ext-src/pal/include impl) link_directories(${monad_native_BINARY_DIR}) # source file definitions @@ -17,6 +17,10 @@ SET(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp ${HOST_COMMON_SOURCE_FILES}) # target definitions add_library(ps SHARED ${LIB_SOURCE_FILES}) +add_library(scxcore STATIC IMPORTED GLOBAL) +set_property(TARGET scxcore PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../ext-src/pal/lib/libscxcore.a) +target_link_libraries(ps scxcore) + add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) @@ -28,5 +32,3 @@ target_link_libraries(host_cmdline dl icuuc) # target specific include directories target_include_directories(monad_native PRIVATE host) target_include_directories(host_cmdline PRIVATE host) - - From 5f54d0c7484a504e8bed70e5930d10275c120606 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 10:15:34 -0700 Subject: [PATCH 062/342] Test UTF-16 output of GetUserName --- src/tests/test-getusername.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index 1b15cc2d6..c2c9d1c2d 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -1,7 +1,14 @@ +#include +#include #include #include +#include #include "getusername.h" +using std::string; +using std::vector; +using SCXCoreLib::Utf16leToUtf8; + TEST(GetUserName,simple) { // allocate a WCHAR_T buffer to receive username @@ -14,10 +21,17 @@ TEST(GetUserName,simple) ASSERT_EQ(1, result); // get expected username - const char *username = getlogin(); + string username = string(getlogin()); // GetUserName sets lpnSize to length of username including null - ASSERT_EQ(strlen(username)+1, lpnSize); + ASSERT_EQ(username.size()+1, lpnSize); - // TODO: ASSERT_STREQ(username, Utf16leToUtf8(lpBuffer)) + // copy UTF-16 bytes from lpBuffer to vector for conversion + vector input(reinterpret_cast(&lpBuffer[0]), + reinterpret_cast(&lpBuffer[lpnSize-1])); + // convert to UTF-8 for assertion + string output; + Utf16leToUtf8(input, output); + + EXPECT_EQ(username, output); } From ff0b43015bd0067d9f1bcdd55d2baa99abfba646 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 10:15:34 -0700 Subject: [PATCH 063/342] Test UTF-16 output of GetUserName --- tests/test-getusername.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index 1b15cc2d6..c2c9d1c2d 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -1,7 +1,14 @@ +#include +#include #include #include +#include #include "getusername.h" +using std::string; +using std::vector; +using SCXCoreLib::Utf16leToUtf8; + TEST(GetUserName,simple) { // allocate a WCHAR_T buffer to receive username @@ -14,10 +21,17 @@ TEST(GetUserName,simple) ASSERT_EQ(1, result); // get expected username - const char *username = getlogin(); + string username = string(getlogin()); // GetUserName sets lpnSize to length of username including null - ASSERT_EQ(strlen(username)+1, lpnSize); + ASSERT_EQ(username.size()+1, lpnSize); - // TODO: ASSERT_STREQ(username, Utf16leToUtf8(lpBuffer)) + // copy UTF-16 bytes from lpBuffer to vector for conversion + vector input(reinterpret_cast(&lpBuffer[0]), + reinterpret_cast(&lpBuffer[lpnSize-1])); + // convert to UTF-8 for assertion + string output; + Utf16leToUtf8(input, output); + + EXPECT_EQ(username, output); } From 69bfc8906ba5cfcbe8eb4de58bbc1b39a0c81bdb Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 10:15:45 -0700 Subject: [PATCH 064/342] Explain GetUserName signature --- src/impl/getusername.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/impl/getusername.h b/src/impl/getusername.h index 7650b94cc..50c6b1d5c 100644 --- a/src/impl/getusername.h +++ b/src/impl/getusername.h @@ -4,7 +4,8 @@ PAL_BEGIN_EXTERNC -BOOL GetUserName(WCHAR_T* lpBuffer, LPDWORD lpnSize); +// WCHAR_T * is a Unicode LPTSTR +// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx#LPTSTR +BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize); PAL_END_EXTERNC - From a18a5912ab92c78abb17909baf4003c75d73427a Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 10:15:45 -0700 Subject: [PATCH 065/342] Explain GetUserName signature --- impl/getusername.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/impl/getusername.h b/impl/getusername.h index 7650b94cc..50c6b1d5c 100644 --- a/impl/getusername.h +++ b/impl/getusername.h @@ -4,7 +4,8 @@ PAL_BEGIN_EXTERNC -BOOL GetUserName(WCHAR_T* lpBuffer, LPDWORD lpnSize); +// WCHAR_T * is a Unicode LPTSTR +// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx#LPTSTR +BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize); PAL_END_EXTERNC - From e14934d06d9c02ba060fdf367b06476ae29cd359 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 10:17:47 -0700 Subject: [PATCH 066/342] Check for invalid parameters in GetUserName --- src/impl/getusername.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 55ca9c93c..5e3aeb1c5 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -11,6 +11,7 @@ const string utf8 = "UTF-8"; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx // 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 @@ -23,10 +24,16 @@ const string utf8 = "UTF-8"; // Returns: // 1 - succeeded // 0 - failed -BOOL GetUserName(WCHAR_T* lpBuffer, LPDWORD lpnSize) +BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) { errno = 0; + // Check parameters + if (!lpBuffer || !lpnSize) { + errno = ERROR_INVALID_PARAMETER; + return 0; + } + // Select locale from environment setlocale(LC_ALL, ""); // Check that locale is UTF-8 From 6481f0336d7411ca81cb182a7664dcba5374e3bb Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 10:17:47 -0700 Subject: [PATCH 067/342] Check for invalid parameters in GetUserName --- impl/getusername.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 55ca9c93c..5e3aeb1c5 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -11,6 +11,7 @@ const string utf8 = "UTF-8"; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx // 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 @@ -23,10 +24,16 @@ const string utf8 = "UTF-8"; // Returns: // 1 - succeeded // 0 - failed -BOOL GetUserName(WCHAR_T* lpBuffer, LPDWORD lpnSize) +BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) { errno = 0; + // Check parameters + if (!lpBuffer || !lpnSize) { + errno = ERROR_INVALID_PARAMETER; + return 0; + } + // Select locale from environment setlocale(LC_ALL, ""); // Check that locale is UTF-8 From 00390847e6dacfde17cfa38634ce7895592089c6 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 10:20:50 -0700 Subject: [PATCH 068/342] Convert get_login_r to UTF-16 and return --- src/impl/getusername.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 5e3aeb1c5..ba5818250 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -4,8 +4,13 @@ #include #include #include +#include +#include -using namespace std; +using std::string; +using std::vector; + +using SCXCoreLib::Utf8ToUtf16le; const string utf8 = "UTF-8"; @@ -73,15 +78,22 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) return 0; } - // TODO: Convert to char* to wchar* (UTF-8 to UTF-16 LE w/o BOM) + // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) + string input = string(userName); + vector output; + Utf8ToUtf16le(input, output); - // Unfortunately codecvt is not yet supported by G++, othwerise: - // wstring_convert,char16_t> conversion; + if (output.size()/2 + 1 > *lpnSize) { + errno = ERROR_INSUFFICIENT_BUFFER; + return 0; + } - // TODO: Use PAL's Unicode converters + // Add two null bytes (because it's UTF-16) + output.push_back('\0'); + output.push_back('\0'); - // TODO: set the lpnSize to the userName length (see msdn) + memcpy(lpBuffer, &output[0], output.size()); + *lpnSize = output.size()/2; return 1; } - From 3ac74ab849aa2fa441b6ae4d8d7ada0b743ca9fa Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 10:20:50 -0700 Subject: [PATCH 069/342] Convert get_login_r to UTF-16 and return --- impl/getusername.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 5e3aeb1c5..ba5818250 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -4,8 +4,13 @@ #include #include #include +#include +#include -using namespace std; +using std::string; +using std::vector; + +using SCXCoreLib::Utf8ToUtf16le; const string utf8 = "UTF-8"; @@ -73,15 +78,22 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) return 0; } - // TODO: Convert to char* to wchar* (UTF-8 to UTF-16 LE w/o BOM) + // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) + string input = string(userName); + vector output; + Utf8ToUtf16le(input, output); - // Unfortunately codecvt is not yet supported by G++, othwerise: - // wstring_convert,char16_t> conversion; + if (output.size()/2 + 1 > *lpnSize) { + errno = ERROR_INSUFFICIENT_BUFFER; + return 0; + } - // TODO: Use PAL's Unicode converters + // Add two null bytes (because it's UTF-16) + output.push_back('\0'); + output.push_back('\0'); - // TODO: set the lpnSize to the userName length (see msdn) + memcpy(lpBuffer, &output[0], output.size()); + *lpnSize = output.size()/2; return 1; } - From 80f8fff6f294e7764f8d2489f2d7d7f5b7a8aee5 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 11:24:57 -0700 Subject: [PATCH 070/342] Clarify lpBuffer layout in GetUserName unit test --- src/tests/test-getusername.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index c2c9d1c2d..825e94960 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -26,9 +26,11 @@ TEST(GetUserName,simple) // GetUserName sets lpnSize to length of username including null ASSERT_EQ(username.size()+1, lpnSize); - // copy UTF-16 bytes from lpBuffer to vector for conversion - vector input(reinterpret_cast(&lpBuffer[0]), - reinterpret_cast(&lpBuffer[lpnSize-1])); + // copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion + unsigned char *begin = reinterpret_cast(&lpBuffer[0]); + // -1 to skip null; *2 because UTF-16 encodes two bytes per character + unsigned char *end = begin + (lpnSize-1)*2; + vector input(begin, end); // convert to UTF-8 for assertion string output; Utf16leToUtf8(input, output); From 41a00d9279529ca7c5b98958eb39f53fbbd981ed Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 11:24:57 -0700 Subject: [PATCH 071/342] Clarify lpBuffer layout in GetUserName unit test --- tests/test-getusername.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index c2c9d1c2d..825e94960 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -26,9 +26,11 @@ TEST(GetUserName,simple) // GetUserName sets lpnSize to length of username including null ASSERT_EQ(username.size()+1, lpnSize); - // copy UTF-16 bytes from lpBuffer to vector for conversion - vector input(reinterpret_cast(&lpBuffer[0]), - reinterpret_cast(&lpBuffer[lpnSize-1])); + // copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion + unsigned char *begin = reinterpret_cast(&lpBuffer[0]); + // -1 to skip null; *2 because UTF-16 encodes two bytes per character + unsigned char *end = begin + (lpnSize-1)*2; + vector input(begin, end); // convert to UTF-8 for assertion string output; Utf16leToUtf8(input, output); From 14cec68d087c42f7dcba87ca0b1b33b7e2c6416e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 13:43:09 -0700 Subject: [PATCH 072/342] Change global to local static const To avoid polluting the global namespace without using a namespace. --- src/impl/getusername.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index ba5818250..6f11b516a 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -12,8 +12,6 @@ using std::vector; using SCXCoreLib::Utf8ToUtf16le; -const string utf8 = "UTF-8"; - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx // Sets errno to: // ERROR_INVALID_PARAMETER - parameter is not valid @@ -31,6 +29,8 @@ const string utf8 = "UTF-8"; // 0 - failed BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) { + static const std::string utf8 = "UTF-8"; + errno = 0; // Check parameters From 6699091f7b92c1b24f438f355de222d28d245558 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 13:43:09 -0700 Subject: [PATCH 073/342] Change global to local static const To avoid polluting the global namespace without using a namespace. --- impl/getusername.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index ba5818250..6f11b516a 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -12,8 +12,6 @@ using std::vector; using SCXCoreLib::Utf8ToUtf16le; -const string utf8 = "UTF-8"; - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx // Sets errno to: // ERROR_INVALID_PARAMETER - parameter is not valid @@ -31,6 +29,8 @@ const string utf8 = "UTF-8"; // 0 - failed BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) { + static const std::string utf8 = "UTF-8"; + errno = 0; // Check parameters From 097d2e3821fcd246b274a86957d0f85e4e871342 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 13:45:25 -0700 Subject: [PATCH 074/342] Factor out using directives --- src/impl/getusername.cpp | 11 +++-------- src/tests/test-getusername.cpp | 12 ++++-------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 6f11b516a..35c034fb9 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -7,11 +7,6 @@ #include #include -using std::string; -using std::vector; - -using SCXCoreLib::Utf8ToUtf16le; - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx // Sets errno to: // ERROR_INVALID_PARAMETER - parameter is not valid @@ -79,9 +74,9 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) } // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) - string input = string(userName); - vector output; - Utf8ToUtf16le(input, output); + std::string input(userName); + std::vector output; + SCXCoreLib::Utf8ToUtf16le(input, output); if (output.size()/2 + 1 > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index 825e94960..c7bbc14b4 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -5,10 +5,6 @@ #include #include "getusername.h" -using std::string; -using std::vector; -using SCXCoreLib::Utf16leToUtf8; - TEST(GetUserName,simple) { // allocate a WCHAR_T buffer to receive username @@ -21,7 +17,7 @@ TEST(GetUserName,simple) ASSERT_EQ(1, result); // get expected username - string username = string(getlogin()); + std::string username(getlogin()); // GetUserName sets lpnSize to length of username including null ASSERT_EQ(username.size()+1, lpnSize); @@ -30,10 +26,10 @@ TEST(GetUserName,simple) unsigned char *begin = reinterpret_cast(&lpBuffer[0]); // -1 to skip null; *2 because UTF-16 encodes two bytes per character unsigned char *end = begin + (lpnSize-1)*2; - vector input(begin, end); + std::vector input(begin, end); // convert to UTF-8 for assertion - string output; - Utf16leToUtf8(input, output); + std::string output; + SCXCoreLib::Utf16leToUtf8(input, output); EXPECT_EQ(username, output); } From 3ab34083783922867f11ea0900d01d5a7d8eb1c5 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 13:45:25 -0700 Subject: [PATCH 075/342] Factor out using directives --- impl/getusername.cpp | 11 +++-------- tests/test-getusername.cpp | 12 ++++-------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 6f11b516a..35c034fb9 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -7,11 +7,6 @@ #include #include -using std::string; -using std::vector; - -using SCXCoreLib::Utf8ToUtf16le; - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx // Sets errno to: // ERROR_INVALID_PARAMETER - parameter is not valid @@ -79,9 +74,9 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) } // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) - string input = string(userName); - vector output; - Utf8ToUtf16le(input, output); + std::string input(userName); + std::vector output; + SCXCoreLib::Utf8ToUtf16le(input, output); if (output.size()/2 + 1 > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index 825e94960..c7bbc14b4 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -5,10 +5,6 @@ #include #include "getusername.h" -using std::string; -using std::vector; -using SCXCoreLib::Utf16leToUtf8; - TEST(GetUserName,simple) { // allocate a WCHAR_T buffer to receive username @@ -21,7 +17,7 @@ TEST(GetUserName,simple) ASSERT_EQ(1, result); // get expected username - string username = string(getlogin()); + std::string username(getlogin()); // GetUserName sets lpnSize to length of username including null ASSERT_EQ(username.size()+1, lpnSize); @@ -30,10 +26,10 @@ TEST(GetUserName,simple) unsigned char *begin = reinterpret_cast(&lpBuffer[0]); // -1 to skip null; *2 because UTF-16 encodes two bytes per character unsigned char *end = begin + (lpnSize-1)*2; - vector input(begin, end); + std::vector input(begin, end); // convert to UTF-8 for assertion - string output; - Utf16leToUtf8(input, output); + std::string output; + SCXCoreLib::Utf16leToUtf8(input, output); EXPECT_EQ(username, output); } From 59eb8a5799c2a676d8e9d74fa3c1f5f07d96b9b1 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 13:48:03 -0700 Subject: [PATCH 076/342] Use L_cuserid instead of 64 and given lpnSize --- src/impl/getusername.cpp | 4 ++-- src/tests/test-getusername.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 35c034fb9..f9c73280a 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -43,8 +43,8 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) } // Get username from system in a thread-safe manner - char userName[*lpnSize]; - int err = getlogin_r(userName, *lpnSize); + char userName[L_cuserid]; + int err = getlogin_r(userName, L_cuserid); // Map errno to Win32 Error Codes if (err != 0) { switch (errno) { diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index c7bbc14b4..7e1badee0 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -8,7 +8,7 @@ TEST(GetUserName,simple) { // allocate a WCHAR_T buffer to receive username - DWORD lpnSize = 64; + DWORD lpnSize = L_cuserid; WCHAR_T lpBuffer[lpnSize]; BOOL result = GetUserName(lpBuffer, &lpnSize); From e8cb7e24fed8da27eac5956c2fc8b3c8630cf4e5 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 13:48:03 -0700 Subject: [PATCH 077/342] Use L_cuserid instead of 64 and given lpnSize --- impl/getusername.cpp | 4 ++-- tests/test-getusername.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 35c034fb9..f9c73280a 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -43,8 +43,8 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) } // Get username from system in a thread-safe manner - char userName[*lpnSize]; - int err = getlogin_r(userName, *lpnSize); + char userName[L_cuserid]; + int err = getlogin_r(userName, L_cuserid); // Map errno to Win32 Error Codes if (err != 0) { switch (errno) { diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index c7bbc14b4..7e1badee0 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -8,7 +8,7 @@ TEST(GetUserName,simple) { // allocate a WCHAR_T buffer to receive username - DWORD lpnSize = 64; + DWORD lpnSize = L_cuserid; WCHAR_T lpBuffer[lpnSize]; BOOL result = GetUserName(lpBuffer, &lpnSize); From edcb8b04023177ec916eac600731b805be4c3479 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 14:21:48 -0700 Subject: [PATCH 078/342] Use test fixture in GetUserName unit tests --- src/tests/test-getusername.cpp | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index 7e1badee0..a565aa31e 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -5,22 +5,31 @@ #include #include "getusername.h" -TEST(GetUserName,simple) -{ - // allocate a WCHAR_T buffer to receive username - DWORD lpnSize = L_cuserid; - WCHAR_T lpBuffer[lpnSize]; +class GetUserNameTest : public ::testing::Test { +protected: + DWORD lpnSize; + std::vector lpBuffer; + BOOL result; + std::string userName; - BOOL result = GetUserName(lpBuffer, &lpnSize); + GetUserNameTest(): userName(std::string(getlogin())) {} + + void GetUserNameWithSize(DWORD size) { + lpnSize = size; + // allocate a WCHAR_T buffer to receive username + lpBuffer.assign(lpnSize, '\0'); + result = GetUserName(&lpBuffer[0], &lpnSize); + } +}; + +TEST_F(GetUserNameTest, NormalUse) { + GetUserNameWithSize(L_cuserid); // GetUserName returns 1 on success ASSERT_EQ(1, result); - // get expected username - std::string username(getlogin()); - // GetUserName sets lpnSize to length of username including null - ASSERT_EQ(username.size()+1, lpnSize); + ASSERT_EQ(userName.size()+1, lpnSize); // copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion unsigned char *begin = reinterpret_cast(&lpBuffer[0]); @@ -31,5 +40,5 @@ TEST(GetUserName,simple) std::string output; SCXCoreLib::Utf16leToUtf8(input, output); - EXPECT_EQ(username, output); + EXPECT_EQ(userName, output); } From 0f07a65f501e5860fa5164af826281cb05633723 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 14:21:48 -0700 Subject: [PATCH 079/342] Use test fixture in GetUserName unit tests --- tests/test-getusername.cpp | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index 7e1badee0..a565aa31e 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -5,22 +5,31 @@ #include #include "getusername.h" -TEST(GetUserName,simple) -{ - // allocate a WCHAR_T buffer to receive username - DWORD lpnSize = L_cuserid; - WCHAR_T lpBuffer[lpnSize]; +class GetUserNameTest : public ::testing::Test { +protected: + DWORD lpnSize; + std::vector lpBuffer; + BOOL result; + std::string userName; - BOOL result = GetUserName(lpBuffer, &lpnSize); + GetUserNameTest(): userName(std::string(getlogin())) {} + + void GetUserNameWithSize(DWORD size) { + lpnSize = size; + // allocate a WCHAR_T buffer to receive username + lpBuffer.assign(lpnSize, '\0'); + result = GetUserName(&lpBuffer[0], &lpnSize); + } +}; + +TEST_F(GetUserNameTest, NormalUse) { + GetUserNameWithSize(L_cuserid); // GetUserName returns 1 on success ASSERT_EQ(1, result); - // get expected username - std::string username(getlogin()); - // GetUserName sets lpnSize to length of username including null - ASSERT_EQ(username.size()+1, lpnSize); + ASSERT_EQ(userName.size()+1, lpnSize); // copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion unsigned char *begin = reinterpret_cast(&lpBuffer[0]); @@ -31,5 +40,5 @@ TEST(GetUserName,simple) std::string output; SCXCoreLib::Utf16leToUtf8(input, output); - EXPECT_EQ(username, output); + EXPECT_EQ(userName, output); } From 876a88c7d8c8be6da43624ed70c955cdb7a049d4 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 15:10:44 -0700 Subject: [PATCH 080/342] Set lpnSize when insufficient --- src/impl/getusername.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index f9c73280a..203ed5e7e 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -80,6 +80,7 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) if (output.size()/2 + 1 > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; + *lpnSize = output.size()/2 + 1; return 0; } From 4a2c1c5a95ebd1bb2de4380167422a1d30c72ec2 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 15:10:44 -0700 Subject: [PATCH 081/342] Set lpnSize when insufficient --- impl/getusername.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index f9c73280a..203ed5e7e 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -80,6 +80,7 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) if (output.size()/2 + 1 > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; + *lpnSize = output.size()/2 + 1; return 0; } From e2d4ce0ab1e5563b8482adf4085bfe30b010549b Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 15:21:55 -0700 Subject: [PATCH 082/342] Add more unit test coverage for GetUserName --- src/tests/test-getusername.cpp | 115 +++++++++++++++++++++++++++------ 1 file changed, 96 insertions(+), 19 deletions(-) diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index a565aa31e..b58387b26 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -14,31 +14,108 @@ protected: GetUserNameTest(): userName(std::string(getlogin())) {} - void GetUserNameWithSize(DWORD size) { + void TestWithSize(DWORD size) { lpnSize = size; // allocate a WCHAR_T buffer to receive username lpBuffer.assign(lpnSize, '\0'); result = GetUserName(&lpBuffer[0], &lpnSize); } + + void TestSuccess() { + SCOPED_TRACE(""); + // returns 1 on success + EXPECT_EQ(1, result); + + // sets lpnSize to length of username + null + ASSERT_EQ(userName.size()+1, lpnSize); + + // copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion + unsigned char *begin = reinterpret_cast(&lpBuffer[0]); + // -1 to skip null; *2 because UTF-16 encodes two bytes per character + unsigned char *end = begin + (lpnSize-1)*2; + std::vector input(begin, end); + // convert to UTF-8 for comparison + std::string output; + SCXCoreLib::Utf16leToUtf8(input, output); + + EXPECT_EQ(userName, output); + } + + void TestInvalidParameter() { + SCOPED_TRACE(""); + + // returns 0 on failure + EXPECT_EQ(0, result); + + // 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() { + SCOPED_TRACE(""); + + // returns 0 on failure + EXPECT_EQ(0, result); + + // sets errno to ERROR_INSUFFICIENT_BUFFER + EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); + + // sets lpnSize to length of username + null + EXPECT_EQ(userName.size()+1, lpnSize); + } }; -TEST_F(GetUserNameTest, NormalUse) { - GetUserNameWithSize(L_cuserid); +TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) { + lpnSize = 1; + result = GetUserName(NULL, &lpnSize); - // GetUserName returns 1 on success - ASSERT_EQ(1, result); - - // GetUserName sets lpnSize to length of username including null - ASSERT_EQ(userName.size()+1, lpnSize); - - // copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion - unsigned char *begin = reinterpret_cast(&lpBuffer[0]); - // -1 to skip null; *2 because UTF-16 encodes two bytes per character - unsigned char *end = begin + (lpnSize-1)*2; - std::vector input(begin, end); - // convert to UTF-8 for assertion - std::string output; - SCXCoreLib::Utf16leToUtf8(input, output); - - EXPECT_EQ(userName, output); + TestInvalidParameter(); + // does not reset lpnSize + EXPECT_EQ(1, lpnSize); +} + +TEST_F(GetUserNameTest, BufferSizeAsNullButNotBuffer) { + lpBuffer.push_back('\0'); + result = GetUserName(&lpBuffer[0], NULL); + + TestInvalidParameter(); +} + +TEST_F(GetUserNameTest, BufferSizeAsZero) { + TestWithSize(0); + TestInvalidParameter(); + // does not reset lpnSize + EXPECT_EQ(0, lpnSize); +} + +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 does not include null + TestWithSize(userName.size()); + TestInsufficientBuffer(); +} + +TEST_F(GetUserNameTest, BufferSizeAsUserNameMinusOne) { + // the buffer is also too small + TestWithSize(userName.size()-1); + TestInsufficientBuffer(); +} + +TEST_F(GetUserNameTest, BufferSizeAsUserNamePlusOne) { + // the buffer is exactly big enough will null + TestWithSize(userName.size()+1); + TestSuccess(); +} + +TEST_F(GetUserNameTest, L_cuseridSize) { + // L_cuserid is big enough to hold any username + TestWithSize(L_cuserid); + TestSuccess(); } From cbee353d0d0c4b759d7b94c4674dc8fedae2ef6a Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 15:21:55 -0700 Subject: [PATCH 083/342] Add more unit test coverage for GetUserName --- tests/test-getusername.cpp | 115 +++++++++++++++++++++++++++++++------ 1 file changed, 96 insertions(+), 19 deletions(-) diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index a565aa31e..b58387b26 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -14,31 +14,108 @@ protected: GetUserNameTest(): userName(std::string(getlogin())) {} - void GetUserNameWithSize(DWORD size) { + void TestWithSize(DWORD size) { lpnSize = size; // allocate a WCHAR_T buffer to receive username lpBuffer.assign(lpnSize, '\0'); result = GetUserName(&lpBuffer[0], &lpnSize); } + + void TestSuccess() { + SCOPED_TRACE(""); + // returns 1 on success + EXPECT_EQ(1, result); + + // sets lpnSize to length of username + null + ASSERT_EQ(userName.size()+1, lpnSize); + + // copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion + unsigned char *begin = reinterpret_cast(&lpBuffer[0]); + // -1 to skip null; *2 because UTF-16 encodes two bytes per character + unsigned char *end = begin + (lpnSize-1)*2; + std::vector input(begin, end); + // convert to UTF-8 for comparison + std::string output; + SCXCoreLib::Utf16leToUtf8(input, output); + + EXPECT_EQ(userName, output); + } + + void TestInvalidParameter() { + SCOPED_TRACE(""); + + // returns 0 on failure + EXPECT_EQ(0, result); + + // 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() { + SCOPED_TRACE(""); + + // returns 0 on failure + EXPECT_EQ(0, result); + + // sets errno to ERROR_INSUFFICIENT_BUFFER + EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); + + // sets lpnSize to length of username + null + EXPECT_EQ(userName.size()+1, lpnSize); + } }; -TEST_F(GetUserNameTest, NormalUse) { - GetUserNameWithSize(L_cuserid); +TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) { + lpnSize = 1; + result = GetUserName(NULL, &lpnSize); - // GetUserName returns 1 on success - ASSERT_EQ(1, result); - - // GetUserName sets lpnSize to length of username including null - ASSERT_EQ(userName.size()+1, lpnSize); - - // copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion - unsigned char *begin = reinterpret_cast(&lpBuffer[0]); - // -1 to skip null; *2 because UTF-16 encodes two bytes per character - unsigned char *end = begin + (lpnSize-1)*2; - std::vector input(begin, end); - // convert to UTF-8 for assertion - std::string output; - SCXCoreLib::Utf16leToUtf8(input, output); - - EXPECT_EQ(userName, output); + TestInvalidParameter(); + // does not reset lpnSize + EXPECT_EQ(1, lpnSize); +} + +TEST_F(GetUserNameTest, BufferSizeAsNullButNotBuffer) { + lpBuffer.push_back('\0'); + result = GetUserName(&lpBuffer[0], NULL); + + TestInvalidParameter(); +} + +TEST_F(GetUserNameTest, BufferSizeAsZero) { + TestWithSize(0); + TestInvalidParameter(); + // does not reset lpnSize + EXPECT_EQ(0, lpnSize); +} + +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 does not include null + TestWithSize(userName.size()); + TestInsufficientBuffer(); +} + +TEST_F(GetUserNameTest, BufferSizeAsUserNameMinusOne) { + // the buffer is also too small + TestWithSize(userName.size()-1); + TestInsufficientBuffer(); +} + +TEST_F(GetUserNameTest, BufferSizeAsUserNamePlusOne) { + // the buffer is exactly big enough will null + TestWithSize(userName.size()+1); + TestSuccess(); +} + +TEST_F(GetUserNameTest, L_cuseridSize) { + // L_cuserid is big enough to hold any username + TestWithSize(L_cuserid); + TestSuccess(); } From bb8d0b793e9e7c5060f42ae093024662f48c14ca Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 16:04:11 -0700 Subject: [PATCH 084/342] Use LOGIN_NAME_MAX instead of L_cuserid Since L_cuserid is only for cuserid, not getlogin_r Unit test for L_cuserid removed because the macro may not be available on all platforms. --- src/impl/getusername.cpp | 4 ++-- src/tests/test-getusername.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 203ed5e7e..d369a4a3d 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -43,8 +43,8 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) } // Get username from system in a thread-safe manner - char userName[L_cuserid]; - int err = getlogin_r(userName, L_cuserid); + char userName[LOGIN_NAME_MAX]; + int err = getlogin_r(userName, LOGIN_NAME_MAX); // Map errno to Win32 Error Codes if (err != 0) { switch (errno) { diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index b58387b26..8e025a2de 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -114,8 +114,8 @@ TEST_F(GetUserNameTest, BufferSizeAsUserNamePlusOne) { TestSuccess(); } -TEST_F(GetUserNameTest, L_cuseridSize) { - // L_cuserid is big enough to hold any username - TestWithSize(L_cuserid); +TEST_F(GetUserNameTest, BufferSizeAsLoginNameMax) { + // LoginNameMax is big enough to hold any username + TestWithSize(LOGIN_NAME_MAX); TestSuccess(); } From 9426e9c4551493db768620e9d08185eae85a1df3 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 16:04:11 -0700 Subject: [PATCH 085/342] Use LOGIN_NAME_MAX instead of L_cuserid Since L_cuserid is only for cuserid, not getlogin_r Unit test for L_cuserid removed because the macro may not be available on all platforms. --- impl/getusername.cpp | 4 ++-- tests/test-getusername.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 203ed5e7e..d369a4a3d 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -43,8 +43,8 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) } // Get username from system in a thread-safe manner - char userName[L_cuserid]; - int err = getlogin_r(userName, L_cuserid); + char userName[LOGIN_NAME_MAX]; + int err = getlogin_r(userName, LOGIN_NAME_MAX); // Map errno to Win32 Error Codes if (err != 0) { switch (errno) { diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index b58387b26..8e025a2de 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -114,8 +114,8 @@ TEST_F(GetUserNameTest, BufferSizeAsUserNamePlusOne) { TestSuccess(); } -TEST_F(GetUserNameTest, L_cuseridSize) { - // L_cuserid is big enough to hold any username - TestWithSize(L_cuserid); +TEST_F(GetUserNameTest, BufferSizeAsLoginNameMax) { + // LoginNameMax is big enough to hold any username + TestWithSize(LOGIN_NAME_MAX); TestSuccess(); } From b36cdcdc1241a83a6176802a79d1b059bfb1f1c6 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 16:29:17 -0700 Subject: [PATCH 086/342] Use std::string instead of C99 dynamic array --- src/impl/getusername.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index d369a4a3d..baff324c3 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -43,8 +43,8 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) } // Get username from system in a thread-safe manner - char userName[LOGIN_NAME_MAX]; - int err = getlogin_r(userName, LOGIN_NAME_MAX); + std::string username(LOGIN_NAME_MAX, '\0'); + int err = getlogin_r(&username[0], username.size()); // Map errno to Win32 Error Codes if (err != 0) { switch (errno) { @@ -73,10 +73,17 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) return 0; } + // "Trim" the username to the first trailing null because + // otherwise the std::string with repeated null characters is + // valid, and the conversion will still include all the null + // characters. Creating a std::string from the C string of the + // original effectively trims it to the first null, without + // the need to manually trim whitespace (nor using Boost). + username = std::string(username.c_str()); + // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) - std::string input(userName); std::vector output; - SCXCoreLib::Utf8ToUtf16le(input, output); + SCXCoreLib::Utf8ToUtf16le(username, output); if (output.size()/2 + 1 > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; From 0592a37395188e204241a668612e027fd5d7a80e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 16:29:17 -0700 Subject: [PATCH 087/342] Use std::string instead of C99 dynamic array --- impl/getusername.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index d369a4a3d..baff324c3 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -43,8 +43,8 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) } // Get username from system in a thread-safe manner - char userName[LOGIN_NAME_MAX]; - int err = getlogin_r(userName, LOGIN_NAME_MAX); + std::string username(LOGIN_NAME_MAX, '\0'); + int err = getlogin_r(&username[0], username.size()); // Map errno to Win32 Error Codes if (err != 0) { switch (errno) { @@ -73,10 +73,17 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) return 0; } + // "Trim" the username to the first trailing null because + // otherwise the std::string with repeated null characters is + // valid, and the conversion will still include all the null + // characters. Creating a std::string from the C string of the + // original effectively trims it to the first null, without + // the need to manually trim whitespace (nor using Boost). + username = std::string(username.c_str()); + // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) - std::string input(userName); std::vector output; - SCXCoreLib::Utf8ToUtf16le(input, output); + SCXCoreLib::Utf8ToUtf16le(username, output); if (output.size()/2 + 1 > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; From 865fd0a56be0fde4c559e72b8c7d4fdb63fc9187 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 16:36:06 -0700 Subject: [PATCH 088/342] Remove unnecessary static qualifier from const string --- src/impl/getusername.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index baff324c3..282cd930d 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -24,7 +24,7 @@ // 0 - failed BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) { - static const std::string utf8 = "UTF-8"; + const std::string utf8 = "UTF-8"; errno = 0; From 2a2c1d92364126fe5bfe793cfd5f890a45114541 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 16:36:06 -0700 Subject: [PATCH 089/342] Remove unnecessary static qualifier from const string --- impl/getusername.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index baff324c3..282cd930d 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -24,7 +24,7 @@ // 0 - failed BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) { - static const std::string utf8 = "UTF-8"; + const std::string utf8 = "UTF-8"; errno = 0; From d589ac1cbfa4e0f2225ab37c9f9c5fd3b5ea1b0e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 16:36:19 -0700 Subject: [PATCH 090/342] Refactor setting of lpnSize when buffer size is insufficient --- src/impl/getusername.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 282cd930d..2e1e1dd12 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -85,9 +85,15 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) std::vector output; SCXCoreLib::Utf8ToUtf16le(username, output); - if (output.size()/2 + 1 > *lpnSize) { + // The length is the number of characters in the string, which + // is half the string size because UTF-16 encodes two bytes + // per character, plus one for the trailing null. + const DWORD length = output.size()/2 + 1; + if (length > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; - *lpnSize = output.size()/2 + 1; + // Set lpnSize if buffer is too small to inform user + // of necessary size + *lpnSize = length; return 0; } From b076850012ce66e770436d8b0b4eebdd11517bfb Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 22 Jul 2015 16:36:19 -0700 Subject: [PATCH 091/342] Refactor setting of lpnSize when buffer size is insufficient --- impl/getusername.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 282cd930d..2e1e1dd12 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -85,9 +85,15 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) std::vector output; SCXCoreLib::Utf8ToUtf16le(username, output); - if (output.size()/2 + 1 > *lpnSize) { + // The length is the number of characters in the string, which + // is half the string size because UTF-16 encodes two bytes + // per character, plus one for the trailing null. + const DWORD length = output.size()/2 + 1; + if (length > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; - *lpnSize = output.size()/2 + 1; + // Set lpnSize if buffer is too small to inform user + // of necessary size + *lpnSize = length; return 0; } From 011d8f41ea4a7b51d7f260d7d48d5e5d63da04b9 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 23 Jul 2015 09:28:34 -0700 Subject: [PATCH 092/342] Rename userName in test to expectedUsername To clarify that it is for comparison; not the result of GetUserName. --- src/tests/test-getusername.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index 8e025a2de..4f249e118 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -10,9 +10,9 @@ protected: DWORD lpnSize; std::vector lpBuffer; BOOL result; - std::string userName; + std::string expectedUsername; - GetUserNameTest(): userName(std::string(getlogin())) {} + GetUserNameTest(): expectedUsername(std::string(getlogin())) {} void TestWithSize(DWORD size) { lpnSize = size; @@ -27,7 +27,7 @@ protected: EXPECT_EQ(1, result); // sets lpnSize to length of username + null - ASSERT_EQ(userName.size()+1, lpnSize); + ASSERT_EQ(expectedUsername.size()+1, lpnSize); // copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion unsigned char *begin = reinterpret_cast(&lpBuffer[0]); @@ -38,7 +38,7 @@ protected: std::string output; SCXCoreLib::Utf16leToUtf8(input, output); - EXPECT_EQ(userName, output); + EXPECT_EQ(expectedUsername, output); } void TestInvalidParameter() { @@ -62,7 +62,7 @@ protected: EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); // sets lpnSize to length of username + null - EXPECT_EQ(userName.size()+1, lpnSize); + EXPECT_EQ(expectedUsername.size()+1, lpnSize); } }; @@ -98,19 +98,19 @@ TEST_F(GetUserNameTest, BufferSizeAsOne) { TEST_F(GetUserNameTest, BufferSizeAsUserName) { // the buffer is too small because this does not include null - TestWithSize(userName.size()); + TestWithSize(expectedUsername.size()); TestInsufficientBuffer(); } TEST_F(GetUserNameTest, BufferSizeAsUserNameMinusOne) { // the buffer is also too small - TestWithSize(userName.size()-1); + TestWithSize(expectedUsername.size()-1); TestInsufficientBuffer(); } TEST_F(GetUserNameTest, BufferSizeAsUserNamePlusOne) { // the buffer is exactly big enough will null - TestWithSize(userName.size()+1); + TestWithSize(expectedUsername.size()+1); TestSuccess(); } From 0c9fb0d01b23b5ef68eea4cd93eb01d06a9b4ab6 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 23 Jul 2015 09:28:34 -0700 Subject: [PATCH 093/342] Rename userName in test to expectedUsername To clarify that it is for comparison; not the result of GetUserName. --- tests/test-getusername.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index 8e025a2de..4f249e118 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -10,9 +10,9 @@ protected: DWORD lpnSize; std::vector lpBuffer; BOOL result; - std::string userName; + std::string expectedUsername; - GetUserNameTest(): userName(std::string(getlogin())) {} + GetUserNameTest(): expectedUsername(std::string(getlogin())) {} void TestWithSize(DWORD size) { lpnSize = size; @@ -27,7 +27,7 @@ protected: EXPECT_EQ(1, result); // sets lpnSize to length of username + null - ASSERT_EQ(userName.size()+1, lpnSize); + ASSERT_EQ(expectedUsername.size()+1, lpnSize); // copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion unsigned char *begin = reinterpret_cast(&lpBuffer[0]); @@ -38,7 +38,7 @@ protected: std::string output; SCXCoreLib::Utf16leToUtf8(input, output); - EXPECT_EQ(userName, output); + EXPECT_EQ(expectedUsername, output); } void TestInvalidParameter() { @@ -62,7 +62,7 @@ protected: EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); // sets lpnSize to length of username + null - EXPECT_EQ(userName.size()+1, lpnSize); + EXPECT_EQ(expectedUsername.size()+1, lpnSize); } }; @@ -98,19 +98,19 @@ TEST_F(GetUserNameTest, BufferSizeAsOne) { TEST_F(GetUserNameTest, BufferSizeAsUserName) { // the buffer is too small because this does not include null - TestWithSize(userName.size()); + TestWithSize(expectedUsername.size()); TestInsufficientBuffer(); } TEST_F(GetUserNameTest, BufferSizeAsUserNameMinusOne) { // the buffer is also too small - TestWithSize(userName.size()-1); + TestWithSize(expectedUsername.size()-1); TestInsufficientBuffer(); } TEST_F(GetUserNameTest, BufferSizeAsUserNamePlusOne) { // the buffer is exactly big enough will null - TestWithSize(userName.size()+1); + TestWithSize(expectedUsername.size()+1); TestSuccess(); } From c97988180434ec0fc59d12b188fe96f19b6149f3 Mon Sep 17 00:00:00 2001 From: Aaron Date: Mon, 3 Aug 2015 13:54:07 -0700 Subject: [PATCH 094/342] added more error handling --- CMakeLists.txt | 5 +- impl/getcomputername.cpp | 89 +++++++++++++++++++++++++++++++++- impl/pal.h | 8 ++- tests/test-getcomputername.cpp | 8 +-- 4 files changed, 101 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 97b14a942..e25d43a83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(monad_native) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest -include_directories(../ext-src/gtest/fused-src impl) +include_directories(../ext-src/gtest/fused-src ../ext-src/pal/include impl) link_directories(${monad_native_BINARY_DIR}) # source file definitions @@ -18,6 +18,9 @@ SET(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp ${HOST_COMMON_SOURCE_FILES}) # target definitions add_library(ps SHARED ${LIB_SOURCE_FILES}) +add_library(scxcore STATIC IMPORTED GLOBAL) +set_property(TARGET scxcore PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../ext-src/pal/lib/libscxcore.a) +target_link_libraries(ps scxcore) add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp index 5946851b2..1d9894014 100644 --- a/impl/getcomputername.cpp +++ b/impl/getcomputername.cpp @@ -1,9 +1,28 @@ #include "getcomputername.h" -#include #include -#include #include +#include +#include +#include +#include +#include + +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx +// 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 +// +// Returns: +// 1 - succeeded +// 0 - failed BOOL GetComputerNameW(LPTSTR name, LPDWORD len) { const std::string utf8 = "UTF-8"; @@ -23,6 +42,71 @@ BOOL GetComputerNameW(LPTSTR name, LPDWORD len) return 0; } + // Get username from system in a thread-safe manner + std::string username(LOGIN_NAME_MAX, '\0'); + int err = gethostname(&username[0], username.size()); + // Map errno to Win32 Error Codes + if (err != 0) { + switch (errno) { + case EMFILE: + case ENFILE: + errno = ERROR_TOO_MANY_OPEN_FILES; + break; + case ENXIO: + errno = ERROR_NO_ASSOCIATION; + break; + case ERANGE: + errno = ERROR_INSUFFICIENT_BUFFER; + break; + case ENOENT: + errno = ERROR_NO_SUCH_USER; + break; + case ENOMEM: + errno = ERROR_OUTOFMEMORY; + break; + case ENOTTY: + errno = ERROR_NO_ASSOCIATION; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return 0; + } + + // "Trim" the username to the first trailing null because + // otherwise the std::string with repeated null characters is + // valid, and the conversion will still include all the null + // characters. Creating a std::string from the C string of the + // original effectively trims it to the first null, without + // the need to manually trim whitespace (nor using Boost). + username = std::string(username.c_str()); + + // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) + std::vector output; + SCXCoreLib::Utf8ToUtf16le(username, output); + + // The length is the number of characters in the string, which + // is half the string size because UTF-16 encodes two bytes + // per character, plus one for the trailing null. + const DWORD length = output.size()/2 + 1; + if (length > *len) { + errno = ERROR_INSUFFICIENT_BUFFER; + // Set lpnSize if buffer is too small to inform user + // of necessary size + *len= length; + return 0; + } + + // Add two null bytes (because it's UTF-16) + output.push_back('\0'); + output.push_back('\0'); + + memcpy(name, &output[0], output.size()); + *len = output.size()/2; + + return 1; + + /* size_t len2 = *len; int host = gethostname(name, len2); if(host == 0) @@ -34,5 +118,6 @@ BOOL GetComputerNameW(LPTSTR name, LPDWORD len) errno = ERROR_BUFFER_OVERFLOW; return FALSE; } + */ } diff --git a/impl/pal.h b/impl/pal.h index 196e0314a..38ff35934 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -73,8 +73,12 @@ #define FALSE 0 #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 - #define ERROR_BAD_ENVIRONMENT 10; - #define ERROR_BUFFER_OVERFLOW 111 + #define ERROR_BAD_ENVIRONMENT 0x0000000A + #define ERROR_TOO_MANY_OPEN_FILES 0x00000004 + #define ERROR_INSUFFICIENT_BUFFER 0x0000007A + #define ERROR_NO_ASSOCIATION 0x00000483 + #define ERROR_NO_SUCH_USER 0x00000525 + #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 typedef unsigned long long uint64; #endif diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index e76e88df4..0ca76c2c1 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -5,13 +5,13 @@ TEST(GetComputerName,simple) { char hostname[HOST_NAME_MAX]; - std::string hostnameFunctionTest(LOGIN_NAME_MAX, '\0');; + std::string hostnameFunctionTest(LOGIN_NAME_MAX, '\0'); DWORD hostSize = HOST_NAME_MAX; BOOL getComputerName = GetComputerNameW(&hostnameFunctionTest[0], &hostSize); BOOL host = gethostname(hostname, sizeof hostname); std::string hostnameString(hostname); - std::string hostnameStringTest(&hostnameFunctionTest[0]); + std::string hostnameStringTest(hostnameFunctionTest); ASSERT_TRUE(getComputerName == TRUE); ASSERT_EQ(host,0); @@ -20,9 +20,9 @@ TEST(GetComputerName,simple) TEST(GetComputerName,bufferttoosmall) { - std::string hostnameFunctionTest; + std::string hostnameFunctionTest(LOGIN_NAME_MAX, '\0'); DWORD hostSize = 0; BOOL getComputerName = GetComputerNameW(&hostnameFunctionTest[0], &hostSize); ASSERT_TRUE(getComputerName == 0); - EXPECT_EQ(errno, ERROR_BUFFER_OVERFLOW); +// EXPECT_EQ(errno, ERROR_BUFFER_OVERFLOW); } \ No newline at end of file From 245b2874435caa83a6b331cac5f17b1d05dc5c7e Mon Sep 17 00:00:00 2001 From: Aaron Date: Mon, 3 Aug 2015 13:54:07 -0700 Subject: [PATCH 095/342] added more error handling --- src/CMakeLists.txt | 5 +- src/impl/getcomputername.cpp | 89 +++++++++++++++++++++++++++++- src/impl/pal.h | 8 ++- src/tests/test-getcomputername.cpp | 8 +-- 4 files changed, 101 insertions(+), 9 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 97b14a942..e25d43a83 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ project(monad_native) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest -include_directories(../ext-src/gtest/fused-src impl) +include_directories(../ext-src/gtest/fused-src ../ext-src/pal/include impl) link_directories(${monad_native_BINARY_DIR}) # source file definitions @@ -18,6 +18,9 @@ SET(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp ${HOST_COMMON_SOURCE_FILES}) # target definitions add_library(ps SHARED ${LIB_SOURCE_FILES}) +add_library(scxcore STATIC IMPORTED GLOBAL) +set_property(TARGET scxcore PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../ext-src/pal/lib/libscxcore.a) +target_link_libraries(ps scxcore) add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp index 5946851b2..1d9894014 100644 --- a/src/impl/getcomputername.cpp +++ b/src/impl/getcomputername.cpp @@ -1,9 +1,28 @@ #include "getcomputername.h" -#include #include -#include #include +#include +#include +#include +#include +#include + +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx +// 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 +// +// Returns: +// 1 - succeeded +// 0 - failed BOOL GetComputerNameW(LPTSTR name, LPDWORD len) { const std::string utf8 = "UTF-8"; @@ -23,6 +42,71 @@ BOOL GetComputerNameW(LPTSTR name, LPDWORD len) return 0; } + // Get username from system in a thread-safe manner + std::string username(LOGIN_NAME_MAX, '\0'); + int err = gethostname(&username[0], username.size()); + // Map errno to Win32 Error Codes + if (err != 0) { + switch (errno) { + case EMFILE: + case ENFILE: + errno = ERROR_TOO_MANY_OPEN_FILES; + break; + case ENXIO: + errno = ERROR_NO_ASSOCIATION; + break; + case ERANGE: + errno = ERROR_INSUFFICIENT_BUFFER; + break; + case ENOENT: + errno = ERROR_NO_SUCH_USER; + break; + case ENOMEM: + errno = ERROR_OUTOFMEMORY; + break; + case ENOTTY: + errno = ERROR_NO_ASSOCIATION; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return 0; + } + + // "Trim" the username to the first trailing null because + // otherwise the std::string with repeated null characters is + // valid, and the conversion will still include all the null + // characters. Creating a std::string from the C string of the + // original effectively trims it to the first null, without + // the need to manually trim whitespace (nor using Boost). + username = std::string(username.c_str()); + + // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) + std::vector output; + SCXCoreLib::Utf8ToUtf16le(username, output); + + // The length is the number of characters in the string, which + // is half the string size because UTF-16 encodes two bytes + // per character, plus one for the trailing null. + const DWORD length = output.size()/2 + 1; + if (length > *len) { + errno = ERROR_INSUFFICIENT_BUFFER; + // Set lpnSize if buffer is too small to inform user + // of necessary size + *len= length; + return 0; + } + + // Add two null bytes (because it's UTF-16) + output.push_back('\0'); + output.push_back('\0'); + + memcpy(name, &output[0], output.size()); + *len = output.size()/2; + + return 1; + + /* size_t len2 = *len; int host = gethostname(name, len2); if(host == 0) @@ -34,5 +118,6 @@ BOOL GetComputerNameW(LPTSTR name, LPDWORD len) errno = ERROR_BUFFER_OVERFLOW; return FALSE; } + */ } diff --git a/src/impl/pal.h b/src/impl/pal.h index 196e0314a..38ff35934 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -73,8 +73,12 @@ #define FALSE 0 #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 - #define ERROR_BAD_ENVIRONMENT 10; - #define ERROR_BUFFER_OVERFLOW 111 + #define ERROR_BAD_ENVIRONMENT 0x0000000A + #define ERROR_TOO_MANY_OPEN_FILES 0x00000004 + #define ERROR_INSUFFICIENT_BUFFER 0x0000007A + #define ERROR_NO_ASSOCIATION 0x00000483 + #define ERROR_NO_SUCH_USER 0x00000525 + #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 typedef unsigned long long uint64; #endif diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp index e76e88df4..0ca76c2c1 100644 --- a/src/tests/test-getcomputername.cpp +++ b/src/tests/test-getcomputername.cpp @@ -5,13 +5,13 @@ TEST(GetComputerName,simple) { char hostname[HOST_NAME_MAX]; - std::string hostnameFunctionTest(LOGIN_NAME_MAX, '\0');; + std::string hostnameFunctionTest(LOGIN_NAME_MAX, '\0'); DWORD hostSize = HOST_NAME_MAX; BOOL getComputerName = GetComputerNameW(&hostnameFunctionTest[0], &hostSize); BOOL host = gethostname(hostname, sizeof hostname); std::string hostnameString(hostname); - std::string hostnameStringTest(&hostnameFunctionTest[0]); + std::string hostnameStringTest(hostnameFunctionTest); ASSERT_TRUE(getComputerName == TRUE); ASSERT_EQ(host,0); @@ -20,9 +20,9 @@ TEST(GetComputerName,simple) TEST(GetComputerName,bufferttoosmall) { - std::string hostnameFunctionTest; + std::string hostnameFunctionTest(LOGIN_NAME_MAX, '\0'); DWORD hostSize = 0; BOOL getComputerName = GetComputerNameW(&hostnameFunctionTest[0], &hostSize); ASSERT_TRUE(getComputerName == 0); - EXPECT_EQ(errno, ERROR_BUFFER_OVERFLOW); +// EXPECT_EQ(errno, ERROR_BUFFER_OVERFLOW); } \ No newline at end of file From 84d24589befa85bb12685678dba477444e3b6669 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 4 Aug 2015 13:53:44 -0700 Subject: [PATCH 096/342] Link ps against icu instead of scxcore Remove scxcore library from CMake --- src/CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 382bf3970..439546e2a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ project(monad_native) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest -include_directories(../ext-src/gtest/fused-src ../ext-src/pal/include impl) +include_directories(../ext-src/gtest/fused-src impl) link_directories(${monad_native_BINARY_DIR}) # source file definitions @@ -17,9 +17,7 @@ SET(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp ${HOST_COMMON_SOURCE_FILES}) # target definitions add_library(ps SHARED ${LIB_SOURCE_FILES}) -add_library(scxcore STATIC IMPORTED GLOBAL) -set_property(TARGET scxcore PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../ext-src/pal/lib/libscxcore.a) -target_link_libraries(ps scxcore) +target_link_libraries(ps icuuc) add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) From 6ddb39e33760e633aafabf8c7fa671ef53a54195 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 4 Aug 2015 13:53:44 -0700 Subject: [PATCH 097/342] Link ps against icu instead of scxcore Remove scxcore library from CMake --- CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 382bf3970..439546e2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(monad_native) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest -include_directories(../ext-src/gtest/fused-src ../ext-src/pal/include impl) +include_directories(../ext-src/gtest/fused-src impl) link_directories(${monad_native_BINARY_DIR}) # source file definitions @@ -17,9 +17,7 @@ SET(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp ${HOST_COMMON_SOURCE_FILES}) # target definitions add_library(ps SHARED ${LIB_SOURCE_FILES}) -add_library(scxcore STATIC IMPORTED GLOBAL) -set_property(TARGET scxcore PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../ext-src/pal/lib/libscxcore.a) -target_link_libraries(ps scxcore) +target_link_libraries(ps icuuc) add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) From 052ecc801d1360722d02eee4f6022b7c016baa2d Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 4 Aug 2015 13:58:44 -0700 Subject: [PATCH 098/342] Use icu for Unicode conversion and fix lpnSize A careful reading of the GetUserName documentation and Windows Data Types says that lpnSize is "the number of TCHARs copied to the buffer...including the terminating null character," and a TCHAR in this environment is a CHAR because we assume UNICODE is always defined for CoreCLR. A CHAR is a byte. So lpSize is number of bytes, not number of UTF-16 characters as we previously believed. --- src/impl/getusername.cpp | 112 +++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 39 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 2e1e1dd12..0314b0abe 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -4,24 +4,65 @@ #include #include #include -#include -#include +#include +#include +#include +#include -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx -// 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 -// -// Returns: -// 1 - succeeded -// 0 - failed +/* + GetUserName 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 CHAR 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 GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) { const std::string utf8 = "UTF-8"; @@ -73,36 +114,29 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) return 0; } - // "Trim" the username to the first trailing null because - // otherwise the std::string with repeated null characters is - // valid, and the conversion will still include all the null - // characters. Creating a std::string from the C string of the - // original effectively trims it to the first null, without - // the need to manually trim whitespace (nor using Boost). - username = std::string(username.c_str()); - // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) - std::vector output; - SCXCoreLib::Utf8ToUtf16le(username, output); + 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]), + (username16.size()-1)*sizeof(char16_t), + "UTF-16LE"); + // number of characters including null + username16.resize(targetSize/sizeof(char16_t)+1); - // The length is the number of characters in the string, which - // is half the string size because UTF-16 encodes two bytes - // per character, plus one for the trailing null. - const DWORD length = output.size()/2 + 1; - if (length > *lpnSize) { + // Size in bytes including null + const DWORD size = username16.length()*sizeof(char16_t); + if (size > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; // Set lpnSize if buffer is too small to inform user // of necessary size - *lpnSize = length; + *lpnSize = size; return 0; } - // Add two null bytes (because it's UTF-16) - output.push_back('\0'); - output.push_back('\0'); - - memcpy(lpBuffer, &output[0], output.size()); - *lpnSize = output.size()/2; + // Copy bytes from string to buffer + memcpy(lpBuffer, &username16[0], size); + *lpnSize = size; return 1; } From d60bfe03764102b5a3c8fbe81d374f00758eb406 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 4 Aug 2015 13:58:44 -0700 Subject: [PATCH 099/342] Use icu for Unicode conversion and fix lpnSize A careful reading of the GetUserName documentation and Windows Data Types says that lpnSize is "the number of TCHARs copied to the buffer...including the terminating null character," and a TCHAR in this environment is a CHAR because we assume UNICODE is always defined for CoreCLR. A CHAR is a byte. So lpSize is number of bytes, not number of UTF-16 characters as we previously believed. --- impl/getusername.cpp | 112 ++++++++++++++++++++++++++++--------------- 1 file changed, 73 insertions(+), 39 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 2e1e1dd12..0314b0abe 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -4,24 +4,65 @@ #include #include #include -#include -#include +#include +#include +#include +#include -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx -// 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 -// -// Returns: -// 1 - succeeded -// 0 - failed +/* + GetUserName 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 CHAR 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 GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) { const std::string utf8 = "UTF-8"; @@ -73,36 +114,29 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) return 0; } - // "Trim" the username to the first trailing null because - // otherwise the std::string with repeated null characters is - // valid, and the conversion will still include all the null - // characters. Creating a std::string from the C string of the - // original effectively trims it to the first null, without - // the need to manually trim whitespace (nor using Boost). - username = std::string(username.c_str()); - // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) - std::vector output; - SCXCoreLib::Utf8ToUtf16le(username, output); + 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]), + (username16.size()-1)*sizeof(char16_t), + "UTF-16LE"); + // number of characters including null + username16.resize(targetSize/sizeof(char16_t)+1); - // The length is the number of characters in the string, which - // is half the string size because UTF-16 encodes two bytes - // per character, plus one for the trailing null. - const DWORD length = output.size()/2 + 1; - if (length > *lpnSize) { + // Size in bytes including null + const DWORD size = username16.length()*sizeof(char16_t); + if (size > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; // Set lpnSize if buffer is too small to inform user // of necessary size - *lpnSize = length; + *lpnSize = size; return 0; } - // Add two null bytes (because it's UTF-16) - output.push_back('\0'); - output.push_back('\0'); - - memcpy(lpBuffer, &output[0], output.size()); - *lpnSize = output.size()/2; + // Copy bytes from string to buffer + memcpy(lpBuffer, &username16[0], size); + *lpnSize = size; return 1; } From b77b0a7e6c56c4e0af239f0f572469c4f5b62247 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 4 Aug 2015 14:02:34 -0700 Subject: [PATCH 100/342] Update GetUserName tests Note that these fail when run in a Docker container because a) the current container's locale is not completely set, and b) getlogin() returns null with ENOENT since /var/run/utmp is being mapped to the host, and thus denied access from within the container. The container needs the locale set and its own /run/utmp, see https://lists.linuxcontainers.org/pipermail/lxc-users/2011-July/002374.html --- src/tests/test-getusername.cpp | 69 ++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index 4f249e118..575aa8545 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -1,8 +1,10 @@ #include -#include #include #include -#include +#include +#include +#include +#include #include "getusername.h" class GetUserNameTest : public ::testing::Test { @@ -11,8 +13,11 @@ protected: std::vector lpBuffer; BOOL result; std::string expectedUsername; + DWORD expectedSize; - GetUserNameTest(): expectedUsername(std::string(getlogin())) {} + GetUserNameTest(): expectedUsername(std::string(getlogin())), + expectedSize((expectedUsername.length()+1)*sizeof(char16_t)) + {} void TestWithSize(DWORD size) { lpnSize = size; @@ -23,22 +28,28 @@ protected: void TestSuccess() { SCOPED_TRACE(""); + // returns 1 on success EXPECT_EQ(1, result); - // sets lpnSize to length of username + null - ASSERT_EQ(expectedUsername.size()+1, lpnSize); + // sets lpnSize to number of bytes including null, + // note that this is (length+1)*sizeof(char16_t) + ASSERT_EQ(expectedSize, lpnSize); - // copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion - unsigned char *begin = reinterpret_cast(&lpBuffer[0]); - // -1 to skip null; *2 because UTF-16 encodes two bytes per character - unsigned char *end = begin + (lpnSize-1)*2; - std::vector input(begin, end); - // convert to UTF-8 for comparison - std::string output; - SCXCoreLib::Utf16leToUtf8(input, output); + // setup for conversion from UTF-16LE + const char *begin = reinterpret_cast(&lpBuffer[0]); + icu::UnicodeString username16(begin, lpnSize, "UTF-16LE"); + // username16 length includes null and is number of characters + ASSERT_EQ(expectedUsername.length()+1, username16.length()); - EXPECT_EQ(expectedUsername, output); + // convert (minus null) to UTF-8 for comparison + std::string username(lpnSize/sizeof(char16_t)-1, 0); + ASSERT_EQ(expectedUsername.length(), username.length()); + int32_t targetSize = username16.extract(0, username.length(), + reinterpret_cast(&username[0]), + "UTF-8"); + + EXPECT_EQ(expectedUsername, username); } void TestInvalidParameter() { @@ -62,7 +73,7 @@ protected: EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); // sets lpnSize to length of username + null - EXPECT_EQ(expectedUsername.size()+1, lpnSize); + EXPECT_EQ(expectedSize, lpnSize); } }; @@ -96,21 +107,33 @@ TEST_F(GetUserNameTest, BufferSizeAsOne) { TestInsufficientBuffer(); } -TEST_F(GetUserNameTest, BufferSizeAsUserName) { - // the buffer is too small because this does not include null +TEST_F(GetUserNameTest, BufferSizeAsUsername) { + // the buffer is too small because this is a UTF-8 size TestWithSize(expectedUsername.size()); TestInsufficientBuffer(); } -TEST_F(GetUserNameTest, BufferSizeAsUserNameMinusOne) { - // the buffer is also too small - TestWithSize(expectedUsername.size()-1); +TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOne) { + // the buffer is still too small even with null + TestWithSize(expectedUsername.size()+1); TestInsufficientBuffer(); } -TEST_F(GetUserNameTest, BufferSizeAsUserNamePlusOne) { - // the buffer is exactly big enough will null - TestWithSize(expectedUsername.size()+1); +TEST_F(GetUserNameTest, BufferSizeAsUsernameInUTF16) { + // the buffer is still too small because it is missing null + TestWithSize(expectedUsername.size()*sizeof(char16_t)); + TestInsufficientBuffer(); +} + +TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOneInUTF16) { + // the buffer is exactly big enough + TestWithSize((expectedUsername.size()+1)*sizeof(char16_t)); + TestSuccess(); +} + +TEST_F(GetUserNameTest, BufferSizeAsExpectedSize) { + // expectedSize is the same as username.size()+1 in UTF16 + TestWithSize(expectedSize); TestSuccess(); } From e64c8961c935a4ffdd13dc82c97d3f074b6a219f Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 4 Aug 2015 14:02:34 -0700 Subject: [PATCH 101/342] Update GetUserName tests Note that these fail when run in a Docker container because a) the current container's locale is not completely set, and b) getlogin() returns null with ENOENT since /var/run/utmp is being mapped to the host, and thus denied access from within the container. The container needs the locale set and its own /run/utmp, see https://lists.linuxcontainers.org/pipermail/lxc-users/2011-July/002374.html --- tests/test-getusername.cpp | 69 +++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index 4f249e118..575aa8545 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -1,8 +1,10 @@ #include -#include #include #include -#include +#include +#include +#include +#include #include "getusername.h" class GetUserNameTest : public ::testing::Test { @@ -11,8 +13,11 @@ protected: std::vector lpBuffer; BOOL result; std::string expectedUsername; + DWORD expectedSize; - GetUserNameTest(): expectedUsername(std::string(getlogin())) {} + GetUserNameTest(): expectedUsername(std::string(getlogin())), + expectedSize((expectedUsername.length()+1)*sizeof(char16_t)) + {} void TestWithSize(DWORD size) { lpnSize = size; @@ -23,22 +28,28 @@ protected: void TestSuccess() { SCOPED_TRACE(""); + // returns 1 on success EXPECT_EQ(1, result); - // sets lpnSize to length of username + null - ASSERT_EQ(expectedUsername.size()+1, lpnSize); + // sets lpnSize to number of bytes including null, + // note that this is (length+1)*sizeof(char16_t) + ASSERT_EQ(expectedSize, lpnSize); - // copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion - unsigned char *begin = reinterpret_cast(&lpBuffer[0]); - // -1 to skip null; *2 because UTF-16 encodes two bytes per character - unsigned char *end = begin + (lpnSize-1)*2; - std::vector input(begin, end); - // convert to UTF-8 for comparison - std::string output; - SCXCoreLib::Utf16leToUtf8(input, output); + // setup for conversion from UTF-16LE + const char *begin = reinterpret_cast(&lpBuffer[0]); + icu::UnicodeString username16(begin, lpnSize, "UTF-16LE"); + // username16 length includes null and is number of characters + ASSERT_EQ(expectedUsername.length()+1, username16.length()); - EXPECT_EQ(expectedUsername, output); + // convert (minus null) to UTF-8 for comparison + std::string username(lpnSize/sizeof(char16_t)-1, 0); + ASSERT_EQ(expectedUsername.length(), username.length()); + int32_t targetSize = username16.extract(0, username.length(), + reinterpret_cast(&username[0]), + "UTF-8"); + + EXPECT_EQ(expectedUsername, username); } void TestInvalidParameter() { @@ -62,7 +73,7 @@ protected: EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); // sets lpnSize to length of username + null - EXPECT_EQ(expectedUsername.size()+1, lpnSize); + EXPECT_EQ(expectedSize, lpnSize); } }; @@ -96,21 +107,33 @@ TEST_F(GetUserNameTest, BufferSizeAsOne) { TestInsufficientBuffer(); } -TEST_F(GetUserNameTest, BufferSizeAsUserName) { - // the buffer is too small because this does not include null +TEST_F(GetUserNameTest, BufferSizeAsUsername) { + // the buffer is too small because this is a UTF-8 size TestWithSize(expectedUsername.size()); TestInsufficientBuffer(); } -TEST_F(GetUserNameTest, BufferSizeAsUserNameMinusOne) { - // the buffer is also too small - TestWithSize(expectedUsername.size()-1); +TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOne) { + // the buffer is still too small even with null + TestWithSize(expectedUsername.size()+1); TestInsufficientBuffer(); } -TEST_F(GetUserNameTest, BufferSizeAsUserNamePlusOne) { - // the buffer is exactly big enough will null - TestWithSize(expectedUsername.size()+1); +TEST_F(GetUserNameTest, BufferSizeAsUsernameInUTF16) { + // the buffer is still too small because it is missing null + TestWithSize(expectedUsername.size()*sizeof(char16_t)); + TestInsufficientBuffer(); +} + +TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOneInUTF16) { + // the buffer is exactly big enough + TestWithSize((expectedUsername.size()+1)*sizeof(char16_t)); + TestSuccess(); +} + +TEST_F(GetUserNameTest, BufferSizeAsExpectedSize) { + // expectedSize is the same as username.size()+1 in UTF16 + TestWithSize(expectedSize); TestSuccess(); } From 7d007d67084ef9a4bce364af05d36a31619066b0 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 4 Aug 2015 14:08:27 -0700 Subject: [PATCH 102/342] Remove PAL submodule --- .gitmodules | 3 --- ext-src/pal | 1 - 2 files changed, 4 deletions(-) delete mode 160000 ext-src/pal diff --git a/.gitmodules b/.gitmodules index d01dc9065..63ba77f86 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "ext-src/gtest"] path = ext-src/gtest url = https://msostc.visualstudio.com/DefaultCollection/PS/_git/ext-gtest -[submodule "ext-src/pal"] - path = ext-src/pal - url = https://msostc.visualstudio.com/DefaultCollection/PS/_git/ext-pal diff --git a/ext-src/pal b/ext-src/pal deleted file mode 160000 index 56765ad5b..000000000 --- a/ext-src/pal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 56765ad5b11e3b061b5af45b74519ce5eda99127 From 54618f1750a4567b5c66a23cfedaf76070b51dd4 Mon Sep 17 00:00:00 2001 From: Aaron Date: Tue, 4 Aug 2015 14:38:53 -0700 Subject: [PATCH 103/342] Made changes based off feedback from Peter. Also added more unit tests --- CMakeLists.txt | 2 +- impl/getcomputername.cpp | 56 ++++------------- impl/getcomputername.h | 2 +- impl/pal.h | 1 + tests/test-getcomputername.cpp | 107 +++++++++++++++++++++++++++------ 5 files changed, 103 insertions(+), 65 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e25d43a83..755b5c1db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(monad_native) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest -include_directories(../ext-src/gtest/fused-src ../ext-src/pal/include impl) +include_directories(../ext-src/gtest/fused-src impl) link_directories(${monad_native_BINARY_DIR}) # source file definitions diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp index 1d9894014..c403cfe6d 100644 --- a/impl/getcomputername.cpp +++ b/impl/getcomputername.cpp @@ -1,11 +1,9 @@ #include "getcomputername.h" #include #include -#include #include #include -#include -#include +#include // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx @@ -23,13 +21,13 @@ // Returns: // 1 - succeeded // 0 - failed -BOOL GetComputerNameW(LPTSTR name, LPDWORD len) +BOOL GetComputerNameW(LPTSTR nameOfComputer, LPDWORD len) { const std::string utf8 = "UTF-8"; errno = 0; // Check parameters - if (!name || !len) { + if (!nameOfComputer || !len) { errno = ERROR_INVALID_PARAMETER; return 0; } @@ -42,9 +40,9 @@ BOOL GetComputerNameW(LPTSTR name, LPDWORD len) return 0; } - // Get username from system in a thread-safe manner - std::string username(LOGIN_NAME_MAX, '\0'); - int err = gethostname(&username[0], username.size()); + // Get computername from system in a thread-safe manner + std::string computerName(HOST_MAX_NAME, '\0'); + int err = gethostname(&computerName[0], computerName.size()); // Map errno to Win32 Error Codes if (err != 0) { switch (errno) { @@ -67,28 +65,18 @@ BOOL GetComputerNameW(LPTSTR name, LPDWORD len) case ENOTTY: errno = ERROR_NO_ASSOCIATION; break; + errno = ERROR_NO_ASSOCIATION; default: errno = ERROR_INVALID_FUNCTION; } return 0; } - // "Trim" the username to the first trailing null because - // otherwise the std::string with repeated null characters is - // valid, and the conversion will still include all the null - // characters. Creating a std::string from the C string of the - // original effectively trims it to the first null, without - // the need to manually trim whitespace (nor using Boost). - username = std::string(username.c_str()); + //Resize the string to not inlcude extra buffer space + const DWORD length = computerName.find_first_of('\0') + 1; + computerName.resize(length); - // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) - std::vector output; - SCXCoreLib::Utf8ToUtf16le(username, output); - - // The length is the number of characters in the string, which - // is half the string size because UTF-16 encodes two bytes - // per character, plus one for the trailing null. - const DWORD length = output.size()/2 + 1; + //Check if parameters passed enough buffer space if (length > *len) { errno = ERROR_INSUFFICIENT_BUFFER; // Set lpnSize if buffer is too small to inform user @@ -97,27 +85,9 @@ BOOL GetComputerNameW(LPTSTR name, LPDWORD len) return 0; } - // Add two null bytes (because it's UTF-16) - output.push_back('\0'); - output.push_back('\0'); - - memcpy(name, &output[0], output.size()); - *len = output.size()/2; - + memcpy(nameOfComputer, &computerName[0], length); + *len = length; return 1; - /* - size_t len2 = *len; - int host = gethostname(name, len2); - if(host == 0) - { - return TRUE; - } - else - { - errno = ERROR_BUFFER_OVERFLOW; - return FALSE; - } - */ } diff --git a/impl/getcomputername.h b/impl/getcomputername.h index 3c83030df..5e0d5be2b 100644 --- a/impl/getcomputername.h +++ b/impl/getcomputername.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetComputerNameW(LPTSTR name, LPDWORD len); +BOOL GetComputerNameW(LPTSTR nameOfComputer, LPDWORD len); PAL_END_EXTERNC \ No newline at end of file diff --git a/impl/pal.h b/impl/pal.h index 38ff35934..1692f15df 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -80,6 +80,7 @@ #define ERROR_NO_SUCH_USER 0x00000525 #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 + #define HOST_MAX_NAME 256 typedef unsigned long long uint64; #endif diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index 0ca76c2c1..b91730553 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -2,27 +2,94 @@ #include "getcomputername.h" #include -TEST(GetComputerName,simple) -{ - char hostname[HOST_NAME_MAX]; - std::string hostnameFunctionTest(LOGIN_NAME_MAX, '\0'); - DWORD hostSize = HOST_NAME_MAX; - BOOL getComputerName = GetComputerNameW(&hostnameFunctionTest[0], &hostSize); - BOOL host = gethostname(hostname, sizeof hostname); +class GetComputerNameTest : public ::testing::Test { +protected: + DWORD lpnSize; + BOOL result; + std::string expectedComputerName; + std::string computerName; + + //Get expected result from using linux call + GetComputerNameTest(){ + char hostname[HOST_MAX_NAME]; + BOOL host = gethostname(hostname, sizeof hostname); + expectedComputerName = hostname; + } + + void TestWithSize(DWORD size) { + lpnSize = size; + // allocate a DWORD buffer to receive computername + computerName.assign(lpnSize, '\0'); + result = GetComputerNameW(&computerName[0], &lpnSize); + } + + void TestSuccess() { + SCOPED_TRACE(""); + // returns 1 on success + EXPECT_EQ(1, result); + //Resize to cut off '\0' + computerName.resize(expectedComputerName.length()); + ASSERT_EQ(expectedComputerName.size()+1, lpnSize); + EXPECT_EQ(computerName, expectedComputerName); + } + + void TestInvalidParameter() { + SCOPED_TRACE(""); + + // returns 0 on failure + EXPECT_EQ(0, result); + + // sets errno to ERROR_INVALID_PARAMETER when lpBuffer is null + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); + } + + void TestInsufficientBuffer() { + SCOPED_TRACE(""); + + // returns 0 on failure + EXPECT_EQ(0, result); + + // sets errno to ERROR_INSUFFICIENT_BUFFER + EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); + + // sets lpnSize to length of username + null + ASSERT_EQ(expectedComputerName.size()+1, lpnSize); + } +}; - std::string hostnameString(hostname); - std::string hostnameStringTest(hostnameFunctionTest); - - ASSERT_TRUE(getComputerName == TRUE); - ASSERT_EQ(host,0); - ASSERT_EQ(hostnameString,hostnameStringTest); +TEST_F(GetComputerNameTest, BufferAsNullButNotBufferSize) { + lpnSize = 1; + result = GetComputerNameW(NULL, &lpnSize); + TestInvalidParameter(); + // does not reset lpnSize + EXPECT_EQ(1, lpnSize); } -TEST(GetComputerName,bufferttoosmall) -{ - std::string hostnameFunctionTest(LOGIN_NAME_MAX, '\0'); - DWORD hostSize = 0; - BOOL getComputerName = GetComputerNameW(&hostnameFunctionTest[0], &hostSize); - ASSERT_TRUE(getComputerName == 0); -// EXPECT_EQ(errno, ERROR_BUFFER_OVERFLOW); +TEST_F(GetComputerNameTest, BufferSizeAsNullButNotBuffer) { + computerName.push_back('\0'); + result = GetComputerNameW(&computerName[0], NULL); + TestInvalidParameter(); +} + +TEST_F(GetComputerNameTest, BufferSizeAsZero) { + TestWithSize(0); + EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); +} + +TEST_F(GetComputerNameTest, BufferSizeAsUserNameMinusOne) { + // the buffer is also too small + TestWithSize(expectedComputerName.size()-1); + TestInsufficientBuffer(); +} + +TEST_F(GetComputerNameTest, BufferSizeAsUserNamePlusOne) { + // the buffer is exactly big enough + TestWithSize(expectedComputerName.size()+1); + TestSuccess(); +} + +TEST_F(GetComputerNameTest, BufferSizeAsLoginNameMax) { + // the buffer larger than needed + TestWithSize(HOST_MAX_NAME); + TestSuccess(); } \ No newline at end of file From 9ff9a882796ac63249dd27b71491db0ff5075404 Mon Sep 17 00:00:00 2001 From: Aaron Date: Tue, 4 Aug 2015 14:38:53 -0700 Subject: [PATCH 104/342] Made changes based off feedback from Peter. Also added more unit tests --- src/CMakeLists.txt | 2 +- src/impl/getcomputername.cpp | 56 ++++----------- src/impl/getcomputername.h | 2 +- src/impl/pal.h | 1 + src/tests/test-getcomputername.cpp | 107 +++++++++++++++++++++++------ 5 files changed, 103 insertions(+), 65 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e25d43a83..755b5c1db 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ project(monad_native) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #include gtest -include_directories(../ext-src/gtest/fused-src ../ext-src/pal/include impl) +include_directories(../ext-src/gtest/fused-src impl) link_directories(${monad_native_BINARY_DIR}) # source file definitions diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp index 1d9894014..c403cfe6d 100644 --- a/src/impl/getcomputername.cpp +++ b/src/impl/getcomputername.cpp @@ -1,11 +1,9 @@ #include "getcomputername.h" #include #include -#include #include #include -#include -#include +#include // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx @@ -23,13 +21,13 @@ // Returns: // 1 - succeeded // 0 - failed -BOOL GetComputerNameW(LPTSTR name, LPDWORD len) +BOOL GetComputerNameW(LPTSTR nameOfComputer, LPDWORD len) { const std::string utf8 = "UTF-8"; errno = 0; // Check parameters - if (!name || !len) { + if (!nameOfComputer || !len) { errno = ERROR_INVALID_PARAMETER; return 0; } @@ -42,9 +40,9 @@ BOOL GetComputerNameW(LPTSTR name, LPDWORD len) return 0; } - // Get username from system in a thread-safe manner - std::string username(LOGIN_NAME_MAX, '\0'); - int err = gethostname(&username[0], username.size()); + // Get computername from system in a thread-safe manner + std::string computerName(HOST_MAX_NAME, '\0'); + int err = gethostname(&computerName[0], computerName.size()); // Map errno to Win32 Error Codes if (err != 0) { switch (errno) { @@ -67,28 +65,18 @@ BOOL GetComputerNameW(LPTSTR name, LPDWORD len) case ENOTTY: errno = ERROR_NO_ASSOCIATION; break; + errno = ERROR_NO_ASSOCIATION; default: errno = ERROR_INVALID_FUNCTION; } return 0; } - // "Trim" the username to the first trailing null because - // otherwise the std::string with repeated null characters is - // valid, and the conversion will still include all the null - // characters. Creating a std::string from the C string of the - // original effectively trims it to the first null, without - // the need to manually trim whitespace (nor using Boost). - username = std::string(username.c_str()); + //Resize the string to not inlcude extra buffer space + const DWORD length = computerName.find_first_of('\0') + 1; + computerName.resize(length); - // Convert to char * to WCHAR_T * (UTF-8 to UTF-16 LE w/o BOM) - std::vector output; - SCXCoreLib::Utf8ToUtf16le(username, output); - - // The length is the number of characters in the string, which - // is half the string size because UTF-16 encodes two bytes - // per character, plus one for the trailing null. - const DWORD length = output.size()/2 + 1; + //Check if parameters passed enough buffer space if (length > *len) { errno = ERROR_INSUFFICIENT_BUFFER; // Set lpnSize if buffer is too small to inform user @@ -97,27 +85,9 @@ BOOL GetComputerNameW(LPTSTR name, LPDWORD len) return 0; } - // Add two null bytes (because it's UTF-16) - output.push_back('\0'); - output.push_back('\0'); - - memcpy(name, &output[0], output.size()); - *len = output.size()/2; - + memcpy(nameOfComputer, &computerName[0], length); + *len = length; return 1; - /* - size_t len2 = *len; - int host = gethostname(name, len2); - if(host == 0) - { - return TRUE; - } - else - { - errno = ERROR_BUFFER_OVERFLOW; - return FALSE; - } - */ } diff --git a/src/impl/getcomputername.h b/src/impl/getcomputername.h index 3c83030df..5e0d5be2b 100644 --- a/src/impl/getcomputername.h +++ b/src/impl/getcomputername.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetComputerNameW(LPTSTR name, LPDWORD len); +BOOL GetComputerNameW(LPTSTR nameOfComputer, LPDWORD len); PAL_END_EXTERNC \ No newline at end of file diff --git a/src/impl/pal.h b/src/impl/pal.h index 38ff35934..1692f15df 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -80,6 +80,7 @@ #define ERROR_NO_SUCH_USER 0x00000525 #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 + #define HOST_MAX_NAME 256 typedef unsigned long long uint64; #endif diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp index 0ca76c2c1..b91730553 100644 --- a/src/tests/test-getcomputername.cpp +++ b/src/tests/test-getcomputername.cpp @@ -2,27 +2,94 @@ #include "getcomputername.h" #include -TEST(GetComputerName,simple) -{ - char hostname[HOST_NAME_MAX]; - std::string hostnameFunctionTest(LOGIN_NAME_MAX, '\0'); - DWORD hostSize = HOST_NAME_MAX; - BOOL getComputerName = GetComputerNameW(&hostnameFunctionTest[0], &hostSize); - BOOL host = gethostname(hostname, sizeof hostname); +class GetComputerNameTest : public ::testing::Test { +protected: + DWORD lpnSize; + BOOL result; + std::string expectedComputerName; + std::string computerName; + + //Get expected result from using linux call + GetComputerNameTest(){ + char hostname[HOST_MAX_NAME]; + BOOL host = gethostname(hostname, sizeof hostname); + expectedComputerName = hostname; + } + + void TestWithSize(DWORD size) { + lpnSize = size; + // allocate a DWORD buffer to receive computername + computerName.assign(lpnSize, '\0'); + result = GetComputerNameW(&computerName[0], &lpnSize); + } + + void TestSuccess() { + SCOPED_TRACE(""); + // returns 1 on success + EXPECT_EQ(1, result); + //Resize to cut off '\0' + computerName.resize(expectedComputerName.length()); + ASSERT_EQ(expectedComputerName.size()+1, lpnSize); + EXPECT_EQ(computerName, expectedComputerName); + } + + void TestInvalidParameter() { + SCOPED_TRACE(""); + + // returns 0 on failure + EXPECT_EQ(0, result); + + // sets errno to ERROR_INVALID_PARAMETER when lpBuffer is null + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); + } + + void TestInsufficientBuffer() { + SCOPED_TRACE(""); + + // returns 0 on failure + EXPECT_EQ(0, result); + + // sets errno to ERROR_INSUFFICIENT_BUFFER + EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); + + // sets lpnSize to length of username + null + ASSERT_EQ(expectedComputerName.size()+1, lpnSize); + } +}; - std::string hostnameString(hostname); - std::string hostnameStringTest(hostnameFunctionTest); - - ASSERT_TRUE(getComputerName == TRUE); - ASSERT_EQ(host,0); - ASSERT_EQ(hostnameString,hostnameStringTest); +TEST_F(GetComputerNameTest, BufferAsNullButNotBufferSize) { + lpnSize = 1; + result = GetComputerNameW(NULL, &lpnSize); + TestInvalidParameter(); + // does not reset lpnSize + EXPECT_EQ(1, lpnSize); } -TEST(GetComputerName,bufferttoosmall) -{ - std::string hostnameFunctionTest(LOGIN_NAME_MAX, '\0'); - DWORD hostSize = 0; - BOOL getComputerName = GetComputerNameW(&hostnameFunctionTest[0], &hostSize); - ASSERT_TRUE(getComputerName == 0); -// EXPECT_EQ(errno, ERROR_BUFFER_OVERFLOW); +TEST_F(GetComputerNameTest, BufferSizeAsNullButNotBuffer) { + computerName.push_back('\0'); + result = GetComputerNameW(&computerName[0], NULL); + TestInvalidParameter(); +} + +TEST_F(GetComputerNameTest, BufferSizeAsZero) { + TestWithSize(0); + EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); +} + +TEST_F(GetComputerNameTest, BufferSizeAsUserNameMinusOne) { + // the buffer is also too small + TestWithSize(expectedComputerName.size()-1); + TestInsufficientBuffer(); +} + +TEST_F(GetComputerNameTest, BufferSizeAsUserNamePlusOne) { + // the buffer is exactly big enough + TestWithSize(expectedComputerName.size()+1); + TestSuccess(); +} + +TEST_F(GetComputerNameTest, BufferSizeAsLoginNameMax) { + // the buffer larger than needed + TestWithSize(HOST_MAX_NAME); + TestSuccess(); } \ No newline at end of file From 447896aede3dbea54ff3a3078565c149d6466de7 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 4 Aug 2015 18:27:29 -0700 Subject: [PATCH 105/342] Use WCHAR sizes instead of CHAR sizes Such that lpnSize is the length (number of UTF-16 characters, including null) of the username. Must be multiplied by sizeof(char16_t) for bytes. --- impl/getusername.cpp | 10 +++++----- tests/test-getusername.cpp | 36 ++++++++++++------------------------ 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 0314b0abe..e2bd4e837 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -32,7 +32,7 @@ in TCHARs. On output, the variable receives the number of TCHARs copied to the buffer, including the terminating null character. - Note that TCHAR is CHAR here because UNICODE is defined, and so a + 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 @@ -121,11 +121,11 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) reinterpret_cast(&username16[0]), (username16.size()-1)*sizeof(char16_t), "UTF-16LE"); - // number of characters including null + // Number of characters including null username16.resize(targetSize/sizeof(char16_t)+1); - // Size in bytes including null - const DWORD size = username16.length()*sizeof(char16_t); + // Size in WCHARs including null + const DWORD size = username16.length(); if (size > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; // Set lpnSize if buffer is too small to inform user @@ -135,7 +135,7 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) } // Copy bytes from string to buffer - memcpy(lpBuffer, &username16[0], size); + memcpy(lpBuffer, &username16[0], size*sizeof(char16_t)); *lpnSize = size; return 1; diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index 575aa8545..1aab90721 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -16,7 +17,7 @@ protected: DWORD expectedSize; GetUserNameTest(): expectedUsername(std::string(getlogin())), - expectedSize((expectedUsername.length()+1)*sizeof(char16_t)) + expectedSize(expectedUsername.length()+1) {} void TestWithSize(DWORD size) { @@ -32,22 +33,21 @@ protected: // returns 1 on success EXPECT_EQ(1, result); - // sets lpnSize to number of bytes including null, - // note that this is (length+1)*sizeof(char16_t) + // 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]); - icu::UnicodeString username16(begin, lpnSize, "UTF-16LE"); + // 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 - ASSERT_EQ(expectedUsername.length()+1, username16.length()); + ASSERT_EQ(expectedSize, username16.length()); // convert (minus null) to UTF-8 for comparison - std::string username(lpnSize/sizeof(char16_t)-1, 0); + 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"); + reinterpret_cast(&username[0]), "UTF-8"); EXPECT_EQ(expectedUsername, username); } @@ -109,30 +109,18 @@ TEST_F(GetUserNameTest, BufferSizeAsOne) { TEST_F(GetUserNameTest, BufferSizeAsUsername) { // the buffer is too small because this is a UTF-8 size - TestWithSize(expectedUsername.size()); + TestWithSize(expectedUsername.length()); TestInsufficientBuffer(); } TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOne) { - // the buffer is still too small even with null - TestWithSize(expectedUsername.size()+1); - TestInsufficientBuffer(); -} - -TEST_F(GetUserNameTest, BufferSizeAsUsernameInUTF16) { - // the buffer is still too small because it is missing null - TestWithSize(expectedUsername.size()*sizeof(char16_t)); - TestInsufficientBuffer(); -} - -TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOneInUTF16) { - // the buffer is exactly big enough - TestWithSize((expectedUsername.size()+1)*sizeof(char16_t)); + // includes null and so should be sufficient + TestWithSize(expectedUsername.length()+1); TestSuccess(); } TEST_F(GetUserNameTest, BufferSizeAsExpectedSize) { - // expectedSize is the same as username.size()+1 in UTF16 + // expectedSize is the same as username.size()+1 TestWithSize(expectedSize); TestSuccess(); } From 2ec0c2996f8048d5feb84e660af674bd5528ec2b Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 4 Aug 2015 18:27:29 -0700 Subject: [PATCH 106/342] Use WCHAR sizes instead of CHAR sizes Such that lpnSize is the length (number of UTF-16 characters, including null) of the username. Must be multiplied by sizeof(char16_t) for bytes. --- src/impl/getusername.cpp | 10 +++++----- src/tests/test-getusername.cpp | 36 ++++++++++++---------------------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 0314b0abe..e2bd4e837 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -32,7 +32,7 @@ in TCHARs. On output, the variable receives the number of TCHARs copied to the buffer, including the terminating null character. - Note that TCHAR is CHAR here because UNICODE is defined, and so a + 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 @@ -121,11 +121,11 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) reinterpret_cast(&username16[0]), (username16.size()-1)*sizeof(char16_t), "UTF-16LE"); - // number of characters including null + // Number of characters including null username16.resize(targetSize/sizeof(char16_t)+1); - // Size in bytes including null - const DWORD size = username16.length()*sizeof(char16_t); + // Size in WCHARs including null + const DWORD size = username16.length(); if (size > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; // Set lpnSize if buffer is too small to inform user @@ -135,7 +135,7 @@ BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) } // Copy bytes from string to buffer - memcpy(lpBuffer, &username16[0], size); + memcpy(lpBuffer, &username16[0], size*sizeof(char16_t)); *lpnSize = size; return 1; diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index 575aa8545..1aab90721 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -16,7 +17,7 @@ protected: DWORD expectedSize; GetUserNameTest(): expectedUsername(std::string(getlogin())), - expectedSize((expectedUsername.length()+1)*sizeof(char16_t)) + expectedSize(expectedUsername.length()+1) {} void TestWithSize(DWORD size) { @@ -32,22 +33,21 @@ protected: // returns 1 on success EXPECT_EQ(1, result); - // sets lpnSize to number of bytes including null, - // note that this is (length+1)*sizeof(char16_t) + // 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]); - icu::UnicodeString username16(begin, lpnSize, "UTF-16LE"); + // 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 - ASSERT_EQ(expectedUsername.length()+1, username16.length()); + ASSERT_EQ(expectedSize, username16.length()); // convert (minus null) to UTF-8 for comparison - std::string username(lpnSize/sizeof(char16_t)-1, 0); + 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"); + reinterpret_cast(&username[0]), "UTF-8"); EXPECT_EQ(expectedUsername, username); } @@ -109,30 +109,18 @@ TEST_F(GetUserNameTest, BufferSizeAsOne) { TEST_F(GetUserNameTest, BufferSizeAsUsername) { // the buffer is too small because this is a UTF-8 size - TestWithSize(expectedUsername.size()); + TestWithSize(expectedUsername.length()); TestInsufficientBuffer(); } TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOne) { - // the buffer is still too small even with null - TestWithSize(expectedUsername.size()+1); - TestInsufficientBuffer(); -} - -TEST_F(GetUserNameTest, BufferSizeAsUsernameInUTF16) { - // the buffer is still too small because it is missing null - TestWithSize(expectedUsername.size()*sizeof(char16_t)); - TestInsufficientBuffer(); -} - -TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOneInUTF16) { - // the buffer is exactly big enough - TestWithSize((expectedUsername.size()+1)*sizeof(char16_t)); + // includes null and so should be sufficient + TestWithSize(expectedUsername.length()+1); TestSuccess(); } TEST_F(GetUserNameTest, BufferSizeAsExpectedSize) { - // expectedSize is the same as username.size()+1 in UTF16 + // expectedSize is the same as username.size()+1 TestWithSize(expectedSize); TestSuccess(); } From 3aba128b6d9a0ce572a0dcd85b5cb0da3fdeb944 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 6 Aug 2015 10:16:13 -0700 Subject: [PATCH 107/342] Got rid of tests for UTF7, added error checking, adding test to check for null paramater for codepage --- src/CMakeLists.txt | 4 +-- src/impl/getcpinfo.cpp | 52 +++++++++++++++++++++++++----------- src/impl/getcpinfo.h | 2 +- src/impl/pal.h | 2 ++ src/tests/test-getcpinfo.cpp | 34 +++++++++++++---------- 5 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a5d27e7bf..9fce473e1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,10 +8,10 @@ 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) +set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.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 ${HOST_COMMON_SOURCE_FILES} ${HOST_COMMON_TEST_SOURCE_FILES}) +set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.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}) diff --git a/src/impl/getcpinfo.cpp b/src/impl/getcpinfo.cpp index 857b00de7..419c4c5f6 100644 --- a/src/impl/getcpinfo.cpp +++ b/src/impl/getcpinfo.cpp @@ -1,28 +1,50 @@ #include "getcpinfo.h" -#include +#include #include +#include -BOOL GetCPInfo(UINT codepage, CPINFO &cpinfo) + +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx +// Sets errno to: +// ERROR_INVALID_PARAMETER - parameter is not valid +// ERROR_BAD_ENVIRONMENT - locale is not UTF-8 +// +// Returns: +// TRUE - succeeded +// FALSE - failed + +BOOL GetCPInfoW(UINT codepage, CPINFO &cpinfo) { - std::string test; - switch(codepage) - { - case 65000: - cpinfo.DefaultChar[0] = '?'; - cpinfo.DefaultChar[1] = '0'; - cpinfo.LeadByte[0] = '0'; - cpinfo.LeadByte[1] = '0'; - cpinfo.MaxCharSize = 5; - return TRUE; - case 65001: + + const std::string utf8 = "UTF-8"; + errno = 0; + + //Check that codepage is not null + if(!codepage) { + errno = ERROR_INVALID_PARAMETER; + return FALSE; + } + + // Select locale from environment + setlocale(LC_ALL, ""); + // Check that locale is UTF-8 + if (nl_langinfo(CODESET) != utf8) { + errno = ERROR_BAD_ENVIRONMENT; + return 0; + } + + //if codepage is utf8 + if(codepage == 65001) { cpinfo.DefaultChar[0] = '?'; cpinfo.DefaultChar[1] = '0'; cpinfo.LeadByte[0] = '0'; cpinfo.LeadByte[1] = '0'; cpinfo.MaxCharSize = 4; return TRUE; - default: + } + else{ + errno = ERROR_INVALID_PARAMETER; return FALSE; - } + } } diff --git a/src/impl/getcpinfo.h b/src/impl/getcpinfo.h index 0e5d57462..e1b203bc1 100644 --- a/src/impl/getcpinfo.h +++ b/src/impl/getcpinfo.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetCPInfo(UINT codepage, CPINFO &cpinfo); +BOOL GetCPInfoW(UINT codepage, CPINFO &cpinfo); PAL_END_EXTERNC diff --git a/src/impl/pal.h b/src/impl/pal.h index 46ae8feb5..5d398c8b8 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -75,6 +75,8 @@ #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 #define MAX_PATH 0x00000104 + #define UTF8 65001 + #define ERROR_BAD_ENVIRONMENT 0x0000000A typedef unsigned long long uint64; #endif diff --git a/src/tests/test-getcpinfo.cpp b/src/tests/test-getcpinfo.cpp index 0a8d110e9..341c5279d 100644 --- a/src/tests/test-getcpinfo.cpp +++ b/src/tests/test-getcpinfo.cpp @@ -1,14 +1,14 @@ #include #include "getcpinfo.h" -// This is a very simple test case to show how tests can be written -TEST(GetCPInfo,utf8) +// This test is with correct parameters +TEST(GetCPInfo,Utf8) { CPINFO cpinfo; - BOOL utf8 = GetCPInfo(65001, cpinfo); + BOOL result = GetCPInfoW(UTF8, cpinfo); // first make sure that the function worked - ASSERT_TRUE(utf8 == TRUE); + ASSERT_TRUE(result == TRUE); // now compare the actual values ASSERT_EQ(cpinfo.DefaultChar[0],'?'); @@ -18,18 +18,24 @@ TEST(GetCPInfo,utf8) ASSERT_EQ(cpinfo.MaxCharSize,4); } -TEST(GetCPInfo,utf7) +// This test is with codepage being null +TEST(GetCPInfo, NullForCodePageUINTButNotCpinfo) { CPINFO cpinfo; - BOOL utf7 = GetCPInfo(65000, cpinfo); + BOOL result = GetCPInfoW(NULL, cpinfo); - // first make sure that the function worked - ASSERT_TRUE(utf7 == TRUE); + ASSERT_TRUE(result == FALSE); + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); + +} - // now compare the actual values - ASSERT_EQ(cpinfo.DefaultChar[0],'?'); - ASSERT_EQ(cpinfo.DefaultChar[1],'0'); - ASSERT_EQ(cpinfo.LeadByte[0],'0'); - ASSERT_EQ(cpinfo.LeadByte[1],'0'); - ASSERT_EQ(cpinfo.MaxCharSize,5); +// This test is with codepage not being utf8 +TEST(GetCPInfo, CodePageNotUTF8) +{ + CPINFO cpinfo; + BOOL result = GetCPInfoW(65000, cpinfo); + + ASSERT_TRUE(result == FALSE); + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); + } \ No newline at end of file From 316cabbdcf367d409eb2ab281be02ced3ea08e65 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 6 Aug 2015 10:16:13 -0700 Subject: [PATCH 108/342] Got rid of tests for UTF7, added error checking, adding test to check for null paramater for codepage --- CMakeLists.txt | 4 ++-- impl/getcpinfo.cpp | 52 ++++++++++++++++++++++++++++------------ impl/getcpinfo.h | 2 +- impl/pal.h | 2 ++ tests/test-getcpinfo.cpp | 34 +++++++++++++++----------- 5 files changed, 62 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a5d27e7bf..9fce473e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,10 +8,10 @@ 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) +set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.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 ${HOST_COMMON_SOURCE_FILES} ${HOST_COMMON_TEST_SOURCE_FILES}) +set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.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}) diff --git a/impl/getcpinfo.cpp b/impl/getcpinfo.cpp index 857b00de7..419c4c5f6 100644 --- a/impl/getcpinfo.cpp +++ b/impl/getcpinfo.cpp @@ -1,28 +1,50 @@ #include "getcpinfo.h" -#include +#include #include +#include -BOOL GetCPInfo(UINT codepage, CPINFO &cpinfo) + +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx +// Sets errno to: +// ERROR_INVALID_PARAMETER - parameter is not valid +// ERROR_BAD_ENVIRONMENT - locale is not UTF-8 +// +// Returns: +// TRUE - succeeded +// FALSE - failed + +BOOL GetCPInfoW(UINT codepage, CPINFO &cpinfo) { - std::string test; - switch(codepage) - { - case 65000: - cpinfo.DefaultChar[0] = '?'; - cpinfo.DefaultChar[1] = '0'; - cpinfo.LeadByte[0] = '0'; - cpinfo.LeadByte[1] = '0'; - cpinfo.MaxCharSize = 5; - return TRUE; - case 65001: + + const std::string utf8 = "UTF-8"; + errno = 0; + + //Check that codepage is not null + if(!codepage) { + errno = ERROR_INVALID_PARAMETER; + return FALSE; + } + + // Select locale from environment + setlocale(LC_ALL, ""); + // Check that locale is UTF-8 + if (nl_langinfo(CODESET) != utf8) { + errno = ERROR_BAD_ENVIRONMENT; + return 0; + } + + //if codepage is utf8 + if(codepage == 65001) { cpinfo.DefaultChar[0] = '?'; cpinfo.DefaultChar[1] = '0'; cpinfo.LeadByte[0] = '0'; cpinfo.LeadByte[1] = '0'; cpinfo.MaxCharSize = 4; return TRUE; - default: + } + else{ + errno = ERROR_INVALID_PARAMETER; return FALSE; - } + } } diff --git a/impl/getcpinfo.h b/impl/getcpinfo.h index 0e5d57462..e1b203bc1 100644 --- a/impl/getcpinfo.h +++ b/impl/getcpinfo.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetCPInfo(UINT codepage, CPINFO &cpinfo); +BOOL GetCPInfoW(UINT codepage, CPINFO &cpinfo); PAL_END_EXTERNC diff --git a/impl/pal.h b/impl/pal.h index 46ae8feb5..5d398c8b8 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -75,6 +75,8 @@ #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 #define MAX_PATH 0x00000104 + #define UTF8 65001 + #define ERROR_BAD_ENVIRONMENT 0x0000000A typedef unsigned long long uint64; #endif diff --git a/tests/test-getcpinfo.cpp b/tests/test-getcpinfo.cpp index 0a8d110e9..341c5279d 100644 --- a/tests/test-getcpinfo.cpp +++ b/tests/test-getcpinfo.cpp @@ -1,14 +1,14 @@ #include #include "getcpinfo.h" -// This is a very simple test case to show how tests can be written -TEST(GetCPInfo,utf8) +// This test is with correct parameters +TEST(GetCPInfo,Utf8) { CPINFO cpinfo; - BOOL utf8 = GetCPInfo(65001, cpinfo); + BOOL result = GetCPInfoW(UTF8, cpinfo); // first make sure that the function worked - ASSERT_TRUE(utf8 == TRUE); + ASSERT_TRUE(result == TRUE); // now compare the actual values ASSERT_EQ(cpinfo.DefaultChar[0],'?'); @@ -18,18 +18,24 @@ TEST(GetCPInfo,utf8) ASSERT_EQ(cpinfo.MaxCharSize,4); } -TEST(GetCPInfo,utf7) +// This test is with codepage being null +TEST(GetCPInfo, NullForCodePageUINTButNotCpinfo) { CPINFO cpinfo; - BOOL utf7 = GetCPInfo(65000, cpinfo); + BOOL result = GetCPInfoW(NULL, cpinfo); - // first make sure that the function worked - ASSERT_TRUE(utf7 == TRUE); + ASSERT_TRUE(result == FALSE); + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); + +} - // now compare the actual values - ASSERT_EQ(cpinfo.DefaultChar[0],'?'); - ASSERT_EQ(cpinfo.DefaultChar[1],'0'); - ASSERT_EQ(cpinfo.LeadByte[0],'0'); - ASSERT_EQ(cpinfo.LeadByte[1],'0'); - ASSERT_EQ(cpinfo.MaxCharSize,5); +// This test is with codepage not being utf8 +TEST(GetCPInfo, CodePageNotUTF8) +{ + CPINFO cpinfo; + BOOL result = GetCPInfoW(65000, cpinfo); + + ASSERT_TRUE(result == FALSE); + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); + } \ No newline at end of file From b379fb4a6b8f9d56d4fa0f7fbe4f7673fe3f53d7 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 6 Aug 2015 16:28:29 -0700 Subject: [PATCH 109/342] Rename to GetUserNameW since it is Unicode --- impl/getusername.cpp | 4 ++-- impl/getusername.h | 2 +- tests/test-getusername.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index e2bd4e837..ba6f64ad8 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -10,7 +10,7 @@ #include /* - GetUserName function + GetUserNameW function https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx @@ -63,7 +63,7 @@ If the function fails, the return value is zero. To get extended error information, call GetLastError. */ -BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) +BOOL GetUserNameW(WCHAR_T *lpBuffer, LPDWORD lpnSize) { const std::string utf8 = "UTF-8"; diff --git a/impl/getusername.h b/impl/getusername.h index 50c6b1d5c..ad6099c4b 100644 --- a/impl/getusername.h +++ b/impl/getusername.h @@ -6,6 +6,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 GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize); +BOOL GetUserNameW(WCHAR_T *lpBuffer, LPDWORD lpnSize); PAL_END_EXTERNC diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index 1aab90721..5a6a8535c 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -24,7 +24,7 @@ protected: lpnSize = size; // allocate a WCHAR_T buffer to receive username lpBuffer.assign(lpnSize, '\0'); - result = GetUserName(&lpBuffer[0], &lpnSize); + result = GetUserNameW(&lpBuffer[0], &lpnSize); } void TestSuccess() { @@ -79,7 +79,7 @@ protected: TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) { lpnSize = 1; - result = GetUserName(NULL, &lpnSize); + result = GetUserNameW(NULL, &lpnSize); TestInvalidParameter(); // does not reset lpnSize @@ -88,7 +88,7 @@ TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) { TEST_F(GetUserNameTest, BufferSizeAsNullButNotBuffer) { lpBuffer.push_back('\0'); - result = GetUserName(&lpBuffer[0], NULL); + result = GetUserNameW(&lpBuffer[0], NULL); TestInvalidParameter(); } From afab62205adba68538fdef3dbdef5f57ec3c6c26 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 6 Aug 2015 16:28:29 -0700 Subject: [PATCH 110/342] Rename to GetUserNameW since it is Unicode --- src/impl/getusername.cpp | 4 ++-- src/impl/getusername.h | 2 +- src/tests/test-getusername.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index e2bd4e837..ba6f64ad8 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -10,7 +10,7 @@ #include /* - GetUserName function + GetUserNameW function https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx @@ -63,7 +63,7 @@ If the function fails, the return value is zero. To get extended error information, call GetLastError. */ -BOOL GetUserName(WCHAR_T *lpBuffer, LPDWORD lpnSize) +BOOL GetUserNameW(WCHAR_T *lpBuffer, LPDWORD lpnSize) { const std::string utf8 = "UTF-8"; diff --git a/src/impl/getusername.h b/src/impl/getusername.h index 50c6b1d5c..ad6099c4b 100644 --- a/src/impl/getusername.h +++ b/src/impl/getusername.h @@ -6,6 +6,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 GetUserName(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 1aab90721..5a6a8535c 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -24,7 +24,7 @@ protected: lpnSize = size; // allocate a WCHAR_T buffer to receive username lpBuffer.assign(lpnSize, '\0'); - result = GetUserName(&lpBuffer[0], &lpnSize); + result = GetUserNameW(&lpBuffer[0], &lpnSize); } void TestSuccess() { @@ -79,7 +79,7 @@ protected: TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) { lpnSize = 1; - result = GetUserName(NULL, &lpnSize); + result = GetUserNameW(NULL, &lpnSize); TestInvalidParameter(); // does not reset lpnSize @@ -88,7 +88,7 @@ TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) { TEST_F(GetUserNameTest, BufferSizeAsNullButNotBuffer) { lpBuffer.push_back('\0'); - result = GetUserName(&lpBuffer[0], NULL); + result = GetUserNameW(&lpBuffer[0], NULL); TestInvalidParameter(); } From c8f977748123ad360b0917262099d8db896e2d98 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 6 Aug 2015 17:03:53 -0700 Subject: [PATCH 111/342] Clean up CMakeLists --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 439546e2a..1e6cafdbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,17 +13,17 @@ 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-getusername.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}) +set(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp ${HOST_COMMON_SOURCE_FILES}) # target definitions add_library(ps SHARED ${LIB_SOURCE_FILES}) -target_link_libraries(ps icuuc) add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) # add pthread and other libs find_package(Threads) +target_link_libraries(ps icuuc) target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) target_link_libraries(host_cmdline dl icuuc) From 1b18bfd5e13e274a389a7b867a0476c8dbfdda02 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 6 Aug 2015 17:03:53 -0700 Subject: [PATCH 112/342] Clean up CMakeLists --- src/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 439546e2a..1e6cafdbd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,17 +13,17 @@ 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-getusername.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}) +set(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp ${HOST_COMMON_SOURCE_FILES}) # target definitions add_library(ps SHARED ${LIB_SOURCE_FILES}) -target_link_libraries(ps icuuc) add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) # add pthread and other libs find_package(Threads) +target_link_libraries(ps icuuc) target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) target_link_libraries(host_cmdline dl icuuc) From f8e9dfde8cabd1826b664f5ac71b66caf881f374 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 6 Aug 2015 17:06:04 -0700 Subject: [PATCH 113/342] Fix style issues - Use Doxygen style comments (with better comments) - Use `type* ident` instead of `type *ident` - Start { on new lines - Use TRUE/FALSE from PAL.H --- impl/getusername.cpp | 127 ++++++++++++++++++------------------- impl/getusername.h | 4 +- tests/test-getusername.cpp | 84 +++++++++++++++--------- 3 files changed, 119 insertions(+), 96 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index ba6f64ad8..eb35137bd 100644 --- a/impl/getusername.cpp +++ b/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/impl/getusername.h b/impl/getusername.h index ad6099c4b..6083078bc 100644 --- a/impl/getusername.h +++ b/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/tests/test-getusername.cpp b/tests/test-getusername.cpp index 5a6a8535c..d00acdf30 100644 --- a/tests/test-getusername.cpp +++ b/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(); } From 062eb5a7b4e8be20bbde962239abfc6843d10076 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 6 Aug 2015 17:06:04 -0700 Subject: [PATCH 114/342] Fix style issues - Use Doxygen style comments (with better comments) - Use `type* ident` instead of `type *ident` - Start { on new lines - Use TRUE/FALSE from PAL.H --- src/impl/getusername.cpp | 127 ++++++++++++++++----------------- src/impl/getusername.h | 4 +- src/tests/test-getusername.cpp | 84 ++++++++++++++-------- 3 files changed, 119 insertions(+), 96 deletions(-) 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(); } From 665f8f1e87439d8045f1ca8b5f325b3d990acd05 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 7 Aug 2015 12:05:07 -0700 Subject: [PATCH 115/342] Map getlogin_r()'s ERANGE to ERROR_GEN_FAILURE ERROR_INSUFFICIENT_BUFFER should never occur here and would be a misleading error for the user. --- impl/getusername.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index eb35137bd..0ca96e5a9 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -96,7 +96,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) errno = ERROR_NO_ASSOCIATION; break; case ERANGE: - errno = ERROR_INSUFFICIENT_BUFFER; + errno = ERROR_GEN_FAILURE; break; case ENOENT: errno = ERROR_NO_SUCH_USER; From 467fdeeb0ce1ceb5ca46f956ea0c673c5ec3d026 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 7 Aug 2015 12:05:07 -0700 Subject: [PATCH 116/342] Map getlogin_r()'s ERANGE to ERROR_GEN_FAILURE ERROR_INSUFFICIENT_BUFFER should never occur here and would be a misleading error for the user. --- src/impl/getusername.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index eb35137bd..0ca96e5a9 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -96,7 +96,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) errno = ERROR_NO_ASSOCIATION; break; case ERANGE: - errno = ERROR_INSUFFICIENT_BUFFER; + errno = ERROR_GEN_FAILURE; break; case ENOENT: errno = ERROR_NO_SUCH_USER; From da1e65cfaff8f709f9470c5ee646b0b99af2d9fd Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 7 Aug 2015 12:07:19 -0700 Subject: [PATCH 117/342] Add -Wall to CMAKE_CXX_FLAGS --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e6cafdbd..ae57dc376 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.8.4) project(monad_native) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") #include gtest include_directories(../ext-src/gtest/fused-src impl) From f35efda7e782f7904d5ce4c0439058ac2b283d3c Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 7 Aug 2015 12:07:19 -0700 Subject: [PATCH 118/342] Add -Wall to CMAKE_CXX_FLAGS --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1e6cafdbd..ae57dc376 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.8.4) project(monad_native) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") #include gtest include_directories(../ext-src/gtest/fused-src impl) From 9a42b894f286cb0a77d5ae3478ed63cdba13fa09 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 7 Aug 2015 18:43:58 -0700 Subject: [PATCH 119/342] Convert to Allman style with 4-space indentation --- impl/getusername.cpp | 137 ++++++++++++++-------------- tests/test-getusername.cpp | 181 +++++++++++++++++++------------------ 2 files changed, 162 insertions(+), 156 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 0ca96e5a9..5d0bec036 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -64,78 +64,83 @@ //! [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"; + const std::string utf8 = "UTF-8"; - errno = FALSE; + errno = FALSE; - // Check parameters - if (!lpBuffer || !lpnSize) { - errno = ERROR_INVALID_PARAMETER; - return 0; - } + // Check parameters + if (!lpBuffer || !lpnSize) + { + errno = ERROR_INVALID_PARAMETER; + return 0; + } - // Select locale from environment - setlocale(LC_ALL, ""); - // Check that locale is UTF-8 - if (nl_langinfo(CODESET) != utf8) { - errno = ERROR_BAD_ENVIRONMENT; - return FALSE; - } + // Select locale from environment + setlocale(LC_ALL, ""); + // Check that locale is UTF-8 + if (nl_langinfo(CODESET) != utf8) + { + errno = ERROR_BAD_ENVIRONMENT; + return FALSE; + } - // Get username from system in a thread-safe manner - std::string username(LOGIN_NAME_MAX, '\0'); - int ret = getlogin_r(&username[0], username.size()); - // Map errno to Win32 Error Codes - if (ret) { - switch (errno) { - case EMFILE: - case ENFILE: - errno = ERROR_TOO_MANY_OPEN_FILES; - break; - case ENXIO: - errno = ERROR_NO_ASSOCIATION; - break; - case ERANGE: - errno = ERROR_GEN_FAILURE; - break; - case ENOENT: - errno = ERROR_NO_SUCH_USER; - break; - case ENOMEM: - errno = ERROR_OUTOFMEMORY; - break; - case ENOTTY: - errno = ERROR_NO_ASSOCIATION; - break; - default: - errno = ERROR_INVALID_FUNCTION; - } - return FALSE; - } + // Get username from system in a thread-safe manner + std::string username(LOGIN_NAME_MAX, '\0'); + int ret = getlogin_r(&username[0], username.size()); + // Map errno to Win32 Error Codes + if (ret) + { + switch (errno) + { + case EMFILE: + case ENFILE: + errno = ERROR_TOO_MANY_OPEN_FILES; + break; + case ENXIO: + errno = ERROR_NO_ASSOCIATION; + break; + case ERANGE: + errno = ERROR_GEN_FAILURE; + break; + case ENOENT: + errno = ERROR_NO_SUCH_USER; + break; + case ENOMEM: + errno = ERROR_OUTOFMEMORY; + break; + case ENOTTY: + errno = ERROR_NO_ASSOCIATION; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return FALSE; + } - // 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]), - (username16.size()-1)*sizeof(char16_t), - "UTF-16LE"); - // Number of characters including null - username16.resize(targetSize/sizeof(char16_t)+1); + // 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]), + (username16.size()-1)*sizeof(char16_t), + "UTF-16LE"); + // Number of characters including null + username16.resize(targetSize/sizeof(char16_t)+1); - // Size in WCHARs including null - const DWORD size = username16.length(); - if (size > *lpnSize) { - errno = ERROR_INSUFFICIENT_BUFFER; - // Set lpnSize if buffer is too small to inform user - // of necessary size - *lpnSize = size; - return 0; - } + // Size in WCHARs including null + const DWORD size = username16.length(); + if (size > *lpnSize) + { + errno = ERROR_INSUFFICIENT_BUFFER; + // Set lpnSize if buffer is too small to inform user + // of necessary size + *lpnSize = size; + return 0; + } - // Copy bytes from string to buffer - memcpy(lpBuffer, &username16[0], size*sizeof(char16_t)); - *lpnSize = size; + // Copy bytes from string to buffer + memcpy(lpBuffer, &username16[0], size*sizeof(char16_t)); + *lpnSize = size; - return TRUE; + return TRUE; } diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index d00acdf30..e27aeef28 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -16,143 +16,144 @@ class GetUserNameTest : public ::testing::Test { protected: - DWORD lpnSize; - std::vector lpBuffer; - BOOL result; - std::string expectedUsername; - DWORD expectedSize; + DWORD lpnSize; + std::vector lpBuffer; + BOOL result; + std::string expectedUsername; + DWORD expectedSize; - GetUserNameTest(): expectedUsername(std::string(getlogin())), - expectedSize(expectedUsername.length()+1) - {} + GetUserNameTest(): expectedUsername(std::string(getlogin())), + expectedSize(expectedUsername.length()+1) + { + } - //! 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); - } + //! 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); + } - //! Checks the effects of GetUserNameW for success. - void TestSuccess() - { - SCOPED_TRACE(""); + //! Checks the effects of GetUserNameW for success. + void TestSuccess() + { + SCOPED_TRACE(""); - //! Returns TRUE on success. - EXPECT_EQ(TRUE, result); + //! Returns TRUE on success. + EXPECT_EQ(TRUE, result); - //! Sets lpnSize to number of WCHARs including null. - ASSERT_EQ(expectedSize, lpnSize); + //! 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]); - // 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 - ASSERT_EQ(expectedSize, username16.length()); + // setup for conversion from UTF-16LE + 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 + ASSERT_EQ(expectedSize, username16.length()); - // convert (minus null) to UTF-8 for comparison - std::string username(lpnSize-1, 0); - ASSERT_EQ(expectedUsername.length(), username.length()); - username16.extract(0, username.length(), - reinterpret_cast(&username[0]), "UTF-8"); + // convert (minus null) to UTF-8 for comparison + std::string username(lpnSize-1, 0); + ASSERT_EQ(expectedUsername.length(), username.length()); + username16.extract(0, username.length(), + reinterpret_cast(&username[0]), "UTF-8"); - //! Returned username (after conversion) is what was expected. - EXPECT_EQ(expectedUsername, username); - } + //! Returned username (after conversion) is what was expected. + EXPECT_EQ(expectedUsername, username); + } - //! Checks the effects of GetUserNameW on failure with invalid parameters. - void TestInvalidParameter() - { - SCOPED_TRACE(""); + //! Checks the effects of GetUserNameW on failure with invalid parameters. + void TestInvalidParameter() + { + SCOPED_TRACE(""); - //! Returns FALSE on failure. - EXPECT_EQ(FALSE, 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). - EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); - } + //! Sets errno to ERROR_INVALID_PARAMETER when lpBuffer is null + //! (which is the case for an empty vector). + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); + } - //! Checks the effects of GetUserNameW on failure with a buffer that is too small. - void TestInsufficientBuffer() - { - SCOPED_TRACE(""); + //! Checks the effects of GetUserNameW on failure with a buffer that is too small. + void TestInsufficientBuffer() + { + SCOPED_TRACE(""); - //! Returns FALSE on failure. - EXPECT_EQ(FALSE, result); + //! Returns FALSE on failure. + EXPECT_EQ(FALSE, result); - //! Sets errno to ERROR_INSUFFICIENT_BUFFER. - EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); + //! Sets errno to ERROR_INSUFFICIENT_BUFFER. + EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); - //! Sets lpnSize to length of username plus null. - EXPECT_EQ(expectedSize, lpnSize); - } + //! Sets lpnSize to length of username plus null. + EXPECT_EQ(expectedSize, lpnSize); + } }; TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) { - lpnSize = 1; - result = GetUserNameW(NULL, &lpnSize); + lpnSize = 1; + result = GetUserNameW(NULL, &lpnSize); - TestInvalidParameter(); - // does not reset lpnSize - EXPECT_EQ(1, lpnSize); + TestInvalidParameter(); + // does not reset lpnSize + EXPECT_EQ(1, lpnSize); } TEST_F(GetUserNameTest, BufferSizeAsNullButNotBuffer) { - lpBuffer.push_back('\0'); - result = GetUserNameW(&lpBuffer[0], NULL); + lpBuffer.push_back('\0'); + result = GetUserNameW(&lpBuffer[0], NULL); - TestInvalidParameter(); + TestInvalidParameter(); } TEST_F(GetUserNameTest, BufferSizeAsZero) { - TestWithSize(0); - TestInvalidParameter(); - // does not reset lpnSize - EXPECT_EQ(0, lpnSize); + TestWithSize(0); + TestInvalidParameter(); + // does not reset lpnSize + EXPECT_EQ(0, lpnSize); } TEST_F(GetUserNameTest, BufferSizeAsOne) { - // theoretically this should never fail because any non-empty - // username length will be >1 with trailing null - TestWithSize(1); - TestInsufficientBuffer(); + // 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 it does not account for null - TestWithSize(expectedUsername.length()); - TestInsufficientBuffer(); + // the buffer is too small because it does not account for null + TestWithSize(expectedUsername.length()); + TestInsufficientBuffer(); } TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOne) { - // includes null and so should be sufficient - TestWithSize(expectedUsername.length()+1); - TestSuccess(); + // includes null and so should be sufficient + TestWithSize(expectedUsername.length()+1); + TestSuccess(); } TEST_F(GetUserNameTest, BufferSizeAsExpectedSize) { - // expectedSize is the same as username.size()+1 - TestWithSize(expectedSize); - TestSuccess(); + // expectedSize is the same as username.size()+1 + TestWithSize(expectedSize); + TestSuccess(); } TEST_F(GetUserNameTest, BufferSizeAsLoginNameMax) { - // LoginNameMax is big enough to hold any username, including null - TestWithSize(LOGIN_NAME_MAX); - TestSuccess(); + // LoginNameMax is big enough to hold any username, including null + TestWithSize(LOGIN_NAME_MAX); + TestSuccess(); } From a99c56eea3264b8c492bc0edf5e3a65102397af9 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 7 Aug 2015 18:43:58 -0700 Subject: [PATCH 120/342] Convert to Allman style with 4-space indentation --- src/impl/getusername.cpp | 137 +++++++++++++------------ src/tests/test-getusername.cpp | 181 +++++++++++++++++---------------- 2 files changed, 162 insertions(+), 156 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 0ca96e5a9..5d0bec036 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -64,78 +64,83 @@ //! [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"; + const std::string utf8 = "UTF-8"; - errno = FALSE; + errno = FALSE; - // Check parameters - if (!lpBuffer || !lpnSize) { - errno = ERROR_INVALID_PARAMETER; - return 0; - } + // Check parameters + if (!lpBuffer || !lpnSize) + { + errno = ERROR_INVALID_PARAMETER; + return 0; + } - // Select locale from environment - setlocale(LC_ALL, ""); - // Check that locale is UTF-8 - if (nl_langinfo(CODESET) != utf8) { - errno = ERROR_BAD_ENVIRONMENT; - return FALSE; - } + // Select locale from environment + setlocale(LC_ALL, ""); + // Check that locale is UTF-8 + if (nl_langinfo(CODESET) != utf8) + { + errno = ERROR_BAD_ENVIRONMENT; + return FALSE; + } - // Get username from system in a thread-safe manner - std::string username(LOGIN_NAME_MAX, '\0'); - int ret = getlogin_r(&username[0], username.size()); - // Map errno to Win32 Error Codes - if (ret) { - switch (errno) { - case EMFILE: - case ENFILE: - errno = ERROR_TOO_MANY_OPEN_FILES; - break; - case ENXIO: - errno = ERROR_NO_ASSOCIATION; - break; - case ERANGE: - errno = ERROR_GEN_FAILURE; - break; - case ENOENT: - errno = ERROR_NO_SUCH_USER; - break; - case ENOMEM: - errno = ERROR_OUTOFMEMORY; - break; - case ENOTTY: - errno = ERROR_NO_ASSOCIATION; - break; - default: - errno = ERROR_INVALID_FUNCTION; - } - return FALSE; - } + // Get username from system in a thread-safe manner + std::string username(LOGIN_NAME_MAX, '\0'); + int ret = getlogin_r(&username[0], username.size()); + // Map errno to Win32 Error Codes + if (ret) + { + switch (errno) + { + case EMFILE: + case ENFILE: + errno = ERROR_TOO_MANY_OPEN_FILES; + break; + case ENXIO: + errno = ERROR_NO_ASSOCIATION; + break; + case ERANGE: + errno = ERROR_GEN_FAILURE; + break; + case ENOENT: + errno = ERROR_NO_SUCH_USER; + break; + case ENOMEM: + errno = ERROR_OUTOFMEMORY; + break; + case ENOTTY: + errno = ERROR_NO_ASSOCIATION; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return FALSE; + } - // 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]), - (username16.size()-1)*sizeof(char16_t), - "UTF-16LE"); - // Number of characters including null - username16.resize(targetSize/sizeof(char16_t)+1); + // 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]), + (username16.size()-1)*sizeof(char16_t), + "UTF-16LE"); + // Number of characters including null + username16.resize(targetSize/sizeof(char16_t)+1); - // Size in WCHARs including null - const DWORD size = username16.length(); - if (size > *lpnSize) { - errno = ERROR_INSUFFICIENT_BUFFER; - // Set lpnSize if buffer is too small to inform user - // of necessary size - *lpnSize = size; - return 0; - } + // Size in WCHARs including null + const DWORD size = username16.length(); + if (size > *lpnSize) + { + errno = ERROR_INSUFFICIENT_BUFFER; + // Set lpnSize if buffer is too small to inform user + // of necessary size + *lpnSize = size; + return 0; + } - // Copy bytes from string to buffer - memcpy(lpBuffer, &username16[0], size*sizeof(char16_t)); - *lpnSize = size; + // Copy bytes from string to buffer + memcpy(lpBuffer, &username16[0], size*sizeof(char16_t)); + *lpnSize = size; - return TRUE; + return TRUE; } diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index d00acdf30..e27aeef28 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -16,143 +16,144 @@ class GetUserNameTest : public ::testing::Test { protected: - DWORD lpnSize; - std::vector lpBuffer; - BOOL result; - std::string expectedUsername; - DWORD expectedSize; + DWORD lpnSize; + std::vector lpBuffer; + BOOL result; + std::string expectedUsername; + DWORD expectedSize; - GetUserNameTest(): expectedUsername(std::string(getlogin())), - expectedSize(expectedUsername.length()+1) - {} + GetUserNameTest(): expectedUsername(std::string(getlogin())), + expectedSize(expectedUsername.length()+1) + { + } - //! 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); - } + //! 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); + } - //! Checks the effects of GetUserNameW for success. - void TestSuccess() - { - SCOPED_TRACE(""); + //! Checks the effects of GetUserNameW for success. + void TestSuccess() + { + SCOPED_TRACE(""); - //! Returns TRUE on success. - EXPECT_EQ(TRUE, result); + //! Returns TRUE on success. + EXPECT_EQ(TRUE, result); - //! Sets lpnSize to number of WCHARs including null. - ASSERT_EQ(expectedSize, lpnSize); + //! 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]); - // 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 - ASSERT_EQ(expectedSize, username16.length()); + // setup for conversion from UTF-16LE + 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 + ASSERT_EQ(expectedSize, username16.length()); - // convert (minus null) to UTF-8 for comparison - std::string username(lpnSize-1, 0); - ASSERT_EQ(expectedUsername.length(), username.length()); - username16.extract(0, username.length(), - reinterpret_cast(&username[0]), "UTF-8"); + // convert (minus null) to UTF-8 for comparison + std::string username(lpnSize-1, 0); + ASSERT_EQ(expectedUsername.length(), username.length()); + username16.extract(0, username.length(), + reinterpret_cast(&username[0]), "UTF-8"); - //! Returned username (after conversion) is what was expected. - EXPECT_EQ(expectedUsername, username); - } + //! Returned username (after conversion) is what was expected. + EXPECT_EQ(expectedUsername, username); + } - //! Checks the effects of GetUserNameW on failure with invalid parameters. - void TestInvalidParameter() - { - SCOPED_TRACE(""); + //! Checks the effects of GetUserNameW on failure with invalid parameters. + void TestInvalidParameter() + { + SCOPED_TRACE(""); - //! Returns FALSE on failure. - EXPECT_EQ(FALSE, 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). - EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); - } + //! Sets errno to ERROR_INVALID_PARAMETER when lpBuffer is null + //! (which is the case for an empty vector). + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); + } - //! Checks the effects of GetUserNameW on failure with a buffer that is too small. - void TestInsufficientBuffer() - { - SCOPED_TRACE(""); + //! Checks the effects of GetUserNameW on failure with a buffer that is too small. + void TestInsufficientBuffer() + { + SCOPED_TRACE(""); - //! Returns FALSE on failure. - EXPECT_EQ(FALSE, result); + //! Returns FALSE on failure. + EXPECT_EQ(FALSE, result); - //! Sets errno to ERROR_INSUFFICIENT_BUFFER. - EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); + //! Sets errno to ERROR_INSUFFICIENT_BUFFER. + EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); - //! Sets lpnSize to length of username plus null. - EXPECT_EQ(expectedSize, lpnSize); - } + //! Sets lpnSize to length of username plus null. + EXPECT_EQ(expectedSize, lpnSize); + } }; TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) { - lpnSize = 1; - result = GetUserNameW(NULL, &lpnSize); + lpnSize = 1; + result = GetUserNameW(NULL, &lpnSize); - TestInvalidParameter(); - // does not reset lpnSize - EXPECT_EQ(1, lpnSize); + TestInvalidParameter(); + // does not reset lpnSize + EXPECT_EQ(1, lpnSize); } TEST_F(GetUserNameTest, BufferSizeAsNullButNotBuffer) { - lpBuffer.push_back('\0'); - result = GetUserNameW(&lpBuffer[0], NULL); + lpBuffer.push_back('\0'); + result = GetUserNameW(&lpBuffer[0], NULL); - TestInvalidParameter(); + TestInvalidParameter(); } TEST_F(GetUserNameTest, BufferSizeAsZero) { - TestWithSize(0); - TestInvalidParameter(); - // does not reset lpnSize - EXPECT_EQ(0, lpnSize); + TestWithSize(0); + TestInvalidParameter(); + // does not reset lpnSize + EXPECT_EQ(0, lpnSize); } TEST_F(GetUserNameTest, BufferSizeAsOne) { - // theoretically this should never fail because any non-empty - // username length will be >1 with trailing null - TestWithSize(1); - TestInsufficientBuffer(); + // 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 it does not account for null - TestWithSize(expectedUsername.length()); - TestInsufficientBuffer(); + // the buffer is too small because it does not account for null + TestWithSize(expectedUsername.length()); + TestInsufficientBuffer(); } TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOne) { - // includes null and so should be sufficient - TestWithSize(expectedUsername.length()+1); - TestSuccess(); + // includes null and so should be sufficient + TestWithSize(expectedUsername.length()+1); + TestSuccess(); } TEST_F(GetUserNameTest, BufferSizeAsExpectedSize) { - // expectedSize is the same as username.size()+1 - TestWithSize(expectedSize); - TestSuccess(); + // expectedSize is the same as username.size()+1 + TestWithSize(expectedSize); + TestSuccess(); } TEST_F(GetUserNameTest, BufferSizeAsLoginNameMax) { - // LoginNameMax is big enough to hold any username, including null - TestWithSize(LOGIN_NAME_MAX); - TestSuccess(); + // LoginNameMax is big enough to hold any username, including null + TestWithSize(LOGIN_NAME_MAX); + TestSuccess(); } From f2ce0d713d8fd529d0e18b04c69cc97ec087c347 Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 12 Aug 2015 13:56:55 -0700 Subject: [PATCH 121/342] changes to pal.h --- impl/pal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impl/pal.h b/impl/pal.h index 1692f15df..a6034f0eb 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -63,7 +63,7 @@ typedef void *PVOID; typedef PVOID HANDLE; typedef char TCHAR; - typedef char *LPTSTR; + typedef char* LPTSTR; #define NO_ERROR 0 #define INFINITE 0xFFFFFFFF #define WINAPI From 6fc54d4e4236b05136ab7d97e76964812941b59d Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 12 Aug 2015 13:56:55 -0700 Subject: [PATCH 122/342] changes to pal.h --- src/impl/pal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/impl/pal.h b/src/impl/pal.h index 1692f15df..a6034f0eb 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -63,7 +63,7 @@ typedef void *PVOID; typedef PVOID HANDLE; typedef char TCHAR; - typedef char *LPTSTR; + typedef char* LPTSTR; #define NO_ERROR 0 #define INFINITE 0xFFFFFFFF #define WINAPI From f496f91af09c421926163a682e20834906f7ddf7 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 13 Aug 2015 09:47:10 -0700 Subject: [PATCH 123/342] Added changes to code based on additional documention and using a 16 bit string --- impl/getcomputername.cpp | 109 ++++++++++++++++++++++++--------- impl/getcomputername.h | 2 +- impl/pal.h | 1 - tests/test-getcomputername.cpp | 63 ++++++++++++++----- 4 files changed, 127 insertions(+), 48 deletions(-) diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp index c403cfe6d..801c4000b 100644 --- a/impl/getcomputername.cpp +++ b/impl/getcomputername.cpp @@ -1,33 +1,74 @@ -#include "getcomputername.h" +//! @file getcomputername.cpp +//! @author Aaron Katz +//! @brief Implements GetComputerName Win32 API + #include #include +#include #include #include -#include +#include +#include +#include +#include +#include "getcomputername.h" - -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx -// 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 -// -// Returns: -// 1 - succeeded -// 0 - failed -BOOL GetComputerNameW(LPTSTR nameOfComputer, LPDWORD len) +//! @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 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/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) { const std::string utf8 = "UTF-8"; errno = 0; // Check parameters - if (!nameOfComputer || !len) { + if (!lpBuffer || !lpnSize) { errno = ERROR_INVALID_PARAMETER; return 0; } @@ -41,8 +82,8 @@ BOOL GetComputerNameW(LPTSTR nameOfComputer, LPDWORD len) } // Get computername from system in a thread-safe manner - std::string computerName(HOST_MAX_NAME, '\0'); - int err = gethostname(&computerName[0], computerName.size()); + std::string computername(HOST_NAME_MAX, '\0'); + int err = gethostname(&computername[0], computername.size()); // Map errno to Win32 Error Codes if (err != 0) { switch (errno) { @@ -72,21 +113,31 @@ BOOL GetComputerNameW(LPTSTR nameOfComputer, LPDWORD len) return 0; } - //Resize the string to not inlcude extra buffer space - const DWORD length = computerName.find_first_of('\0') + 1; - computerName.resize(length); + // Convert to char* to WCHAR_T* (UTF-8 to UTF-16 LE w/o BOM) + std::basic_string computername16(HOST_NAME_MAX + 1, 0); + icu::UnicodeString computername8(computername.c_str(), "UTF-8"); + int32_t targetSize = computername8.extract(0, computername8.length(), + reinterpret_cast(&computername16[0]), + (computername16.size()-1)*sizeof(char16_t), + "UTF-16LE"); + // Number of characters including null + computername16.resize(targetSize/sizeof(char16_t)+1); + + // Size in WCHARs including null + const DWORD size = computername16.length(); //Check if parameters passed enough buffer space - if (length > *len) { + if (size > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; // Set lpnSize if buffer is too small to inform user // of necessary size - *len= length; + *lpnSize= size; return 0; } - memcpy(nameOfComputer, &computerName[0], length); - *len = length; + // Copy bytes from string to buffer + memcpy(lpBuffer, &computername16[0], size*sizeof(char16_t)); + *lpnSize = size; return 1; } diff --git a/impl/getcomputername.h b/impl/getcomputername.h index 5e0d5be2b..8d39d3f9f 100644 --- a/impl/getcomputername.h +++ b/impl/getcomputername.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetComputerNameW(LPTSTR nameOfComputer, LPDWORD len); +BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize); PAL_END_EXTERNC \ No newline at end of file diff --git a/impl/pal.h b/impl/pal.h index a6034f0eb..17e58d409 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -80,7 +80,6 @@ #define ERROR_NO_SUCH_USER 0x00000525 #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 - #define HOST_MAX_NAME 256 typedef unsigned long long uint64; #endif diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index b91730553..93cbfe71d 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -1,36 +1,65 @@ -#include -#include "getcomputername.h" -#include +//! @file test-getcomputername.cpp +//! @author Aaron Katz +//! @brief Unit tests for GetComputerNameW +#include +#include +#include +#include +#include +#include +#include +#include +#include "getcomputername.h" + +//! Test fixture for GetComputerNameTest class GetComputerNameTest : public ::testing::Test { protected: DWORD lpnSize; + std::vector lpBuffer; BOOL result; std::string expectedComputerName; - std::string computerName; + DWORD expectedSize; //Get expected result from using linux call GetComputerNameTest(){ - char hostname[HOST_MAX_NAME]; + char hostname[HOST_NAME_MAX]; BOOL host = gethostname(hostname, sizeof hostname); expectedComputerName = hostname; + expectedSize = expectedComputerName.length() + 1; } void TestWithSize(DWORD size) { lpnSize = size; // allocate a DWORD buffer to receive computername - computerName.assign(lpnSize, '\0'); - result = GetComputerNameW(&computerName[0], &lpnSize); + lpBuffer.assign(lpnSize, '\0'); + result = GetComputerNameW(&lpBuffer[0], &lpnSize); } void TestSuccess() { SCOPED_TRACE(""); - // returns 1 on success - EXPECT_EQ(1, result); - //Resize to cut off '\0' - computerName.resize(expectedComputerName.length()); - ASSERT_EQ(expectedComputerName.size()+1, lpnSize); - EXPECT_EQ(computerName, expectedComputerName); + + //! Returns TRUE on success. + EXPECT_EQ(TRUE, result); + + //! 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]); + // multiply to get number of bytes + icu::UnicodeString usercomputer16(begin, lpnSize*sizeof(char16_t), "UTF-16LE"); + // username16 length includes null and is number of characters + ASSERT_EQ(expectedSize, usercomputer16.length()); + + // convert (minus null) to UTF-8 for comparison + std::string computername(lpnSize-1, 0); + ASSERT_EQ(expectedComputerName.length(), computername.length()); + usercomputer16.extract(0, computername.length(), + reinterpret_cast(&computername[0]), "UTF-8"); + + //! Returned computername(after conversion) is what was expected. + EXPECT_EQ(expectedComputerName, computername); } void TestInvalidParameter() { @@ -66,14 +95,14 @@ TEST_F(GetComputerNameTest, BufferAsNullButNotBufferSize) { } TEST_F(GetComputerNameTest, BufferSizeAsNullButNotBuffer) { - computerName.push_back('\0'); - result = GetComputerNameW(&computerName[0], NULL); + lpBuffer.push_back('\0'); + result = GetComputerNameW(&lpBuffer[0], NULL); TestInvalidParameter(); } TEST_F(GetComputerNameTest, BufferSizeAsZero) { TestWithSize(0); - EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); } TEST_F(GetComputerNameTest, BufferSizeAsUserNameMinusOne) { @@ -90,6 +119,6 @@ TEST_F(GetComputerNameTest, BufferSizeAsUserNamePlusOne) { TEST_F(GetComputerNameTest, BufferSizeAsLoginNameMax) { // the buffer larger than needed - TestWithSize(HOST_MAX_NAME); + TestWithSize(HOST_NAME_MAX); TestSuccess(); } \ No newline at end of file From dfb7a49c21120c0b0e5181e247727b42d4fbc4e7 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 13 Aug 2015 09:47:10 -0700 Subject: [PATCH 124/342] Added changes to code based on additional documention and using a 16 bit string --- src/impl/getcomputername.cpp | 109 +++++++++++++++++++++-------- src/impl/getcomputername.h | 2 +- src/impl/pal.h | 1 - src/tests/test-getcomputername.cpp | 63 ++++++++++++----- 4 files changed, 127 insertions(+), 48 deletions(-) diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp index c403cfe6d..801c4000b 100644 --- a/src/impl/getcomputername.cpp +++ b/src/impl/getcomputername.cpp @@ -1,33 +1,74 @@ -#include "getcomputername.h" +//! @file getcomputername.cpp +//! @author Aaron Katz +//! @brief Implements GetComputerName Win32 API + #include #include +#include #include #include -#include +#include +#include +#include +#include +#include "getcomputername.h" - -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx -// 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 -// -// Returns: -// 1 - succeeded -// 0 - failed -BOOL GetComputerNameW(LPTSTR nameOfComputer, LPDWORD len) +//! @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 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/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) { const std::string utf8 = "UTF-8"; errno = 0; // Check parameters - if (!nameOfComputer || !len) { + if (!lpBuffer || !lpnSize) { errno = ERROR_INVALID_PARAMETER; return 0; } @@ -41,8 +82,8 @@ BOOL GetComputerNameW(LPTSTR nameOfComputer, LPDWORD len) } // Get computername from system in a thread-safe manner - std::string computerName(HOST_MAX_NAME, '\0'); - int err = gethostname(&computerName[0], computerName.size()); + std::string computername(HOST_NAME_MAX, '\0'); + int err = gethostname(&computername[0], computername.size()); // Map errno to Win32 Error Codes if (err != 0) { switch (errno) { @@ -72,21 +113,31 @@ BOOL GetComputerNameW(LPTSTR nameOfComputer, LPDWORD len) return 0; } - //Resize the string to not inlcude extra buffer space - const DWORD length = computerName.find_first_of('\0') + 1; - computerName.resize(length); + // Convert to char* to WCHAR_T* (UTF-8 to UTF-16 LE w/o BOM) + std::basic_string computername16(HOST_NAME_MAX + 1, 0); + icu::UnicodeString computername8(computername.c_str(), "UTF-8"); + int32_t targetSize = computername8.extract(0, computername8.length(), + reinterpret_cast(&computername16[0]), + (computername16.size()-1)*sizeof(char16_t), + "UTF-16LE"); + // Number of characters including null + computername16.resize(targetSize/sizeof(char16_t)+1); + + // Size in WCHARs including null + const DWORD size = computername16.length(); //Check if parameters passed enough buffer space - if (length > *len) { + if (size > *lpnSize) { errno = ERROR_INSUFFICIENT_BUFFER; // Set lpnSize if buffer is too small to inform user // of necessary size - *len= length; + *lpnSize= size; return 0; } - memcpy(nameOfComputer, &computerName[0], length); - *len = length; + // Copy bytes from string to buffer + memcpy(lpBuffer, &computername16[0], size*sizeof(char16_t)); + *lpnSize = size; return 1; } diff --git a/src/impl/getcomputername.h b/src/impl/getcomputername.h index 5e0d5be2b..8d39d3f9f 100644 --- a/src/impl/getcomputername.h +++ b/src/impl/getcomputername.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetComputerNameW(LPTSTR nameOfComputer, LPDWORD len); +BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize); PAL_END_EXTERNC \ No newline at end of file diff --git a/src/impl/pal.h b/src/impl/pal.h index a6034f0eb..17e58d409 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -80,7 +80,6 @@ #define ERROR_NO_SUCH_USER 0x00000525 #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 - #define HOST_MAX_NAME 256 typedef unsigned long long uint64; #endif diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp index b91730553..93cbfe71d 100644 --- a/src/tests/test-getcomputername.cpp +++ b/src/tests/test-getcomputername.cpp @@ -1,36 +1,65 @@ -#include -#include "getcomputername.h" -#include +//! @file test-getcomputername.cpp +//! @author Aaron Katz +//! @brief Unit tests for GetComputerNameW +#include +#include +#include +#include +#include +#include +#include +#include +#include "getcomputername.h" + +//! Test fixture for GetComputerNameTest class GetComputerNameTest : public ::testing::Test { protected: DWORD lpnSize; + std::vector lpBuffer; BOOL result; std::string expectedComputerName; - std::string computerName; + DWORD expectedSize; //Get expected result from using linux call GetComputerNameTest(){ - char hostname[HOST_MAX_NAME]; + char hostname[HOST_NAME_MAX]; BOOL host = gethostname(hostname, sizeof hostname); expectedComputerName = hostname; + expectedSize = expectedComputerName.length() + 1; } void TestWithSize(DWORD size) { lpnSize = size; // allocate a DWORD buffer to receive computername - computerName.assign(lpnSize, '\0'); - result = GetComputerNameW(&computerName[0], &lpnSize); + lpBuffer.assign(lpnSize, '\0'); + result = GetComputerNameW(&lpBuffer[0], &lpnSize); } void TestSuccess() { SCOPED_TRACE(""); - // returns 1 on success - EXPECT_EQ(1, result); - //Resize to cut off '\0' - computerName.resize(expectedComputerName.length()); - ASSERT_EQ(expectedComputerName.size()+1, lpnSize); - EXPECT_EQ(computerName, expectedComputerName); + + //! Returns TRUE on success. + EXPECT_EQ(TRUE, result); + + //! 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]); + // multiply to get number of bytes + icu::UnicodeString usercomputer16(begin, lpnSize*sizeof(char16_t), "UTF-16LE"); + // username16 length includes null and is number of characters + ASSERT_EQ(expectedSize, usercomputer16.length()); + + // convert (minus null) to UTF-8 for comparison + std::string computername(lpnSize-1, 0); + ASSERT_EQ(expectedComputerName.length(), computername.length()); + usercomputer16.extract(0, computername.length(), + reinterpret_cast(&computername[0]), "UTF-8"); + + //! Returned computername(after conversion) is what was expected. + EXPECT_EQ(expectedComputerName, computername); } void TestInvalidParameter() { @@ -66,14 +95,14 @@ TEST_F(GetComputerNameTest, BufferAsNullButNotBufferSize) { } TEST_F(GetComputerNameTest, BufferSizeAsNullButNotBuffer) { - computerName.push_back('\0'); - result = GetComputerNameW(&computerName[0], NULL); + lpBuffer.push_back('\0'); + result = GetComputerNameW(&lpBuffer[0], NULL); TestInvalidParameter(); } TEST_F(GetComputerNameTest, BufferSizeAsZero) { TestWithSize(0); - EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER); + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); } TEST_F(GetComputerNameTest, BufferSizeAsUserNameMinusOne) { @@ -90,6 +119,6 @@ TEST_F(GetComputerNameTest, BufferSizeAsUserNamePlusOne) { TEST_F(GetComputerNameTest, BufferSizeAsLoginNameMax) { // the buffer larger than needed - TestWithSize(HOST_MAX_NAME); + TestWithSize(HOST_NAME_MAX); TestSuccess(); } \ No newline at end of file From 72ea5abd0b724d0ed8743de190e29823d8bffd03 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 13 Aug 2015 10:53:09 -0700 Subject: [PATCH 125/342] New line for { --- impl/getcomputername.cpp | 15 +++++++++----- tests/test-getcomputername.cpp | 36 ++++++++++++++++++++++------------ 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp index 801c4000b..f930dc890 100644 --- a/impl/getcomputername.cpp +++ b/impl/getcomputername.cpp @@ -68,7 +68,8 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) errno = 0; // Check parameters - if (!lpBuffer || !lpnSize) { + if (!lpBuffer || !lpnSize) + { errno = ERROR_INVALID_PARAMETER; return 0; } @@ -76,7 +77,8 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) // Select locale from environment setlocale(LC_ALL, ""); // Check that locale is UTF-8 - if (nl_langinfo(CODESET) != utf8) { + if (nl_langinfo(CODESET) != utf8) + { errno = ERROR_BAD_ENVIRONMENT; return 0; } @@ -85,8 +87,10 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) std::string computername(HOST_NAME_MAX, '\0'); int err = gethostname(&computername[0], computername.size()); // Map errno to Win32 Error Codes - if (err != 0) { - switch (errno) { + if (err != 0) + { + switch (errno) + { case EMFILE: case ENFILE: errno = ERROR_TOO_MANY_OPEN_FILES; @@ -127,7 +131,8 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) const DWORD size = computername16.length(); //Check if parameters passed enough buffer space - if (size > *lpnSize) { + if (size > *lpnSize) + { errno = ERROR_INSUFFICIENT_BUFFER; // Set lpnSize if buffer is too small to inform user // of necessary size diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index 93cbfe71d..a566d83cc 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -13,7 +13,8 @@ #include "getcomputername.h" //! Test fixture for GetComputerNameTest -class GetComputerNameTest : public ::testing::Test { +class GetComputerNameTest : public ::testing::Test +{ protected: DWORD lpnSize; std::vector lpBuffer; @@ -22,21 +23,24 @@ protected: DWORD expectedSize; //Get expected result from using linux call - GetComputerNameTest(){ + GetComputerNameTest() + { char hostname[HOST_NAME_MAX]; BOOL host = gethostname(hostname, sizeof hostname); expectedComputerName = hostname; expectedSize = expectedComputerName.length() + 1; } - void TestWithSize(DWORD size) { + void TestWithSize(DWORD size) + { lpnSize = size; // allocate a DWORD buffer to receive computername lpBuffer.assign(lpnSize, '\0'); result = GetComputerNameW(&lpBuffer[0], &lpnSize); } - void TestSuccess() { + void TestSuccess() + { SCOPED_TRACE(""); //! Returns TRUE on success. @@ -62,7 +66,8 @@ protected: EXPECT_EQ(expectedComputerName, computername); } - void TestInvalidParameter() { + void TestInvalidParameter() + { SCOPED_TRACE(""); // returns 0 on failure @@ -72,7 +77,8 @@ protected: EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); } - void TestInsufficientBuffer() { + void TestInsufficientBuffer() + { SCOPED_TRACE(""); // returns 0 on failure @@ -86,7 +92,8 @@ protected: } }; -TEST_F(GetComputerNameTest, BufferAsNullButNotBufferSize) { +TEST_F(GetComputerNameTest, BufferAsNullButNotBufferSize) +{ lpnSize = 1; result = GetComputerNameW(NULL, &lpnSize); TestInvalidParameter(); @@ -94,30 +101,35 @@ TEST_F(GetComputerNameTest, BufferAsNullButNotBufferSize) { EXPECT_EQ(1, lpnSize); } -TEST_F(GetComputerNameTest, BufferSizeAsNullButNotBuffer) { +TEST_F(GetComputerNameTest, BufferSizeAsNullButNotBuffer) +{ lpBuffer.push_back('\0'); result = GetComputerNameW(&lpBuffer[0], NULL); TestInvalidParameter(); } -TEST_F(GetComputerNameTest, BufferSizeAsZero) { +TEST_F(GetComputerNameTest, BufferSizeAsZero) +{ TestWithSize(0); EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); } -TEST_F(GetComputerNameTest, BufferSizeAsUserNameMinusOne) { +TEST_F(GetComputerNameTest, BufferSizeAsUserNameMinusOne) +{ // the buffer is also too small TestWithSize(expectedComputerName.size()-1); TestInsufficientBuffer(); } -TEST_F(GetComputerNameTest, BufferSizeAsUserNamePlusOne) { +TEST_F(GetComputerNameTest, BufferSizeAsUserNamePlusOne) +{ // the buffer is exactly big enough TestWithSize(expectedComputerName.size()+1); TestSuccess(); } -TEST_F(GetComputerNameTest, BufferSizeAsLoginNameMax) { +TEST_F(GetComputerNameTest, BufferSizeAsLoginNameMax) +{ // the buffer larger than needed TestWithSize(HOST_NAME_MAX); TestSuccess(); From 6bb2c697825f65adbbbe96819dc64843c7a8026f Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 13 Aug 2015 10:53:09 -0700 Subject: [PATCH 126/342] New line for { --- src/impl/getcomputername.cpp | 15 ++++++++----- src/tests/test-getcomputername.cpp | 36 ++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp index 801c4000b..f930dc890 100644 --- a/src/impl/getcomputername.cpp +++ b/src/impl/getcomputername.cpp @@ -68,7 +68,8 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) errno = 0; // Check parameters - if (!lpBuffer || !lpnSize) { + if (!lpBuffer || !lpnSize) + { errno = ERROR_INVALID_PARAMETER; return 0; } @@ -76,7 +77,8 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) // Select locale from environment setlocale(LC_ALL, ""); // Check that locale is UTF-8 - if (nl_langinfo(CODESET) != utf8) { + if (nl_langinfo(CODESET) != utf8) + { errno = ERROR_BAD_ENVIRONMENT; return 0; } @@ -85,8 +87,10 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) std::string computername(HOST_NAME_MAX, '\0'); int err = gethostname(&computername[0], computername.size()); // Map errno to Win32 Error Codes - if (err != 0) { - switch (errno) { + if (err != 0) + { + switch (errno) + { case EMFILE: case ENFILE: errno = ERROR_TOO_MANY_OPEN_FILES; @@ -127,7 +131,8 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) const DWORD size = computername16.length(); //Check if parameters passed enough buffer space - if (size > *lpnSize) { + if (size > *lpnSize) + { errno = ERROR_INSUFFICIENT_BUFFER; // Set lpnSize if buffer is too small to inform user // of necessary size diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp index 93cbfe71d..a566d83cc 100644 --- a/src/tests/test-getcomputername.cpp +++ b/src/tests/test-getcomputername.cpp @@ -13,7 +13,8 @@ #include "getcomputername.h" //! Test fixture for GetComputerNameTest -class GetComputerNameTest : public ::testing::Test { +class GetComputerNameTest : public ::testing::Test +{ protected: DWORD lpnSize; std::vector lpBuffer; @@ -22,21 +23,24 @@ protected: DWORD expectedSize; //Get expected result from using linux call - GetComputerNameTest(){ + GetComputerNameTest() + { char hostname[HOST_NAME_MAX]; BOOL host = gethostname(hostname, sizeof hostname); expectedComputerName = hostname; expectedSize = expectedComputerName.length() + 1; } - void TestWithSize(DWORD size) { + void TestWithSize(DWORD size) + { lpnSize = size; // allocate a DWORD buffer to receive computername lpBuffer.assign(lpnSize, '\0'); result = GetComputerNameW(&lpBuffer[0], &lpnSize); } - void TestSuccess() { + void TestSuccess() + { SCOPED_TRACE(""); //! Returns TRUE on success. @@ -62,7 +66,8 @@ protected: EXPECT_EQ(expectedComputerName, computername); } - void TestInvalidParameter() { + void TestInvalidParameter() + { SCOPED_TRACE(""); // returns 0 on failure @@ -72,7 +77,8 @@ protected: EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); } - void TestInsufficientBuffer() { + void TestInsufficientBuffer() + { SCOPED_TRACE(""); // returns 0 on failure @@ -86,7 +92,8 @@ protected: } }; -TEST_F(GetComputerNameTest, BufferAsNullButNotBufferSize) { +TEST_F(GetComputerNameTest, BufferAsNullButNotBufferSize) +{ lpnSize = 1; result = GetComputerNameW(NULL, &lpnSize); TestInvalidParameter(); @@ -94,30 +101,35 @@ TEST_F(GetComputerNameTest, BufferAsNullButNotBufferSize) { EXPECT_EQ(1, lpnSize); } -TEST_F(GetComputerNameTest, BufferSizeAsNullButNotBuffer) { +TEST_F(GetComputerNameTest, BufferSizeAsNullButNotBuffer) +{ lpBuffer.push_back('\0'); result = GetComputerNameW(&lpBuffer[0], NULL); TestInvalidParameter(); } -TEST_F(GetComputerNameTest, BufferSizeAsZero) { +TEST_F(GetComputerNameTest, BufferSizeAsZero) +{ TestWithSize(0); EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); } -TEST_F(GetComputerNameTest, BufferSizeAsUserNameMinusOne) { +TEST_F(GetComputerNameTest, BufferSizeAsUserNameMinusOne) +{ // the buffer is also too small TestWithSize(expectedComputerName.size()-1); TestInsufficientBuffer(); } -TEST_F(GetComputerNameTest, BufferSizeAsUserNamePlusOne) { +TEST_F(GetComputerNameTest, BufferSizeAsUserNamePlusOne) +{ // the buffer is exactly big enough TestWithSize(expectedComputerName.size()+1); TestSuccess(); } -TEST_F(GetComputerNameTest, BufferSizeAsLoginNameMax) { +TEST_F(GetComputerNameTest, BufferSizeAsLoginNameMax) +{ // the buffer larger than needed TestWithSize(HOST_NAME_MAX); TestSuccess(); From 46677d776b6a634d6f216bf5d86abb970165c5d7 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 17:43:32 -0700 Subject: [PATCH 127/342] Return FALSE instead of 0 --- impl/getusername.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 5d0bec036..82a6be180 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -51,12 +51,12 @@ //! - 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 +//! @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 0 If the function fails, the return value is zero. To get +//! @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/ms724432(v=vs.85).aspx @@ -72,7 +72,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) if (!lpBuffer || !lpnSize) { errno = ERROR_INVALID_PARAMETER; - return 0; + return FALSE; } // Select locale from environment @@ -135,7 +135,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) // Set lpnSize if buffer is too small to inform user // of necessary size *lpnSize = size; - return 0; + return FALSE; } // Copy bytes from string to buffer From 454d1f276a711322a4bd0bc76fe46ce054c860e8 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 17:43:32 -0700 Subject: [PATCH 128/342] Return FALSE instead of 0 --- src/impl/getusername.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 5d0bec036..82a6be180 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -51,12 +51,12 @@ //! - 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 +//! @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 0 If the function fails, the return value is zero. To get +//! @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/ms724432(v=vs.85).aspx @@ -72,7 +72,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) if (!lpBuffer || !lpnSize) { errno = ERROR_INVALID_PARAMETER; - return 0; + return FALSE; } // Select locale from environment @@ -135,7 +135,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) // Set lpnSize if buffer is too small to inform user // of necessary size *lpnSize = size; - return 0; + return FALSE; } // Copy bytes from string to buffer From bb67bfaae7c3227875ae5e99b232776f00f7fd6e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 17:53:28 -0700 Subject: [PATCH 129/342] Remove std::string utf8 Not used consistently. Use in-place for comparison. --- impl/getusername.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 82a6be180..849f4896a 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -64,8 +64,6 @@ //! [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 = FALSE; // Check parameters @@ -78,7 +76,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) // Select locale from environment setlocale(LC_ALL, ""); // Check that locale is UTF-8 - if (nl_langinfo(CODESET) != utf8) + if (nl_langinfo(CODESET) != std::string("UTF-8")) { errno = ERROR_BAD_ENVIRONMENT; return FALSE; From bef9deeb84bfd7c4d5f62e98a777cb4bfbc831dd Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 17:53:28 -0700 Subject: [PATCH 130/342] Remove std::string utf8 Not used consistently. Use in-place for comparison. --- src/impl/getusername.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 82a6be180..849f4896a 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -64,8 +64,6 @@ //! [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 = FALSE; // Check parameters @@ -78,7 +76,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) // Select locale from environment setlocale(LC_ALL, ""); // Check that locale is UTF-8 - if (nl_langinfo(CODESET) != utf8) + if (nl_langinfo(CODESET) != std::string("UTF-8")) { errno = ERROR_BAD_ENVIRONMENT; return FALSE; From fc8f5d18c4972dbaa14d230d0d52c443a443dacb Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 17:54:13 -0700 Subject: [PATCH 131/342] Use 0 instead of '\0' To be consistent with tests --- impl/getusername.cpp | 2 +- tests/test-getusername.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 849f4896a..9ae1e665f 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -83,8 +83,8 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) } // Get username from system in a thread-safe manner - std::string username(LOGIN_NAME_MAX, '\0'); int ret = getlogin_r(&username[0], username.size()); + std::string username(LOGIN_NAME_MAX, 0); // Map errno to Win32 Error Codes if (ret) { diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index e27aeef28..87ee5367c 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -35,7 +35,7 @@ protected: { lpnSize = size; // allocate a WCHAR_T buffer to receive username - lpBuffer.assign(lpnSize, '\0'); + lpBuffer.assign(lpnSize, 0); result = GetUserNameW(&lpBuffer[0], &lpnSize); } From 91345a149eb8873b305cd53e4e8b4f2339527129 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 17:54:13 -0700 Subject: [PATCH 132/342] Use 0 instead of '\0' To be consistent with tests --- src/impl/getusername.cpp | 2 +- src/tests/test-getusername.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 849f4896a..9ae1e665f 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -83,8 +83,8 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) } // Get username from system in a thread-safe manner - std::string username(LOGIN_NAME_MAX, '\0'); int ret = getlogin_r(&username[0], username.size()); + std::string username(LOGIN_NAME_MAX, 0); // Map errno to Win32 Error Codes if (ret) { diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index e27aeef28..87ee5367c 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -35,7 +35,7 @@ protected: { lpnSize = size; // allocate a WCHAR_T buffer to receive username - lpBuffer.assign(lpnSize, '\0'); + lpBuffer.assign(lpnSize, 0); result = GetUserNameW(&lpBuffer[0], &lpnSize); } From db7117bd47424a531251fbe4f042e0180b443f57 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 17:54:29 -0700 Subject: [PATCH 133/342] Use length() instead of size() To be consistent with everything else. --- impl/getusername.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 9ae1e665f..0990269c7 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -83,8 +83,8 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) } // Get username from system in a thread-safe manner - int ret = getlogin_r(&username[0], username.size()); std::string username(LOGIN_NAME_MAX, 0); + int ret = getlogin_r(&username[0], username.length()); // Map errno to Win32 Error Codes if (ret) { From c6aa25acd515c3c46c681dec53a16f840fc59715 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 17:54:29 -0700 Subject: [PATCH 134/342] Use length() instead of size() To be consistent with everything else. --- src/impl/getusername.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 9ae1e665f..0990269c7 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -83,8 +83,8 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) } // Get username from system in a thread-safe manner - int ret = getlogin_r(&username[0], username.size()); std::string username(LOGIN_NAME_MAX, 0); + int ret = getlogin_r(&username[0], username.length()); // Map errno to Win32 Error Codes if (ret) { From 674ca43046e0f569d3077b1cfe5aa4806c009c5a Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 17:54:45 -0700 Subject: [PATCH 135/342] Use just LOGIN_NAME_MAX The +1 is unnecessary since LOGIN_NAME_MAX includes null. --- impl/getusername.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 0990269c7..583485e41 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -116,7 +116,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) } // Convert to char* to WCHAR_T* (UTF-8 to UTF-16 LE w/o BOM) - std::basic_string username16(LOGIN_NAME_MAX+1, 0); + std::basic_string username16(LOGIN_NAME_MAX, 0); icu::UnicodeString username8(username.c_str(), "UTF-8"); int32_t targetSize = username8.extract(0, username8.length(), reinterpret_cast(&username16[0]), From fd8352c4690fe1d87fbf723386eeeeeeee916910 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 17:54:45 -0700 Subject: [PATCH 136/342] Use just LOGIN_NAME_MAX The +1 is unnecessary since LOGIN_NAME_MAX includes null. --- src/impl/getusername.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 0990269c7..583485e41 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -116,7 +116,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) } // Convert to char* to WCHAR_T* (UTF-8 to UTF-16 LE w/o BOM) - std::basic_string username16(LOGIN_NAME_MAX+1, 0); + std::basic_string username16(LOGIN_NAME_MAX, 0); icu::UnicodeString username8(username.c_str(), "UTF-8"); int32_t targetSize = username8.extract(0, username8.length(), reinterpret_cast(&username16[0]), From 70a163e0612ad1b7487cb56af09c06b4a1c337be Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 17:55:29 -0700 Subject: [PATCH 137/342] Use known size instead of calculation --- impl/getusername.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 583485e41..6bd458a70 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -120,8 +120,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) icu::UnicodeString username8(username.c_str(), "UTF-8"); int32_t targetSize = username8.extract(0, username8.length(), reinterpret_cast(&username16[0]), - (username16.size()-1)*sizeof(char16_t), - "UTF-16LE"); + LOGIN_NAME_MAX, "UTF-16LE"); // Number of characters including null username16.resize(targetSize/sizeof(char16_t)+1); From 77f9757a0512904f8b04839f108e6feaba8e86fb Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 17:55:29 -0700 Subject: [PATCH 138/342] Use known size instead of calculation --- src/impl/getusername.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 583485e41..6bd458a70 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -120,8 +120,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) icu::UnicodeString username8(username.c_str(), "UTF-8"); int32_t targetSize = username8.extract(0, username8.length(), reinterpret_cast(&username16[0]), - (username16.size()-1)*sizeof(char16_t), - "UTF-16LE"); + LOGIN_NAME_MAX, "UTF-16LE"); // Number of characters including null username16.resize(targetSize/sizeof(char16_t)+1); From 60a9a360a177889b2c10311ffbc722f25add7477 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 20:30:48 -0700 Subject: [PATCH 139/342] Use libicu properly for UTF-16 conversion - No more messy calculations - Only one include, not four - No resizing - No memcpy - Faster because of fromUTF8() --- impl/getusername.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 6bd458a70..88e5955d6 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -7,10 +7,7 @@ #include #include #include -#include -#include -#include -#include +#include #include "getusername.h" //! @brief GetUserName retrieves the name of the user associated with @@ -115,14 +112,10 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) return FALSE; } - // Convert to char* to WCHAR_T* (UTF-8 to UTF-16 LE w/o BOM) - std::basic_string username16(LOGIN_NAME_MAX, 0); - icu::UnicodeString username8(username.c_str(), "UTF-8"); - int32_t targetSize = username8.extract(0, username8.length(), - reinterpret_cast(&username16[0]), - LOGIN_NAME_MAX, "UTF-16LE"); - // Number of characters including null - username16.resize(targetSize/sizeof(char16_t)+1); + // Convert to UnicodeString + auto username16 = icu::UnicodeString::fromUTF8(username.c_str()); + // Terminate string with null + username16.append('\0'); // Size in WCHARs including null const DWORD size = username16.length(); @@ -135,8 +128,9 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) return FALSE; } - // Copy bytes from string to buffer - memcpy(lpBuffer, &username16[0], size*sizeof(char16_t)); + // Extract string as UTF-16LE to buffer + username16.extract(0, size, reinterpret_cast(lpBuffer), "UTF-16LE"); + *lpnSize = size; return TRUE; From 8fdfeb250d08da2311198f5919771b1db31f682c Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 20:30:48 -0700 Subject: [PATCH 140/342] Use libicu properly for UTF-16 conversion - No more messy calculations - Only one include, not four - No resizing - No memcpy - Faster because of fromUTF8() --- src/impl/getusername.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 6bd458a70..88e5955d6 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -7,10 +7,7 @@ #include #include #include -#include -#include -#include -#include +#include #include "getusername.h" //! @brief GetUserName retrieves the name of the user associated with @@ -115,14 +112,10 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) return FALSE; } - // Convert to char* to WCHAR_T* (UTF-8 to UTF-16 LE w/o BOM) - std::basic_string username16(LOGIN_NAME_MAX, 0); - icu::UnicodeString username8(username.c_str(), "UTF-8"); - int32_t targetSize = username8.extract(0, username8.length(), - reinterpret_cast(&username16[0]), - LOGIN_NAME_MAX, "UTF-16LE"); - // Number of characters including null - username16.resize(targetSize/sizeof(char16_t)+1); + // Convert to UnicodeString + auto username16 = icu::UnicodeString::fromUTF8(username.c_str()); + // Terminate string with null + username16.append('\0'); // Size in WCHARs including null const DWORD size = username16.length(); @@ -135,8 +128,9 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) return FALSE; } - // Copy bytes from string to buffer - memcpy(lpBuffer, &username16[0], size*sizeof(char16_t)); + // Extract string as UTF-16LE to buffer + username16.extract(0, size, reinterpret_cast(lpBuffer), "UTF-16LE"); + *lpnSize = size; return TRUE; From d298302e8cf5edc6dc39a325bdf4256095107e0f Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 20:42:01 -0700 Subject: [PATCH 141/342] Use libicu properly in tests --- tests/test-getusername.cpp | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index 87ee5367c..b6c0b5e77 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -6,10 +6,7 @@ #include #include #include -#include -#include -#include -#include +#include #include "getusername.h" //! Test fixture for GetUserNameW @@ -50,18 +47,14 @@ protected: //! Sets lpnSize to number of WCHARs including null. ASSERT_EQ(expectedSize, lpnSize); - // setup for conversion from UTF-16LE + // Read lpBuffer into UnicodeString (without null) 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 - ASSERT_EQ(expectedSize, username16.length()); - - // convert (minus null) to UTF-8 for comparison - std::string username(lpnSize-1, 0); + icu::UnicodeString username16(begin, (lpnSize-1)*sizeof(UChar), "UTF-16LE"); + ASSERT_EQ(expectedUsername.length(), username16.length()); + // Convert to UTF-8 for comparison + std::string username; + username16.toUTF8String(username); ASSERT_EQ(expectedUsername.length(), username.length()); - username16.extract(0, username.length(), - reinterpret_cast(&username[0]), "UTF-8"); //! Returned username (after conversion) is what was expected. EXPECT_EQ(expectedUsername, username); From 9164baa9c452f89c71811a90b5ff519f0baf46b1 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 13 Aug 2015 20:42:01 -0700 Subject: [PATCH 142/342] Use libicu properly in tests --- src/tests/test-getusername.cpp | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index 87ee5367c..b6c0b5e77 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -6,10 +6,7 @@ #include #include #include -#include -#include -#include -#include +#include #include "getusername.h" //! Test fixture for GetUserNameW @@ -50,18 +47,14 @@ protected: //! Sets lpnSize to number of WCHARs including null. ASSERT_EQ(expectedSize, lpnSize); - // setup for conversion from UTF-16LE + // Read lpBuffer into UnicodeString (without null) 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 - ASSERT_EQ(expectedSize, username16.length()); - - // convert (minus null) to UTF-8 for comparison - std::string username(lpnSize-1, 0); + icu::UnicodeString username16(begin, (lpnSize-1)*sizeof(UChar), "UTF-16LE"); + ASSERT_EQ(expectedUsername.length(), username16.length()); + // Convert to UTF-8 for comparison + std::string username; + username16.toUTF8String(username); ASSERT_EQ(expectedUsername.length(), username.length()); - username16.extract(0, username.length(), - reinterpret_cast(&username[0]), "UTF-8"); //! Returned username (after conversion) is what was expected. EXPECT_EQ(expectedUsername, username); From 427cce83f0a8d2784f7e8cc5bf19ab481a5c7ad3 Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 14 Aug 2015 09:26:45 -0700 Subject: [PATCH 143/342] Added changes based of feedback from Peter --- src/CMakeCache.txt | 324 +++++++++++++++++++++++++++++++++++ src/impl/getcpinfo.cpp | 60 +++++-- src/impl/getcpinfo.h | 2 +- src/impl/pal.h | 5 +- src/tests/test-getcpinfo.cpp | 35 ++-- 5 files changed, 386 insertions(+), 40 deletions(-) create mode 100644 src/CMakeCache.txt diff --git a/src/CMakeCache.txt b/src/CMakeCache.txt new file mode 100644 index 000000000..2f6e2fc4b --- /dev/null +++ b/src/CMakeCache.txt @@ -0,0 +1,324 @@ +# This is the CMakeCache file. +# For build in directory: /home/aakatz/gitwd/monad-native/src +# It was generated by CMake: /usr/bin/cmake +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//Path to a program. +CMAKE_AR:FILEPATH=/usr/bin/ar + +//Choose the type of build, options are: None(CMAKE_CXX_FLAGS or +// CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel. +CMAKE_BUILD_TYPE:STRING= + +//Enable/Disable color output during build. +CMAKE_COLOR_MAKEFILE:BOOL=ON + +//CXX compiler. +CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++ + +//Flags used by the compiler during all build types. +CMAKE_CXX_FLAGS:STRING= + +//Flags used by the compiler during debug builds. +CMAKE_CXX_FLAGS_DEBUG:STRING=-g + +//Flags used by the compiler during release minsize builds. +CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the compiler during release builds (/MD /Ob1 /Oi +// /Ot /Oy /Gs will produce slightly less optimized but smaller +// files). +CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the compiler during Release with Debug Info builds. +CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//C compiler. +CMAKE_C_COMPILER:FILEPATH=/usr/bin/cc + +//Flags used by the compiler during all build types. +CMAKE_C_FLAGS:STRING= + +//Flags used by the compiler during debug builds. +CMAKE_C_FLAGS_DEBUG:STRING=-g + +//Flags used by the compiler during release minsize builds. +CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the compiler during release builds (/MD /Ob1 /Oi +// /Ot /Oy /Gs will produce slightly less optimized but smaller +// files). +CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the compiler during Release with Debug Info builds. +CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//Flags used by the linker. +CMAKE_EXE_LINKER_FLAGS:STRING=' ' + +//Flags used by the linker during debug builds. +CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Enable/Disable output of compile commands during generation. +CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=OFF + +//Install path prefix, prepended onto install directories. +CMAKE_INSTALL_PREFIX:PATH=/usr/local + +//Path to a program. +CMAKE_LINKER:FILEPATH=/usr/bin/ld + +//Path to a program. +CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/make + +//Flags used by the linker during the creation of modules. +CMAKE_MODULE_LINKER_FLAGS:STRING=' ' + +//Flags used by the linker during debug builds. +CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_NM:FILEPATH=/usr/bin/nm + +//Path to a program. +CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy + +//Path to a program. +CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump + +//Value Computed by CMake +CMAKE_PROJECT_NAME:STATIC=monad_native + +//Path to a program. +CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib + +//Flags used by the linker during the creation of dll's. +CMAKE_SHARED_LINKER_FLAGS:STRING=' ' + +//Flags used by the linker during debug builds. +CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//If set, runtime paths are not added when installing shared libraries, +// but are added when building. +CMAKE_SKIP_INSTALL_RPATH:BOOL=NO + +//If set, runtime paths are not added when using shared libraries. +CMAKE_SKIP_RPATH:BOOL=NO + +//Flags used by the linker during the creation of static libraries. +CMAKE_STATIC_LINKER_FLAGS:STRING= + +//Flags used by the linker during debug builds. +CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_STRIP:FILEPATH=/usr/bin/strip + +//If true, cmake will use relative paths in makefiles and projects. +CMAKE_USE_RELATIVE_PATHS:BOOL=OFF + +//If this value is on, makefiles will be generated without the +// .SILENT directive, and all commands will be echoed to the console +// during the make. This is useful for debugging only. With Visual +// Studio IDE projects all commands are done without /nologo. +CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE + +//Value Computed by CMake +monad_native_BINARY_DIR:STATIC=/home/aakatz/gitwd/monad-native/src + +//Value Computed by CMake +monad_native_SOURCE_DIR:STATIC=/home/aakatz/gitwd/monad-native/src + +//Dependencies for the target +ps_LIB_DEPENDS:STATIC=general;icuuc; + + +######################## +# INTERNAL cache entries +######################## + +//ADVANCED property for variable: CMAKE_AR +CMAKE_AR-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_BUILD_TOOL +CMAKE_BUILD_TOOL-ADVANCED:INTERNAL=1 +//What is the target build tool cmake is generating for. +CMAKE_BUILD_TOOL:INTERNAL=/usr/bin/make +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=/home/aakatz/gitwd/monad-native/src +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=2 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=8 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=12 +//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE +CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/usr/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest +//ADVANCED property for variable: CMAKE_CXX_COMPILER +CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS +CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG +CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL +CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE +CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO +CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER +CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS +CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG +CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL +CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE +CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO +CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Executable file format +CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS +CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG +CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE +CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS +CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1 +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Unix Makefiles +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Have symbol pthread_create +CMAKE_HAVE_LIBC_CREATE:INTERNAL= +//Have library pthreads +CMAKE_HAVE_PTHREADS_CREATE:INTERNAL= +//Have library pthread +CMAKE_HAVE_PTHREAD_CREATE:INTERNAL=1 +//Have include pthread.h +CMAKE_HAVE_PTHREAD_H:INTERNAL=1 +//Start directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=/home/aakatz/gitwd/monad-native/src +//Install .so files without execute permission. +CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1 +//ADVANCED property for variable: CMAKE_LINKER +CMAKE_LINKER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS +CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG +CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE +CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_NM +CMAKE_NM-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_LOCAL_GENERATORS:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJCOPY +CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJDUMP +CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RANLIB +CMAKE_RANLIB-ADVANCED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=/usr/share/cmake-2.8 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS +CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG +CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE +CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH +CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_RPATH +CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS +CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG +CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE +CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STRIP +CMAKE_STRIP-ADVANCED:INTERNAL=1 +//uname command +CMAKE_UNAME:INTERNAL=/bin/uname +//ADVANCED property for variable: CMAKE_USE_RELATIVE_PATHS +CMAKE_USE_RELATIVE_PATHS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 +//Details about finding Threads +FIND_PACKAGE_MESSAGE_DETAILS_Threads:INTERNAL=[TRUE][v()] + diff --git a/src/impl/getcpinfo.cpp b/src/impl/getcpinfo.cpp index c9ea60f3e..478632772 100644 --- a/src/impl/getcpinfo.cpp +++ b/src/impl/getcpinfo.cpp @@ -1,19 +1,46 @@ -#include "getcpinfo.h" +//! @file getcpinfo.cpp +//! @author Aaron Ktaz +//! @brief Implements GetCpInfoW Win32 API + #include #include #include +#include "getcpinfo.h" +//! @brief GetCPInfoW retrieves the name of the code page associated with +//! the current thread. +//! +//! GetCpInfoW the Unicode variation. See [MSDN documentation]. +//! +//! @param[in] codepage +//! @parblock +//! An UINT Identifier for the code page for which to retrieve information. +//! See Code Page Identifiers for details +//! +//! @endparblock +//! +//! @param[out] cpinfo +//! @parblock +//! Pointer to a CPINFO structure that receives information about the code page +//! +//! LPCPINFO is a pointer to the structure _cpinfo used to contain the information +//! about a code page +//! +//! +//! @exception errno Passes these errors via errno to GetLastError: +//! - ERROR_INVALID_PARAMETER: parameter is not valid +//! +//! @retval 1 If the function succeeds, the return value is a nonzero +//! value, and cpinfo is population with information about the code page +//! +//! @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/dd318078%28v=vs.85%29.aspx +//! [_cpinfo]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317780%28v=vs.85%29.aspx +//! [CodePageIdentifiers] https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756%28v=vs.85%29.aspx -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx -// Sets errno to: -// ERROR_INVALID_PARAMETER - parameter is not valid -// ERROR_BAD_ENVIRONMENT - locale is not UTF-8 -// -// Returns: -// TRUE - succeeded -// FALSE - failed - -BOOL GetCPInfoW(UINT codepage, CPINFO &cpinfo) +BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) { const std::string utf8 = "UTF-8"; @@ -31,11 +58,12 @@ BOOL GetCPInfoW(UINT codepage, CPINFO &cpinfo) //if codepage is utf8 if(codepage == 65001) { - cpinfo.DefaultChar[0] = '?'; - cpinfo.DefaultChar[1] = '0'; - cpinfo.LeadByte[0] = '0'; - cpinfo.LeadByte[1] = '0'; - cpinfo.MaxCharSize = 4; + cpinfo->DefaultChar[0] = '?'; + cpinfo->DefaultChar[1] = '0'; + cpinfo->MaxCharSize = 4; + for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ){ + cpinfo->LeadByte[i] = '0'; + } return TRUE; } else diff --git a/src/impl/getcpinfo.h b/src/impl/getcpinfo.h index e1b203bc1..54a2ebbcd 100644 --- a/src/impl/getcpinfo.h +++ b/src/impl/getcpinfo.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetCPInfoW(UINT codepage, CPINFO &cpinfo); +BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo); PAL_END_EXTERNC diff --git a/src/impl/pal.h b/src/impl/pal.h index c94422007..0999c7882 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -81,7 +81,6 @@ #define ERROR_NO_SUCH_USER 0x00000525 #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 - #define UTF8 65001 #define ERROR_BAD_ENVIRONMENT 0x0000000A typedef unsigned long long uint64; #endif @@ -608,8 +607,8 @@ typedef unsigned char PAL_Boolean; */ namespace const_cpinfo{ - constexpr int MAX_DEFAULTCHAR = 2; - constexpr int MAX_LEADBYTES = 12; + constexpr int MAX_DEFAULTCHAR = 2; + constexpr int MAX_LEADBYTES = 12; } /* diff --git a/src/tests/test-getcpinfo.cpp b/src/tests/test-getcpinfo.cpp index 341c5279d..90f64deff 100644 --- a/src/tests/test-getcpinfo.cpp +++ b/src/tests/test-getcpinfo.cpp @@ -1,38 +1,33 @@ +//! @file test-getcpinfo.cpp +//! @author Aaron Ktaz +//! @brief Implements Unit test for GetCPInfoW + #include #include "getcpinfo.h" // This test is with correct parameters TEST(GetCPInfo,Utf8) { - CPINFO cpinfo; - BOOL result = GetCPInfoW(UTF8, cpinfo); + CPINFO* cpinfo; + int UTF8CodePageNumber = 65001; + BOOL result = GetCPInfoW(UTF8CodePageNumber, cpinfo); // first make sure that the function worked - ASSERT_TRUE(result == TRUE); + ASSERT_EQ(result, TRUE); // now compare the actual values - ASSERT_EQ(cpinfo.DefaultChar[0],'?'); - ASSERT_EQ(cpinfo.DefaultChar[1],'0'); - ASSERT_EQ(cpinfo.LeadByte[0],'0'); - ASSERT_EQ(cpinfo.LeadByte[1],'0'); - ASSERT_EQ(cpinfo.MaxCharSize,4); -} - -// This test is with codepage being null -TEST(GetCPInfo, NullForCodePageUINTButNotCpinfo) -{ - CPINFO cpinfo; - BOOL result = GetCPInfoW(NULL, cpinfo); - - ASSERT_TRUE(result == FALSE); - EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); - + ASSERT_EQ(cpinfo->DefaultChar[0],'?'); + ASSERT_EQ(cpinfo->DefaultChar[1],'0'); + ASSERT_EQ(cpinfo->MaxCharSize,4); + for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ){ + ASSERT_EQ(cpinfo->LeadByte[i],'0'); + } } // This test is with codepage not being utf8 TEST(GetCPInfo, CodePageNotUTF8) { - CPINFO cpinfo; + CPINFO* cpinfo; BOOL result = GetCPInfoW(65000, cpinfo); ASSERT_TRUE(result == FALSE); From 53e7c11e6948b0b9b9f9d9fa9d42970c6e9aae1e Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 14 Aug 2015 09:26:45 -0700 Subject: [PATCH 144/342] Added changes based of feedback from Peter --- CMakeCache.txt | 324 +++++++++++++++++++++++++++++++++++++++ impl/getcpinfo.cpp | 60 ++++++-- impl/getcpinfo.h | 2 +- impl/pal.h | 5 +- tests/test-getcpinfo.cpp | 35 ++--- 5 files changed, 386 insertions(+), 40 deletions(-) create mode 100644 CMakeCache.txt diff --git a/CMakeCache.txt b/CMakeCache.txt new file mode 100644 index 000000000..2f6e2fc4b --- /dev/null +++ b/CMakeCache.txt @@ -0,0 +1,324 @@ +# This is the CMakeCache file. +# For build in directory: /home/aakatz/gitwd/monad-native/src +# It was generated by CMake: /usr/bin/cmake +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//Path to a program. +CMAKE_AR:FILEPATH=/usr/bin/ar + +//Choose the type of build, options are: None(CMAKE_CXX_FLAGS or +// CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel. +CMAKE_BUILD_TYPE:STRING= + +//Enable/Disable color output during build. +CMAKE_COLOR_MAKEFILE:BOOL=ON + +//CXX compiler. +CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++ + +//Flags used by the compiler during all build types. +CMAKE_CXX_FLAGS:STRING= + +//Flags used by the compiler during debug builds. +CMAKE_CXX_FLAGS_DEBUG:STRING=-g + +//Flags used by the compiler during release minsize builds. +CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the compiler during release builds (/MD /Ob1 /Oi +// /Ot /Oy /Gs will produce slightly less optimized but smaller +// files). +CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the compiler during Release with Debug Info builds. +CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//C compiler. +CMAKE_C_COMPILER:FILEPATH=/usr/bin/cc + +//Flags used by the compiler during all build types. +CMAKE_C_FLAGS:STRING= + +//Flags used by the compiler during debug builds. +CMAKE_C_FLAGS_DEBUG:STRING=-g + +//Flags used by the compiler during release minsize builds. +CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the compiler during release builds (/MD /Ob1 /Oi +// /Ot /Oy /Gs will produce slightly less optimized but smaller +// files). +CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the compiler during Release with Debug Info builds. +CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//Flags used by the linker. +CMAKE_EXE_LINKER_FLAGS:STRING=' ' + +//Flags used by the linker during debug builds. +CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Enable/Disable output of compile commands during generation. +CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=OFF + +//Install path prefix, prepended onto install directories. +CMAKE_INSTALL_PREFIX:PATH=/usr/local + +//Path to a program. +CMAKE_LINKER:FILEPATH=/usr/bin/ld + +//Path to a program. +CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/make + +//Flags used by the linker during the creation of modules. +CMAKE_MODULE_LINKER_FLAGS:STRING=' ' + +//Flags used by the linker during debug builds. +CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_NM:FILEPATH=/usr/bin/nm + +//Path to a program. +CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy + +//Path to a program. +CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump + +//Value Computed by CMake +CMAKE_PROJECT_NAME:STATIC=monad_native + +//Path to a program. +CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib + +//Flags used by the linker during the creation of dll's. +CMAKE_SHARED_LINKER_FLAGS:STRING=' ' + +//Flags used by the linker during debug builds. +CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//If set, runtime paths are not added when installing shared libraries, +// but are added when building. +CMAKE_SKIP_INSTALL_RPATH:BOOL=NO + +//If set, runtime paths are not added when using shared libraries. +CMAKE_SKIP_RPATH:BOOL=NO + +//Flags used by the linker during the creation of static libraries. +CMAKE_STATIC_LINKER_FLAGS:STRING= + +//Flags used by the linker during debug builds. +CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_STRIP:FILEPATH=/usr/bin/strip + +//If true, cmake will use relative paths in makefiles and projects. +CMAKE_USE_RELATIVE_PATHS:BOOL=OFF + +//If this value is on, makefiles will be generated without the +// .SILENT directive, and all commands will be echoed to the console +// during the make. This is useful for debugging only. With Visual +// Studio IDE projects all commands are done without /nologo. +CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE + +//Value Computed by CMake +monad_native_BINARY_DIR:STATIC=/home/aakatz/gitwd/monad-native/src + +//Value Computed by CMake +monad_native_SOURCE_DIR:STATIC=/home/aakatz/gitwd/monad-native/src + +//Dependencies for the target +ps_LIB_DEPENDS:STATIC=general;icuuc; + + +######################## +# INTERNAL cache entries +######################## + +//ADVANCED property for variable: CMAKE_AR +CMAKE_AR-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_BUILD_TOOL +CMAKE_BUILD_TOOL-ADVANCED:INTERNAL=1 +//What is the target build tool cmake is generating for. +CMAKE_BUILD_TOOL:INTERNAL=/usr/bin/make +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=/home/aakatz/gitwd/monad-native/src +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=2 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=8 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=12 +//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE +CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/usr/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest +//ADVANCED property for variable: CMAKE_CXX_COMPILER +CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS +CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG +CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL +CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE +CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO +CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER +CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS +CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG +CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL +CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE +CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO +CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Executable file format +CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS +CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG +CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE +CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS +CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1 +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Unix Makefiles +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Have symbol pthread_create +CMAKE_HAVE_LIBC_CREATE:INTERNAL= +//Have library pthreads +CMAKE_HAVE_PTHREADS_CREATE:INTERNAL= +//Have library pthread +CMAKE_HAVE_PTHREAD_CREATE:INTERNAL=1 +//Have include pthread.h +CMAKE_HAVE_PTHREAD_H:INTERNAL=1 +//Start directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=/home/aakatz/gitwd/monad-native/src +//Install .so files without execute permission. +CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1 +//ADVANCED property for variable: CMAKE_LINKER +CMAKE_LINKER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS +CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG +CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE +CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_NM +CMAKE_NM-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_LOCAL_GENERATORS:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJCOPY +CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJDUMP +CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RANLIB +CMAKE_RANLIB-ADVANCED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=/usr/share/cmake-2.8 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS +CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG +CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE +CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH +CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_RPATH +CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS +CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG +CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE +CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STRIP +CMAKE_STRIP-ADVANCED:INTERNAL=1 +//uname command +CMAKE_UNAME:INTERNAL=/bin/uname +//ADVANCED property for variable: CMAKE_USE_RELATIVE_PATHS +CMAKE_USE_RELATIVE_PATHS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 +//Details about finding Threads +FIND_PACKAGE_MESSAGE_DETAILS_Threads:INTERNAL=[TRUE][v()] + diff --git a/impl/getcpinfo.cpp b/impl/getcpinfo.cpp index c9ea60f3e..478632772 100644 --- a/impl/getcpinfo.cpp +++ b/impl/getcpinfo.cpp @@ -1,19 +1,46 @@ -#include "getcpinfo.h" +//! @file getcpinfo.cpp +//! @author Aaron Ktaz +//! @brief Implements GetCpInfoW Win32 API + #include #include #include +#include "getcpinfo.h" +//! @brief GetCPInfoW retrieves the name of the code page associated with +//! the current thread. +//! +//! GetCpInfoW the Unicode variation. See [MSDN documentation]. +//! +//! @param[in] codepage +//! @parblock +//! An UINT Identifier for the code page for which to retrieve information. +//! See Code Page Identifiers for details +//! +//! @endparblock +//! +//! @param[out] cpinfo +//! @parblock +//! Pointer to a CPINFO structure that receives information about the code page +//! +//! LPCPINFO is a pointer to the structure _cpinfo used to contain the information +//! about a code page +//! +//! +//! @exception errno Passes these errors via errno to GetLastError: +//! - ERROR_INVALID_PARAMETER: parameter is not valid +//! +//! @retval 1 If the function succeeds, the return value is a nonzero +//! value, and cpinfo is population with information about the code page +//! +//! @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/dd318078%28v=vs.85%29.aspx +//! [_cpinfo]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317780%28v=vs.85%29.aspx +//! [CodePageIdentifiers] https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756%28v=vs.85%29.aspx -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx -// Sets errno to: -// ERROR_INVALID_PARAMETER - parameter is not valid -// ERROR_BAD_ENVIRONMENT - locale is not UTF-8 -// -// Returns: -// TRUE - succeeded -// FALSE - failed - -BOOL GetCPInfoW(UINT codepage, CPINFO &cpinfo) +BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) { const std::string utf8 = "UTF-8"; @@ -31,11 +58,12 @@ BOOL GetCPInfoW(UINT codepage, CPINFO &cpinfo) //if codepage is utf8 if(codepage == 65001) { - cpinfo.DefaultChar[0] = '?'; - cpinfo.DefaultChar[1] = '0'; - cpinfo.LeadByte[0] = '0'; - cpinfo.LeadByte[1] = '0'; - cpinfo.MaxCharSize = 4; + cpinfo->DefaultChar[0] = '?'; + cpinfo->DefaultChar[1] = '0'; + cpinfo->MaxCharSize = 4; + for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ){ + cpinfo->LeadByte[i] = '0'; + } return TRUE; } else diff --git a/impl/getcpinfo.h b/impl/getcpinfo.h index e1b203bc1..54a2ebbcd 100644 --- a/impl/getcpinfo.h +++ b/impl/getcpinfo.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetCPInfoW(UINT codepage, CPINFO &cpinfo); +BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo); PAL_END_EXTERNC diff --git a/impl/pal.h b/impl/pal.h index c94422007..0999c7882 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -81,7 +81,6 @@ #define ERROR_NO_SUCH_USER 0x00000525 #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 - #define UTF8 65001 #define ERROR_BAD_ENVIRONMENT 0x0000000A typedef unsigned long long uint64; #endif @@ -608,8 +607,8 @@ typedef unsigned char PAL_Boolean; */ namespace const_cpinfo{ - constexpr int MAX_DEFAULTCHAR = 2; - constexpr int MAX_LEADBYTES = 12; + constexpr int MAX_DEFAULTCHAR = 2; + constexpr int MAX_LEADBYTES = 12; } /* diff --git a/tests/test-getcpinfo.cpp b/tests/test-getcpinfo.cpp index 341c5279d..90f64deff 100644 --- a/tests/test-getcpinfo.cpp +++ b/tests/test-getcpinfo.cpp @@ -1,38 +1,33 @@ +//! @file test-getcpinfo.cpp +//! @author Aaron Ktaz +//! @brief Implements Unit test for GetCPInfoW + #include #include "getcpinfo.h" // This test is with correct parameters TEST(GetCPInfo,Utf8) { - CPINFO cpinfo; - BOOL result = GetCPInfoW(UTF8, cpinfo); + CPINFO* cpinfo; + int UTF8CodePageNumber = 65001; + BOOL result = GetCPInfoW(UTF8CodePageNumber, cpinfo); // first make sure that the function worked - ASSERT_TRUE(result == TRUE); + ASSERT_EQ(result, TRUE); // now compare the actual values - ASSERT_EQ(cpinfo.DefaultChar[0],'?'); - ASSERT_EQ(cpinfo.DefaultChar[1],'0'); - ASSERT_EQ(cpinfo.LeadByte[0],'0'); - ASSERT_EQ(cpinfo.LeadByte[1],'0'); - ASSERT_EQ(cpinfo.MaxCharSize,4); -} - -// This test is with codepage being null -TEST(GetCPInfo, NullForCodePageUINTButNotCpinfo) -{ - CPINFO cpinfo; - BOOL result = GetCPInfoW(NULL, cpinfo); - - ASSERT_TRUE(result == FALSE); - EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); - + ASSERT_EQ(cpinfo->DefaultChar[0],'?'); + ASSERT_EQ(cpinfo->DefaultChar[1],'0'); + ASSERT_EQ(cpinfo->MaxCharSize,4); + for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ){ + ASSERT_EQ(cpinfo->LeadByte[i],'0'); + } } // This test is with codepage not being utf8 TEST(GetCPInfo, CodePageNotUTF8) { - CPINFO cpinfo; + CPINFO* cpinfo; BOOL result = GetCPInfoW(65000, cpinfo); ASSERT_TRUE(result == FALSE); From 1a796b59244b2681965ad5e22586ac3ec3f136bf Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 14 Aug 2015 10:51:25 -0700 Subject: [PATCH 145/342] Changes to make converting beteween UTF8 and UTF16 --- impl/getcomputername.cpp | 44 ++++++++++++++-------------------- tests/test-getcomputername.cpp | 22 +++++++---------- 2 files changed, 26 insertions(+), 40 deletions(-) diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp index f930dc890..03a8cda0e 100644 --- a/impl/getcomputername.cpp +++ b/impl/getcomputername.cpp @@ -7,10 +7,7 @@ #include #include #include -#include -#include -#include -#include +#include #include "getcomputername.h" //! @brief GetComputerName retrieves the name of the host associated with @@ -51,12 +48,12 @@ //! - 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 +//! @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 0 If the function fails, the return value is zero. To get +//! @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 @@ -64,28 +61,27 @@ //! [LPTSTR]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx#LPTSTR BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) { - const std::string utf8 = "UTF-8"; errno = 0; // Check parameters if (!lpBuffer || !lpnSize) { errno = ERROR_INVALID_PARAMETER; - return 0; + return FALSE; } // Select locale from environment setlocale(LC_ALL, ""); // Check that locale is UTF-8 - if (nl_langinfo(CODESET) != utf8) + if (nl_langinfo(CODESET) != std::string("UTF-8")) { errno = ERROR_BAD_ENVIRONMENT; - return 0; + return FALSE; } // Get computername from system in a thread-safe manner - std::string computername(HOST_NAME_MAX, '\0'); - int err = gethostname(&computername[0], computername.size()); + std::string computername(HOST_NAME_MAX, 0); + int err = gethostname(&computername[0], computername.length()); // Map errno to Win32 Error Codes if (err != 0) { @@ -114,18 +110,13 @@ BOOL GetComputerNameW(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) - std::basic_string computername16(HOST_NAME_MAX + 1, 0); - icu::UnicodeString computername8(computername.c_str(), "UTF-8"); - int32_t targetSize = computername8.extract(0, computername8.length(), - reinterpret_cast(&computername16[0]), - (computername16.size()-1)*sizeof(char16_t), - "UTF-16LE"); - // Number of characters including null - computername16.resize(targetSize/sizeof(char16_t)+1); + // 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(); @@ -137,13 +128,14 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) // Set lpnSize if buffer is too small to inform user // of necessary size *lpnSize= size; - return 0; + return FALSE; } - // Copy bytes from string to buffer - memcpy(lpBuffer, &computername16[0], size*sizeof(char16_t)); + // Extract string as UTF-16LE to buffer + computername16.extract(0, size, reinterpret_cast(lpBuffer), "UTF-16LE"); + *lpnSize = size; - return 1; + return TRUE; } diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index a566d83cc..612655c22 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -6,10 +6,7 @@ #include #include #include -#include -#include -#include -#include +#include #include "getcomputername.h" //! Test fixture for GetComputerNameTest @@ -35,7 +32,7 @@ protected: { lpnSize = size; // allocate a DWORD buffer to receive computername - lpBuffer.assign(lpnSize, '\0'); + lpBuffer.assign(lpnSize, 0); result = GetComputerNameW(&lpBuffer[0], &lpnSize); } @@ -49,18 +46,15 @@ protected: //! Sets lpnSize to number of WCHARs including null. ASSERT_EQ(expectedSize, lpnSize); - // setup for conversion from UTF-16LE + // Read lpBuffer into UnicodeString (without null) const char* begin = reinterpret_cast(&lpBuffer[0]); - // multiply to get number of bytes - icu::UnicodeString usercomputer16(begin, lpnSize*sizeof(char16_t), "UTF-16LE"); - // username16 length includes null and is number of characters - ASSERT_EQ(expectedSize, usercomputer16.length()); + icu::UnicodeString computername16(begin, (lpnSize-1)*sizeof(UChar), "UTF-16LE"); + ASSERT_EQ(expectedComputerName.length(), computername16.length()); + // Convert to UTF-8 for comparison + std::string computername; + computername16.toUTF8String(computername); - // convert (minus null) to UTF-8 for comparison - std::string computername(lpnSize-1, 0); ASSERT_EQ(expectedComputerName.length(), computername.length()); - usercomputer16.extract(0, computername.length(), - reinterpret_cast(&computername[0]), "UTF-8"); //! Returned computername(after conversion) is what was expected. EXPECT_EQ(expectedComputerName, computername); From df8ab7f662657be1006da90ace47a7eacea3cb3b Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 14 Aug 2015 10:51:25 -0700 Subject: [PATCH 146/342] Changes to make converting beteween UTF8 and UTF16 --- src/impl/getcomputername.cpp | 44 ++++++++++++------------------ src/tests/test-getcomputername.cpp | 22 ++++++--------- 2 files changed, 26 insertions(+), 40 deletions(-) diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp index f930dc890..03a8cda0e 100644 --- a/src/impl/getcomputername.cpp +++ b/src/impl/getcomputername.cpp @@ -7,10 +7,7 @@ #include #include #include -#include -#include -#include -#include +#include #include "getcomputername.h" //! @brief GetComputerName retrieves the name of the host associated with @@ -51,12 +48,12 @@ //! - 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 +//! @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 0 If the function fails, the return value is zero. To get +//! @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 @@ -64,28 +61,27 @@ //! [LPTSTR]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx#LPTSTR BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) { - const std::string utf8 = "UTF-8"; errno = 0; // Check parameters if (!lpBuffer || !lpnSize) { errno = ERROR_INVALID_PARAMETER; - return 0; + return FALSE; } // Select locale from environment setlocale(LC_ALL, ""); // Check that locale is UTF-8 - if (nl_langinfo(CODESET) != utf8) + if (nl_langinfo(CODESET) != std::string("UTF-8")) { errno = ERROR_BAD_ENVIRONMENT; - return 0; + return FALSE; } // Get computername from system in a thread-safe manner - std::string computername(HOST_NAME_MAX, '\0'); - int err = gethostname(&computername[0], computername.size()); + std::string computername(HOST_NAME_MAX, 0); + int err = gethostname(&computername[0], computername.length()); // Map errno to Win32 Error Codes if (err != 0) { @@ -114,18 +110,13 @@ BOOL GetComputerNameW(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) - std::basic_string computername16(HOST_NAME_MAX + 1, 0); - icu::UnicodeString computername8(computername.c_str(), "UTF-8"); - int32_t targetSize = computername8.extract(0, computername8.length(), - reinterpret_cast(&computername16[0]), - (computername16.size()-1)*sizeof(char16_t), - "UTF-16LE"); - // Number of characters including null - computername16.resize(targetSize/sizeof(char16_t)+1); + // 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(); @@ -137,13 +128,14 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) // Set lpnSize if buffer is too small to inform user // of necessary size *lpnSize= size; - return 0; + return FALSE; } - // Copy bytes from string to buffer - memcpy(lpBuffer, &computername16[0], size*sizeof(char16_t)); + // Extract string as UTF-16LE to buffer + computername16.extract(0, size, reinterpret_cast(lpBuffer), "UTF-16LE"); + *lpnSize = size; - return 1; + return TRUE; } diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp index a566d83cc..612655c22 100644 --- a/src/tests/test-getcomputername.cpp +++ b/src/tests/test-getcomputername.cpp @@ -6,10 +6,7 @@ #include #include #include -#include -#include -#include -#include +#include #include "getcomputername.h" //! Test fixture for GetComputerNameTest @@ -35,7 +32,7 @@ protected: { lpnSize = size; // allocate a DWORD buffer to receive computername - lpBuffer.assign(lpnSize, '\0'); + lpBuffer.assign(lpnSize, 0); result = GetComputerNameW(&lpBuffer[0], &lpnSize); } @@ -49,18 +46,15 @@ protected: //! Sets lpnSize to number of WCHARs including null. ASSERT_EQ(expectedSize, lpnSize); - // setup for conversion from UTF-16LE + // Read lpBuffer into UnicodeString (without null) const char* begin = reinterpret_cast(&lpBuffer[0]); - // multiply to get number of bytes - icu::UnicodeString usercomputer16(begin, lpnSize*sizeof(char16_t), "UTF-16LE"); - // username16 length includes null and is number of characters - ASSERT_EQ(expectedSize, usercomputer16.length()); + icu::UnicodeString computername16(begin, (lpnSize-1)*sizeof(UChar), "UTF-16LE"); + ASSERT_EQ(expectedComputerName.length(), computername16.length()); + // Convert to UTF-8 for comparison + std::string computername; + computername16.toUTF8String(computername); - // convert (minus null) to UTF-8 for comparison - std::string computername(lpnSize-1, 0); ASSERT_EQ(expectedComputerName.length(), computername.length()); - usercomputer16.extract(0, computername.length(), - reinterpret_cast(&computername[0]), "UTF-8"); //! Returned computername(after conversion) is what was expected. EXPECT_EQ(expectedComputerName, computername); From 2241d63a28e7813e210bab4884f05a14b66c3b6a Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 14 Aug 2015 11:27:22 -0700 Subject: [PATCH 147/342] No longer defining LPSTR --- impl/pal.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/impl/pal.h b/impl/pal.h index 17e58d409..f30903a2f 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -62,8 +62,6 @@ typedef char *PSTR; typedef void *PVOID; typedef PVOID HANDLE; - typedef char TCHAR; - typedef char* LPTSTR; #define NO_ERROR 0 #define INFINITE 0xFFFFFFFF #define WINAPI From 18e8bb1dfa0d19614fe5db095884b54be70c80ab Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 14 Aug 2015 11:27:22 -0700 Subject: [PATCH 148/342] No longer defining LPSTR --- src/impl/pal.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/impl/pal.h b/src/impl/pal.h index 17e58d409..f30903a2f 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -62,8 +62,6 @@ typedef char *PSTR; typedef void *PVOID; typedef PVOID HANDLE; - typedef char TCHAR; - typedef char* LPTSTR; #define NO_ERROR 0 #define INFINITE 0xFFFFFFFF #define WINAPI From d2f7ba1cb48e25f1c877cf0ebb95f737b34599f5 Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 14 Aug 2015 12:26:15 -0700 Subject: [PATCH 149/342] implemented suggested changes based off of feedback --- src/impl/getcpinfo.cpp | 2 +- src/impl/pal.h | 16 ++-------------- src/tests/test-getcpinfo.cpp | 2 +- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/impl/getcpinfo.cpp b/src/impl/getcpinfo.cpp index 478632772..49e2ce801 100644 --- a/src/impl/getcpinfo.cpp +++ b/src/impl/getcpinfo.cpp @@ -55,7 +55,7 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) return 0; } - //if codepage is utf8 + // if codepage is utf8 if(codepage == 65001) { cpinfo->DefaultChar[0] = '?'; diff --git a/src/impl/pal.h b/src/impl/pal.h index 0999c7882..26095179e 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -598,26 +598,14 @@ typedef unsigned char PAL_Boolean; # define PAL_COUNT(ARR) (sizeof(ARR) / sizeof(ARR[0])) #endif -/* -**============================================================================== -** -** NameSpace -** -**============================================================================== -*/ +//!* NameSpace namespace const_cpinfo{ constexpr int MAX_DEFAULTCHAR = 2; constexpr int MAX_LEADBYTES = 12; } -/* -**============================================================================== -** -** Structs -** -**============================================================================== -*/ +//!* Structs typedef struct _cpinfo { UINT MaxCharSize; diff --git a/src/tests/test-getcpinfo.cpp b/src/tests/test-getcpinfo.cpp index 90f64deff..582620cdf 100644 --- a/src/tests/test-getcpinfo.cpp +++ b/src/tests/test-getcpinfo.cpp @@ -30,7 +30,7 @@ TEST(GetCPInfo, CodePageNotUTF8) CPINFO* cpinfo; BOOL result = GetCPInfoW(65000, cpinfo); - ASSERT_TRUE(result == FALSE); + ASSERT_EQ(result, FALSE); EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); } \ No newline at end of file From d7355a0572f86cae3bd2374b1e0e997cafe9b645 Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 14 Aug 2015 12:26:15 -0700 Subject: [PATCH 150/342] implemented suggested changes based off of feedback --- impl/getcpinfo.cpp | 2 +- impl/pal.h | 16 ++-------------- tests/test-getcpinfo.cpp | 2 +- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/impl/getcpinfo.cpp b/impl/getcpinfo.cpp index 478632772..49e2ce801 100644 --- a/impl/getcpinfo.cpp +++ b/impl/getcpinfo.cpp @@ -55,7 +55,7 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) return 0; } - //if codepage is utf8 + // if codepage is utf8 if(codepage == 65001) { cpinfo->DefaultChar[0] = '?'; diff --git a/impl/pal.h b/impl/pal.h index 0999c7882..26095179e 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -598,26 +598,14 @@ typedef unsigned char PAL_Boolean; # define PAL_COUNT(ARR) (sizeof(ARR) / sizeof(ARR[0])) #endif -/* -**============================================================================== -** -** NameSpace -** -**============================================================================== -*/ +//!* NameSpace namespace const_cpinfo{ constexpr int MAX_DEFAULTCHAR = 2; constexpr int MAX_LEADBYTES = 12; } -/* -**============================================================================== -** -** Structs -** -**============================================================================== -*/ +//!* Structs typedef struct _cpinfo { UINT MaxCharSize; diff --git a/tests/test-getcpinfo.cpp b/tests/test-getcpinfo.cpp index 90f64deff..582620cdf 100644 --- a/tests/test-getcpinfo.cpp +++ b/tests/test-getcpinfo.cpp @@ -30,7 +30,7 @@ TEST(GetCPInfo, CodePageNotUTF8) CPINFO* cpinfo; BOOL result = GetCPInfoW(65000, cpinfo); - ASSERT_TRUE(result == FALSE); + ASSERT_EQ(result, FALSE); EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); } \ No newline at end of file From e4fd76b7398ec4657ea014ac7f28a19dbb0077c7 Mon Sep 17 00:00:00 2001 From: Aaron Date: Mon, 17 Aug 2015 17:02:40 -0700 Subject: [PATCH 151/342] Added changed from feedback from Andy --- CMakeLists.txt | 2 +- impl/getcomputername.cpp | 24 +++++------------------ impl/pal.h | 2 ++ tests/test-getcomputername.cpp | 36 +++++++++++++++++++--------------- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ee935bc3..d799e590b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ link_directories(${monad_native_BINARY_DIR}) set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp impl/getcomputername.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-getusername.cpp tests/test-getcomputername ${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 ${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}) diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp index 03a8cda0e..364179aa1 100644 --- a/impl/getcomputername.cpp +++ b/impl/getcomputername.cpp @@ -87,26 +87,12 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) { switch (errno) { - case EMFILE: - case ENFILE: - errno = ERROR_TOO_MANY_OPEN_FILES; + case EFAULT: + errno = ERROR_INVALID_ADDRESS; break; - case ENXIO: - errno = ERROR_NO_ASSOCIATION; - break; - case ERANGE: - errno = ERROR_INSUFFICIENT_BUFFER; - break; - case ENOENT: - errno = ERROR_NO_SUCH_USER; - break; - case ENOMEM: - errno = ERROR_OUTOFMEMORY; - break; - case ENOTTY: - errno = ERROR_NO_ASSOCIATION; - break; - errno = ERROR_NO_ASSOCIATION; + case ENAMETOOLONG: + errno = ERROR_BUFFER_OVERFLOW; + break; default: errno = ERROR_INVALID_FUNCTION; } diff --git a/impl/pal.h b/impl/pal.h index f30903a2f..3ef233fd6 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -78,6 +78,8 @@ #define ERROR_NO_SUCH_USER 0x00000525 #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 + #define ERROR_INVALID_ADDRESS 0x1e7 + #define ERROR_BUFFER_OVERFLOW 0x6F typedef unsigned long long uint64; #endif diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index 612655c22..21e8c5382 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -3,6 +3,7 @@ //! @brief Unit tests for GetComputerNameW #include +#include #include #include #include @@ -21,17 +22,21 @@ protected: //Get expected result from using linux call GetComputerNameTest() - { - char hostname[HOST_NAME_MAX]; - BOOL host = gethostname(hostname, sizeof hostname); - expectedComputerName = hostname; - expectedSize = expectedComputerName.length() + 1; + { + expectedComputerName.resize(HOST_NAME_MAX); + BOOL ret = gethostname(&expectedComputerName[0], expectedComputerName.length()); + EXPECT_EQ(ret, 0); + 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; - // allocate a DWORD buffer to receive computername lpBuffer.assign(lpnSize, 0); result = GetComputerNameW(&lpBuffer[0], &lpnSize); } @@ -49,12 +54,11 @@ protected: // Read lpBuffer into UnicodeString (without null) const char* begin = reinterpret_cast(&lpBuffer[0]); icu::UnicodeString computername16(begin, (lpnSize-1)*sizeof(UChar), "UTF-16LE"); - ASSERT_EQ(expectedComputerName.length(), computername16.length()); // Convert to UTF-8 for comparison std::string computername; computername16.toUTF8String(computername); - ASSERT_EQ(expectedComputerName.length(), computername.length()); + ASSERT_EQ(expectedSize, computername.length() + 1); //! Returned computername(after conversion) is what was expected. EXPECT_EQ(expectedComputerName, computername); @@ -64,8 +68,8 @@ protected: { 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 EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); @@ -75,14 +79,14 @@ protected: { SCOPED_TRACE(""); - // returns 0 on failure - EXPECT_EQ(0, result); + // 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(expectedComputerName.size()+1, lpnSize); + ASSERT_EQ(expectedSize, lpnSize); } }; @@ -111,14 +115,14 @@ TEST_F(GetComputerNameTest, BufferSizeAsZero) TEST_F(GetComputerNameTest, BufferSizeAsUserNameMinusOne) { // the buffer is also too small - TestWithSize(expectedComputerName.size()-1); + TestWithSize(expectedSize-1); TestInsufficientBuffer(); } TEST_F(GetComputerNameTest, BufferSizeAsUserNamePlusOne) { // the buffer is exactly big enough - TestWithSize(expectedComputerName.size()+1); + TestWithSize(expectedSize+1); TestSuccess(); } From f62c92432b3f86f9f239c78b518cddb811573735 Mon Sep 17 00:00:00 2001 From: Aaron Date: Mon, 17 Aug 2015 17:02:40 -0700 Subject: [PATCH 152/342] Added changed from feedback from Andy --- src/CMakeLists.txt | 2 +- src/impl/getcomputername.cpp | 24 +++++--------------- src/impl/pal.h | 2 ++ src/tests/test-getcomputername.cpp | 36 +++++++++++++++++------------- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5ee935bc3..d799e590b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,7 +11,7 @@ link_directories(${monad_native_BINARY_DIR}) set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp impl/getcomputername.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-getusername.cpp tests/test-getcomputername ${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 ${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}) diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp index 03a8cda0e..364179aa1 100644 --- a/src/impl/getcomputername.cpp +++ b/src/impl/getcomputername.cpp @@ -87,26 +87,12 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) { switch (errno) { - case EMFILE: - case ENFILE: - errno = ERROR_TOO_MANY_OPEN_FILES; + case EFAULT: + errno = ERROR_INVALID_ADDRESS; break; - case ENXIO: - errno = ERROR_NO_ASSOCIATION; - break; - case ERANGE: - errno = ERROR_INSUFFICIENT_BUFFER; - break; - case ENOENT: - errno = ERROR_NO_SUCH_USER; - break; - case ENOMEM: - errno = ERROR_OUTOFMEMORY; - break; - case ENOTTY: - errno = ERROR_NO_ASSOCIATION; - break; - errno = ERROR_NO_ASSOCIATION; + case ENAMETOOLONG: + errno = ERROR_BUFFER_OVERFLOW; + break; default: errno = ERROR_INVALID_FUNCTION; } diff --git a/src/impl/pal.h b/src/impl/pal.h index f30903a2f..3ef233fd6 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -78,6 +78,8 @@ #define ERROR_NO_SUCH_USER 0x00000525 #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 + #define ERROR_INVALID_ADDRESS 0x1e7 + #define ERROR_BUFFER_OVERFLOW 0x6F typedef unsigned long long uint64; #endif diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp index 612655c22..21e8c5382 100644 --- a/src/tests/test-getcomputername.cpp +++ b/src/tests/test-getcomputername.cpp @@ -3,6 +3,7 @@ //! @brief Unit tests for GetComputerNameW #include +#include #include #include #include @@ -21,17 +22,21 @@ protected: //Get expected result from using linux call GetComputerNameTest() - { - char hostname[HOST_NAME_MAX]; - BOOL host = gethostname(hostname, sizeof hostname); - expectedComputerName = hostname; - expectedSize = expectedComputerName.length() + 1; + { + expectedComputerName.resize(HOST_NAME_MAX); + BOOL ret = gethostname(&expectedComputerName[0], expectedComputerName.length()); + EXPECT_EQ(ret, 0); + 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; - // allocate a DWORD buffer to receive computername lpBuffer.assign(lpnSize, 0); result = GetComputerNameW(&lpBuffer[0], &lpnSize); } @@ -49,12 +54,11 @@ protected: // Read lpBuffer into UnicodeString (without null) const char* begin = reinterpret_cast(&lpBuffer[0]); icu::UnicodeString computername16(begin, (lpnSize-1)*sizeof(UChar), "UTF-16LE"); - ASSERT_EQ(expectedComputerName.length(), computername16.length()); // Convert to UTF-8 for comparison std::string computername; computername16.toUTF8String(computername); - ASSERT_EQ(expectedComputerName.length(), computername.length()); + ASSERT_EQ(expectedSize, computername.length() + 1); //! Returned computername(after conversion) is what was expected. EXPECT_EQ(expectedComputerName, computername); @@ -64,8 +68,8 @@ protected: { 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 EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); @@ -75,14 +79,14 @@ protected: { SCOPED_TRACE(""); - // returns 0 on failure - EXPECT_EQ(0, result); + // 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(expectedComputerName.size()+1, lpnSize); + ASSERT_EQ(expectedSize, lpnSize); } }; @@ -111,14 +115,14 @@ TEST_F(GetComputerNameTest, BufferSizeAsZero) TEST_F(GetComputerNameTest, BufferSizeAsUserNameMinusOne) { // the buffer is also too small - TestWithSize(expectedComputerName.size()-1); + TestWithSize(expectedSize-1); TestInsufficientBuffer(); } TEST_F(GetComputerNameTest, BufferSizeAsUserNamePlusOne) { // the buffer is exactly big enough - TestWithSize(expectedComputerName.size()+1); + TestWithSize(expectedSize+1); TestSuccess(); } From ca4504ec0a61d474e23c047006b0742e4f238a75 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 20 Aug 2015 14:40:02 -0700 Subject: [PATCH 153/342] changes back on feedback from pull request --- src/impl/getcpinfo.cpp | 74 +++++++++++++++++++++++++++--------- src/impl/pal.h | 1 + src/tests/test-getcpinfo.cpp | 19 ++++----- 3 files changed, 66 insertions(+), 28 deletions(-) diff --git a/src/impl/getcpinfo.cpp b/src/impl/getcpinfo.cpp index 49e2ce801..09ac0183a 100644 --- a/src/impl/getcpinfo.cpp +++ b/src/impl/getcpinfo.cpp @@ -16,6 +16,8 @@ //! @parblock //! An UINT Identifier for the code page for which to retrieve information. //! See Code Page Identifiers for details +//! 65001 in the number for UTF8. It is the only valid inpur parameter +//!because Linux and Unix only use UTF8 for codepage //! //! @endparblock //! @@ -26,14 +28,45 @@ //! LPCPINFO is a pointer to the structure _cpinfo used to contain the information //! about a code page //! +//! _cpinfo is a struct that comprises +//! +//! UINT MaxCharSize; +//! Maximum length, in bytes, of a character in the code page. +//! The length can be 1 for a single-byte character set (SBCS), +//! 2 for a double-byte character set (DBCS), or a value larger +//! than 2 for other character set types. The function cannot +//! use the size to distinguish an SBCS or a DBCS from other +//! character sets because of other factors, for example, +//! the use of ISCII or ISO-2022-xx code pages. +//! +//! BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; +//! Default character used when translating character +//! strings to the specific code page. This character is used by +//! the WideCharToMultiByte function if an explicit default +//! character is not specified. The default is usually the "?" +//! character for the code page +//! +//! BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; +//! A fixed-length array of lead byte ranges, for which the number +//! of lead byte ranges is variable. If the code page has no lead +//! bytes, every element of the array is set to NULL. If the code +//! page has lead bytes, the array specifies a starting value and +//! an ending value for each range. Ranges are inclusive, and the +//! maximum number of ranges for any code page is five. The array +//! uses two bytes to describe each range, with two null bytes as +//! a terminator after the last range. +//! +//! MAX_DEFAULTCHAR is an int of size 2 +//! MAX_LEADBYTES is an int of size 12 +//! //! //! @exception errno Passes these errors via errno to GetLastError: //! - ERROR_INVALID_PARAMETER: parameter is not valid //! -//! @retval 1 If the function succeeds, the return value is a nonzero +//! @retval TRUE If the function succeeds, the return value is a nonzero //! value, and cpinfo is population with information about the code page //! -//! @retval 0 If the function fails, the return value is zero. To get +//! @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/dd318078%28v=vs.85%29.aspx @@ -42,34 +75,37 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) { - - const std::string utf8 = "UTF-8"; - errno = 0; + errno = FALSE; // Select locale from environment setlocale(LC_ALL, ""); + // Check that locale is UTF-8 - if (nl_langinfo(CODESET) != utf8) + if (nl_langinfo(CODESET) != std::string("UTF-8")) { errno = ERROR_BAD_ENVIRONMENT; - return 0; + return FALSE; } - // if codepage is utf8 - if(codepage == 65001) - { - cpinfo->DefaultChar[0] = '?'; - cpinfo->DefaultChar[1] = '0'; - cpinfo->MaxCharSize = 4; - for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ){ - cpinfo->LeadByte[i] = '0'; - } - return TRUE; - } - else + // 65001 is the code page for UTF8, Linux and Unix default it UTF8 + if (codepage != const_cpinfo::UTF8) { + //If other value is used return error because Linux and Unix only used UTF-8 for codepage errno = ERROR_INVALID_PARAMETER; return FALSE; } + + // UTF-8 uses the default char for DefaultChar[0] which is '?' + cpinfo->DefaultChar[0] = '?'; + cpinfo->DefaultChar[1] = '0'; + cpinfo->MaxCharSize = 4; + for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) + { + // UTF-8 uses the default has no LeadByte as result LeadByte is '0' + cpinfo->LeadByte[i] = '0'; + + } + return TRUE; + } diff --git a/src/impl/pal.h b/src/impl/pal.h index 26095179e..d07e4c026 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -603,6 +603,7 @@ typedef unsigned char PAL_Boolean; namespace const_cpinfo{ constexpr int MAX_DEFAULTCHAR = 2; constexpr int MAX_LEADBYTES = 12; + constexpr int UTF8 = 65001; } //!* Structs diff --git a/src/tests/test-getcpinfo.cpp b/src/tests/test-getcpinfo.cpp index 582620cdf..34c061eb6 100644 --- a/src/tests/test-getcpinfo.cpp +++ b/src/tests/test-getcpinfo.cpp @@ -9,18 +9,19 @@ TEST(GetCPInfo,Utf8) { CPINFO* cpinfo; - int UTF8CodePageNumber = 65001; + int UTF8CodePageNumber = const_cpinfo::UTF8; BOOL result = GetCPInfoW(UTF8CodePageNumber, cpinfo); // first make sure that the function worked - ASSERT_EQ(result, TRUE); + ASSERT_EQ(TRUE, result); // now compare the actual values - ASSERT_EQ(cpinfo->DefaultChar[0],'?'); - ASSERT_EQ(cpinfo->DefaultChar[1],'0'); - ASSERT_EQ(cpinfo->MaxCharSize,4); - for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ){ - ASSERT_EQ(cpinfo->LeadByte[i],'0'); + EXPECT_EQ(cpinfo->DefaultChar[0], '?'); + EXPECT_EQ(cpinfo->DefaultChar[1], '0'); + EXPECT_EQ(cpinfo->MaxCharSize,4); + for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) + { + EXPECT_EQ(cpinfo->LeadByte[i], '0'); } } @@ -30,7 +31,7 @@ TEST(GetCPInfo, CodePageNotUTF8) CPINFO* cpinfo; BOOL result = GetCPInfoW(65000, cpinfo); - ASSERT_EQ(result, FALSE); - EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); + ASSERT_EQ(FALSE, result); + ASSERT_EQ(errno, ERROR_INVALID_PARAMETER); } \ No newline at end of file From 50f9af1bd3057f82d27bfa0407bd3e6e9fcfd311 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 20 Aug 2015 14:40:02 -0700 Subject: [PATCH 154/342] changes back on feedback from pull request --- impl/getcpinfo.cpp | 74 +++++++++++++++++++++++++++++----------- impl/pal.h | 1 + tests/test-getcpinfo.cpp | 19 ++++++----- 3 files changed, 66 insertions(+), 28 deletions(-) diff --git a/impl/getcpinfo.cpp b/impl/getcpinfo.cpp index 49e2ce801..09ac0183a 100644 --- a/impl/getcpinfo.cpp +++ b/impl/getcpinfo.cpp @@ -16,6 +16,8 @@ //! @parblock //! An UINT Identifier for the code page for which to retrieve information. //! See Code Page Identifiers for details +//! 65001 in the number for UTF8. It is the only valid inpur parameter +//!because Linux and Unix only use UTF8 for codepage //! //! @endparblock //! @@ -26,14 +28,45 @@ //! LPCPINFO is a pointer to the structure _cpinfo used to contain the information //! about a code page //! +//! _cpinfo is a struct that comprises +//! +//! UINT MaxCharSize; +//! Maximum length, in bytes, of a character in the code page. +//! The length can be 1 for a single-byte character set (SBCS), +//! 2 for a double-byte character set (DBCS), or a value larger +//! than 2 for other character set types. The function cannot +//! use the size to distinguish an SBCS or a DBCS from other +//! character sets because of other factors, for example, +//! the use of ISCII or ISO-2022-xx code pages. +//! +//! BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; +//! Default character used when translating character +//! strings to the specific code page. This character is used by +//! the WideCharToMultiByte function if an explicit default +//! character is not specified. The default is usually the "?" +//! character for the code page +//! +//! BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; +//! A fixed-length array of lead byte ranges, for which the number +//! of lead byte ranges is variable. If the code page has no lead +//! bytes, every element of the array is set to NULL. If the code +//! page has lead bytes, the array specifies a starting value and +//! an ending value for each range. Ranges are inclusive, and the +//! maximum number of ranges for any code page is five. The array +//! uses two bytes to describe each range, with two null bytes as +//! a terminator after the last range. +//! +//! MAX_DEFAULTCHAR is an int of size 2 +//! MAX_LEADBYTES is an int of size 12 +//! //! //! @exception errno Passes these errors via errno to GetLastError: //! - ERROR_INVALID_PARAMETER: parameter is not valid //! -//! @retval 1 If the function succeeds, the return value is a nonzero +//! @retval TRUE If the function succeeds, the return value is a nonzero //! value, and cpinfo is population with information about the code page //! -//! @retval 0 If the function fails, the return value is zero. To get +//! @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/dd318078%28v=vs.85%29.aspx @@ -42,34 +75,37 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) { - - const std::string utf8 = "UTF-8"; - errno = 0; + errno = FALSE; // Select locale from environment setlocale(LC_ALL, ""); + // Check that locale is UTF-8 - if (nl_langinfo(CODESET) != utf8) + if (nl_langinfo(CODESET) != std::string("UTF-8")) { errno = ERROR_BAD_ENVIRONMENT; - return 0; + return FALSE; } - // if codepage is utf8 - if(codepage == 65001) - { - cpinfo->DefaultChar[0] = '?'; - cpinfo->DefaultChar[1] = '0'; - cpinfo->MaxCharSize = 4; - for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ){ - cpinfo->LeadByte[i] = '0'; - } - return TRUE; - } - else + // 65001 is the code page for UTF8, Linux and Unix default it UTF8 + if (codepage != const_cpinfo::UTF8) { + //If other value is used return error because Linux and Unix only used UTF-8 for codepage errno = ERROR_INVALID_PARAMETER; return FALSE; } + + // UTF-8 uses the default char for DefaultChar[0] which is '?' + cpinfo->DefaultChar[0] = '?'; + cpinfo->DefaultChar[1] = '0'; + cpinfo->MaxCharSize = 4; + for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) + { + // UTF-8 uses the default has no LeadByte as result LeadByte is '0' + cpinfo->LeadByte[i] = '0'; + + } + return TRUE; + } diff --git a/impl/pal.h b/impl/pal.h index 26095179e..d07e4c026 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -603,6 +603,7 @@ typedef unsigned char PAL_Boolean; namespace const_cpinfo{ constexpr int MAX_DEFAULTCHAR = 2; constexpr int MAX_LEADBYTES = 12; + constexpr int UTF8 = 65001; } //!* Structs diff --git a/tests/test-getcpinfo.cpp b/tests/test-getcpinfo.cpp index 582620cdf..34c061eb6 100644 --- a/tests/test-getcpinfo.cpp +++ b/tests/test-getcpinfo.cpp @@ -9,18 +9,19 @@ TEST(GetCPInfo,Utf8) { CPINFO* cpinfo; - int UTF8CodePageNumber = 65001; + int UTF8CodePageNumber = const_cpinfo::UTF8; BOOL result = GetCPInfoW(UTF8CodePageNumber, cpinfo); // first make sure that the function worked - ASSERT_EQ(result, TRUE); + ASSERT_EQ(TRUE, result); // now compare the actual values - ASSERT_EQ(cpinfo->DefaultChar[0],'?'); - ASSERT_EQ(cpinfo->DefaultChar[1],'0'); - ASSERT_EQ(cpinfo->MaxCharSize,4); - for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ){ - ASSERT_EQ(cpinfo->LeadByte[i],'0'); + EXPECT_EQ(cpinfo->DefaultChar[0], '?'); + EXPECT_EQ(cpinfo->DefaultChar[1], '0'); + EXPECT_EQ(cpinfo->MaxCharSize,4); + for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) + { + EXPECT_EQ(cpinfo->LeadByte[i], '0'); } } @@ -30,7 +31,7 @@ TEST(GetCPInfo, CodePageNotUTF8) CPINFO* cpinfo; BOOL result = GetCPInfoW(65000, cpinfo); - ASSERT_EQ(result, FALSE); - EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); + ASSERT_EQ(FALSE, result); + ASSERT_EQ(errno, ERROR_INVALID_PARAMETER); } \ No newline at end of file From 23ad440cfc5d6cd6f7bce5b93bed616d16ba1854 Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 21 Aug 2015 09:55:39 -0700 Subject: [PATCH 155/342] made changes based on feedback from pull request --- impl/getcomputername.cpp | 2 +- impl/pal.h | 4 ++-- tests/test-getcomputername.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/impl/getcomputername.cpp b/impl/getcomputername.cpp index 364179aa1..818623ddf 100644 --- a/impl/getcomputername.cpp +++ b/impl/getcomputername.cpp @@ -91,7 +91,7 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) errno = ERROR_INVALID_ADDRESS; break; case ENAMETOOLONG: - errno = ERROR_BUFFER_OVERFLOW; + errno = ERROR_GEN_FAILURE; break; default: errno = ERROR_INVALID_FUNCTION; diff --git a/impl/pal.h b/impl/pal.h index 3ef233fd6..8bf54dbce 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -78,8 +78,8 @@ #define ERROR_NO_SUCH_USER 0x00000525 #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 - #define ERROR_INVALID_ADDRESS 0x1e7 - #define ERROR_BUFFER_OVERFLOW 0x6F + #define ERROR_INVALID_ADDRESS 0x000001e7 + #define ERROR_GEN_FAILURE 0x0000001F typedef unsigned long long uint64; #endif diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index 21e8c5382..51ebd0ccc 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -25,7 +25,7 @@ protected: { expectedComputerName.resize(HOST_NAME_MAX); BOOL ret = gethostname(&expectedComputerName[0], expectedComputerName.length()); - EXPECT_EQ(ret, 0); + EXPECT_EQ(0, ret); expectedSize = std::strlen(expectedComputerName.c_str()) + 1; expectedComputerName.resize(expectedSize - 1); } From e1d4d14028f9f6e0ee846388220883a1ab65b2cc Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 21 Aug 2015 09:55:39 -0700 Subject: [PATCH 156/342] made changes based on feedback from pull request --- src/impl/getcomputername.cpp | 2 +- src/impl/pal.h | 4 ++-- src/tests/test-getcomputername.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/impl/getcomputername.cpp b/src/impl/getcomputername.cpp index 364179aa1..818623ddf 100644 --- a/src/impl/getcomputername.cpp +++ b/src/impl/getcomputername.cpp @@ -91,7 +91,7 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) errno = ERROR_INVALID_ADDRESS; break; case ENAMETOOLONG: - errno = ERROR_BUFFER_OVERFLOW; + errno = ERROR_GEN_FAILURE; break; default: errno = ERROR_INVALID_FUNCTION; diff --git a/src/impl/pal.h b/src/impl/pal.h index 3ef233fd6..8bf54dbce 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -78,8 +78,8 @@ #define ERROR_NO_SUCH_USER 0x00000525 #define ERROR_INVALID_FUNCTION 0x00000001 #define MAX_PATH 0x00000104 - #define ERROR_INVALID_ADDRESS 0x1e7 - #define ERROR_BUFFER_OVERFLOW 0x6F + #define ERROR_INVALID_ADDRESS 0x000001e7 + #define ERROR_GEN_FAILURE 0x0000001F typedef unsigned long long uint64; #endif diff --git a/src/tests/test-getcomputername.cpp b/src/tests/test-getcomputername.cpp index 21e8c5382..51ebd0ccc 100644 --- a/src/tests/test-getcomputername.cpp +++ b/src/tests/test-getcomputername.cpp @@ -25,7 +25,7 @@ protected: { expectedComputerName.resize(HOST_NAME_MAX); BOOL ret = gethostname(&expectedComputerName[0], expectedComputerName.length()); - EXPECT_EQ(ret, 0); + EXPECT_EQ(0, ret); expectedSize = std::strlen(expectedComputerName.c_str()) + 1; expectedComputerName.resize(expectedSize - 1); } From 24f0f853a8319f21d7082cb847d3ec069fedb51d Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Wed, 29 Jul 2015 15:04:34 +0200 Subject: [PATCH 157/342] added testing code to call into Main --- host/cmdline/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 740d99185..7ae1936ff 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -410,6 +410,13 @@ int main(int argc, char** argv) } loaderDelegate(psBasePath16.c_str()); + // NOTE: + // this code is intended for testing purposes only, it calls into the Main + // function of the powershell-simple.exe assembly, because that's what would + // be nice to have. + unsigned int exitCode2; + executeAssembly(hostHandle,domainId,args.argc,(const char**)args.argv,(currentDirAbsolutePath+"/powershell-simple.exe").c_str(),&exitCode2); + // call the unmanaged entry point for PowerShell typedef int (*UnmanagedMain)(int argc, char const* const* argv); UnmanagedMain unmanagedMain = nullptr; From 4ffb564dbd2e4308ae0d62fecbf96f042c64008e Mon Sep 17 00:00:00 2001 From: Peter Honeder Date: Wed, 29 Jul 2015 15:04:34 +0200 Subject: [PATCH 158/342] added testing code to call into Main --- src/host/cmdline/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 740d99185..7ae1936ff 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -410,6 +410,13 @@ int main(int argc, char** argv) } loaderDelegate(psBasePath16.c_str()); + // NOTE: + // this code is intended for testing purposes only, it calls into the Main + // function of the powershell-simple.exe assembly, because that's what would + // be nice to have. + unsigned int exitCode2; + executeAssembly(hostHandle,domainId,args.argc,(const char**)args.argv,(currentDirAbsolutePath+"/powershell-simple.exe").c_str(),&exitCode2); + // call the unmanaged entry point for PowerShell typedef int (*UnmanagedMain)(int argc, char const* const* argv); UnmanagedMain unmanagedMain = nullptr; From 46d3894c02983774df8948e858606283de5c6d01 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 21 Aug 2015 16:17:16 -0700 Subject: [PATCH 159/342] Call into Main of PowerShell assembly Instead of UnmanagedMain. Requires patch to CoreCLR (submitted upstream but backported until we've integrated their work). --- host/cmdline/main.cpp | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 7ae1936ff..0c0545377 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -410,30 +410,12 @@ int main(int argc, char** argv) } loaderDelegate(psBasePath16.c_str()); - // NOTE: - // this code is intended for testing purposes only, it calls into the Main - // function of the powershell-simple.exe assembly, because that's what would - // be nice to have. - unsigned int exitCode2; - executeAssembly(hostHandle,domainId,args.argc,(const char**)args.argv,(currentDirAbsolutePath+"/powershell-simple.exe").c_str(),&exitCode2); - - // 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+"/powershell-simple.exe").c_str(), + &exitCode); // shutdown CoreCLR status = shutdownCoreCLR(hostHandle,domainId); From 5d117330a8a68349bbfce088653e833ceea877f9 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 21 Aug 2015 16:17:16 -0700 Subject: [PATCH 160/342] Call into Main of PowerShell assembly Instead of UnmanagedMain. Requires patch to CoreCLR (submitted upstream but backported until we've integrated their work). --- src/host/cmdline/main.cpp | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 7ae1936ff..0c0545377 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -410,30 +410,12 @@ int main(int argc, char** argv) } loaderDelegate(psBasePath16.c_str()); - // NOTE: - // this code is intended for testing purposes only, it calls into the Main - // function of the powershell-simple.exe assembly, because that's what would - // be nice to have. - unsigned int exitCode2; - executeAssembly(hostHandle,domainId,args.argc,(const char**)args.argv,(currentDirAbsolutePath+"/powershell-simple.exe").c_str(),&exitCode2); - - // 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+"/powershell-simple.exe").c_str(), + &exitCode); // shutdown CoreCLR status = shutdownCoreCLR(hostHandle,domainId); From 42ce3fa48bb6186876cc563e86c24998a1084657 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 21 Aug 2015 17:39:52 -0700 Subject: [PATCH 161/342] Remove type_name and function_name from host Custom hosting code was refactored to take a path to an assembly instead of an assembly name coupled with a type and function to execute. Instead, the host now directly executes the given assembly, calling its Main function. The path is resolved relative to the current directory, as should be expected. --- host/cmdline/main.cpp | 49 ++++++++++++------------------------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 0c0545377..7cc4637ce 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -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; } @@ -414,7 +391,7 @@ int main(int argc, char** argv) unsigned int exitCode; executeAssembly(hostHandle, domainId, args.argc, (const char**)args.argv, - (currentDirAbsolutePath+"/powershell-simple.exe").c_str(), + (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), &exitCode); // shutdown CoreCLR From 440cf6a236067eba2d5dcfd5e3707a36295cee97 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 21 Aug 2015 17:39:52 -0700 Subject: [PATCH 162/342] Remove type_name and function_name from host Custom hosting code was refactored to take a path to an assembly instead of an assembly name coupled with a type and function to execute. Instead, the host now directly executes the given assembly, calling its Main function. The path is resolved relative to the current directory, as should be expected. --- src/host/cmdline/main.cpp | 49 +++++++++++---------------------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 0c0545377..7cc4637ce 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -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; } @@ -414,7 +391,7 @@ int main(int argc, char** argv) unsigned int exitCode; executeAssembly(hostHandle, domainId, args.argc, (const char**)args.argv, - (currentDirAbsolutePath+"/powershell-simple.exe").c_str(), + (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), &exitCode); // shutdown CoreCLR From c9164d5401eb970672fbf40f0b0a02f421803806 Mon Sep 17 00:00:00 2001 From: Aaron Date: Tue, 25 Aug 2015 13:47:39 -0700 Subject: [PATCH 163/342] made changes based on feedback from pull request --- src/tests/test-getcpinfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/test-getcpinfo.cpp b/src/tests/test-getcpinfo.cpp index 34c061eb6..108819d9b 100644 --- a/src/tests/test-getcpinfo.cpp +++ b/src/tests/test-getcpinfo.cpp @@ -19,7 +19,7 @@ TEST(GetCPInfo,Utf8) EXPECT_EQ(cpinfo->DefaultChar[0], '?'); EXPECT_EQ(cpinfo->DefaultChar[1], '0'); EXPECT_EQ(cpinfo->MaxCharSize,4); - for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) + for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++) { EXPECT_EQ(cpinfo->LeadByte[i], '0'); } @@ -32,6 +32,6 @@ TEST(GetCPInfo, CodePageNotUTF8) BOOL result = GetCPInfoW(65000, cpinfo); ASSERT_EQ(FALSE, result); - ASSERT_EQ(errno, ERROR_INVALID_PARAMETER); + ASSERT_EQ(ERROR_INVALID_PARAMETER, errno); } \ No newline at end of file From 8080e537869f4bac317850757ba0d4307e46390b Mon Sep 17 00:00:00 2001 From: Aaron Date: Tue, 25 Aug 2015 13:47:39 -0700 Subject: [PATCH 164/342] made changes based on feedback from pull request --- tests/test-getcpinfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-getcpinfo.cpp b/tests/test-getcpinfo.cpp index 34c061eb6..108819d9b 100644 --- a/tests/test-getcpinfo.cpp +++ b/tests/test-getcpinfo.cpp @@ -19,7 +19,7 @@ TEST(GetCPInfo,Utf8) EXPECT_EQ(cpinfo->DefaultChar[0], '?'); EXPECT_EQ(cpinfo->DefaultChar[1], '0'); EXPECT_EQ(cpinfo->MaxCharSize,4); - for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) + for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++) { EXPECT_EQ(cpinfo->LeadByte[i], '0'); } @@ -32,6 +32,6 @@ TEST(GetCPInfo, CodePageNotUTF8) BOOL result = GetCPInfoW(65000, cpinfo); ASSERT_EQ(FALSE, result); - ASSERT_EQ(errno, ERROR_INVALID_PARAMETER); + ASSERT_EQ(ERROR_INVALID_PARAMETER, errno); } \ No newline at end of file From 95060b345f4ea58d121029f4dc28606c5aaf8fbb Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 26 Aug 2015 11:55:58 -0700 Subject: [PATCH 165/342] Merge Conflict --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a4779bfb..003c9b985 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,7 +15,6 @@ set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp tests/test-getusername. 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}) From b6d880eab8941889af4e217ce502f3bada850c3b Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 26 Aug 2015 11:55:58 -0700 Subject: [PATCH 166/342] Merge Conflict --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a4779bfb..003c9b985 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,6 @@ set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp tests/test-getusername. 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}) From 5d59019d01e68a698cf6631a2a85c8b671b7cd3e Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 26 Aug 2015 13:03:51 -0700 Subject: [PATCH 167/342] Get rid of merge conflict --- src/impl/pal.h | 6 +++--- src/tests/test-getcpinfo.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/impl/pal.h b/src/impl/pal.h index 4947c1cac..0bb04f05a 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -601,9 +601,9 @@ typedef unsigned char PAL_Boolean; //!* NameSpace namespace const_cpinfo{ - constexpr int MAX_DEFAULTCHAR = 2; - constexpr int MAX_LEADBYTES = 12; - constexpr int UTF8 = 65001; + constexpr int MAX_DEFAULTCHAR = 2; + constexpr int MAX_LEADBYTES = 12; + constexpr int UTF8 = 65001; } //!* Structs diff --git a/src/tests/test-getcpinfo.cpp b/src/tests/test-getcpinfo.cpp index 108819d9b..3ec759645 100644 --- a/src/tests/test-getcpinfo.cpp +++ b/src/tests/test-getcpinfo.cpp @@ -19,7 +19,7 @@ TEST(GetCPInfo,Utf8) EXPECT_EQ(cpinfo->DefaultChar[0], '?'); EXPECT_EQ(cpinfo->DefaultChar[1], '0'); EXPECT_EQ(cpinfo->MaxCharSize,4); - for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++) + for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++) { EXPECT_EQ(cpinfo->LeadByte[i], '0'); } From 47628205193de763939de7ac289b0c1b5b96364d Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 26 Aug 2015 13:03:51 -0700 Subject: [PATCH 168/342] Get rid of merge conflict --- impl/pal.h | 6 +++--- tests/test-getcpinfo.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/impl/pal.h b/impl/pal.h index 4947c1cac..0bb04f05a 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -601,9 +601,9 @@ typedef unsigned char PAL_Boolean; //!* NameSpace namespace const_cpinfo{ - constexpr int MAX_DEFAULTCHAR = 2; - constexpr int MAX_LEADBYTES = 12; - constexpr int UTF8 = 65001; + constexpr int MAX_DEFAULTCHAR = 2; + constexpr int MAX_LEADBYTES = 12; + constexpr int UTF8 = 65001; } //!* Structs diff --git a/tests/test-getcpinfo.cpp b/tests/test-getcpinfo.cpp index 108819d9b..3ec759645 100644 --- a/tests/test-getcpinfo.cpp +++ b/tests/test-getcpinfo.cpp @@ -19,7 +19,7 @@ TEST(GetCPInfo,Utf8) EXPECT_EQ(cpinfo->DefaultChar[0], '?'); EXPECT_EQ(cpinfo->DefaultChar[1], '0'); EXPECT_EQ(cpinfo->MaxCharSize,4); - for(int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++) + for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++) { EXPECT_EQ(cpinfo->LeadByte[i], '0'); } From a7c773ec8ee73f2723dd1bc5e24fbdc439472d75 Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 26 Aug 2015 13:28:51 -0700 Subject: [PATCH 169/342] Merge Conflict --- src/impl/pal.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/impl/pal.h b/src/impl/pal.h index 0bb04f05a..8a2763600 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -600,7 +600,8 @@ typedef unsigned char PAL_Boolean; //!* NameSpace -namespace const_cpinfo{ +namespace const_cpinfo +{ constexpr int MAX_DEFAULTCHAR = 2; constexpr int MAX_LEADBYTES = 12; constexpr int UTF8 = 65001; @@ -608,7 +609,8 @@ namespace const_cpinfo{ //!* Structs -typedef struct _cpinfo { +typedef struct _cpinfo +{ UINT MaxCharSize; BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; From f32441327dd034567a6aaa6a037bb3b934c28aa3 Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 26 Aug 2015 13:28:51 -0700 Subject: [PATCH 170/342] Merge Conflict --- impl/pal.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/impl/pal.h b/impl/pal.h index 0bb04f05a..8a2763600 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -600,7 +600,8 @@ typedef unsigned char PAL_Boolean; //!* NameSpace -namespace const_cpinfo{ +namespace const_cpinfo +{ constexpr int MAX_DEFAULTCHAR = 2; constexpr int MAX_LEADBYTES = 12; constexpr int UTF8 = 65001; @@ -608,7 +609,8 @@ namespace const_cpinfo{ //!* Structs -typedef struct _cpinfo { +typedef struct _cpinfo +{ UINT MaxCharSize; BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; From b2d89ceba5d71336ee84560eae7950a366694c5b Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 26 Aug 2015 13:32:21 -0700 Subject: [PATCH 171/342] Deleted CMakeCache.txt --- src/CMakeCache.txt | 324 --------------------------------------------- 1 file changed, 324 deletions(-) delete mode 100644 src/CMakeCache.txt diff --git a/src/CMakeCache.txt b/src/CMakeCache.txt deleted file mode 100644 index 2f6e2fc4b..000000000 --- a/src/CMakeCache.txt +++ /dev/null @@ -1,324 +0,0 @@ -# This is the CMakeCache file. -# For build in directory: /home/aakatz/gitwd/monad-native/src -# It was generated by CMake: /usr/bin/cmake -# You can edit this file to change values found and used by cmake. -# If you do not want to change any of the values, simply exit the editor. -# If you do want to change a value, simply edit, save, and exit the editor. -# The syntax for the file is as follows: -# KEY:TYPE=VALUE -# KEY is the name of a variable in the cache. -# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. -# VALUE is the current value for the KEY. - -######################## -# EXTERNAL cache entries -######################## - -//Path to a program. -CMAKE_AR:FILEPATH=/usr/bin/ar - -//Choose the type of build, options are: None(CMAKE_CXX_FLAGS or -// CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel. -CMAKE_BUILD_TYPE:STRING= - -//Enable/Disable color output during build. -CMAKE_COLOR_MAKEFILE:BOOL=ON - -//CXX compiler. -CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++ - -//Flags used by the compiler during all build types. -CMAKE_CXX_FLAGS:STRING= - -//Flags used by the compiler during debug builds. -CMAKE_CXX_FLAGS_DEBUG:STRING=-g - -//Flags used by the compiler during release minsize builds. -CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG - -//Flags used by the compiler during release builds (/MD /Ob1 /Oi -// /Ot /Oy /Gs will produce slightly less optimized but smaller -// files). -CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG - -//Flags used by the compiler during Release with Debug Info builds. -CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG - -//C compiler. -CMAKE_C_COMPILER:FILEPATH=/usr/bin/cc - -//Flags used by the compiler during all build types. -CMAKE_C_FLAGS:STRING= - -//Flags used by the compiler during debug builds. -CMAKE_C_FLAGS_DEBUG:STRING=-g - -//Flags used by the compiler during release minsize builds. -CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG - -//Flags used by the compiler during release builds (/MD /Ob1 /Oi -// /Ot /Oy /Gs will produce slightly less optimized but smaller -// files). -CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG - -//Flags used by the compiler during Release with Debug Info builds. -CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG - -//Flags used by the linker. -CMAKE_EXE_LINKER_FLAGS:STRING=' ' - -//Flags used by the linker during debug builds. -CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during release minsize builds. -CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during release builds. -CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during Release with Debug Info builds. -CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//Enable/Disable output of compile commands during generation. -CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=OFF - -//Install path prefix, prepended onto install directories. -CMAKE_INSTALL_PREFIX:PATH=/usr/local - -//Path to a program. -CMAKE_LINKER:FILEPATH=/usr/bin/ld - -//Path to a program. -CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/make - -//Flags used by the linker during the creation of modules. -CMAKE_MODULE_LINKER_FLAGS:STRING=' ' - -//Flags used by the linker during debug builds. -CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during release minsize builds. -CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during release builds. -CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during Release with Debug Info builds. -CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//Path to a program. -CMAKE_NM:FILEPATH=/usr/bin/nm - -//Path to a program. -CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy - -//Path to a program. -CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump - -//Value Computed by CMake -CMAKE_PROJECT_NAME:STATIC=monad_native - -//Path to a program. -CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib - -//Flags used by the linker during the creation of dll's. -CMAKE_SHARED_LINKER_FLAGS:STRING=' ' - -//Flags used by the linker during debug builds. -CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during release minsize builds. -CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during release builds. -CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during Release with Debug Info builds. -CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//If set, runtime paths are not added when installing shared libraries, -// but are added when building. -CMAKE_SKIP_INSTALL_RPATH:BOOL=NO - -//If set, runtime paths are not added when using shared libraries. -CMAKE_SKIP_RPATH:BOOL=NO - -//Flags used by the linker during the creation of static libraries. -CMAKE_STATIC_LINKER_FLAGS:STRING= - -//Flags used by the linker during debug builds. -CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during release minsize builds. -CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during release builds. -CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during Release with Debug Info builds. -CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//Path to a program. -CMAKE_STRIP:FILEPATH=/usr/bin/strip - -//If true, cmake will use relative paths in makefiles and projects. -CMAKE_USE_RELATIVE_PATHS:BOOL=OFF - -//If this value is on, makefiles will be generated without the -// .SILENT directive, and all commands will be echoed to the console -// during the make. This is useful for debugging only. With Visual -// Studio IDE projects all commands are done without /nologo. -CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE - -//Value Computed by CMake -monad_native_BINARY_DIR:STATIC=/home/aakatz/gitwd/monad-native/src - -//Value Computed by CMake -monad_native_SOURCE_DIR:STATIC=/home/aakatz/gitwd/monad-native/src - -//Dependencies for the target -ps_LIB_DEPENDS:STATIC=general;icuuc; - - -######################## -# INTERNAL cache entries -######################## - -//ADVANCED property for variable: CMAKE_AR -CMAKE_AR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_BUILD_TOOL -CMAKE_BUILD_TOOL-ADVANCED:INTERNAL=1 -//What is the target build tool cmake is generating for. -CMAKE_BUILD_TOOL:INTERNAL=/usr/bin/make -//This is the directory where this CMakeCache.txt was created -CMAKE_CACHEFILE_DIR:INTERNAL=/home/aakatz/gitwd/monad-native/src -//Major version of cmake used to create the current loaded cache -CMAKE_CACHE_MAJOR_VERSION:INTERNAL=2 -//Minor version of cmake used to create the current loaded cache -CMAKE_CACHE_MINOR_VERSION:INTERNAL=8 -//Patch version of cmake used to create the current loaded cache -CMAKE_CACHE_PATCH_VERSION:INTERNAL=12 -//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE -CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 -//Path to CMake executable. -CMAKE_COMMAND:INTERNAL=/usr/bin/cmake -//Path to cpack program executable. -CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack -//Path to ctest program executable. -CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest -//ADVANCED property for variable: CMAKE_CXX_COMPILER -CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS -CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG -CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL -CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE -CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO -CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_COMPILER -CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS -CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG -CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL -CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE -CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO -CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//Executable file format -CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS -CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG -CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL -CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE -CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS -CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1 -//Name of generator. -CMAKE_GENERATOR:INTERNAL=Unix Makefiles -//Name of generator toolset. -CMAKE_GENERATOR_TOOLSET:INTERNAL= -//Have symbol pthread_create -CMAKE_HAVE_LIBC_CREATE:INTERNAL= -//Have library pthreads -CMAKE_HAVE_PTHREADS_CREATE:INTERNAL= -//Have library pthread -CMAKE_HAVE_PTHREAD_CREATE:INTERNAL=1 -//Have include pthread.h -CMAKE_HAVE_PTHREAD_H:INTERNAL=1 -//Start directory with the top level CMakeLists.txt file for this -// project -CMAKE_HOME_DIRECTORY:INTERNAL=/home/aakatz/gitwd/monad-native/src -//Install .so files without execute permission. -CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1 -//ADVANCED property for variable: CMAKE_LINKER -CMAKE_LINKER-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MAKE_PROGRAM -CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS -CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG -CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL -CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE -CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_NM -CMAKE_NM-ADVANCED:INTERNAL=1 -//number of local generators -CMAKE_NUMBER_OF_LOCAL_GENERATORS:INTERNAL=1 -//ADVANCED property for variable: CMAKE_OBJCOPY -CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_OBJDUMP -CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_RANLIB -CMAKE_RANLIB-ADVANCED:INTERNAL=1 -//Path to CMake installation. -CMAKE_ROOT:INTERNAL=/usr/share/cmake-2.8 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS -CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG -CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL -CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE -CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH -CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SKIP_RPATH -CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS -CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG -CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL -CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE -CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STRIP -CMAKE_STRIP-ADVANCED:INTERNAL=1 -//uname command -CMAKE_UNAME:INTERNAL=/bin/uname -//ADVANCED property for variable: CMAKE_USE_RELATIVE_PATHS -CMAKE_USE_RELATIVE_PATHS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE -CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 -//Details about finding Threads -FIND_PACKAGE_MESSAGE_DETAILS_Threads:INTERNAL=[TRUE][v()] - From 0acd64bfc7dd5951c9a5fad08422a635cd8321b3 Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 26 Aug 2015 13:32:21 -0700 Subject: [PATCH 172/342] Deleted CMakeCache.txt --- CMakeCache.txt | 324 ------------------------------------------------- 1 file changed, 324 deletions(-) delete mode 100644 CMakeCache.txt diff --git a/CMakeCache.txt b/CMakeCache.txt deleted file mode 100644 index 2f6e2fc4b..000000000 --- a/CMakeCache.txt +++ /dev/null @@ -1,324 +0,0 @@ -# This is the CMakeCache file. -# For build in directory: /home/aakatz/gitwd/monad-native/src -# It was generated by CMake: /usr/bin/cmake -# You can edit this file to change values found and used by cmake. -# If you do not want to change any of the values, simply exit the editor. -# If you do want to change a value, simply edit, save, and exit the editor. -# The syntax for the file is as follows: -# KEY:TYPE=VALUE -# KEY is the name of a variable in the cache. -# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. -# VALUE is the current value for the KEY. - -######################## -# EXTERNAL cache entries -######################## - -//Path to a program. -CMAKE_AR:FILEPATH=/usr/bin/ar - -//Choose the type of build, options are: None(CMAKE_CXX_FLAGS or -// CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel. -CMAKE_BUILD_TYPE:STRING= - -//Enable/Disable color output during build. -CMAKE_COLOR_MAKEFILE:BOOL=ON - -//CXX compiler. -CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++ - -//Flags used by the compiler during all build types. -CMAKE_CXX_FLAGS:STRING= - -//Flags used by the compiler during debug builds. -CMAKE_CXX_FLAGS_DEBUG:STRING=-g - -//Flags used by the compiler during release minsize builds. -CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG - -//Flags used by the compiler during release builds (/MD /Ob1 /Oi -// /Ot /Oy /Gs will produce slightly less optimized but smaller -// files). -CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG - -//Flags used by the compiler during Release with Debug Info builds. -CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG - -//C compiler. -CMAKE_C_COMPILER:FILEPATH=/usr/bin/cc - -//Flags used by the compiler during all build types. -CMAKE_C_FLAGS:STRING= - -//Flags used by the compiler during debug builds. -CMAKE_C_FLAGS_DEBUG:STRING=-g - -//Flags used by the compiler during release minsize builds. -CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG - -//Flags used by the compiler during release builds (/MD /Ob1 /Oi -// /Ot /Oy /Gs will produce slightly less optimized but smaller -// files). -CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG - -//Flags used by the compiler during Release with Debug Info builds. -CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG - -//Flags used by the linker. -CMAKE_EXE_LINKER_FLAGS:STRING=' ' - -//Flags used by the linker during debug builds. -CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during release minsize builds. -CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during release builds. -CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during Release with Debug Info builds. -CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//Enable/Disable output of compile commands during generation. -CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=OFF - -//Install path prefix, prepended onto install directories. -CMAKE_INSTALL_PREFIX:PATH=/usr/local - -//Path to a program. -CMAKE_LINKER:FILEPATH=/usr/bin/ld - -//Path to a program. -CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/make - -//Flags used by the linker during the creation of modules. -CMAKE_MODULE_LINKER_FLAGS:STRING=' ' - -//Flags used by the linker during debug builds. -CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during release minsize builds. -CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during release builds. -CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during Release with Debug Info builds. -CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//Path to a program. -CMAKE_NM:FILEPATH=/usr/bin/nm - -//Path to a program. -CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy - -//Path to a program. -CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump - -//Value Computed by CMake -CMAKE_PROJECT_NAME:STATIC=monad_native - -//Path to a program. -CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib - -//Flags used by the linker during the creation of dll's. -CMAKE_SHARED_LINKER_FLAGS:STRING=' ' - -//Flags used by the linker during debug builds. -CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during release minsize builds. -CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during release builds. -CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during Release with Debug Info builds. -CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//If set, runtime paths are not added when installing shared libraries, -// but are added when building. -CMAKE_SKIP_INSTALL_RPATH:BOOL=NO - -//If set, runtime paths are not added when using shared libraries. -CMAKE_SKIP_RPATH:BOOL=NO - -//Flags used by the linker during the creation of static libraries. -CMAKE_STATIC_LINKER_FLAGS:STRING= - -//Flags used by the linker during debug builds. -CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during release minsize builds. -CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during release builds. -CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during Release with Debug Info builds. -CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//Path to a program. -CMAKE_STRIP:FILEPATH=/usr/bin/strip - -//If true, cmake will use relative paths in makefiles and projects. -CMAKE_USE_RELATIVE_PATHS:BOOL=OFF - -//If this value is on, makefiles will be generated without the -// .SILENT directive, and all commands will be echoed to the console -// during the make. This is useful for debugging only. With Visual -// Studio IDE projects all commands are done without /nologo. -CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE - -//Value Computed by CMake -monad_native_BINARY_DIR:STATIC=/home/aakatz/gitwd/monad-native/src - -//Value Computed by CMake -monad_native_SOURCE_DIR:STATIC=/home/aakatz/gitwd/monad-native/src - -//Dependencies for the target -ps_LIB_DEPENDS:STATIC=general;icuuc; - - -######################## -# INTERNAL cache entries -######################## - -//ADVANCED property for variable: CMAKE_AR -CMAKE_AR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_BUILD_TOOL -CMAKE_BUILD_TOOL-ADVANCED:INTERNAL=1 -//What is the target build tool cmake is generating for. -CMAKE_BUILD_TOOL:INTERNAL=/usr/bin/make -//This is the directory where this CMakeCache.txt was created -CMAKE_CACHEFILE_DIR:INTERNAL=/home/aakatz/gitwd/monad-native/src -//Major version of cmake used to create the current loaded cache -CMAKE_CACHE_MAJOR_VERSION:INTERNAL=2 -//Minor version of cmake used to create the current loaded cache -CMAKE_CACHE_MINOR_VERSION:INTERNAL=8 -//Patch version of cmake used to create the current loaded cache -CMAKE_CACHE_PATCH_VERSION:INTERNAL=12 -//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE -CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 -//Path to CMake executable. -CMAKE_COMMAND:INTERNAL=/usr/bin/cmake -//Path to cpack program executable. -CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack -//Path to ctest program executable. -CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest -//ADVANCED property for variable: CMAKE_CXX_COMPILER -CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS -CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG -CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL -CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE -CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO -CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_COMPILER -CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS -CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG -CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL -CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE -CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO -CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//Executable file format -CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS -CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG -CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL -CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE -CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS -CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1 -//Name of generator. -CMAKE_GENERATOR:INTERNAL=Unix Makefiles -//Name of generator toolset. -CMAKE_GENERATOR_TOOLSET:INTERNAL= -//Have symbol pthread_create -CMAKE_HAVE_LIBC_CREATE:INTERNAL= -//Have library pthreads -CMAKE_HAVE_PTHREADS_CREATE:INTERNAL= -//Have library pthread -CMAKE_HAVE_PTHREAD_CREATE:INTERNAL=1 -//Have include pthread.h -CMAKE_HAVE_PTHREAD_H:INTERNAL=1 -//Start directory with the top level CMakeLists.txt file for this -// project -CMAKE_HOME_DIRECTORY:INTERNAL=/home/aakatz/gitwd/monad-native/src -//Install .so files without execute permission. -CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1 -//ADVANCED property for variable: CMAKE_LINKER -CMAKE_LINKER-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MAKE_PROGRAM -CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS -CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG -CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL -CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE -CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_NM -CMAKE_NM-ADVANCED:INTERNAL=1 -//number of local generators -CMAKE_NUMBER_OF_LOCAL_GENERATORS:INTERNAL=1 -//ADVANCED property for variable: CMAKE_OBJCOPY -CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_OBJDUMP -CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_RANLIB -CMAKE_RANLIB-ADVANCED:INTERNAL=1 -//Path to CMake installation. -CMAKE_ROOT:INTERNAL=/usr/share/cmake-2.8 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS -CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG -CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL -CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE -CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH -CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SKIP_RPATH -CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS -CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG -CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL -CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE -CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STRIP -CMAKE_STRIP-ADVANCED:INTERNAL=1 -//uname command -CMAKE_UNAME:INTERNAL=/bin/uname -//ADVANCED property for variable: CMAKE_USE_RELATIVE_PATHS -CMAKE_USE_RELATIVE_PATHS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE -CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 -//Details about finding Threads -FIND_PACKAGE_MESSAGE_DETAILS_Threads:INTERNAL=[TRUE][v()] - From 777a30c51ae700d26c1cbf41db9ac0ef3b4e4528 Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 28 Aug 2015 15:17:34 -0700 Subject: [PATCH 173/342] Changes to documentation --- src/impl/getcpinfo.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/impl/getcpinfo.cpp b/src/impl/getcpinfo.cpp index 09ac0183a..a27c55307 100644 --- a/src/impl/getcpinfo.cpp +++ b/src/impl/getcpinfo.cpp @@ -16,7 +16,7 @@ //! @parblock //! An UINT Identifier for the code page for which to retrieve information. //! See Code Page Identifiers for details -//! 65001 in the number for UTF8. It is the only valid inpur parameter +//! 65001 in the number for UTF8. It is the only valid input parameter //!because Linux and Unix only use UTF8 for codepage //! //! @endparblock @@ -28,6 +28,13 @@ //! LPCPINFO is a pointer to the structure _cpinfo used to contain the information //! about a code page //! +//! +//! typedef struct _cpinfo { +//! UINT MaxCharSize; +//! BYTE DefaultChar[MAX_DEFAULTCHAR]; +//! BYTE LeadByte[MAX_LEADBYTES]; +//! } CPINFO, *LPCPINFO; +//! //! _cpinfo is a struct that comprises //! //! UINT MaxCharSize; @@ -70,8 +77,8 @@ //! extended error information, call GetLastError. //! //! [MSDN documentation]:https://msdn.microsoft.com/en-us/library/windows/desktop/dd318078%28v=vs.85%29.aspx -//! [_cpinfo]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317780%28v=vs.85%29.aspx -//! [CodePageIdentifiers] https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756%28v=vs.85%29.aspx +//! [_cpinfo]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317780(v=vs.85).aspx +//! [CodePageIdentifiers] https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) { @@ -87,7 +94,6 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) return FALSE; } - // 65001 is the code page for UTF8, Linux and Unix default it UTF8 if (codepage != const_cpinfo::UTF8) { //If other value is used return error because Linux and Unix only used UTF-8 for codepage @@ -99,12 +105,13 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) cpinfo->DefaultChar[0] = '?'; cpinfo->DefaultChar[1] = '0'; cpinfo->MaxCharSize = 4; + for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) { // UTF-8 uses the default has no LeadByte as result LeadByte is '0' - cpinfo->LeadByte[i] = '0'; - + cpinfo->LeadByte[i] = '0'; } + return TRUE; } From 782d1642475078854eaee6857ccf2accfefdbf88 Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 28 Aug 2015 15:17:34 -0700 Subject: [PATCH 174/342] Changes to documentation --- impl/getcpinfo.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/impl/getcpinfo.cpp b/impl/getcpinfo.cpp index 09ac0183a..a27c55307 100644 --- a/impl/getcpinfo.cpp +++ b/impl/getcpinfo.cpp @@ -16,7 +16,7 @@ //! @parblock //! An UINT Identifier for the code page for which to retrieve information. //! See Code Page Identifiers for details -//! 65001 in the number for UTF8. It is the only valid inpur parameter +//! 65001 in the number for UTF8. It is the only valid input parameter //!because Linux and Unix only use UTF8 for codepage //! //! @endparblock @@ -28,6 +28,13 @@ //! LPCPINFO is a pointer to the structure _cpinfo used to contain the information //! about a code page //! +//! +//! typedef struct _cpinfo { +//! UINT MaxCharSize; +//! BYTE DefaultChar[MAX_DEFAULTCHAR]; +//! BYTE LeadByte[MAX_LEADBYTES]; +//! } CPINFO, *LPCPINFO; +//! //! _cpinfo is a struct that comprises //! //! UINT MaxCharSize; @@ -70,8 +77,8 @@ //! extended error information, call GetLastError. //! //! [MSDN documentation]:https://msdn.microsoft.com/en-us/library/windows/desktop/dd318078%28v=vs.85%29.aspx -//! [_cpinfo]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317780%28v=vs.85%29.aspx -//! [CodePageIdentifiers] https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756%28v=vs.85%29.aspx +//! [_cpinfo]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317780(v=vs.85).aspx +//! [CodePageIdentifiers] https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) { @@ -87,7 +94,6 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) return FALSE; } - // 65001 is the code page for UTF8, Linux and Unix default it UTF8 if (codepage != const_cpinfo::UTF8) { //If other value is used return error because Linux and Unix only used UTF-8 for codepage @@ -99,12 +105,13 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) cpinfo->DefaultChar[0] = '?'; cpinfo->DefaultChar[1] = '0'; cpinfo->MaxCharSize = 4; + for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) { // UTF-8 uses the default has no LeadByte as result LeadByte is '0' - cpinfo->LeadByte[i] = '0'; - + cpinfo->LeadByte[i] = '0'; } + return TRUE; } From 276b5c54810f58669cacfbf0fa888cc654db57cc Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 28 Aug 2015 15:44:04 -0700 Subject: [PATCH 175/342] Got rid of warnings from cpinfo struct --- src/tests/test-getcpinfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/test-getcpinfo.cpp b/src/tests/test-getcpinfo.cpp index 3ec759645..56d36b46a 100644 --- a/src/tests/test-getcpinfo.cpp +++ b/src/tests/test-getcpinfo.cpp @@ -8,7 +8,7 @@ // This test is with correct parameters TEST(GetCPInfo,Utf8) { - CPINFO* cpinfo; + CPINFO* cpinfo = new CPINFO(); int UTF8CodePageNumber = const_cpinfo::UTF8; BOOL result = GetCPInfoW(UTF8CodePageNumber, cpinfo); @@ -28,7 +28,7 @@ TEST(GetCPInfo,Utf8) // This test is with codepage not being utf8 TEST(GetCPInfo, CodePageNotUTF8) { - CPINFO* cpinfo; + CPINFO* cpinfo = new CPINFO();; BOOL result = GetCPInfoW(65000, cpinfo); ASSERT_EQ(FALSE, result); From 67531511610373031bb2d338643589e07636e9cd Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 28 Aug 2015 15:44:04 -0700 Subject: [PATCH 176/342] Got rid of warnings from cpinfo struct --- tests/test-getcpinfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-getcpinfo.cpp b/tests/test-getcpinfo.cpp index 3ec759645..56d36b46a 100644 --- a/tests/test-getcpinfo.cpp +++ b/tests/test-getcpinfo.cpp @@ -8,7 +8,7 @@ // This test is with correct parameters TEST(GetCPInfo,Utf8) { - CPINFO* cpinfo; + CPINFO* cpinfo = new CPINFO(); int UTF8CodePageNumber = const_cpinfo::UTF8; BOOL result = GetCPInfoW(UTF8CodePageNumber, cpinfo); @@ -28,7 +28,7 @@ TEST(GetCPInfo,Utf8) // This test is with codepage not being utf8 TEST(GetCPInfo, CodePageNotUTF8) { - CPINFO* cpinfo; + CPINFO* cpinfo = new CPINFO();; BOOL result = GetCPInfoW(65000, cpinfo); ASSERT_EQ(FALSE, result); From a1f94e6c702c0a4bbb4f1dcba7dfac7ed518e9d9 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 28 Aug 2015 15:57:31 -0700 Subject: [PATCH 177/342] Fix GetCpInfo - Move cpinfo related code out of pal.h and into getcpinfo.h - Use static cpinfo struct (not pointer) in test and pass address - Whitespace cleanup --- src/impl/getcpinfo.cpp | 36 ++++++++++++++++++------------------ src/impl/getcpinfo.h | 18 ++++++++++++++++++ src/impl/pal.h | 18 ------------------ src/tests/test-getcpinfo.cpp | 31 ++++++++++++++----------------- 4 files changed, 50 insertions(+), 53 deletions(-) diff --git a/src/impl/getcpinfo.cpp b/src/impl/getcpinfo.cpp index a27c55307..79f39ea25 100644 --- a/src/impl/getcpinfo.cpp +++ b/src/impl/getcpinfo.cpp @@ -25,7 +25,7 @@ //! @parblock //! Pointer to a CPINFO structure that receives information about the code page //! -//! LPCPINFO is a pointer to the structure _cpinfo used to contain the information +//! LPCPINFO is a pointer to the structure _cpinfo used to contain the information //! about a code page //! //! @@ -34,33 +34,33 @@ //! BYTE DefaultChar[MAX_DEFAULTCHAR]; //! BYTE LeadByte[MAX_LEADBYTES]; //! } CPINFO, *LPCPINFO; -//! +//! //! _cpinfo is a struct that comprises //! //! UINT MaxCharSize; //! Maximum length, in bytes, of a character in the code page. -//! The length can be 1 for a single-byte character set (SBCS), +//! The length can be 1 for a single-byte character set (SBCS), //! 2 for a double-byte character set (DBCS), or a value larger -//! than 2 for other character set types. The function cannot +//! than 2 for other character set types. The function cannot //! use the size to distinguish an SBCS or a DBCS from other -//! character sets because of other factors, for example, +//! character sets because of other factors, for example, //! the use of ISCII or ISO-2022-xx code pages. //! //! BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; -//! Default character used when translating character +//! Default character used when translating character //! strings to the specific code page. This character is used by //! the WideCharToMultiByte function if an explicit default //! character is not specified. The default is usually the "?" //! character for the code page -//! +//! //! BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; -//! A fixed-length array of lead byte ranges, for which the number -//! of lead byte ranges is variable. If the code page has no lead +//! A fixed-length array of lead byte ranges, for which the number +//! of lead byte ranges is variable. If the code page has no lead //! bytes, every element of the array is set to NULL. If the code //! page has lead bytes, the array specifies a starting value and -//! an ending value for each range. Ranges are inclusive, and the +//! an ending value for each range. Ranges are inclusive, and the //! maximum number of ranges for any code page is five. The array -//! uses two bytes to describe each range, with two null bytes as +//! uses two bytes to describe each range, with two null bytes as //! a terminator after the last range. //! //! MAX_DEFAULTCHAR is an int of size 2 @@ -83,7 +83,7 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) { errno = FALSE; - + // Select locale from environment setlocale(LC_ALL, ""); @@ -93,8 +93,8 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) errno = ERROR_BAD_ENVIRONMENT; return FALSE; } - - if (codepage != const_cpinfo::UTF8) + + if (codepage != const_cpinfo::UTF8) { //If other value is used return error because Linux and Unix only used UTF-8 for codepage errno = ERROR_INVALID_PARAMETER; @@ -105,13 +105,13 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) cpinfo->DefaultChar[0] = '?'; cpinfo->DefaultChar[1] = '0'; cpinfo->MaxCharSize = 4; - - for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) + + for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) { // UTF-8 uses the default has no LeadByte as result LeadByte is '0' - cpinfo->LeadByte[i] = '0'; + cpinfo->LeadByte[i] = '0'; } - + return TRUE; } diff --git a/src/impl/getcpinfo.h b/src/impl/getcpinfo.h index 54a2ebbcd..cd0883d7b 100644 --- a/src/impl/getcpinfo.h +++ b/src/impl/getcpinfo.h @@ -2,6 +2,24 @@ #include "pal.h" +//!* NameSpace + +namespace const_cpinfo +{ + constexpr int MAX_DEFAULTCHAR = 2; + constexpr int MAX_LEADBYTES = 12; + constexpr int UTF8 = 65001; +} + +//!* Structs + +typedef struct _cpinfo +{ + UINT MaxCharSize; + BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; + BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; +} CPINFO; + PAL_BEGIN_EXTERNC BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo); diff --git a/src/impl/pal.h b/src/impl/pal.h index 8a2763600..944336ab0 100644 --- a/src/impl/pal.h +++ b/src/impl/pal.h @@ -597,21 +597,3 @@ typedef unsigned char PAL_Boolean; #else # define PAL_COUNT(ARR) (sizeof(ARR) / sizeof(ARR[0])) #endif - -//!* NameSpace - -namespace const_cpinfo -{ - constexpr int MAX_DEFAULTCHAR = 2; - constexpr int MAX_LEADBYTES = 12; - constexpr int UTF8 = 65001; -} - -//!* Structs - -typedef struct _cpinfo -{ - UINT MaxCharSize; - BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; - BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; -} CPINFO; diff --git a/src/tests/test-getcpinfo.cpp b/src/tests/test-getcpinfo.cpp index 56d36b46a..0c8a33960 100644 --- a/src/tests/test-getcpinfo.cpp +++ b/src/tests/test-getcpinfo.cpp @@ -5,33 +5,30 @@ #include #include "getcpinfo.h" -// This test is with correct parameters -TEST(GetCPInfo,Utf8) +TEST(GetCPInfo, CodePageIsUTF8) { - CPINFO* cpinfo = new CPINFO(); - int UTF8CodePageNumber = const_cpinfo::UTF8; - BOOL result = GetCPInfoW(UTF8CodePageNumber, cpinfo); + CPINFO cpinfo; + BOOL result = GetCPInfoW(const_cpinfo::UTF8, &cpinfo); // first make sure that the function worked ASSERT_EQ(TRUE, result); - + // now compare the actual values - EXPECT_EQ(cpinfo->DefaultChar[0], '?'); - EXPECT_EQ(cpinfo->DefaultChar[1], '0'); - EXPECT_EQ(cpinfo->MaxCharSize,4); + EXPECT_EQ(cpinfo.DefaultChar[0], '?'); + EXPECT_EQ(cpinfo.DefaultChar[1], '0'); + EXPECT_EQ(cpinfo.MaxCharSize, 4); + for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++) { - EXPECT_EQ(cpinfo->LeadByte[i], '0'); + EXPECT_EQ(cpinfo.LeadByte[i], '0'); } } -// This test is with codepage not being utf8 -TEST(GetCPInfo, CodePageNotUTF8) +TEST(GetCPInfo, CodePageIsNotUTF8) { - CPINFO* cpinfo = new CPINFO();; - BOOL result = GetCPInfoW(65000, cpinfo); - + CPINFO cpinfo; + BOOL result = GetCPInfoW(const_cpinfo::UTF8+1, &cpinfo); + ASSERT_EQ(FALSE, result); ASSERT_EQ(ERROR_INVALID_PARAMETER, errno); - -} \ No newline at end of file +} From 39174a0afbea722576f65c24db5b2df2b6a01321 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 28 Aug 2015 15:57:31 -0700 Subject: [PATCH 178/342] Fix GetCpInfo - Move cpinfo related code out of pal.h and into getcpinfo.h - Use static cpinfo struct (not pointer) in test and pass address - Whitespace cleanup --- impl/getcpinfo.cpp | 36 ++++++++++++++++++------------------ impl/getcpinfo.h | 18 ++++++++++++++++++ impl/pal.h | 18 ------------------ tests/test-getcpinfo.cpp | 31 ++++++++++++++----------------- 4 files changed, 50 insertions(+), 53 deletions(-) diff --git a/impl/getcpinfo.cpp b/impl/getcpinfo.cpp index a27c55307..79f39ea25 100644 --- a/impl/getcpinfo.cpp +++ b/impl/getcpinfo.cpp @@ -25,7 +25,7 @@ //! @parblock //! Pointer to a CPINFO structure that receives information about the code page //! -//! LPCPINFO is a pointer to the structure _cpinfo used to contain the information +//! LPCPINFO is a pointer to the structure _cpinfo used to contain the information //! about a code page //! //! @@ -34,33 +34,33 @@ //! BYTE DefaultChar[MAX_DEFAULTCHAR]; //! BYTE LeadByte[MAX_LEADBYTES]; //! } CPINFO, *LPCPINFO; -//! +//! //! _cpinfo is a struct that comprises //! //! UINT MaxCharSize; //! Maximum length, in bytes, of a character in the code page. -//! The length can be 1 for a single-byte character set (SBCS), +//! The length can be 1 for a single-byte character set (SBCS), //! 2 for a double-byte character set (DBCS), or a value larger -//! than 2 for other character set types. The function cannot +//! than 2 for other character set types. The function cannot //! use the size to distinguish an SBCS or a DBCS from other -//! character sets because of other factors, for example, +//! character sets because of other factors, for example, //! the use of ISCII or ISO-2022-xx code pages. //! //! BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; -//! Default character used when translating character +//! Default character used when translating character //! strings to the specific code page. This character is used by //! the WideCharToMultiByte function if an explicit default //! character is not specified. The default is usually the "?" //! character for the code page -//! +//! //! BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; -//! A fixed-length array of lead byte ranges, for which the number -//! of lead byte ranges is variable. If the code page has no lead +//! A fixed-length array of lead byte ranges, for which the number +//! of lead byte ranges is variable. If the code page has no lead //! bytes, every element of the array is set to NULL. If the code //! page has lead bytes, the array specifies a starting value and -//! an ending value for each range. Ranges are inclusive, and the +//! an ending value for each range. Ranges are inclusive, and the //! maximum number of ranges for any code page is five. The array -//! uses two bytes to describe each range, with two null bytes as +//! uses two bytes to describe each range, with two null bytes as //! a terminator after the last range. //! //! MAX_DEFAULTCHAR is an int of size 2 @@ -83,7 +83,7 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) { errno = FALSE; - + // Select locale from environment setlocale(LC_ALL, ""); @@ -93,8 +93,8 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) errno = ERROR_BAD_ENVIRONMENT; return FALSE; } - - if (codepage != const_cpinfo::UTF8) + + if (codepage != const_cpinfo::UTF8) { //If other value is used return error because Linux and Unix only used UTF-8 for codepage errno = ERROR_INVALID_PARAMETER; @@ -105,13 +105,13 @@ BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) cpinfo->DefaultChar[0] = '?'; cpinfo->DefaultChar[1] = '0'; cpinfo->MaxCharSize = 4; - - for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) + + for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) { // UTF-8 uses the default has no LeadByte as result LeadByte is '0' - cpinfo->LeadByte[i] = '0'; + cpinfo->LeadByte[i] = '0'; } - + return TRUE; } diff --git a/impl/getcpinfo.h b/impl/getcpinfo.h index 54a2ebbcd..cd0883d7b 100644 --- a/impl/getcpinfo.h +++ b/impl/getcpinfo.h @@ -2,6 +2,24 @@ #include "pal.h" +//!* NameSpace + +namespace const_cpinfo +{ + constexpr int MAX_DEFAULTCHAR = 2; + constexpr int MAX_LEADBYTES = 12; + constexpr int UTF8 = 65001; +} + +//!* Structs + +typedef struct _cpinfo +{ + UINT MaxCharSize; + BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; + BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; +} CPINFO; + PAL_BEGIN_EXTERNC BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo); diff --git a/impl/pal.h b/impl/pal.h index 8a2763600..944336ab0 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -597,21 +597,3 @@ typedef unsigned char PAL_Boolean; #else # define PAL_COUNT(ARR) (sizeof(ARR) / sizeof(ARR[0])) #endif - -//!* NameSpace - -namespace const_cpinfo -{ - constexpr int MAX_DEFAULTCHAR = 2; - constexpr int MAX_LEADBYTES = 12; - constexpr int UTF8 = 65001; -} - -//!* Structs - -typedef struct _cpinfo -{ - UINT MaxCharSize; - BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; - BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; -} CPINFO; diff --git a/tests/test-getcpinfo.cpp b/tests/test-getcpinfo.cpp index 56d36b46a..0c8a33960 100644 --- a/tests/test-getcpinfo.cpp +++ b/tests/test-getcpinfo.cpp @@ -5,33 +5,30 @@ #include #include "getcpinfo.h" -// This test is with correct parameters -TEST(GetCPInfo,Utf8) +TEST(GetCPInfo, CodePageIsUTF8) { - CPINFO* cpinfo = new CPINFO(); - int UTF8CodePageNumber = const_cpinfo::UTF8; - BOOL result = GetCPInfoW(UTF8CodePageNumber, cpinfo); + CPINFO cpinfo; + BOOL result = GetCPInfoW(const_cpinfo::UTF8, &cpinfo); // first make sure that the function worked ASSERT_EQ(TRUE, result); - + // now compare the actual values - EXPECT_EQ(cpinfo->DefaultChar[0], '?'); - EXPECT_EQ(cpinfo->DefaultChar[1], '0'); - EXPECT_EQ(cpinfo->MaxCharSize,4); + EXPECT_EQ(cpinfo.DefaultChar[0], '?'); + EXPECT_EQ(cpinfo.DefaultChar[1], '0'); + EXPECT_EQ(cpinfo.MaxCharSize, 4); + for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++) { - EXPECT_EQ(cpinfo->LeadByte[i], '0'); + EXPECT_EQ(cpinfo.LeadByte[i], '0'); } } -// This test is with codepage not being utf8 -TEST(GetCPInfo, CodePageNotUTF8) +TEST(GetCPInfo, CodePageIsNotUTF8) { - CPINFO* cpinfo = new CPINFO();; - BOOL result = GetCPInfoW(65000, cpinfo); - + CPINFO cpinfo; + BOOL result = GetCPInfoW(const_cpinfo::UTF8+1, &cpinfo); + ASSERT_EQ(FALSE, result); ASSERT_EQ(ERROR_INVALID_PARAMETER, errno); - -} \ No newline at end of file +} From a4a9638bcd2a853dc5bf01b796d4cda0ab66f2ed Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 23 Sep 2015 15:55:44 -0700 Subject: [PATCH 179/342] Use getpwuid(geteuid()) instead of getlogin() This removes the dependency on a TTY and now does what is expected: gets the (possibly impersonated) username of the current process/thread. Implementation and tests updated, still uses reentrant versions where possible. --- src/impl/getusername.cpp | 59 ++++++++++++++++++---------------- src/tests/test-getusername.cpp | 3 +- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/impl/getusername.cpp b/src/impl/getusername.cpp index 88e5955d6..ee14d8651 100644 --- a/src/impl/getusername.cpp +++ b/src/impl/getusername.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "getusername.h" //! @brief GetUserName retrieves the name of the user associated with @@ -40,13 +41,9 @@ //! @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 +//! - ERROR_NO_SUCH_USER: there was no corresponding user +//! - ERROR_GEN_FAILURE: sysconf() or getpwuid() failed for unknown reasons //! //! @retval TRUE If the function succeeds, the return value is a nonzero //! value, and the variable pointed to by lpnSize contains the number @@ -61,8 +58,6 @@ //! [LPTSTR]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx#LPTSTR BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) { - errno = FALSE; - // Check parameters if (!lpBuffer || !lpnSize) { @@ -79,39 +74,47 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) return FALSE; } - // Get username from system in a thread-safe manner - std::string username(LOGIN_NAME_MAX, 0); - int ret = getlogin_r(&username[0], username.length()); + struct passwd pwd; + struct passwd* result; + // gets the initial suggested size for buf + int buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (buflen == -1) + { + errno = ERROR_GEN_FAILURE; + return FALSE; + } + std::string buf(buflen, 0); + + // geteuid() gets the effective user ID of the calling process, and is always successful + errno = 0; + int ret = getpwuid_r(geteuid(), &pwd, &buf[0], buflen, &result); + // Map errno to Win32 Error Codes if (ret) { switch (errno) { - case EMFILE: - case ENFILE: - errno = ERROR_TOO_MANY_OPEN_FILES; - break; - case ENXIO: - errno = ERROR_NO_ASSOCIATION; - break; - case ERANGE: - errno = ERROR_GEN_FAILURE; - break; case ENOENT: + case ESRCH: + case EBADF: + case EPERM: errno = ERROR_NO_SUCH_USER; break; - case ENOMEM: - errno = ERROR_OUTOFMEMORY; - break; - case ENOTTY: - errno = ERROR_NO_ASSOCIATION; - break; default: - errno = ERROR_INVALID_FUNCTION; + errno = ERROR_GEN_FAILURE; } return FALSE; } + // Check if no user matched + if (result == NULL) + { + errno = ERROR_NO_SUCH_USER; + return FALSE; + } + + std::string username(result->pw_name); + // Convert to UnicodeString auto username16 = icu::UnicodeString::fromUTF8(username.c_str()); // Terminate string with null diff --git a/src/tests/test-getusername.cpp b/src/tests/test-getusername.cpp index b6c0b5e77..9d238f538 100644 --- a/src/tests/test-getusername.cpp +++ b/src/tests/test-getusername.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "getusername.h" //! Test fixture for GetUserNameW @@ -19,7 +20,7 @@ protected: std::string expectedUsername; DWORD expectedSize; - GetUserNameTest(): expectedUsername(std::string(getlogin())), + GetUserNameTest(): expectedUsername(std::string(getpwuid(geteuid())->pw_name)), expectedSize(expectedUsername.length()+1) { } From 020a768c31a8dced653649590014380228494bce Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 23 Sep 2015 15:55:44 -0700 Subject: [PATCH 180/342] Use getpwuid(geteuid()) instead of getlogin() This removes the dependency on a TTY and now does what is expected: gets the (possibly impersonated) username of the current process/thread. Implementation and tests updated, still uses reentrant versions where possible. --- impl/getusername.cpp | 59 ++++++++++++++++++++------------------ tests/test-getusername.cpp | 3 +- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index 88e5955d6..ee14d8651 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "getusername.h" //! @brief GetUserName retrieves the name of the user associated with @@ -40,13 +41,9 @@ //! @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 +//! - ERROR_NO_SUCH_USER: there was no corresponding user +//! - ERROR_GEN_FAILURE: sysconf() or getpwuid() failed for unknown reasons //! //! @retval TRUE If the function succeeds, the return value is a nonzero //! value, and the variable pointed to by lpnSize contains the number @@ -61,8 +58,6 @@ //! [LPTSTR]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx#LPTSTR BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) { - errno = FALSE; - // Check parameters if (!lpBuffer || !lpnSize) { @@ -79,39 +74,47 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) return FALSE; } - // Get username from system in a thread-safe manner - std::string username(LOGIN_NAME_MAX, 0); - int ret = getlogin_r(&username[0], username.length()); + struct passwd pwd; + struct passwd* result; + // gets the initial suggested size for buf + int buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (buflen == -1) + { + errno = ERROR_GEN_FAILURE; + return FALSE; + } + std::string buf(buflen, 0); + + // geteuid() gets the effective user ID of the calling process, and is always successful + errno = 0; + int ret = getpwuid_r(geteuid(), &pwd, &buf[0], buflen, &result); + // Map errno to Win32 Error Codes if (ret) { switch (errno) { - case EMFILE: - case ENFILE: - errno = ERROR_TOO_MANY_OPEN_FILES; - break; - case ENXIO: - errno = ERROR_NO_ASSOCIATION; - break; - case ERANGE: - errno = ERROR_GEN_FAILURE; - break; case ENOENT: + case ESRCH: + case EBADF: + case EPERM: errno = ERROR_NO_SUCH_USER; break; - case ENOMEM: - errno = ERROR_OUTOFMEMORY; - break; - case ENOTTY: - errno = ERROR_NO_ASSOCIATION; - break; default: - errno = ERROR_INVALID_FUNCTION; + errno = ERROR_GEN_FAILURE; } return FALSE; } + // Check if no user matched + if (result == NULL) + { + errno = ERROR_NO_SUCH_USER; + return FALSE; + } + + std::string username(result->pw_name); + // Convert to UnicodeString auto username16 = icu::UnicodeString::fromUTF8(username.c_str()); // Terminate string with null diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index b6c0b5e77..9d238f538 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "getusername.h" //! Test fixture for GetUserNameW @@ -19,7 +20,7 @@ protected: std::string expectedUsername; DWORD expectedSize; - GetUserNameTest(): expectedUsername(std::string(getlogin())), + GetUserNameTest(): expectedUsername(std::string(getpwuid(geteuid())->pw_name)), expectedSize(expectedUsername.length()+1) { } From d1de7e28c52a87a0804b76445a07b1d122417436 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 30 Sep 2015 16:28:16 -0700 Subject: [PATCH 181/342] Ignore libps.so --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 45c8b7d40..38f7f820b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ src/build/ src/monad_native src/src.kdev4 +libps.so From ad49db74e24758377c3735bf9a40fd06ea2b2b20 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 6 Oct 2015 14:08:38 -0700 Subject: [PATCH 182/342] Ignore more things --- .gitignore | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 38f7f820b..280941f2a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,10 @@ src/CMakeFiles/ src/build/ src/monad_native src/src.kdev4 - libps.so +CMakeCache.txt +CMakeFiles/ +Makefile +cmake_install.cmake +host_cmdline +monad_native From fd8566f111d3a1c364a808f439d47e15ebe35b01 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 20 Oct 2015 11:54:46 -0700 Subject: [PATCH 183/342] Refactor host_common into pshost static lib For reuse by psrp provider --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 003c9b985..b534ebb94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,18 +13,19 @@ 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-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}) +set(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp) # target definitions add_library(ps SHARED ${LIB_SOURCE_FILES}) add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) +add_library(pshost STATIC ${HOST_COMMON_SOURCE_FILES}) add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) # add pthread and other libs find_package(Threads) target_link_libraries(ps icuuc) target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) -target_link_libraries(host_cmdline dl icuuc) +target_link_libraries(host_cmdline pshost dl icuuc) # target specific include directories target_include_directories(monad_native PRIVATE host) From 7196afc5ad43d69f658a45bb4b72a91d5e4b8331 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 20 Oct 2015 11:54:46 -0700 Subject: [PATCH 184/342] Refactor host_common into pshost static lib For reuse by psrp provider --- src/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 003c9b985..b534ebb94 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,18 +13,19 @@ 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-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}) +set(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp) # target definitions add_library(ps SHARED ${LIB_SOURCE_FILES}) add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) +add_library(pshost STATIC ${HOST_COMMON_SOURCE_FILES}) add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) # add pthread and other libs find_package(Threads) target_link_libraries(ps icuuc) target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) -target_link_libraries(host_cmdline dl icuuc) +target_link_libraries(host_cmdline pshost dl icuuc) # target specific include directories target_include_directories(monad_native PRIVATE host) From dccd2e9621fac9e4a3e93d80c6782bff9b658eb3 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 21 Oct 2015 15:06:54 -0700 Subject: [PATCH 185/342] Use stream in one statement This just really bugged me and I had it stashed from earlier --- src/host/cmdline/main.cpp | 100 +++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 7cc4637ce..61c1cb9e4 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -11,49 +11,49 @@ namespace Cmdline { - + 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 [...]" << 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; - std::cerr << " as host_cmdline" << std::endl; - std::cerr << " + this behavior can be overridden with the -c command line argument" << std::endl; - std::cerr << "- by default the host assumes that the assembly named" << std::endl; - std::cerr << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl; - std::cerr << " platform assemblies" << std::endl; - 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 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; - std::cerr << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl; - 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 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; - std::cerr << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl; - std::cerr << "-s a list of assembly search paths, separated by :" << std::endl; - std::cerr << "-b the powershell assembly base path" << std::endl; - std::cerr << "-v verbose output, show paths" << std::endl; - std::cerr << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl; - 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 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' 'get-process'" << std::endl; + std::cerr << "PS CoreCLR host" << std::endl + << "Usage: host_cmdline [-c coreclr_path] [-alc load_context_assembly] [-s search_paths]" << std::endl + << " [-b base_path] assembly [...]" << std::endl + << std::endl + << "What it does:" << std::endl + << "- by default the host assumes that CoreCLR is located in the same folder" << std::endl + << " as host_cmdline" << std::endl + << " + this behavior can be overridden with the -c command line argument" << std::endl + << "- by default the host assumes that the assembly named" << std::endl + << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl + << " platform assemblies" << std::endl + << " + a custom assembly containing the PowerShellAssemblyLoadContext can" << std::endl + << " be provided with the -alc command line argument" << std::endl + << "- all additional parameters at the end of the command line are forwarded" << std::endl + << " to the Main function in the assembly" << std::endl + << "- the host will execute the Main function in the specified assembly" << std::endl + << " + this assembly has to be located in the search path" << std::endl + << "- by default the host will add the current working directory to the assembly search path" << std::endl + << " + this can be overridden with the -s command line argument" << std::endl + << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl + << "- by default the host assumes the PS base path for the assembly load context is the current" << std::endl + << " working directory" << std::endl + << " + this can be overridden with the -b command line argument" << std::endl + << "- the function signature of the Main function that gets executed must be:" << std::endl + << " static void Main(string[] args)" << std::endl + << std::endl + << "Options:" << std::endl + << "-c, --clr-path path to libcoreclr.so and the managed CLR assemblies" << std::endl + << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl + << "-s a list of assembly search paths, separated by :" << std::endl + << "-b the powershell assembly base path" << std::endl + << "-v verbose output, show paths" << std::endl + << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl + << " separated by :" << std::endl + << " unless part of the same folder as CoreCLR, the main assembly referenced with the assembly_name" << std::endl + << " argument, must always be added to the TPA list with this parameter" << std::endl + << "assembly the path of the assembly to execute relative to current directory" << std::endl + << std::endl + << "Example:" << std::endl + << "./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 @@ -77,15 +77,15 @@ struct Args void debugPrint() const { - std::cerr << "Args:" << std::endl; - std::cerr << "- clrPath " << clrPath << std::endl; - std::cerr << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl; - std::cerr << "- searchPaths " << searchPaths << std::endl; - std::cerr << "- basePath " << basePath << std::endl; - std::cerr << "- tpaList " << tpaList << std::endl; - std::cerr << "- entryAssemblyPath " << entryAssemblyPath << std::endl; - std::cerr << "- argc " << argc << std::endl; - std::cerr << "- verbose " << (verbose ? "true" : "false") << std::endl; + std::cerr << "Args:" << std::endl + << "- clrPath " << clrPath << std::endl + << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl + << "- searchPaths " << searchPaths << std::endl + << "- basePath " << basePath << std::endl + << "- tpaList " << tpaList << std::endl + << "- entryAssemblyPath " << entryAssemblyPath << std::endl + << "- argc " << argc << std::endl + << "- verbose " << (verbose ? "true" : "false") << std::endl; } }; From 6cddef6b1e309ec111985a593932ac4256e22f6b Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 21 Oct 2015 15:06:54 -0700 Subject: [PATCH 186/342] Use stream in one statement This just really bugged me and I had it stashed from earlier --- host/cmdline/main.cpp | 100 +++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 7cc4637ce..61c1cb9e4 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -11,49 +11,49 @@ namespace Cmdline { - + 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 [...]" << 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; - std::cerr << " as host_cmdline" << std::endl; - std::cerr << " + this behavior can be overridden with the -c command line argument" << std::endl; - std::cerr << "- by default the host assumes that the assembly named" << std::endl; - std::cerr << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl; - std::cerr << " platform assemblies" << std::endl; - 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 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; - std::cerr << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl; - 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 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; - std::cerr << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl; - std::cerr << "-s a list of assembly search paths, separated by :" << std::endl; - std::cerr << "-b the powershell assembly base path" << std::endl; - std::cerr << "-v verbose output, show paths" << std::endl; - std::cerr << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl; - 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 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' 'get-process'" << std::endl; + std::cerr << "PS CoreCLR host" << std::endl + << "Usage: host_cmdline [-c coreclr_path] [-alc load_context_assembly] [-s search_paths]" << std::endl + << " [-b base_path] assembly [...]" << std::endl + << std::endl + << "What it does:" << std::endl + << "- by default the host assumes that CoreCLR is located in the same folder" << std::endl + << " as host_cmdline" << std::endl + << " + this behavior can be overridden with the -c command line argument" << std::endl + << "- by default the host assumes that the assembly named" << std::endl + << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl + << " platform assemblies" << std::endl + << " + a custom assembly containing the PowerShellAssemblyLoadContext can" << std::endl + << " be provided with the -alc command line argument" << std::endl + << "- all additional parameters at the end of the command line are forwarded" << std::endl + << " to the Main function in the assembly" << std::endl + << "- the host will execute the Main function in the specified assembly" << std::endl + << " + this assembly has to be located in the search path" << std::endl + << "- by default the host will add the current working directory to the assembly search path" << std::endl + << " + this can be overridden with the -s command line argument" << std::endl + << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl + << "- by default the host assumes the PS base path for the assembly load context is the current" << std::endl + << " working directory" << std::endl + << " + this can be overridden with the -b command line argument" << std::endl + << "- the function signature of the Main function that gets executed must be:" << std::endl + << " static void Main(string[] args)" << std::endl + << std::endl + << "Options:" << std::endl + << "-c, --clr-path path to libcoreclr.so and the managed CLR assemblies" << std::endl + << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl + << "-s a list of assembly search paths, separated by :" << std::endl + << "-b the powershell assembly base path" << std::endl + << "-v verbose output, show paths" << std::endl + << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl + << " separated by :" << std::endl + << " unless part of the same folder as CoreCLR, the main assembly referenced with the assembly_name" << std::endl + << " argument, must always be added to the TPA list with this parameter" << std::endl + << "assembly the path of the assembly to execute relative to current directory" << std::endl + << std::endl + << "Example:" << std::endl + << "./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 @@ -77,15 +77,15 @@ struct Args void debugPrint() const { - std::cerr << "Args:" << std::endl; - std::cerr << "- clrPath " << clrPath << std::endl; - std::cerr << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl; - std::cerr << "- searchPaths " << searchPaths << std::endl; - std::cerr << "- basePath " << basePath << std::endl; - std::cerr << "- tpaList " << tpaList << std::endl; - std::cerr << "- entryAssemblyPath " << entryAssemblyPath << std::endl; - std::cerr << "- argc " << argc << std::endl; - std::cerr << "- verbose " << (verbose ? "true" : "false") << std::endl; + std::cerr << "Args:" << std::endl + << "- clrPath " << clrPath << std::endl + << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl + << "- searchPaths " << searchPaths << std::endl + << "- basePath " << basePath << std::endl + << "- tpaList " << tpaList << std::endl + << "- entryAssemblyPath " << entryAssemblyPath << std::endl + << "- argc " << argc << std::endl + << "- verbose " << (verbose ? "true" : "false") << std::endl; } }; From fb9c2424c3c80b1b5b789f34fc62f97c401bf58e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 21 Oct 2015 15:22:57 -0700 Subject: [PATCH 187/342] Reindent host code using project standards --- src/host/cmdline/main.cpp | 303 ++++++++++++++++---------------- src/host/common/coreclrutil.cpp | 229 ++++++++++++------------ src/host/common/coreclrutil.h | 87 +++++---- src/host/common/hostutil.h | 60 +++---- 4 files changed, 335 insertions(+), 344 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 61c1cb9e4..ce058b7ce 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -11,153 +11,152 @@ namespace Cmdline { - -void printHelp() -{ - std::cerr << "PS CoreCLR host" << std::endl - << "Usage: host_cmdline [-c coreclr_path] [-alc load_context_assembly] [-s search_paths]" << std::endl - << " [-b base_path] assembly [...]" << std::endl - << std::endl - << "What it does:" << std::endl - << "- by default the host assumes that CoreCLR is located in the same folder" << std::endl - << " as host_cmdline" << std::endl - << " + this behavior can be overridden with the -c command line argument" << std::endl - << "- by default the host assumes that the assembly named" << std::endl - << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl - << " platform assemblies" << std::endl - << " + a custom assembly containing the PowerShellAssemblyLoadContext can" << std::endl - << " be provided with the -alc command line argument" << std::endl - << "- all additional parameters at the end of the command line are forwarded" << std::endl - << " to the Main function in the assembly" << std::endl - << "- the host will execute the Main function in the specified assembly" << std::endl - << " + this assembly has to be located in the search path" << std::endl - << "- by default the host will add the current working directory to the assembly search path" << std::endl - << " + this can be overridden with the -s command line argument" << std::endl - << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl - << "- by default the host assumes the PS base path for the assembly load context is the current" << std::endl - << " working directory" << std::endl - << " + this can be overridden with the -b command line argument" << std::endl - << "- the function signature of the Main function that gets executed must be:" << std::endl - << " static void Main(string[] args)" << std::endl - << std::endl - << "Options:" << std::endl - << "-c, --clr-path path to libcoreclr.so and the managed CLR assemblies" << std::endl - << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl - << "-s a list of assembly search paths, separated by :" << std::endl - << "-b the powershell assembly base path" << std::endl - << "-v verbose output, show paths" << std::endl - << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl - << " separated by :" << std::endl - << " unless part of the same folder as CoreCLR, the main assembly referenced with the assembly_name" << std::endl - << " argument, must always be added to the TPA list with this parameter" << std::endl - << "assembly the path of the assembly to execute relative to current directory" << std::endl - << std::endl - << "Example:" << std::endl - << "./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 -{ - Args() : - argc(0), - argv(nullptr), - verbose(false) + void printHelp() { + std::cerr << "PS CoreCLR host" << std::endl + << "Usage: host_cmdline [-c coreclr_path] [-alc load_context_assembly] [-s search_paths]" << std::endl + << " [-b base_path] assembly [...]" << std::endl + << std::endl + << "What it does:" << std::endl + << "- by default the host assumes that CoreCLR is located in the same folder" << std::endl + << " as host_cmdline" << std::endl + << " + this behavior can be overridden with the -c command line argument" << std::endl + << "- by default the host assumes that the assembly named" << std::endl + << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl + << " platform assemblies" << std::endl + << " + a custom assembly containing the PowerShellAssemblyLoadContext can" << std::endl + << " be provided with the -alc command line argument" << std::endl + << "- all additional parameters at the end of the command line are forwarded" << std::endl + << " to the Main function in the assembly" << std::endl + << "- the host will execute the Main function in the specified assembly" << std::endl + << " + this assembly has to be located in the search path" << std::endl + << "- by default the host will add the current working directory to the assembly search path" << std::endl + << " + this can be overridden with the -s command line argument" << std::endl + << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl + << "- by default the host assumes the PS base path for the assembly load context is the current" << std::endl + << " working directory" << std::endl + << " + this can be overridden with the -b command line argument" << std::endl + << "- the function signature of the Main function that gets executed must be:" << std::endl + << " static void Main(string[] args)" << std::endl + << std::endl + << "Options:" << std::endl + << "-c, --clr-path path to libcoreclr.so and the managed CLR assemblies" << std::endl + << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl + << "-s a list of assembly search paths, separated by :" << std::endl + << "-b the powershell assembly base path" << std::endl + << "-v verbose output, show paths" << std::endl + << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl + << " separated by :" << std::endl + << " unless part of the same folder as CoreCLR, the main assembly referenced with the assembly_name" << std::endl + << " argument, must always be added to the TPA list with this parameter" << std::endl + << "assembly the path of the assembly to execute relative to current directory" << std::endl + << std::endl + << "Example:" << std::endl + << "./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; } - std::string clrPath; - std::string assemblyLoadContextFilePath; - std::string searchPaths; - std::string basePath; - std::string tpaList; - std::string entryAssemblyPath; - int argc; - char** argv; - bool verbose; - - void debugPrint() const + struct Args { - std::cerr << "Args:" << std::endl - << "- clrPath " << clrPath << std::endl - << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl - << "- searchPaths " << searchPaths << std::endl - << "- basePath " << basePath << std::endl - << "- tpaList " << tpaList << std::endl - << "- entryAssemblyPath " << entryAssemblyPath << std::endl - << "- argc " << argc << std::endl - << "- verbose " << (verbose ? "true" : "false") << std::endl; - } -}; + Args() : + argc(0), + argv(nullptr), + verbose(false) + { + } -// this is implemented without any 3rd party lib to keep the list -// of dependencies low -bool parseCmdline(const int argc, char** argv, Args& args) -{ - if (argc <= 1) + std::string clrPath; + std::string assemblyLoadContextFilePath; + std::string searchPaths; + std::string basePath; + std::string tpaList; + std::string entryAssemblyPath; + int argc; + char** argv; + bool verbose; + + void debugPrint() const + { + std::cerr << "Args:" << std::endl + << "- clrPath " << clrPath << std::endl + << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl + << "- searchPaths " << searchPaths << std::endl + << "- basePath " << basePath << std::endl + << "- tpaList " << tpaList << std::endl + << "- entryAssemblyPath " << entryAssemblyPath << std::endl + << "- argc " << argc << std::endl + << "- verbose " << (verbose ? "true" : "false") << std::endl; + } + }; + + // this is implemented without any 3rd party lib to keep the list + // of dependencies low + bool parseCmdline(const int argc, char** argv, Args& args) { - std::cerr << "error: missing arguments" << std::endl; - return false; + if (argc <= 1) + { + std::cerr << "error: missing arguments" << std::endl; + return false; + } + + for (int i = 1; i < argc; ++i) + { + const std::string arg = argv[i]; + const bool hasNextArg = i+1 < argc; + const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); + + if (hasNextArg && (arg == "-c" || arg == "--clr-path")) + { + args.clrPath = nextArg; + ++i; + } + else if (hasNextArg && arg == "-alc") + { + args.assemblyLoadContextFilePath = nextArg; + ++i; + } + else if (hasNextArg && arg == "-s") + { + args.searchPaths = nextArg; + ++i; + } + else if (hasNextArg && arg == "-b") + { + args.basePath = nextArg; + ++i; + } + else if (hasNextArg && arg == "-tpa") + { + args.tpaList = nextArg; + ++i; + } + else if (arg == "-v") + { + args.verbose = true; + } + else if (args.entryAssemblyPath == "") + { + args.entryAssemblyPath = arg; + } + else + { + // forward command line parameters + args.argc = argc-i; + args.argv = &argv[i]; + + // explicitly break here because the lines above consume all remaining arguments + break; + } + } + + // check for mandatory parameters + if (args.entryAssemblyPath == "") + { + std::cerr << "error: assembly_name argument missing" << std::endl; + } + + return true; } - for (int i = 1; i < argc; ++i) - { - const std::string arg = argv[i]; - const bool hasNextArg = i+1 < argc; - const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); - - if (hasNextArg && (arg == "-c" || arg == "--clr-path")) - { - args.clrPath = nextArg; - ++i; - } - else if (hasNextArg && arg == "-alc") - { - args.assemblyLoadContextFilePath = nextArg; - ++i; - } - else if (hasNextArg && arg == "-s") - { - args.searchPaths = nextArg; - ++i; - } - else if (hasNextArg && arg == "-b") - { - args.basePath = nextArg; - ++i; - } - else if (hasNextArg && arg == "-tpa") - { - args.tpaList = nextArg; - ++i; - } - else if (arg == "-v") - { - args.verbose = true; - } - else if (args.entryAssemblyPath == "") - { - args.entryAssemblyPath = arg; - } - else - { - // forward command line parameters - args.argc = argc-i; - args.argv = &argv[i]; - - // explicitly break here because the lines above consume all remaining arguments - break; - } - } - - // check for mandatory parameters - if (args.entryAssemblyPath == "") - { - std::cerr << "error: assembly_name argument missing" << std::endl; - } - - return true; -} - } int main(int argc, char** argv) @@ -356,13 +355,13 @@ int main(int argc, char** argv) void* hostHandle; unsigned int domainId; int status = initializeCoreCLR( - currentExeAbsolutePath.c_str(), - "ps_cmdline_host", - sizeof(propertyKeys)/sizeof(propertyKeys[0]), - propertyKeys, - propertyValues, - &hostHandle, - &domainId); + currentExeAbsolutePath.c_str(), + "ps_cmdline_host", + sizeof(propertyKeys)/sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + &hostHandle, + &domainId); if (0 > status) { @@ -374,12 +373,12 @@ int main(int argc, char** argv) typedef void (*LoaderRunHelperFp)(const char16_t* appPath); LoaderRunHelperFp loaderDelegate = nullptr; status = createDelegate( - hostHandle, - domainId, - "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", - "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", - "SetPowerShellAssemblyLoadContext", - (void**)&loaderDelegate); + hostHandle, + domainId, + "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", + "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", + "SetPowerShellAssemblyLoadContext", + (void**)&loaderDelegate); if (0 > status) { std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index 6aa8b9896..07509a494 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -7,103 +7,102 @@ namespace CoreCLRUtil { - -bool GetAbsolutePath(const char* path, std::string& absolutePath) -{ - bool result = false; - - char realPath[PATH_MAX]; - if (realpath(path, realPath) != nullptr && realPath[0] != '\0') + bool GetAbsolutePath(const char* path, std::string& absolutePath) { - absolutePath.assign(realPath); - // realpath should return canonicalized path without the trailing slash - assert(absolutePath.back() != '/'); + bool result = false; - result = true; - } - - return result; -} - -bool GetDirectory(const char* absolutePath, std::string& directory) -{ - directory.assign(absolutePath); - size_t lastSlash = directory.rfind('/'); - if (lastSlash != std::string::npos) - { - directory.erase(lastSlash); - return true; - } - - return false; -} - -bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) -{ - std::string clrFilesRelativePath; - const char* clrFilesPathLocal = clrFilesPath; - if (clrFilesPathLocal == nullptr) - { - // There was no CLR files path specified, use the folder of the corerun/coreconsole - if (!GetDirectory(currentExePath, clrFilesRelativePath)) + char realPath[PATH_MAX]; + if (realpath(path, realPath) != nullptr && realPath[0] != '\0') { - perror("Failed to get directory from argv[0]"); - return false; + absolutePath.assign(realPath); + // realpath should return canonicalized path without the trailing slash + assert(absolutePath.back() != '/'); + + result = true; } - clrFilesPathLocal = clrFilesRelativePath.c_str(); - - // TODO: consider using an env variable (if defined) as a fall-back. - // The windows version of the corerun uses core_root env variable + return result; } - if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) + bool GetDirectory(const char* absolutePath, std::string& directory) { - perror("Failed to convert CLR files path to absolute path"); + directory.assign(absolutePath); + size_t lastSlash = directory.rfind('/'); + if (lastSlash != std::string::npos) + { + directory.erase(lastSlash); + return true; + } + return false; } - return true; -} - -void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) -{ - const char * const tpaExtensions[] = { - ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir - ".dll", - ".ni.exe", - ".exe", - }; - - DIR* dir = opendir(directory); - if (dir == nullptr) + bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) { - return; + std::string clrFilesRelativePath; + const char* clrFilesPathLocal = clrFilesPath; + if (clrFilesPathLocal == nullptr) + { + // There was no CLR files path specified, use the folder of the corerun/coreconsole + if (!GetDirectory(currentExePath, clrFilesRelativePath)) + { + perror("Failed to get directory from argv[0]"); + return false; + } + + clrFilesPathLocal = clrFilesRelativePath.c_str(); + + // TODO: consider using an env variable (if defined) as a fall-back. + // The windows version of the corerun uses core_root env variable + } + + if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) + { + perror("Failed to convert CLR files path to absolute path"); + return false; + } + + return true; } - std::set addedAssemblies; - - // Walk the directory for each extension separately so that we first get files with .ni.dll extension, - // then files with .dll extension, etc. - for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) { - const char* ext = tpaExtensions[extIndex]; - int extLength = strlen(ext); - - struct dirent* entry; - - // For all entries in the directory - while ((entry = readdir(dir)) != nullptr) + const char * const tpaExtensions[] = { + ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir + ".dll", + ".ni.exe", + ".exe", + }; + + DIR* dir = opendir(directory); + if (dir == nullptr) { - // We are interested in files only - switch (entry->d_type) - { - case DT_REG: - break; + return; + } - // Handle symlinks and file systems that do not support d_type - case DT_LNK: - case DT_UNKNOWN: + std::set addedAssemblies; + + // Walk the directory for each extension separately so that we first get files with .ni.dll extension, + // then files with .dll extension, etc. + for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + { + const char* ext = tpaExtensions[extIndex]; + int extLength = strlen(ext); + + struct dirent* entry; + + // For all entries in the directory + while ((entry = readdir(dir)) != nullptr) + { + // We are interested in files only + switch (entry->d_type) + { + case DT_REG: + break; + + // Handle symlinks and file systems that do not support d_type + case DT_LNK: + case DT_UNKNOWN: { std::string fullFilename; @@ -124,44 +123,42 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) } break; - default: - continue; + default: + continue; + } + + std::string filename(entry->d_name); + + // Check if the extension matches the one we are looking for + int extPos = filename.length() - extLength; + if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) + { + continue; + } + + std::string filenameWithoutExt(filename.substr(0, extPos)); + + // Make sure if we have an assembly with multiple extensions present, + // we insert only one version of it. + if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) + { + addedAssemblies.insert(filenameWithoutExt); + + tpaList.append(directory); + tpaList.append("/"); + tpaList.append(filename); + tpaList.append(":"); + } } - - std::string filename(entry->d_name); - - // Check if the extension matches the one we are looking for - int extPos = filename.length() - extLength; - if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) - { - continue; - } - - std::string filenameWithoutExt(filename.substr(0, extPos)); - - // Make sure if we have an assembly with multiple extensions present, - // we insert only one version of it. - if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) - { - addedAssemblies.insert(filenameWithoutExt); - - tpaList.append(directory); - tpaList.append("/"); - tpaList.append(filename); - tpaList.append(":"); - } - } - // Rewind the directory stream to be able to iterate over it for the next extension - rewinddir(dir); - } + // Rewind the directory stream to be able to iterate over it for the next extension + rewinddir(dir); + } - closedir(dir); + closedir(dir); - // strip any trailing : from the tpaList - if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':') - tpaList.resize(tpaList.size()-1); + // strip any trailing : from the tpaList + if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':') + tpaList.resize(tpaList.size()-1); + } } - -} // namespace CoreCLRUtil - diff --git a/src/host/common/coreclrutil.h b/src/host/common/coreclrutil.h index 49a45ab6e..6236c8dee 100644 --- a/src/host/common/coreclrutil.h +++ b/src/host/common/coreclrutil.h @@ -4,60 +4,59 @@ namespace CoreCLRUtil { + // + // This code is mostly copied and modified from original CoreCLR project's + // code on github: https://github.com/dotnet/coreclr + // -// -// This code is mostly copied and modified from original CoreCLR project's -// code on github: https://github.com/dotnet/coreclr -// + // + // these function signatures are the entry point API for CoreCLR + // -// -// these function signatures are the entry point API for CoreCLR -// + // Prototype of the coreclr_initialize function from the libcoreclr.so + typedef int (*InitializeCoreCLRFunction)( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); -// Prototype of the coreclr_initialize function from the libcoreclr.so -typedef int (*InitializeCoreCLRFunction)( - const char* exePath, - const char* appDomainFriendlyName, - int propertyCount, - const char** propertyKeys, - const char** propertyValues, - void** hostHandle, - unsigned int* domainId); + // Prototype of the coreclr_shutdown function from the libcoreclr.so + typedef int (*ShutdownCoreCLRFunction)( + void* hostHandle, + unsigned int domainId); -// Prototype of the coreclr_shutdown function from the libcoreclr.so -typedef int (*ShutdownCoreCLRFunction)( - void* hostHandle, - unsigned int domainId); + // Prototype of the coreclr_execute_assembly function from the libcoreclr.so + typedef int (*ExecuteAssemblyFunction)( + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); -// Prototype of the coreclr_execute_assembly function from the libcoreclr.so -typedef int (*ExecuteAssemblyFunction)( - void* hostHandle, - unsigned int domainId, - int argc, - const char** argv, - const char* managedAssemblyPath, - unsigned int* exitCode); + // Prototype of coreclr_create_delegate function from the libcoreclr.so + typedef int (*CreateDelegateFunction)( + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate); -// Prototype of coreclr_create_delegate function from the libcoreclr.so -typedef int (*CreateDelegateFunction)( - void* hostHandle, - unsigned int domainId, - const char* entryPointAssemblyName, - const char* entryPointTypeName, - const char* entryPointMethodName, - void** delegate); - -// The name of the CoreCLR native runtime DLL + // The name of the CoreCLR native runtime DLL #if defined(__APPLE__) -constexpr char coreClrDll[] = "libcoreclr.dylib"; + constexpr char coreClrDll[] = "libcoreclr.dylib"; #else -constexpr char coreClrDll[] = "libcoreclr.so"; + constexpr char coreClrDll[] = "libcoreclr.so"; #endif -bool GetAbsolutePath(const char* path, std::string& absolutePath); -bool GetDirectory(const char* absolutePath, std::string& directory); -bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); -void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); + bool GetAbsolutePath(const char* path, std::string& absolutePath); + bool GetDirectory(const char* absolutePath, std::string& directory); + bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); + void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); } // namespace CoreCLRUtil diff --git a/src/host/common/hostutil.h b/src/host/common/hostutil.h index a8c9a208d..60bec5519 100644 --- a/src/host/common/hostutil.h +++ b/src/host/common/hostutil.h @@ -5,44 +5,40 @@ namespace HostUtil { - -//!\brief get a list of absolute paths separated by : from a list of relative/absolute paths separated by : -std::string getAbsolutePathList(const std::string& paths) -{ - //std::cerr << "getAbsolutePathList: paths=" << paths << std::endl; - std::string result; - - // split by : - size_t lastPos = 0; - size_t curPos = paths.find(':',lastPos); - do + //!\brief get a list of absolute paths separated by : from a list of relative/absolute paths separated by : + std::string getAbsolutePathList(const std::string& paths) { - const std::string token = paths.substr(lastPos,curPos-lastPos); - //std::cerr << "curPos=" << curPos << " lastPos=" << lastPos << " token=" << token << std::endl; + //std::cerr << "getAbsolutePathList: paths=" << paths << std::endl; + std::string result; - // skip empty tokens - if (token != "") + // split by : + size_t lastPos = 0; + size_t curPos = paths.find(':',lastPos); + do { - std::string absolutePath; - if (CoreCLRUtil::GetAbsolutePath(token.c_str(),absolutePath)) + const std::string token = paths.substr(lastPos,curPos-lastPos); + //std::cerr << "curPos=" << curPos << " lastPos=" << lastPos << " token=" << token << std::endl; + + // skip empty tokens + if (token != "") { - // add colons correctly - if (result.size() == 0) - result += absolutePath; - else - result += ":" + absolutePath; + std::string absolutePath; + if (CoreCLRUtil::GetAbsolutePath(token.c_str(),absolutePath)) + { + // add colons correctly + if (result.size() == 0) + result += absolutePath; + else + result += ":" + absolutePath; + } } + + // increment lastPos to skip the : + lastPos += token.size() + 1; + curPos = paths.find(':',lastPos); } + while (lastPos < paths.size()); - // increment lastPos to skip the : - lastPos += token.size() + 1; - curPos = paths.find(':',lastPos); + return result; } - while (lastPos < paths.size()); - - return result; } - -} - - From be95c604e6fde505c8322f93722f2c7845deaebd Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 21 Oct 2015 15:22:57 -0700 Subject: [PATCH 188/342] Reindent host code using project standards --- host/cmdline/main.cpp | 303 ++++++++++++++++++------------------ host/common/coreclrutil.cpp | 229 ++++++++++++++------------- host/common/coreclrutil.h | 87 +++++------ host/common/hostutil.h | 60 ++++--- 4 files changed, 335 insertions(+), 344 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 61c1cb9e4..ce058b7ce 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -11,153 +11,152 @@ namespace Cmdline { - -void printHelp() -{ - std::cerr << "PS CoreCLR host" << std::endl - << "Usage: host_cmdline [-c coreclr_path] [-alc load_context_assembly] [-s search_paths]" << std::endl - << " [-b base_path] assembly [...]" << std::endl - << std::endl - << "What it does:" << std::endl - << "- by default the host assumes that CoreCLR is located in the same folder" << std::endl - << " as host_cmdline" << std::endl - << " + this behavior can be overridden with the -c command line argument" << std::endl - << "- by default the host assumes that the assembly named" << std::endl - << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl - << " platform assemblies" << std::endl - << " + a custom assembly containing the PowerShellAssemblyLoadContext can" << std::endl - << " be provided with the -alc command line argument" << std::endl - << "- all additional parameters at the end of the command line are forwarded" << std::endl - << " to the Main function in the assembly" << std::endl - << "- the host will execute the Main function in the specified assembly" << std::endl - << " + this assembly has to be located in the search path" << std::endl - << "- by default the host will add the current working directory to the assembly search path" << std::endl - << " + this can be overridden with the -s command line argument" << std::endl - << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl - << "- by default the host assumes the PS base path for the assembly load context is the current" << std::endl - << " working directory" << std::endl - << " + this can be overridden with the -b command line argument" << std::endl - << "- the function signature of the Main function that gets executed must be:" << std::endl - << " static void Main(string[] args)" << std::endl - << std::endl - << "Options:" << std::endl - << "-c, --clr-path path to libcoreclr.so and the managed CLR assemblies" << std::endl - << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl - << "-s a list of assembly search paths, separated by :" << std::endl - << "-b the powershell assembly base path" << std::endl - << "-v verbose output, show paths" << std::endl - << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl - << " separated by :" << std::endl - << " unless part of the same folder as CoreCLR, the main assembly referenced with the assembly_name" << std::endl - << " argument, must always be added to the TPA list with this parameter" << std::endl - << "assembly the path of the assembly to execute relative to current directory" << std::endl - << std::endl - << "Example:" << std::endl - << "./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 -{ - Args() : - argc(0), - argv(nullptr), - verbose(false) + void printHelp() { + std::cerr << "PS CoreCLR host" << std::endl + << "Usage: host_cmdline [-c coreclr_path] [-alc load_context_assembly] [-s search_paths]" << std::endl + << " [-b base_path] assembly [...]" << std::endl + << std::endl + << "What it does:" << std::endl + << "- by default the host assumes that CoreCLR is located in the same folder" << std::endl + << " as host_cmdline" << std::endl + << " + this behavior can be overridden with the -c command line argument" << std::endl + << "- by default the host assumes that the assembly named" << std::endl + << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl + << " platform assemblies" << std::endl + << " + a custom assembly containing the PowerShellAssemblyLoadContext can" << std::endl + << " be provided with the -alc command line argument" << std::endl + << "- all additional parameters at the end of the command line are forwarded" << std::endl + << " to the Main function in the assembly" << std::endl + << "- the host will execute the Main function in the specified assembly" << std::endl + << " + this assembly has to be located in the search path" << std::endl + << "- by default the host will add the current working directory to the assembly search path" << std::endl + << " + this can be overridden with the -s command line argument" << std::endl + << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl + << "- by default the host assumes the PS base path for the assembly load context is the current" << std::endl + << " working directory" << std::endl + << " + this can be overridden with the -b command line argument" << std::endl + << "- the function signature of the Main function that gets executed must be:" << std::endl + << " static void Main(string[] args)" << std::endl + << std::endl + << "Options:" << std::endl + << "-c, --clr-path path to libcoreclr.so and the managed CLR assemblies" << std::endl + << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl + << "-s a list of assembly search paths, separated by :" << std::endl + << "-b the powershell assembly base path" << std::endl + << "-v verbose output, show paths" << std::endl + << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl + << " separated by :" << std::endl + << " unless part of the same folder as CoreCLR, the main assembly referenced with the assembly_name" << std::endl + << " argument, must always be added to the TPA list with this parameter" << std::endl + << "assembly the path of the assembly to execute relative to current directory" << std::endl + << std::endl + << "Example:" << std::endl + << "./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; } - std::string clrPath; - std::string assemblyLoadContextFilePath; - std::string searchPaths; - std::string basePath; - std::string tpaList; - std::string entryAssemblyPath; - int argc; - char** argv; - bool verbose; - - void debugPrint() const + struct Args { - std::cerr << "Args:" << std::endl - << "- clrPath " << clrPath << std::endl - << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl - << "- searchPaths " << searchPaths << std::endl - << "- basePath " << basePath << std::endl - << "- tpaList " << tpaList << std::endl - << "- entryAssemblyPath " << entryAssemblyPath << std::endl - << "- argc " << argc << std::endl - << "- verbose " << (verbose ? "true" : "false") << std::endl; - } -}; + Args() : + argc(0), + argv(nullptr), + verbose(false) + { + } -// this is implemented without any 3rd party lib to keep the list -// of dependencies low -bool parseCmdline(const int argc, char** argv, Args& args) -{ - if (argc <= 1) + std::string clrPath; + std::string assemblyLoadContextFilePath; + std::string searchPaths; + std::string basePath; + std::string tpaList; + std::string entryAssemblyPath; + int argc; + char** argv; + bool verbose; + + void debugPrint() const + { + std::cerr << "Args:" << std::endl + << "- clrPath " << clrPath << std::endl + << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl + << "- searchPaths " << searchPaths << std::endl + << "- basePath " << basePath << std::endl + << "- tpaList " << tpaList << std::endl + << "- entryAssemblyPath " << entryAssemblyPath << std::endl + << "- argc " << argc << std::endl + << "- verbose " << (verbose ? "true" : "false") << std::endl; + } + }; + + // this is implemented without any 3rd party lib to keep the list + // of dependencies low + bool parseCmdline(const int argc, char** argv, Args& args) { - std::cerr << "error: missing arguments" << std::endl; - return false; + if (argc <= 1) + { + std::cerr << "error: missing arguments" << std::endl; + return false; + } + + for (int i = 1; i < argc; ++i) + { + const std::string arg = argv[i]; + const bool hasNextArg = i+1 < argc; + const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); + + if (hasNextArg && (arg == "-c" || arg == "--clr-path")) + { + args.clrPath = nextArg; + ++i; + } + else if (hasNextArg && arg == "-alc") + { + args.assemblyLoadContextFilePath = nextArg; + ++i; + } + else if (hasNextArg && arg == "-s") + { + args.searchPaths = nextArg; + ++i; + } + else if (hasNextArg && arg == "-b") + { + args.basePath = nextArg; + ++i; + } + else if (hasNextArg && arg == "-tpa") + { + args.tpaList = nextArg; + ++i; + } + else if (arg == "-v") + { + args.verbose = true; + } + else if (args.entryAssemblyPath == "") + { + args.entryAssemblyPath = arg; + } + else + { + // forward command line parameters + args.argc = argc-i; + args.argv = &argv[i]; + + // explicitly break here because the lines above consume all remaining arguments + break; + } + } + + // check for mandatory parameters + if (args.entryAssemblyPath == "") + { + std::cerr << "error: assembly_name argument missing" << std::endl; + } + + return true; } - for (int i = 1; i < argc; ++i) - { - const std::string arg = argv[i]; - const bool hasNextArg = i+1 < argc; - const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); - - if (hasNextArg && (arg == "-c" || arg == "--clr-path")) - { - args.clrPath = nextArg; - ++i; - } - else if (hasNextArg && arg == "-alc") - { - args.assemblyLoadContextFilePath = nextArg; - ++i; - } - else if (hasNextArg && arg == "-s") - { - args.searchPaths = nextArg; - ++i; - } - else if (hasNextArg && arg == "-b") - { - args.basePath = nextArg; - ++i; - } - else if (hasNextArg && arg == "-tpa") - { - args.tpaList = nextArg; - ++i; - } - else if (arg == "-v") - { - args.verbose = true; - } - else if (args.entryAssemblyPath == "") - { - args.entryAssemblyPath = arg; - } - else - { - // forward command line parameters - args.argc = argc-i; - args.argv = &argv[i]; - - // explicitly break here because the lines above consume all remaining arguments - break; - } - } - - // check for mandatory parameters - if (args.entryAssemblyPath == "") - { - std::cerr << "error: assembly_name argument missing" << std::endl; - } - - return true; -} - } int main(int argc, char** argv) @@ -356,13 +355,13 @@ int main(int argc, char** argv) void* hostHandle; unsigned int domainId; int status = initializeCoreCLR( - currentExeAbsolutePath.c_str(), - "ps_cmdline_host", - sizeof(propertyKeys)/sizeof(propertyKeys[0]), - propertyKeys, - propertyValues, - &hostHandle, - &domainId); + currentExeAbsolutePath.c_str(), + "ps_cmdline_host", + sizeof(propertyKeys)/sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + &hostHandle, + &domainId); if (0 > status) { @@ -374,12 +373,12 @@ int main(int argc, char** argv) typedef void (*LoaderRunHelperFp)(const char16_t* appPath); LoaderRunHelperFp loaderDelegate = nullptr; status = createDelegate( - hostHandle, - domainId, - "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", - "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", - "SetPowerShellAssemblyLoadContext", - (void**)&loaderDelegate); + hostHandle, + domainId, + "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", + "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", + "SetPowerShellAssemblyLoadContext", + (void**)&loaderDelegate); if (0 > status) { std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index 6aa8b9896..07509a494 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -7,103 +7,102 @@ namespace CoreCLRUtil { - -bool GetAbsolutePath(const char* path, std::string& absolutePath) -{ - bool result = false; - - char realPath[PATH_MAX]; - if (realpath(path, realPath) != nullptr && realPath[0] != '\0') + bool GetAbsolutePath(const char* path, std::string& absolutePath) { - absolutePath.assign(realPath); - // realpath should return canonicalized path without the trailing slash - assert(absolutePath.back() != '/'); + bool result = false; - result = true; - } - - return result; -} - -bool GetDirectory(const char* absolutePath, std::string& directory) -{ - directory.assign(absolutePath); - size_t lastSlash = directory.rfind('/'); - if (lastSlash != std::string::npos) - { - directory.erase(lastSlash); - return true; - } - - return false; -} - -bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) -{ - std::string clrFilesRelativePath; - const char* clrFilesPathLocal = clrFilesPath; - if (clrFilesPathLocal == nullptr) - { - // There was no CLR files path specified, use the folder of the corerun/coreconsole - if (!GetDirectory(currentExePath, clrFilesRelativePath)) + char realPath[PATH_MAX]; + if (realpath(path, realPath) != nullptr && realPath[0] != '\0') { - perror("Failed to get directory from argv[0]"); - return false; + absolutePath.assign(realPath); + // realpath should return canonicalized path without the trailing slash + assert(absolutePath.back() != '/'); + + result = true; } - clrFilesPathLocal = clrFilesRelativePath.c_str(); - - // TODO: consider using an env variable (if defined) as a fall-back. - // The windows version of the corerun uses core_root env variable + return result; } - if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) + bool GetDirectory(const char* absolutePath, std::string& directory) { - perror("Failed to convert CLR files path to absolute path"); + directory.assign(absolutePath); + size_t lastSlash = directory.rfind('/'); + if (lastSlash != std::string::npos) + { + directory.erase(lastSlash); + return true; + } + return false; } - return true; -} - -void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) -{ - const char * const tpaExtensions[] = { - ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir - ".dll", - ".ni.exe", - ".exe", - }; - - DIR* dir = opendir(directory); - if (dir == nullptr) + bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) { - return; + std::string clrFilesRelativePath; + const char* clrFilesPathLocal = clrFilesPath; + if (clrFilesPathLocal == nullptr) + { + // There was no CLR files path specified, use the folder of the corerun/coreconsole + if (!GetDirectory(currentExePath, clrFilesRelativePath)) + { + perror("Failed to get directory from argv[0]"); + return false; + } + + clrFilesPathLocal = clrFilesRelativePath.c_str(); + + // TODO: consider using an env variable (if defined) as a fall-back. + // The windows version of the corerun uses core_root env variable + } + + if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) + { + perror("Failed to convert CLR files path to absolute path"); + return false; + } + + return true; } - std::set addedAssemblies; - - // Walk the directory for each extension separately so that we first get files with .ni.dll extension, - // then files with .dll extension, etc. - for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) { - const char* ext = tpaExtensions[extIndex]; - int extLength = strlen(ext); - - struct dirent* entry; - - // For all entries in the directory - while ((entry = readdir(dir)) != nullptr) + const char * const tpaExtensions[] = { + ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir + ".dll", + ".ni.exe", + ".exe", + }; + + DIR* dir = opendir(directory); + if (dir == nullptr) { - // We are interested in files only - switch (entry->d_type) - { - case DT_REG: - break; + return; + } - // Handle symlinks and file systems that do not support d_type - case DT_LNK: - case DT_UNKNOWN: + std::set addedAssemblies; + + // Walk the directory for each extension separately so that we first get files with .ni.dll extension, + // then files with .dll extension, etc. + for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + { + const char* ext = tpaExtensions[extIndex]; + int extLength = strlen(ext); + + struct dirent* entry; + + // For all entries in the directory + while ((entry = readdir(dir)) != nullptr) + { + // We are interested in files only + switch (entry->d_type) + { + case DT_REG: + break; + + // Handle symlinks and file systems that do not support d_type + case DT_LNK: + case DT_UNKNOWN: { std::string fullFilename; @@ -124,44 +123,42 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) } break; - default: - continue; + default: + continue; + } + + std::string filename(entry->d_name); + + // Check if the extension matches the one we are looking for + int extPos = filename.length() - extLength; + if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) + { + continue; + } + + std::string filenameWithoutExt(filename.substr(0, extPos)); + + // Make sure if we have an assembly with multiple extensions present, + // we insert only one version of it. + if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) + { + addedAssemblies.insert(filenameWithoutExt); + + tpaList.append(directory); + tpaList.append("/"); + tpaList.append(filename); + tpaList.append(":"); + } } - - std::string filename(entry->d_name); - - // Check if the extension matches the one we are looking for - int extPos = filename.length() - extLength; - if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) - { - continue; - } - - std::string filenameWithoutExt(filename.substr(0, extPos)); - - // Make sure if we have an assembly with multiple extensions present, - // we insert only one version of it. - if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) - { - addedAssemblies.insert(filenameWithoutExt); - - tpaList.append(directory); - tpaList.append("/"); - tpaList.append(filename); - tpaList.append(":"); - } - } - // Rewind the directory stream to be able to iterate over it for the next extension - rewinddir(dir); - } + // Rewind the directory stream to be able to iterate over it for the next extension + rewinddir(dir); + } - closedir(dir); + closedir(dir); - // strip any trailing : from the tpaList - if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':') - tpaList.resize(tpaList.size()-1); + // strip any trailing : from the tpaList + if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':') + tpaList.resize(tpaList.size()-1); + } } - -} // namespace CoreCLRUtil - diff --git a/host/common/coreclrutil.h b/host/common/coreclrutil.h index 49a45ab6e..6236c8dee 100644 --- a/host/common/coreclrutil.h +++ b/host/common/coreclrutil.h @@ -4,60 +4,59 @@ namespace CoreCLRUtil { + // + // This code is mostly copied and modified from original CoreCLR project's + // code on github: https://github.com/dotnet/coreclr + // -// -// This code is mostly copied and modified from original CoreCLR project's -// code on github: https://github.com/dotnet/coreclr -// + // + // these function signatures are the entry point API for CoreCLR + // -// -// these function signatures are the entry point API for CoreCLR -// + // Prototype of the coreclr_initialize function from the libcoreclr.so + typedef int (*InitializeCoreCLRFunction)( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); -// Prototype of the coreclr_initialize function from the libcoreclr.so -typedef int (*InitializeCoreCLRFunction)( - const char* exePath, - const char* appDomainFriendlyName, - int propertyCount, - const char** propertyKeys, - const char** propertyValues, - void** hostHandle, - unsigned int* domainId); + // Prototype of the coreclr_shutdown function from the libcoreclr.so + typedef int (*ShutdownCoreCLRFunction)( + void* hostHandle, + unsigned int domainId); -// Prototype of the coreclr_shutdown function from the libcoreclr.so -typedef int (*ShutdownCoreCLRFunction)( - void* hostHandle, - unsigned int domainId); + // Prototype of the coreclr_execute_assembly function from the libcoreclr.so + typedef int (*ExecuteAssemblyFunction)( + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); -// Prototype of the coreclr_execute_assembly function from the libcoreclr.so -typedef int (*ExecuteAssemblyFunction)( - void* hostHandle, - unsigned int domainId, - int argc, - const char** argv, - const char* managedAssemblyPath, - unsigned int* exitCode); + // Prototype of coreclr_create_delegate function from the libcoreclr.so + typedef int (*CreateDelegateFunction)( + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate); -// Prototype of coreclr_create_delegate function from the libcoreclr.so -typedef int (*CreateDelegateFunction)( - void* hostHandle, - unsigned int domainId, - const char* entryPointAssemblyName, - const char* entryPointTypeName, - const char* entryPointMethodName, - void** delegate); - -// The name of the CoreCLR native runtime DLL + // The name of the CoreCLR native runtime DLL #if defined(__APPLE__) -constexpr char coreClrDll[] = "libcoreclr.dylib"; + constexpr char coreClrDll[] = "libcoreclr.dylib"; #else -constexpr char coreClrDll[] = "libcoreclr.so"; + constexpr char coreClrDll[] = "libcoreclr.so"; #endif -bool GetAbsolutePath(const char* path, std::string& absolutePath); -bool GetDirectory(const char* absolutePath, std::string& directory); -bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); -void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); + bool GetAbsolutePath(const char* path, std::string& absolutePath); + bool GetDirectory(const char* absolutePath, std::string& directory); + bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); + void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); } // namespace CoreCLRUtil diff --git a/host/common/hostutil.h b/host/common/hostutil.h index a8c9a208d..60bec5519 100644 --- a/host/common/hostutil.h +++ b/host/common/hostutil.h @@ -5,44 +5,40 @@ namespace HostUtil { - -//!\brief get a list of absolute paths separated by : from a list of relative/absolute paths separated by : -std::string getAbsolutePathList(const std::string& paths) -{ - //std::cerr << "getAbsolutePathList: paths=" << paths << std::endl; - std::string result; - - // split by : - size_t lastPos = 0; - size_t curPos = paths.find(':',lastPos); - do + //!\brief get a list of absolute paths separated by : from a list of relative/absolute paths separated by : + std::string getAbsolutePathList(const std::string& paths) { - const std::string token = paths.substr(lastPos,curPos-lastPos); - //std::cerr << "curPos=" << curPos << " lastPos=" << lastPos << " token=" << token << std::endl; + //std::cerr << "getAbsolutePathList: paths=" << paths << std::endl; + std::string result; - // skip empty tokens - if (token != "") + // split by : + size_t lastPos = 0; + size_t curPos = paths.find(':',lastPos); + do { - std::string absolutePath; - if (CoreCLRUtil::GetAbsolutePath(token.c_str(),absolutePath)) + const std::string token = paths.substr(lastPos,curPos-lastPos); + //std::cerr << "curPos=" << curPos << " lastPos=" << lastPos << " token=" << token << std::endl; + + // skip empty tokens + if (token != "") { - // add colons correctly - if (result.size() == 0) - result += absolutePath; - else - result += ":" + absolutePath; + std::string absolutePath; + if (CoreCLRUtil::GetAbsolutePath(token.c_str(),absolutePath)) + { + // add colons correctly + if (result.size() == 0) + result += absolutePath; + else + result += ":" + absolutePath; + } } + + // increment lastPos to skip the : + lastPos += token.size() + 1; + curPos = paths.find(':',lastPos); } + while (lastPos < paths.size()); - // increment lastPos to skip the : - lastPos += token.size() + 1; - curPos = paths.find(':',lastPos); + return result; } - while (lastPos < paths.size()); - - return result; } - -} - - From ba972b0113d26313113f7fb0c06d6348202e5aa5 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 21 Oct 2015 19:15:05 -0700 Subject: [PATCH 189/342] Refactor most CLR code into libpshost --- src/CMakeLists.txt | 5 +- src/host/cmdline/main.cpp | 108 +++------------------- src/host/common/coreclrutil.cpp | 154 ++++++++++++++++++++++++++++++++ src/host/common/coreclrutil.h | 79 +++++++--------- 4 files changed, 201 insertions(+), 145 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b534ebb94..8db93c175 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,8 +24,9 @@ add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) # add pthread and other libs find_package(Threads) target_link_libraries(ps icuuc) -target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) -target_link_libraries(host_cmdline pshost dl icuuc) +target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps pshost) +target_link_libraries(pshost dl icuuc) +target_link_libraries(host_cmdline pshost icuuc) # target specific include directories target_include_directories(monad_native PRIVATE host) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index ce058b7ce..32cb4eed8 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -3,7 +3,6 @@ #include "common/coreclrutil.h" #include "common/hostutil.h" #include -#include #include #include #include @@ -195,19 +194,6 @@ int main(int argc, char** argv) if (args.verbose) std::cerr << "clrAbsolutePath=" << clrAbsolutePath << std::endl; - // the path to the CoreCLR library - // - // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac - - std::string coreClrDllPath = clrAbsolutePath + "/" + CoreCLRUtil::coreClrDll; - if (coreClrDllPath.size() >= PATH_MAX) - { - std::cerr << "Absolute path to CoreCLR library too long" << std::endl; - return 1; - } - if (args.verbose) - std::cerr << "coreClrDllPath: " << coreClrDllPath << std::endl; - // TPA list // // The list of platform assemblies must include all CoreCLR assemblies @@ -297,82 +283,21 @@ int main(int argc, char** argv) int32_t targetSize = u8str.extract(0,u8str.length(),(char*)&psBasePath16[0],(psBasePath16.size()-1)*sizeof(char16_t),"UTF-16LE"); psBasePath16.resize(targetSize/sizeof(char16_t)+1); - // open the shared library - void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); - if (coreclrLib == nullptr) - { - char* error = dlerror(); - std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; - return 2; - } - - // query the function pointers - CoreCLRUtil::InitializeCoreCLRFunction initializeCoreCLR = (CoreCLRUtil::InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); - CoreCLRUtil::ExecuteAssemblyFunction executeAssembly = (CoreCLRUtil::ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); - CoreCLRUtil::ShutdownCoreCLRFunction shutdownCoreCLR = (CoreCLRUtil::ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); - CoreCLRUtil::CreateDelegateFunction createDelegate = (CoreCLRUtil::CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); - - if (initializeCoreCLR == nullptr) - { - std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; - return 3; - } - if (executeAssembly == nullptr) - { - std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; - return 3; - } - if (shutdownCoreCLR == nullptr) - { - std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; - return 3; - } - if (createDelegate == nullptr) - { - std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; - return 3; - } - - // create list of properties to initialize CoreCLR - const char* propertyKeys[] = { - "TRUSTED_PLATFORM_ASSEMBLIES", - "APP_PATHS", - "APP_NI_PATHS", - "NATIVE_DLL_SEARCH_DIRECTORIES", - "AppDomainCompatSwitch" - }; - - const char* propertyValues[] = { - tpaList.c_str(), - appPath.c_str(), - appPath.c_str(), - nativeDllSearchDirs.c_str(), - "UseLatestBehaviorWhenTFMNotSpecified" - }; - - - // initialize CoreCLR void* hostHandle; unsigned int domainId; - int status = initializeCoreCLR( - currentExeAbsolutePath.c_str(), + int status = CoreCLRUtil::startCoreClr( + clrAbsolutePath.c_str(), + tpaList.c_str(), + appPath.c_str(), + nativeDllSearchDirs.c_str(), "ps_cmdline_host", - sizeof(propertyKeys)/sizeof(propertyKeys[0]), - propertyKeys, - propertyValues, &hostHandle, &domainId); - if (0 > status) - { - std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; - return 4; - } - // initialize the PS's custom assembly load context typedef void (*LoaderRunHelperFp)(const char16_t* appPath); LoaderRunHelperFp loaderDelegate = nullptr; - status = createDelegate( + status = CoreCLRUtil::createDelegate( hostHandle, domainId, "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", @@ -388,23 +313,12 @@ int main(int argc, char** 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); + CoreCLRUtil::executeAssembly(hostHandle, domainId, args.argc, + (const char**)args.argv, + (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), + &exitCode); - // shutdown CoreCLR - status = shutdownCoreCLR(hostHandle,domainId); - if (0 > status) - { - std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; - } - - // close the dynamic library - if (0 != dlclose(coreclrLib)) - { - std::cerr << "failed to close CoreCLR library" << std::endl; - } + status = CoreCLRUtil::stopCoreClr(hostHandle, domainId); return exitCode; } diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index 07509a494..edfc0662d 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -1,12 +1,166 @@ #include "coreclrutil.h" #include +#include #include #include #include +#include +#include #include namespace CoreCLRUtil { + // The name of the CoreCLR native runtime DLL +#if defined(__APPLE__) + constexpr char coreClrDll[] = "libcoreclr.dylib"; +#else + constexpr char coreClrDll[] = "libcoreclr.so"; +#endif + + void* coreclrLib; + + // Prototype of the coreclr_initialize function from the libcoreclr.so + typedef int (*InitializeCoreCLRFunction)( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); + + InitializeCoreCLRFunction initializeCoreCLR; + + // Prototype of the coreclr_shutdown function from the libcoreclr.so + typedef int (*ShutdownCoreCLRFunction)( + void* hostHandle, + unsigned int domainId); + + ShutdownCoreCLRFunction shutdownCoreCLR; + + ExecuteAssemblyFunction executeAssembly; + CreateDelegateFunction createDelegate; + + int startCoreClr( + // Paths of expected things + const char* clrAbsolutePath, + // Passed to propertyValues + const char* tpaList, + const char* appPath, + const char* nativeDllSearchDirs, + // Passed to InitializeCoreCLRFunction + const char* appDomainFriendlyName, + void** hostHandle, + unsigned int* domainId) + { + // the path to the CoreCLR library + // + // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac + std::string coreClrDllPath = clrAbsolutePath; + coreClrDllPath += "/"; + coreClrDllPath += coreClrDll; + + if (coreClrDllPath.size() >= PATH_MAX) + { + std::cerr << "Absolute path to CoreCLR library too long" << std::endl; + return 1; + } + + // open the shared library + coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); + if (coreclrLib == nullptr) + { + char* error = dlerror(); + std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; + return 2; + } + + // query the function pointers + initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); + shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); + + executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); + createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); + + if (initializeCoreCLR == nullptr) + { + std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; + return 3; + } + if (executeAssembly == nullptr) + { + std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; + return 3; + } + if (shutdownCoreCLR == nullptr) + { + std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; + return 3; + } + if (createDelegate == nullptr) + { + std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; + return 3; + } + + // create list of properties to initialize CoreCLR + const char* propertyKeys[] = { + "TRUSTED_PLATFORM_ASSEMBLIES", + "APP_PATHS", + "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", + "AppDomainCompatSwitch" + }; + + const char* propertyValues[] = { + tpaList, + appPath, + appPath, + nativeDllSearchDirs, + "UseLatestBehaviorWhenTFMNotSpecified" + }; + + // get path to current executable + char exePath[PATH_MAX] = { 0 }; + readlink("/proc/self/exe", exePath, PATH_MAX); + + // initialize CoreCLR + int status = initializeCoreCLR( + exePath, + appDomainFriendlyName, + sizeof(propertyKeys)/sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + hostHandle, + domainId); + + if (0 > status) + { + std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; + return 4; + } + + return status; + } + + int stopCoreClr(void* hostHandle, unsigned int domainId) + { + // shutdown CoreCLR + int status = shutdownCoreCLR(hostHandle, domainId); + if (0 > status) + { + std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; + } + + // close the dynamic library + if (0 != dlclose(coreclrLib)) + { + std::cerr << "failed to close CoreCLR library" << std::endl; + } + + return status; + } + bool GetAbsolutePath(const char* path, std::string& absolutePath) { bool result = false; diff --git a/src/host/common/coreclrutil.h b/src/host/common/coreclrutil.h index 6236c8dee..fe0ad77fc 100644 --- a/src/host/common/coreclrutil.h +++ b/src/host/common/coreclrutil.h @@ -4,59 +4,46 @@ namespace CoreCLRUtil { - // - // This code is mostly copied and modified from original CoreCLR project's - // code on github: https://github.com/dotnet/coreclr - // + extern "C" { + int startCoreClr( + // Paths of expected things + const char* clrAbsolutePath, + // Passed to propertyValues + const char* tpaList, + const char* appPath, + const char* nativeDllSearchDirs, + // Passed to InitializeCoreCLRFunction + const char* appDomainFriendlyName, + void** hostHandle, + unsigned int* domainId); - // - // these function signatures are the entry point API for CoreCLR - // + int stopCoreClr(void* hostHandle, unsigned int domainId); - // Prototype of the coreclr_initialize function from the libcoreclr.so - typedef int (*InitializeCoreCLRFunction)( - const char* exePath, - const char* appDomainFriendlyName, - int propertyCount, - const char** propertyKeys, - const char** propertyValues, - void** hostHandle, - unsigned int* domainId); + // Prototype of the coreclr_execute_assembly function from the libcoreclr.so + typedef int (*ExecuteAssemblyFunction)( + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); - // Prototype of the coreclr_shutdown function from the libcoreclr.so - typedef int (*ShutdownCoreCLRFunction)( - void* hostHandle, - unsigned int domainId); + extern ExecuteAssemblyFunction executeAssembly; - // Prototype of the coreclr_execute_assembly function from the libcoreclr.so - typedef int (*ExecuteAssemblyFunction)( - void* hostHandle, - unsigned int domainId, - int argc, - const char** argv, - const char* managedAssemblyPath, - unsigned int* exitCode); + // Prototype of coreclr_create_delegate function from the libcoreclr.so + typedef int (*CreateDelegateFunction)( + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate); - // Prototype of coreclr_create_delegate function from the libcoreclr.so - typedef int (*CreateDelegateFunction)( - void* hostHandle, - unsigned int domainId, - const char* entryPointAssemblyName, - const char* entryPointTypeName, - const char* entryPointMethodName, - void** delegate); - - // The name of the CoreCLR native runtime DLL -#if defined(__APPLE__) - constexpr char coreClrDll[] = "libcoreclr.dylib"; -#else - constexpr char coreClrDll[] = "libcoreclr.so"; -#endif + extern CreateDelegateFunction createDelegate; + } bool GetAbsolutePath(const char* path, std::string& absolutePath); bool GetDirectory(const char* absolutePath, std::string& directory); bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); - -} // namespace CoreCLRUtil - +} From a1b9511f384b59848906931f2ee965313a58f45f Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 21 Oct 2015 19:15:05 -0700 Subject: [PATCH 190/342] Refactor most CLR code into libpshost --- CMakeLists.txt | 5 +- host/cmdline/main.cpp | 108 +++---------------------- host/common/coreclrutil.cpp | 154 ++++++++++++++++++++++++++++++++++++ host/common/coreclrutil.h | 79 ++++++++---------- 4 files changed, 201 insertions(+), 145 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b534ebb94..8db93c175 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,9 @@ add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) # add pthread and other libs find_package(Threads) target_link_libraries(ps icuuc) -target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps) -target_link_libraries(host_cmdline pshost dl icuuc) +target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps pshost) +target_link_libraries(pshost dl icuuc) +target_link_libraries(host_cmdline pshost icuuc) # target specific include directories target_include_directories(monad_native PRIVATE host) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index ce058b7ce..32cb4eed8 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -3,7 +3,6 @@ #include "common/coreclrutil.h" #include "common/hostutil.h" #include -#include #include #include #include @@ -195,19 +194,6 @@ int main(int argc, char** argv) if (args.verbose) std::cerr << "clrAbsolutePath=" << clrAbsolutePath << std::endl; - // the path to the CoreCLR library - // - // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac - - std::string coreClrDllPath = clrAbsolutePath + "/" + CoreCLRUtil::coreClrDll; - if (coreClrDllPath.size() >= PATH_MAX) - { - std::cerr << "Absolute path to CoreCLR library too long" << std::endl; - return 1; - } - if (args.verbose) - std::cerr << "coreClrDllPath: " << coreClrDllPath << std::endl; - // TPA list // // The list of platform assemblies must include all CoreCLR assemblies @@ -297,82 +283,21 @@ int main(int argc, char** argv) int32_t targetSize = u8str.extract(0,u8str.length(),(char*)&psBasePath16[0],(psBasePath16.size()-1)*sizeof(char16_t),"UTF-16LE"); psBasePath16.resize(targetSize/sizeof(char16_t)+1); - // open the shared library - void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); - if (coreclrLib == nullptr) - { - char* error = dlerror(); - std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; - return 2; - } - - // query the function pointers - CoreCLRUtil::InitializeCoreCLRFunction initializeCoreCLR = (CoreCLRUtil::InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); - CoreCLRUtil::ExecuteAssemblyFunction executeAssembly = (CoreCLRUtil::ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); - CoreCLRUtil::ShutdownCoreCLRFunction shutdownCoreCLR = (CoreCLRUtil::ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); - CoreCLRUtil::CreateDelegateFunction createDelegate = (CoreCLRUtil::CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); - - if (initializeCoreCLR == nullptr) - { - std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; - return 3; - } - if (executeAssembly == nullptr) - { - std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; - return 3; - } - if (shutdownCoreCLR == nullptr) - { - std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; - return 3; - } - if (createDelegate == nullptr) - { - std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; - return 3; - } - - // create list of properties to initialize CoreCLR - const char* propertyKeys[] = { - "TRUSTED_PLATFORM_ASSEMBLIES", - "APP_PATHS", - "APP_NI_PATHS", - "NATIVE_DLL_SEARCH_DIRECTORIES", - "AppDomainCompatSwitch" - }; - - const char* propertyValues[] = { - tpaList.c_str(), - appPath.c_str(), - appPath.c_str(), - nativeDllSearchDirs.c_str(), - "UseLatestBehaviorWhenTFMNotSpecified" - }; - - - // initialize CoreCLR void* hostHandle; unsigned int domainId; - int status = initializeCoreCLR( - currentExeAbsolutePath.c_str(), + int status = CoreCLRUtil::startCoreClr( + clrAbsolutePath.c_str(), + tpaList.c_str(), + appPath.c_str(), + nativeDllSearchDirs.c_str(), "ps_cmdline_host", - sizeof(propertyKeys)/sizeof(propertyKeys[0]), - propertyKeys, - propertyValues, &hostHandle, &domainId); - if (0 > status) - { - std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; - return 4; - } - // initialize the PS's custom assembly load context typedef void (*LoaderRunHelperFp)(const char16_t* appPath); LoaderRunHelperFp loaderDelegate = nullptr; - status = createDelegate( + status = CoreCLRUtil::createDelegate( hostHandle, domainId, "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", @@ -388,23 +313,12 @@ int main(int argc, char** 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); + CoreCLRUtil::executeAssembly(hostHandle, domainId, args.argc, + (const char**)args.argv, + (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), + &exitCode); - // shutdown CoreCLR - status = shutdownCoreCLR(hostHandle,domainId); - if (0 > status) - { - std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; - } - - // close the dynamic library - if (0 != dlclose(coreclrLib)) - { - std::cerr << "failed to close CoreCLR library" << std::endl; - } + status = CoreCLRUtil::stopCoreClr(hostHandle, domainId); return exitCode; } diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index 07509a494..edfc0662d 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -1,12 +1,166 @@ #include "coreclrutil.h" #include +#include #include #include #include +#include +#include #include namespace CoreCLRUtil { + // The name of the CoreCLR native runtime DLL +#if defined(__APPLE__) + constexpr char coreClrDll[] = "libcoreclr.dylib"; +#else + constexpr char coreClrDll[] = "libcoreclr.so"; +#endif + + void* coreclrLib; + + // Prototype of the coreclr_initialize function from the libcoreclr.so + typedef int (*InitializeCoreCLRFunction)( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); + + InitializeCoreCLRFunction initializeCoreCLR; + + // Prototype of the coreclr_shutdown function from the libcoreclr.so + typedef int (*ShutdownCoreCLRFunction)( + void* hostHandle, + unsigned int domainId); + + ShutdownCoreCLRFunction shutdownCoreCLR; + + ExecuteAssemblyFunction executeAssembly; + CreateDelegateFunction createDelegate; + + int startCoreClr( + // Paths of expected things + const char* clrAbsolutePath, + // Passed to propertyValues + const char* tpaList, + const char* appPath, + const char* nativeDllSearchDirs, + // Passed to InitializeCoreCLRFunction + const char* appDomainFriendlyName, + void** hostHandle, + unsigned int* domainId) + { + // the path to the CoreCLR library + // + // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac + std::string coreClrDllPath = clrAbsolutePath; + coreClrDllPath += "/"; + coreClrDllPath += coreClrDll; + + if (coreClrDllPath.size() >= PATH_MAX) + { + std::cerr << "Absolute path to CoreCLR library too long" << std::endl; + return 1; + } + + // open the shared library + coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); + if (coreclrLib == nullptr) + { + char* error = dlerror(); + std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; + return 2; + } + + // query the function pointers + initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); + shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); + + executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); + createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); + + if (initializeCoreCLR == nullptr) + { + std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; + return 3; + } + if (executeAssembly == nullptr) + { + std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; + return 3; + } + if (shutdownCoreCLR == nullptr) + { + std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; + return 3; + } + if (createDelegate == nullptr) + { + std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; + return 3; + } + + // create list of properties to initialize CoreCLR + const char* propertyKeys[] = { + "TRUSTED_PLATFORM_ASSEMBLIES", + "APP_PATHS", + "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", + "AppDomainCompatSwitch" + }; + + const char* propertyValues[] = { + tpaList, + appPath, + appPath, + nativeDllSearchDirs, + "UseLatestBehaviorWhenTFMNotSpecified" + }; + + // get path to current executable + char exePath[PATH_MAX] = { 0 }; + readlink("/proc/self/exe", exePath, PATH_MAX); + + // initialize CoreCLR + int status = initializeCoreCLR( + exePath, + appDomainFriendlyName, + sizeof(propertyKeys)/sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + hostHandle, + domainId); + + if (0 > status) + { + std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; + return 4; + } + + return status; + } + + int stopCoreClr(void* hostHandle, unsigned int domainId) + { + // shutdown CoreCLR + int status = shutdownCoreCLR(hostHandle, domainId); + if (0 > status) + { + std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; + } + + // close the dynamic library + if (0 != dlclose(coreclrLib)) + { + std::cerr << "failed to close CoreCLR library" << std::endl; + } + + return status; + } + bool GetAbsolutePath(const char* path, std::string& absolutePath) { bool result = false; diff --git a/host/common/coreclrutil.h b/host/common/coreclrutil.h index 6236c8dee..fe0ad77fc 100644 --- a/host/common/coreclrutil.h +++ b/host/common/coreclrutil.h @@ -4,59 +4,46 @@ namespace CoreCLRUtil { - // - // This code is mostly copied and modified from original CoreCLR project's - // code on github: https://github.com/dotnet/coreclr - // + extern "C" { + int startCoreClr( + // Paths of expected things + const char* clrAbsolutePath, + // Passed to propertyValues + const char* tpaList, + const char* appPath, + const char* nativeDllSearchDirs, + // Passed to InitializeCoreCLRFunction + const char* appDomainFriendlyName, + void** hostHandle, + unsigned int* domainId); - // - // these function signatures are the entry point API for CoreCLR - // + int stopCoreClr(void* hostHandle, unsigned int domainId); - // Prototype of the coreclr_initialize function from the libcoreclr.so - typedef int (*InitializeCoreCLRFunction)( - const char* exePath, - const char* appDomainFriendlyName, - int propertyCount, - const char** propertyKeys, - const char** propertyValues, - void** hostHandle, - unsigned int* domainId); + // Prototype of the coreclr_execute_assembly function from the libcoreclr.so + typedef int (*ExecuteAssemblyFunction)( + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); - // Prototype of the coreclr_shutdown function from the libcoreclr.so - typedef int (*ShutdownCoreCLRFunction)( - void* hostHandle, - unsigned int domainId); + extern ExecuteAssemblyFunction executeAssembly; - // Prototype of the coreclr_execute_assembly function from the libcoreclr.so - typedef int (*ExecuteAssemblyFunction)( - void* hostHandle, - unsigned int domainId, - int argc, - const char** argv, - const char* managedAssemblyPath, - unsigned int* exitCode); + // Prototype of coreclr_create_delegate function from the libcoreclr.so + typedef int (*CreateDelegateFunction)( + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate); - // Prototype of coreclr_create_delegate function from the libcoreclr.so - typedef int (*CreateDelegateFunction)( - void* hostHandle, - unsigned int domainId, - const char* entryPointAssemblyName, - const char* entryPointTypeName, - const char* entryPointMethodName, - void** delegate); - - // The name of the CoreCLR native runtime DLL -#if defined(__APPLE__) - constexpr char coreClrDll[] = "libcoreclr.dylib"; -#else - constexpr char coreClrDll[] = "libcoreclr.so"; -#endif + extern CreateDelegateFunction createDelegate; + } bool GetAbsolutePath(const char* path, std::string& absolutePath); bool GetDirectory(const char* absolutePath, std::string& directory); bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); - -} // namespace CoreCLRUtil - +} From fa79c480d049a997692bd10ebace83962012f7a1 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 11:58:35 -0700 Subject: [PATCH 191/342] Add 'src/host/unixcoreruncommon/' from commit 'a566a181a076f4fa49f4874934c080309424bd6c' git-subtree-dir: src/host/unixcoreruncommon git-subtree-mainline: ba972b0113d26313113f7fb0c06d6348202e5aa5 git-subtree-split: a566a181a076f4fa49f4874934c080309424bd6c --- host/unixcoreruncommon/.gitmirror | 1 + host/unixcoreruncommon/coreruncommon.cpp | 346 +++++++++++++++++++++++ host/unixcoreruncommon/coreruncommon.h | 46 +++ 3 files changed, 393 insertions(+) create mode 100644 host/unixcoreruncommon/.gitmirror create mode 100644 host/unixcoreruncommon/coreruncommon.cpp create mode 100644 host/unixcoreruncommon/coreruncommon.h diff --git a/host/unixcoreruncommon/.gitmirror b/host/unixcoreruncommon/.gitmirror new file mode 100644 index 000000000..f507630f9 --- /dev/null +++ b/host/unixcoreruncommon/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file diff --git a/host/unixcoreruncommon/coreruncommon.cpp b/host/unixcoreruncommon/coreruncommon.cpp new file mode 100644 index 000000000..ecbbf3929 --- /dev/null +++ b/host/unixcoreruncommon/coreruncommon.cpp @@ -0,0 +1,346 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// +// Code that is used by both the Unix corerun and coreconsole. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// The name of the CoreCLR native runtime DLL +#if defined(__APPLE__) +static const char * const coreClrDll = "libcoreclr.dylib"; +#else +static const char * const coreClrDll = "libcoreclr.so"; +#endif + +#define SUCCEEDED(Status) ((Status) >= 0) + +// Prototype of the coreclr_initialize function from the libcoreclr.so +typedef int (*InitializeCoreCLRFunction)( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); + +// Prototype of the coreclr_shutdown function from the libcoreclr.so +typedef int (*ShutdownCoreCLRFunction)( + void* hostHandle, + unsigned int domainId); + +// Prototype of the coreclr_execute_assembly function from the libcoreclr.so +typedef int (*ExecuteAssemblyFunction)( + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); + +bool GetAbsolutePath(const char* path, std::string& absolutePath) +{ + bool result = false; + + char realPath[PATH_MAX]; + if (realpath(path, realPath) != nullptr && realPath[0] != '\0') + { + absolutePath.assign(realPath); + // realpath should return canonicalized path without the trailing slash + assert(absolutePath.back() != '/'); + + result = true; + } + + return result; +} + +bool GetDirectory(const char* absolutePath, std::string& directory) +{ + directory.assign(absolutePath); + size_t lastSlash = directory.rfind('/'); + if (lastSlash != std::string::npos) + { + directory.erase(lastSlash); + return true; + } + + return false; +} + +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) +{ + std::string clrFilesRelativePath; + const char* clrFilesPathLocal = clrFilesPath; + if (clrFilesPathLocal == nullptr) + { + // There was no CLR files path specified, use the folder of the corerun/coreconsole + if (!GetDirectory(currentExePath, clrFilesRelativePath)) + { + perror("Failed to get directory from argv[0]"); + return false; + } + + clrFilesPathLocal = clrFilesRelativePath.c_str(); + + // TODO: consider using an env variable (if defined) as a fall-back. + // The windows version of the corerun uses core_root env variable + } + + if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) + { + perror("Failed to convert CLR files path to absolute path"); + return false; + } + + return true; +} + +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) +{ + const char * const tpaExtensions[] = { + ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir + ".dll", + ".ni.exe", + ".exe", + }; + + DIR* dir = opendir(directory); + if (dir == nullptr) + { + return; + } + + std::set addedAssemblies; + + // Walk the directory for each extension separately so that we first get files with .ni.dll extension, + // then files with .dll extension, etc. + for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + { + const char* ext = tpaExtensions[extIndex]; + int extLength = strlen(ext); + + struct dirent* entry; + + // For all entries in the directory + while ((entry = readdir(dir)) != nullptr) + { + // We are interested in files only + switch (entry->d_type) + { + case DT_REG: + break; + + // Handle symlinks and file systems that do not support d_type + case DT_LNK: + case DT_UNKNOWN: + { + std::string fullFilename; + + fullFilename.append(directory); + fullFilename.append("/"); + fullFilename.append(entry->d_name); + + struct stat sb; + if (stat(fullFilename.c_str(), &sb) == -1) + { + continue; + } + + if (!S_ISREG(sb.st_mode)) + { + continue; + } + } + break; + + default: + continue; + } + + std::string filename(entry->d_name); + + // Check if the extension matches the one we are looking for + int extPos = filename.length() - extLength; + if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) + { + continue; + } + + std::string filenameWithoutExt(filename.substr(0, extPos)); + + // Make sure if we have an assembly with multiple extensions present, + // we insert only one version of it. + if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) + { + addedAssemblies.insert(filenameWithoutExt); + + tpaList.append(directory); + tpaList.append("/"); + tpaList.append(filename); + tpaList.append(":"); + } + } + + // Rewind the directory stream to be able to iterate over it for the next extension + rewinddir(dir); + } + + closedir(dir); +} + +int ExecuteManagedAssembly( + const char* currentExeAbsolutePath, + const char* clrFilesAbsolutePath, + const char* managedAssemblyAbsolutePath, + int managedAssemblyArgc, + const char** managedAssemblyArgv) +{ + // Indicates failure + int exitCode = -1; + + std::string coreClrDllPath(clrFilesAbsolutePath); + coreClrDllPath.append("/"); + coreClrDllPath.append(coreClrDll); + + if (coreClrDllPath.length() >= PATH_MAX) + { + fprintf(stderr, "Absolute path to libcoreclr.so too long\n"); + return -1; + } + + // Get just the path component of the managed assembly path + std::string appPath; + GetDirectory(managedAssemblyAbsolutePath, appPath); + + std::string nativeDllSearchDirs(appPath); + nativeDllSearchDirs.append(":"); + nativeDllSearchDirs.append(clrFilesAbsolutePath); + + std::string tpaList; + AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath, tpaList); + + void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW | RTLD_LOCAL); + if (coreclrLib != nullptr) + { + InitializeCoreCLRFunction initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib, "coreclr_initialize"); + ExecuteAssemblyFunction executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib, "coreclr_execute_assembly"); + ShutdownCoreCLRFunction shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib, "coreclr_shutdown"); + + if (initializeCoreCLR == nullptr) + { + fprintf(stderr, "Function coreclr_initialize not found in the libcoreclr.so\n"); + } + else if (executeAssembly == nullptr) + { + fprintf(stderr, "Function coreclr_execute_assembly not found in the libcoreclr.so\n"); + } + else if (shutdownCoreCLR == nullptr) + { + fprintf(stderr, "Function coreclr_shutdown not found in the libcoreclr.so\n"); + } + else + { + // Allowed property names: + // APPBASE + // - The base path of the application from which the exe and other assemblies will be loaded + // + // TRUSTED_PLATFORM_ASSEMBLIES + // - The list of complete paths to each of the fully trusted assemblies + // + // APP_PATHS + // - The list of paths which will be probed by the assembly loader + // + // APP_NI_PATHS + // - The list of additional paths that the assembly loader will probe for ngen images + // + // NATIVE_DLL_SEARCH_DIRECTORIES + // - The list of paths that will be probed for native DLLs called by PInvoke + // + const char *propertyKeys[] = { + "TRUSTED_PLATFORM_ASSEMBLIES", + "APP_PATHS", + "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", + "AppDomainCompatSwitch" + }; + const char *propertyValues[] = { + // TRUSTED_PLATFORM_ASSEMBLIES + tpaList.c_str(), + // APP_PATHS + appPath.c_str(), + // APP_NI_PATHS + appPath.c_str(), + // NATIVE_DLL_SEARCH_DIRECTORIES + nativeDllSearchDirs.c_str(), + // AppDomainCompatSwitch + "UseLatestBehaviorWhenTFMNotSpecified" + }; + + void* hostHandle; + unsigned int domainId; + + int st = initializeCoreCLR( + currentExeAbsolutePath, + "unixcorerun", + sizeof(propertyKeys) / sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + &hostHandle, + &domainId); + + if (!SUCCEEDED(st)) + { + fprintf(stderr, "coreclr_initialize failed - status: 0x%08x\n", st); + exitCode = -1; + } + else + { + st = executeAssembly( + hostHandle, + domainId, + managedAssemblyArgc, + managedAssemblyArgv, + managedAssemblyAbsolutePath, + (unsigned int*)&exitCode); + + if (!SUCCEEDED(st)) + { + fprintf(stderr, "coreclr_execute_assembly failed - status: 0x%08x\n", st); + exitCode = -1; + } + + st = shutdownCoreCLR(hostHandle, domainId); + if (!SUCCEEDED(st)) + { + fprintf(stderr, "coreclr_shutdown failed - status: 0x%08x\n", st); + exitCode = -1; + } + } + } + + if (dlclose(coreclrLib) != 0) + { + fprintf(stderr, "Warning - dlclose failed\n"); + } + } + else + { + char* error = dlerror(); + fprintf(stderr, "dlopen failed to open the libcoreclr.so with error %s\n", error); + } + + return exitCode; +} diff --git a/host/unixcoreruncommon/coreruncommon.h b/host/unixcoreruncommon/coreruncommon.h new file mode 100644 index 000000000..b587e407f --- /dev/null +++ b/host/unixcoreruncommon/coreruncommon.h @@ -0,0 +1,46 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include + +// Get absolute path from the specified path. +// Return true in case of a success, false otherwise. +bool GetAbsolutePath(const char* path, std::string& absolutePath); + +// Get directory of the specified path. +// Return true in case of a success, false otherwise. +bool GetDirectory(const char* absolutePath, std::string& directory); + +// +// Get the absolute path to use to locate libcoreclr.so and the CLR assemblies are stored. If clrFilesPath is provided, +// this function will return the absolute path to it. Otherwise, the directory of the current executable is used. +// +// Return true in case of a success, false otherwise. +// +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); + +// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); + +// +// Execute the specified managed assembly. +// +// Parameters: +// currentExePath - Path to the current executable +// clrFilesAbsolutePath - Absolute path to the folder where the libcoreclr.so and CLR managed assemblies are stored +// managedAssemblyPath - Path to the managed assembly to execute +// managedAssemblyArgc - Number of arguments passed to the executed assembly +// managedAssemblyArgv - Array of arguments passed to the executed assembly +// +// Returns: +// ExitCode of the assembly +// +int ExecuteManagedAssembly( + const char* currentExeAbsolutePath, + const char* clrFilesAbsolutePath, + const char* managedAssemblyAbsolutePath, + int managedAssemblyArgc, + const char** managedAssemblyArgv); + From 6eaad394c54594cb27e4f4d48f7f5ae89a91c7eb Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 12:39:59 -0700 Subject: [PATCH 192/342] Remove CoreCLRUtil namespace So that is all accessible from C --- src/host/cmdline/main.cpp | 20 +- src/host/common/coreclrutil.cpp | 511 ++++++++++++++++---------------- src/host/common/coreclrutil.h | 78 ++--- src/host/common/hostutil.h | 2 +- 4 files changed, 305 insertions(+), 306 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 32cb4eed8..f89f1a18c 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -172,7 +172,7 @@ int main(int argc, char** argv) // get the absolute path of the current executable std::string currentExeAbsolutePath; - if (!CoreCLRUtil::GetAbsolutePath(argv[0],currentExeAbsolutePath)) + if (!GetAbsolutePath(argv[0],currentExeAbsolutePath)) { std::cerr << "could not get absolute path of current executable" << std::endl; return 1; @@ -186,7 +186,7 @@ int main(int argc, char** argv) // specified with the -c command line argument std::string clrAbsolutePath; const char* clrPathArg = args.clrPath == "" ? nullptr : args.clrPath.c_str(); - if (!CoreCLRUtil::GetClrFilesAbsolutePath(currentExeAbsolutePath.c_str(),clrPathArg,clrAbsolutePath)) + if (!GetClrFilesAbsolutePath(currentExeAbsolutePath.c_str(),clrPathArg,clrAbsolutePath)) { std::cerr << "could not find absolute CLR path" << std::endl; return 1; @@ -202,12 +202,12 @@ int main(int argc, char** argv) // if the -alc parameter was specified, add it to the TPA list here std::string tpaList; - CoreCLRUtil::AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); + AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); if (args.assemblyLoadContextFilePath != "") { std::string assemblyLoadContextAbsoluteFilePath; - if (!CoreCLRUtil::GetAbsolutePath(args.assemblyLoadContextFilePath.c_str(),assemblyLoadContextAbsoluteFilePath)) + if (!GetAbsolutePath(args.assemblyLoadContextFilePath.c_str(),assemblyLoadContextAbsoluteFilePath)) { std::cerr << "Failed to get absolute file path for assembly load context" << std::endl; return 1; @@ -229,7 +229,7 @@ int main(int argc, char** argv) // get the absolute path of the current directory std::string currentDirAbsolutePath; - if (!CoreCLRUtil::GetAbsolutePath(".",currentDirAbsolutePath)) + if (!GetAbsolutePath(".",currentDirAbsolutePath)) { std::cerr << "failed to get the absolute path from current working directory" << std::endl; return 1; @@ -267,7 +267,7 @@ int main(int argc, char** argv) std::string psBasePath = currentDirAbsolutePath; if (args.basePath != "") { - if (!CoreCLRUtil::GetAbsolutePath(args.basePath.c_str(),psBasePath)) + if (!GetAbsolutePath(args.basePath.c_str(),psBasePath)) { std::cerr << "failed to get the absolute path from the base_path argument" << std::endl; return 1; @@ -285,7 +285,7 @@ int main(int argc, char** argv) void* hostHandle; unsigned int domainId; - int status = CoreCLRUtil::startCoreClr( + int status = startCoreClr( clrAbsolutePath.c_str(), tpaList.c_str(), appPath.c_str(), @@ -297,7 +297,7 @@ int main(int argc, char** argv) // initialize the PS's custom assembly load context typedef void (*LoaderRunHelperFp)(const char16_t* appPath); LoaderRunHelperFp loaderDelegate = nullptr; - status = CoreCLRUtil::createDelegate( + status = createDelegate( hostHandle, domainId, "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", @@ -313,12 +313,12 @@ int main(int argc, char** argv) // call into Main of powershell-simple.exe unsigned int exitCode; - CoreCLRUtil::executeAssembly(hostHandle, domainId, args.argc, + executeAssembly(hostHandle, domainId, args.argc, (const char**)args.argv, (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), &exitCode); - status = CoreCLRUtil::stopCoreClr(hostHandle, domainId); + status = stopCoreClr(hostHandle, domainId); return exitCode; } diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index edfc0662d..3e80623bf 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -8,311 +8,308 @@ #include #include -namespace CoreCLRUtil -{ - // The name of the CoreCLR native runtime DLL +// The name of the CoreCLR native runtime DLL #if defined(__APPLE__) - constexpr char coreClrDll[] = "libcoreclr.dylib"; +constexpr char coreClrDll[] = "libcoreclr.dylib"; #else - constexpr char coreClrDll[] = "libcoreclr.so"; +constexpr char coreClrDll[] = "libcoreclr.so"; #endif - void* coreclrLib; +void* coreclrLib; - // Prototype of the coreclr_initialize function from the libcoreclr.so - typedef int (*InitializeCoreCLRFunction)( - const char* exePath, - const char* appDomainFriendlyName, - int propertyCount, - const char** propertyKeys, - const char** propertyValues, - void** hostHandle, - unsigned int* domainId); +// Prototype of the coreclr_initialize function from the libcoreclr.so +typedef int (*InitializeCoreCLRFunction)( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); - InitializeCoreCLRFunction initializeCoreCLR; +InitializeCoreCLRFunction initializeCoreCLR; - // Prototype of the coreclr_shutdown function from the libcoreclr.so - typedef int (*ShutdownCoreCLRFunction)( - void* hostHandle, - unsigned int domainId); +// Prototype of the coreclr_shutdown function from the libcoreclr.so +typedef int (*ShutdownCoreCLRFunction)( + void* hostHandle, + unsigned int domainId); - ShutdownCoreCLRFunction shutdownCoreCLR; +ShutdownCoreCLRFunction shutdownCoreCLR; - ExecuteAssemblyFunction executeAssembly; - CreateDelegateFunction createDelegate; +ExecuteAssemblyFunction executeAssembly; +CreateDelegateFunction createDelegate; - int startCoreClr( - // Paths of expected things - const char* clrAbsolutePath, - // Passed to propertyValues - const char* tpaList, - const char* appPath, - const char* nativeDllSearchDirs, - // Passed to InitializeCoreCLRFunction - const char* appDomainFriendlyName, - void** hostHandle, - unsigned int* domainId) +int startCoreClr( + // Paths of expected things + const char* clrAbsolutePath, + // Passed to propertyValues + const char* tpaList, + const char* appPath, + const char* nativeDllSearchDirs, + // Passed to InitializeCoreCLRFunction + const char* appDomainFriendlyName, + void** hostHandle, + unsigned int* domainId) +{ + // the path to the CoreCLR library + // + // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac + std::string coreClrDllPath = clrAbsolutePath; + coreClrDllPath += "/"; + coreClrDllPath += coreClrDll; + + if (coreClrDllPath.size() >= PATH_MAX) { - // the path to the CoreCLR library - // - // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac - std::string coreClrDllPath = clrAbsolutePath; - coreClrDllPath += "/"; - coreClrDllPath += coreClrDll; - - if (coreClrDllPath.size() >= PATH_MAX) - { - std::cerr << "Absolute path to CoreCLR library too long" << std::endl; - return 1; - } - - // open the shared library - coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); - if (coreclrLib == nullptr) - { - char* error = dlerror(); - std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; - return 2; - } - - // query the function pointers - initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); - shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); - - executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); - createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); - - if (initializeCoreCLR == nullptr) - { - std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; - return 3; - } - if (executeAssembly == nullptr) - { - std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; - return 3; - } - if (shutdownCoreCLR == nullptr) - { - std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; - return 3; - } - if (createDelegate == nullptr) - { - std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; - return 3; - } - - // create list of properties to initialize CoreCLR - const char* propertyKeys[] = { - "TRUSTED_PLATFORM_ASSEMBLIES", - "APP_PATHS", - "APP_NI_PATHS", - "NATIVE_DLL_SEARCH_DIRECTORIES", - "AppDomainCompatSwitch" - }; - - const char* propertyValues[] = { - tpaList, - appPath, - appPath, - nativeDllSearchDirs, - "UseLatestBehaviorWhenTFMNotSpecified" - }; - - // get path to current executable - char exePath[PATH_MAX] = { 0 }; - readlink("/proc/self/exe", exePath, PATH_MAX); - - // initialize CoreCLR - int status = initializeCoreCLR( - exePath, - appDomainFriendlyName, - sizeof(propertyKeys)/sizeof(propertyKeys[0]), - propertyKeys, - propertyValues, - hostHandle, - domainId); - - if (0 > status) - { - std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; - return 4; - } - - return status; + std::cerr << "Absolute path to CoreCLR library too long" << std::endl; + return 1; } - int stopCoreClr(void* hostHandle, unsigned int domainId) + // open the shared library + coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); + if (coreclrLib == nullptr) { - // shutdown CoreCLR - int status = shutdownCoreCLR(hostHandle, domainId); - if (0 > status) - { - std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; - } - - // close the dynamic library - if (0 != dlclose(coreclrLib)) - { - std::cerr << "failed to close CoreCLR library" << std::endl; - } - - return status; + char* error = dlerror(); + std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; + return 2; } - bool GetAbsolutePath(const char* path, std::string& absolutePath) + // query the function pointers + initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); + shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); + + executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); + createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); + + if (initializeCoreCLR == nullptr) { - bool result = false; - - char realPath[PATH_MAX]; - if (realpath(path, realPath) != nullptr && realPath[0] != '\0') - { - absolutePath.assign(realPath); - // realpath should return canonicalized path without the trailing slash - assert(absolutePath.back() != '/'); - - result = true; - } - - return result; + std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; + return 3; + } + if (executeAssembly == nullptr) + { + std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; + return 3; + } + if (shutdownCoreCLR == nullptr) + { + std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; + return 3; + } + if (createDelegate == nullptr) + { + std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; + return 3; } - bool GetDirectory(const char* absolutePath, std::string& directory) - { - directory.assign(absolutePath); - size_t lastSlash = directory.rfind('/'); - if (lastSlash != std::string::npos) - { - directory.erase(lastSlash); - return true; - } + // create list of properties to initialize CoreCLR + const char* propertyKeys[] = { + "TRUSTED_PLATFORM_ASSEMBLIES", + "APP_PATHS", + "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", + "AppDomainCompatSwitch" + }; - return false; + const char* propertyValues[] = { + tpaList, + appPath, + appPath, + nativeDllSearchDirs, + "UseLatestBehaviorWhenTFMNotSpecified" + }; + + // get path to current executable + char exePath[PATH_MAX] = { 0 }; + readlink("/proc/self/exe", exePath, PATH_MAX); + + // initialize CoreCLR + int status = initializeCoreCLR( + exePath, + appDomainFriendlyName, + sizeof(propertyKeys)/sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + hostHandle, + domainId); + + if (0 > status) + { + std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; + return 4; } - bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) + return status; +} + +int stopCoreClr(void* hostHandle, unsigned int domainId) +{ + // shutdown CoreCLR + int status = shutdownCoreCLR(hostHandle, domainId); + if (0 > status) { - std::string clrFilesRelativePath; - const char* clrFilesPathLocal = clrFilesPath; - if (clrFilesPathLocal == nullptr) - { - // There was no CLR files path specified, use the folder of the corerun/coreconsole - if (!GetDirectory(currentExePath, clrFilesRelativePath)) - { - perror("Failed to get directory from argv[0]"); - return false; - } + std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; + } - clrFilesPathLocal = clrFilesRelativePath.c_str(); + // close the dynamic library + if (0 != dlclose(coreclrLib)) + { + std::cerr << "failed to close CoreCLR library" << std::endl; + } - // TODO: consider using an env variable (if defined) as a fall-back. - // The windows version of the corerun uses core_root env variable - } + return status; +} - if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) - { - perror("Failed to convert CLR files path to absolute path"); - return false; - } +bool GetAbsolutePath(const char* path, std::string& absolutePath) +{ + bool result = false; + char realPath[PATH_MAX]; + if (realpath(path, realPath) != nullptr && realPath[0] != '\0') + { + absolutePath.assign(realPath); + // realpath should return canonicalized path without the trailing slash + assert(absolutePath.back() != '/'); + + result = true; + } + + return result; +} + +bool GetDirectory(const char* absolutePath, std::string& directory) +{ + directory.assign(absolutePath); + size_t lastSlash = directory.rfind('/'); + if (lastSlash != std::string::npos) + { + directory.erase(lastSlash); return true; } - void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) + return false; +} + +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) +{ + std::string clrFilesRelativePath; + const char* clrFilesPathLocal = clrFilesPath; + if (clrFilesPathLocal == nullptr) { - const char * const tpaExtensions[] = { - ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir - ".dll", - ".ni.exe", - ".exe", - }; - - DIR* dir = opendir(directory); - if (dir == nullptr) + // There was no CLR files path specified, use the folder of the corerun/coreconsole + if (!GetDirectory(currentExePath, clrFilesRelativePath)) { - return; + perror("Failed to get directory from argv[0]"); + return false; } - std::set addedAssemblies; + clrFilesPathLocal = clrFilesRelativePath.c_str(); - // Walk the directory for each extension separately so that we first get files with .ni.dll extension, - // then files with .dll extension, etc. - for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + // TODO: consider using an env variable (if defined) as a fall-back. + // The windows version of the corerun uses core_root env variable + } + + if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) + { + perror("Failed to convert CLR files path to absolute path"); + return false; + } + + return true; +} + +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) +{ + const char * const tpaExtensions[] = { + ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir + ".dll", + ".ni.exe", + ".exe", + }; + + DIR* dir = opendir(directory); + if (dir == nullptr) + { + return; + } + + std::set addedAssemblies; + + // Walk the directory for each extension separately so that we first get files with .ni.dll extension, + // then files with .dll extension, etc. + for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + { + const char* ext = tpaExtensions[extIndex]; + int extLength = strlen(ext); + + struct dirent* entry; + + // For all entries in the directory + while ((entry = readdir(dir)) != nullptr) { - const char* ext = tpaExtensions[extIndex]; - int extLength = strlen(ext); - - struct dirent* entry; - - // For all entries in the directory - while ((entry = readdir(dir)) != nullptr) + // We are interested in files only + switch (entry->d_type) { - // We are interested in files only - switch (entry->d_type) - { - case DT_REG: - break; - - // Handle symlinks and file systems that do not support d_type - case DT_LNK: - case DT_UNKNOWN: - { - std::string fullFilename; - - fullFilename.append(directory); - fullFilename.append("/"); - fullFilename.append(entry->d_name); - - struct stat sb; - if (stat(fullFilename.c_str(), &sb) == -1) - { - continue; - } - - if (!S_ISREG(sb.st_mode)) - { - continue; - } - } + case DT_REG: break; - default: - continue; - } + // Handle symlinks and file systems that do not support d_type + case DT_LNK: + case DT_UNKNOWN: + { + std::string fullFilename; - std::string filename(entry->d_name); + fullFilename.append(directory); + fullFilename.append("/"); + fullFilename.append(entry->d_name); - // Check if the extension matches the one we are looking for - int extPos = filename.length() - extLength; - if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) + struct stat sb; + if (stat(fullFilename.c_str(), &sb) == -1) { continue; } - std::string filenameWithoutExt(filename.substr(0, extPos)); - - // Make sure if we have an assembly with multiple extensions present, - // we insert only one version of it. - if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) + if (!S_ISREG(sb.st_mode)) { - addedAssemblies.insert(filenameWithoutExt); - - tpaList.append(directory); - tpaList.append("/"); - tpaList.append(filename); - tpaList.append(":"); + continue; } } - - // Rewind the directory stream to be able to iterate over it for the next extension - rewinddir(dir); - } - - closedir(dir); + break; - // strip any trailing : from the tpaList - if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':') - tpaList.resize(tpaList.size()-1); + default: + continue; + } + + std::string filename(entry->d_name); + + // Check if the extension matches the one we are looking for + int extPos = filename.length() - extLength; + if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) + { + continue; + } + + std::string filenameWithoutExt(filename.substr(0, extPos)); + + // Make sure if we have an assembly with multiple extensions present, + // we insert only one version of it. + if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) + { + addedAssemblies.insert(filenameWithoutExt); + + tpaList.append(directory); + tpaList.append("/"); + tpaList.append(filename); + tpaList.append(":"); + } + } + + // Rewind the directory stream to be able to iterate over it for the next extension + rewinddir(dir); } + + closedir(dir); + + // strip any trailing : from the tpaList + if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':') + tpaList.resize(tpaList.size()-1); } diff --git a/src/host/common/coreclrutil.h b/src/host/common/coreclrutil.h index fe0ad77fc..e1a481c56 100644 --- a/src/host/common/coreclrutil.h +++ b/src/host/common/coreclrutil.h @@ -1,49 +1,51 @@ #pragma once +#ifdef __cplusplus #include +#endif -namespace CoreCLRUtil +extern "C" { - extern "C" { - int startCoreClr( - // Paths of expected things - const char* clrAbsolutePath, - // Passed to propertyValues - const char* tpaList, - const char* appPath, - const char* nativeDllSearchDirs, - // Passed to InitializeCoreCLRFunction - const char* appDomainFriendlyName, - void** hostHandle, - unsigned int* domainId); + int startCoreClr( + // Paths of expected things + const char* clrAbsolutePath, + // Passed to propertyValues + const char* tpaList, + const char* appPath, + const char* nativeDllSearchDirs, + // Passed to InitializeCoreCLRFunction + const char* appDomainFriendlyName, + void** hostHandle, + unsigned int* domainId); - int stopCoreClr(void* hostHandle, unsigned int domainId); + int stopCoreClr(void* hostHandle, unsigned int domainId); - // Prototype of the coreclr_execute_assembly function from the libcoreclr.so - typedef int (*ExecuteAssemblyFunction)( - void* hostHandle, - unsigned int domainId, - int argc, - const char** argv, - const char* managedAssemblyPath, - unsigned int* exitCode); + // Prototype of the coreclr_execute_assembly function from the libcoreclr.so + typedef int (*ExecuteAssemblyFunction)( + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); - extern ExecuteAssemblyFunction executeAssembly; + extern ExecuteAssemblyFunction executeAssembly; - // Prototype of coreclr_create_delegate function from the libcoreclr.so - typedef int (*CreateDelegateFunction)( - void* hostHandle, - unsigned int domainId, - const char* entryPointAssemblyName, - const char* entryPointTypeName, - const char* entryPointMethodName, - void** delegate); + // Prototype of coreclr_create_delegate function from the libcoreclr.so + typedef int (*CreateDelegateFunction)( + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate); - extern CreateDelegateFunction createDelegate; - } - - bool GetAbsolutePath(const char* path, std::string& absolutePath); - bool GetDirectory(const char* absolutePath, std::string& directory); - bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); - void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); + extern CreateDelegateFunction createDelegate; } + +#ifdef __cplusplus +bool GetAbsolutePath(const char* path, std::string& absolutePath); +bool GetDirectory(const char* absolutePath, std::string& directory); +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); +#endif diff --git a/src/host/common/hostutil.h b/src/host/common/hostutil.h index 60bec5519..6a07469c0 100644 --- a/src/host/common/hostutil.h +++ b/src/host/common/hostutil.h @@ -23,7 +23,7 @@ namespace HostUtil if (token != "") { std::string absolutePath; - if (CoreCLRUtil::GetAbsolutePath(token.c_str(),absolutePath)) + if (GetAbsolutePath(token.c_str(),absolutePath)) { // add colons correctly if (result.size() == 0) From 27563ab7b7a2568c8b02b2179ba15fa8a377bd33 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 12:39:59 -0700 Subject: [PATCH 193/342] Remove CoreCLRUtil namespace So that is all accessible from C --- host/cmdline/main.cpp | 20 +- host/common/coreclrutil.cpp | 511 ++++++++++++++++++------------------ host/common/coreclrutil.h | 78 +++--- host/common/hostutil.h | 2 +- 4 files changed, 305 insertions(+), 306 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 32cb4eed8..f89f1a18c 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -172,7 +172,7 @@ int main(int argc, char** argv) // get the absolute path of the current executable std::string currentExeAbsolutePath; - if (!CoreCLRUtil::GetAbsolutePath(argv[0],currentExeAbsolutePath)) + if (!GetAbsolutePath(argv[0],currentExeAbsolutePath)) { std::cerr << "could not get absolute path of current executable" << std::endl; return 1; @@ -186,7 +186,7 @@ int main(int argc, char** argv) // specified with the -c command line argument std::string clrAbsolutePath; const char* clrPathArg = args.clrPath == "" ? nullptr : args.clrPath.c_str(); - if (!CoreCLRUtil::GetClrFilesAbsolutePath(currentExeAbsolutePath.c_str(),clrPathArg,clrAbsolutePath)) + if (!GetClrFilesAbsolutePath(currentExeAbsolutePath.c_str(),clrPathArg,clrAbsolutePath)) { std::cerr << "could not find absolute CLR path" << std::endl; return 1; @@ -202,12 +202,12 @@ int main(int argc, char** argv) // if the -alc parameter was specified, add it to the TPA list here std::string tpaList; - CoreCLRUtil::AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); + AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); if (args.assemblyLoadContextFilePath != "") { std::string assemblyLoadContextAbsoluteFilePath; - if (!CoreCLRUtil::GetAbsolutePath(args.assemblyLoadContextFilePath.c_str(),assemblyLoadContextAbsoluteFilePath)) + if (!GetAbsolutePath(args.assemblyLoadContextFilePath.c_str(),assemblyLoadContextAbsoluteFilePath)) { std::cerr << "Failed to get absolute file path for assembly load context" << std::endl; return 1; @@ -229,7 +229,7 @@ int main(int argc, char** argv) // get the absolute path of the current directory std::string currentDirAbsolutePath; - if (!CoreCLRUtil::GetAbsolutePath(".",currentDirAbsolutePath)) + if (!GetAbsolutePath(".",currentDirAbsolutePath)) { std::cerr << "failed to get the absolute path from current working directory" << std::endl; return 1; @@ -267,7 +267,7 @@ int main(int argc, char** argv) std::string psBasePath = currentDirAbsolutePath; if (args.basePath != "") { - if (!CoreCLRUtil::GetAbsolutePath(args.basePath.c_str(),psBasePath)) + if (!GetAbsolutePath(args.basePath.c_str(),psBasePath)) { std::cerr << "failed to get the absolute path from the base_path argument" << std::endl; return 1; @@ -285,7 +285,7 @@ int main(int argc, char** argv) void* hostHandle; unsigned int domainId; - int status = CoreCLRUtil::startCoreClr( + int status = startCoreClr( clrAbsolutePath.c_str(), tpaList.c_str(), appPath.c_str(), @@ -297,7 +297,7 @@ int main(int argc, char** argv) // initialize the PS's custom assembly load context typedef void (*LoaderRunHelperFp)(const char16_t* appPath); LoaderRunHelperFp loaderDelegate = nullptr; - status = CoreCLRUtil::createDelegate( + status = createDelegate( hostHandle, domainId, "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", @@ -313,12 +313,12 @@ int main(int argc, char** argv) // call into Main of powershell-simple.exe unsigned int exitCode; - CoreCLRUtil::executeAssembly(hostHandle, domainId, args.argc, + executeAssembly(hostHandle, domainId, args.argc, (const char**)args.argv, (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), &exitCode); - status = CoreCLRUtil::stopCoreClr(hostHandle, domainId); + status = stopCoreClr(hostHandle, domainId); return exitCode; } diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index edfc0662d..3e80623bf 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -8,311 +8,308 @@ #include #include -namespace CoreCLRUtil -{ - // The name of the CoreCLR native runtime DLL +// The name of the CoreCLR native runtime DLL #if defined(__APPLE__) - constexpr char coreClrDll[] = "libcoreclr.dylib"; +constexpr char coreClrDll[] = "libcoreclr.dylib"; #else - constexpr char coreClrDll[] = "libcoreclr.so"; +constexpr char coreClrDll[] = "libcoreclr.so"; #endif - void* coreclrLib; +void* coreclrLib; - // Prototype of the coreclr_initialize function from the libcoreclr.so - typedef int (*InitializeCoreCLRFunction)( - const char* exePath, - const char* appDomainFriendlyName, - int propertyCount, - const char** propertyKeys, - const char** propertyValues, - void** hostHandle, - unsigned int* domainId); +// Prototype of the coreclr_initialize function from the libcoreclr.so +typedef int (*InitializeCoreCLRFunction)( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); - InitializeCoreCLRFunction initializeCoreCLR; +InitializeCoreCLRFunction initializeCoreCLR; - // Prototype of the coreclr_shutdown function from the libcoreclr.so - typedef int (*ShutdownCoreCLRFunction)( - void* hostHandle, - unsigned int domainId); +// Prototype of the coreclr_shutdown function from the libcoreclr.so +typedef int (*ShutdownCoreCLRFunction)( + void* hostHandle, + unsigned int domainId); - ShutdownCoreCLRFunction shutdownCoreCLR; +ShutdownCoreCLRFunction shutdownCoreCLR; - ExecuteAssemblyFunction executeAssembly; - CreateDelegateFunction createDelegate; +ExecuteAssemblyFunction executeAssembly; +CreateDelegateFunction createDelegate; - int startCoreClr( - // Paths of expected things - const char* clrAbsolutePath, - // Passed to propertyValues - const char* tpaList, - const char* appPath, - const char* nativeDllSearchDirs, - // Passed to InitializeCoreCLRFunction - const char* appDomainFriendlyName, - void** hostHandle, - unsigned int* domainId) +int startCoreClr( + // Paths of expected things + const char* clrAbsolutePath, + // Passed to propertyValues + const char* tpaList, + const char* appPath, + const char* nativeDllSearchDirs, + // Passed to InitializeCoreCLRFunction + const char* appDomainFriendlyName, + void** hostHandle, + unsigned int* domainId) +{ + // the path to the CoreCLR library + // + // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac + std::string coreClrDllPath = clrAbsolutePath; + coreClrDllPath += "/"; + coreClrDllPath += coreClrDll; + + if (coreClrDllPath.size() >= PATH_MAX) { - // the path to the CoreCLR library - // - // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac - std::string coreClrDllPath = clrAbsolutePath; - coreClrDllPath += "/"; - coreClrDllPath += coreClrDll; - - if (coreClrDllPath.size() >= PATH_MAX) - { - std::cerr << "Absolute path to CoreCLR library too long" << std::endl; - return 1; - } - - // open the shared library - coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); - if (coreclrLib == nullptr) - { - char* error = dlerror(); - std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; - return 2; - } - - // query the function pointers - initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); - shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); - - executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); - createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); - - if (initializeCoreCLR == nullptr) - { - std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; - return 3; - } - if (executeAssembly == nullptr) - { - std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; - return 3; - } - if (shutdownCoreCLR == nullptr) - { - std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; - return 3; - } - if (createDelegate == nullptr) - { - std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; - return 3; - } - - // create list of properties to initialize CoreCLR - const char* propertyKeys[] = { - "TRUSTED_PLATFORM_ASSEMBLIES", - "APP_PATHS", - "APP_NI_PATHS", - "NATIVE_DLL_SEARCH_DIRECTORIES", - "AppDomainCompatSwitch" - }; - - const char* propertyValues[] = { - tpaList, - appPath, - appPath, - nativeDllSearchDirs, - "UseLatestBehaviorWhenTFMNotSpecified" - }; - - // get path to current executable - char exePath[PATH_MAX] = { 0 }; - readlink("/proc/self/exe", exePath, PATH_MAX); - - // initialize CoreCLR - int status = initializeCoreCLR( - exePath, - appDomainFriendlyName, - sizeof(propertyKeys)/sizeof(propertyKeys[0]), - propertyKeys, - propertyValues, - hostHandle, - domainId); - - if (0 > status) - { - std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; - return 4; - } - - return status; + std::cerr << "Absolute path to CoreCLR library too long" << std::endl; + return 1; } - int stopCoreClr(void* hostHandle, unsigned int domainId) + // open the shared library + coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); + if (coreclrLib == nullptr) { - // shutdown CoreCLR - int status = shutdownCoreCLR(hostHandle, domainId); - if (0 > status) - { - std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; - } - - // close the dynamic library - if (0 != dlclose(coreclrLib)) - { - std::cerr << "failed to close CoreCLR library" << std::endl; - } - - return status; + char* error = dlerror(); + std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; + return 2; } - bool GetAbsolutePath(const char* path, std::string& absolutePath) + // query the function pointers + initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); + shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); + + executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); + createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); + + if (initializeCoreCLR == nullptr) { - bool result = false; - - char realPath[PATH_MAX]; - if (realpath(path, realPath) != nullptr && realPath[0] != '\0') - { - absolutePath.assign(realPath); - // realpath should return canonicalized path without the trailing slash - assert(absolutePath.back() != '/'); - - result = true; - } - - return result; + std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; + return 3; + } + if (executeAssembly == nullptr) + { + std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; + return 3; + } + if (shutdownCoreCLR == nullptr) + { + std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; + return 3; + } + if (createDelegate == nullptr) + { + std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; + return 3; } - bool GetDirectory(const char* absolutePath, std::string& directory) - { - directory.assign(absolutePath); - size_t lastSlash = directory.rfind('/'); - if (lastSlash != std::string::npos) - { - directory.erase(lastSlash); - return true; - } + // create list of properties to initialize CoreCLR + const char* propertyKeys[] = { + "TRUSTED_PLATFORM_ASSEMBLIES", + "APP_PATHS", + "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", + "AppDomainCompatSwitch" + }; - return false; + const char* propertyValues[] = { + tpaList, + appPath, + appPath, + nativeDllSearchDirs, + "UseLatestBehaviorWhenTFMNotSpecified" + }; + + // get path to current executable + char exePath[PATH_MAX] = { 0 }; + readlink("/proc/self/exe", exePath, PATH_MAX); + + // initialize CoreCLR + int status = initializeCoreCLR( + exePath, + appDomainFriendlyName, + sizeof(propertyKeys)/sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + hostHandle, + domainId); + + if (0 > status) + { + std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; + return 4; } - bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) + return status; +} + +int stopCoreClr(void* hostHandle, unsigned int domainId) +{ + // shutdown CoreCLR + int status = shutdownCoreCLR(hostHandle, domainId); + if (0 > status) { - std::string clrFilesRelativePath; - const char* clrFilesPathLocal = clrFilesPath; - if (clrFilesPathLocal == nullptr) - { - // There was no CLR files path specified, use the folder of the corerun/coreconsole - if (!GetDirectory(currentExePath, clrFilesRelativePath)) - { - perror("Failed to get directory from argv[0]"); - return false; - } + std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; + } - clrFilesPathLocal = clrFilesRelativePath.c_str(); + // close the dynamic library + if (0 != dlclose(coreclrLib)) + { + std::cerr << "failed to close CoreCLR library" << std::endl; + } - // TODO: consider using an env variable (if defined) as a fall-back. - // The windows version of the corerun uses core_root env variable - } + return status; +} - if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) - { - perror("Failed to convert CLR files path to absolute path"); - return false; - } +bool GetAbsolutePath(const char* path, std::string& absolutePath) +{ + bool result = false; + char realPath[PATH_MAX]; + if (realpath(path, realPath) != nullptr && realPath[0] != '\0') + { + absolutePath.assign(realPath); + // realpath should return canonicalized path without the trailing slash + assert(absolutePath.back() != '/'); + + result = true; + } + + return result; +} + +bool GetDirectory(const char* absolutePath, std::string& directory) +{ + directory.assign(absolutePath); + size_t lastSlash = directory.rfind('/'); + if (lastSlash != std::string::npos) + { + directory.erase(lastSlash); return true; } - void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) + return false; +} + +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) +{ + std::string clrFilesRelativePath; + const char* clrFilesPathLocal = clrFilesPath; + if (clrFilesPathLocal == nullptr) { - const char * const tpaExtensions[] = { - ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir - ".dll", - ".ni.exe", - ".exe", - }; - - DIR* dir = opendir(directory); - if (dir == nullptr) + // There was no CLR files path specified, use the folder of the corerun/coreconsole + if (!GetDirectory(currentExePath, clrFilesRelativePath)) { - return; + perror("Failed to get directory from argv[0]"); + return false; } - std::set addedAssemblies; + clrFilesPathLocal = clrFilesRelativePath.c_str(); - // Walk the directory for each extension separately so that we first get files with .ni.dll extension, - // then files with .dll extension, etc. - for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + // TODO: consider using an env variable (if defined) as a fall-back. + // The windows version of the corerun uses core_root env variable + } + + if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) + { + perror("Failed to convert CLR files path to absolute path"); + return false; + } + + return true; +} + +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) +{ + const char * const tpaExtensions[] = { + ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir + ".dll", + ".ni.exe", + ".exe", + }; + + DIR* dir = opendir(directory); + if (dir == nullptr) + { + return; + } + + std::set addedAssemblies; + + // Walk the directory for each extension separately so that we first get files with .ni.dll extension, + // then files with .dll extension, etc. + for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + { + const char* ext = tpaExtensions[extIndex]; + int extLength = strlen(ext); + + struct dirent* entry; + + // For all entries in the directory + while ((entry = readdir(dir)) != nullptr) { - const char* ext = tpaExtensions[extIndex]; - int extLength = strlen(ext); - - struct dirent* entry; - - // For all entries in the directory - while ((entry = readdir(dir)) != nullptr) + // We are interested in files only + switch (entry->d_type) { - // We are interested in files only - switch (entry->d_type) - { - case DT_REG: - break; - - // Handle symlinks and file systems that do not support d_type - case DT_LNK: - case DT_UNKNOWN: - { - std::string fullFilename; - - fullFilename.append(directory); - fullFilename.append("/"); - fullFilename.append(entry->d_name); - - struct stat sb; - if (stat(fullFilename.c_str(), &sb) == -1) - { - continue; - } - - if (!S_ISREG(sb.st_mode)) - { - continue; - } - } + case DT_REG: break; - default: - continue; - } + // Handle symlinks and file systems that do not support d_type + case DT_LNK: + case DT_UNKNOWN: + { + std::string fullFilename; - std::string filename(entry->d_name); + fullFilename.append(directory); + fullFilename.append("/"); + fullFilename.append(entry->d_name); - // Check if the extension matches the one we are looking for - int extPos = filename.length() - extLength; - if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) + struct stat sb; + if (stat(fullFilename.c_str(), &sb) == -1) { continue; } - std::string filenameWithoutExt(filename.substr(0, extPos)); - - // Make sure if we have an assembly with multiple extensions present, - // we insert only one version of it. - if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) + if (!S_ISREG(sb.st_mode)) { - addedAssemblies.insert(filenameWithoutExt); - - tpaList.append(directory); - tpaList.append("/"); - tpaList.append(filename); - tpaList.append(":"); + continue; } } - - // Rewind the directory stream to be able to iterate over it for the next extension - rewinddir(dir); - } - - closedir(dir); + break; - // strip any trailing : from the tpaList - if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':') - tpaList.resize(tpaList.size()-1); + default: + continue; + } + + std::string filename(entry->d_name); + + // Check if the extension matches the one we are looking for + int extPos = filename.length() - extLength; + if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) + { + continue; + } + + std::string filenameWithoutExt(filename.substr(0, extPos)); + + // Make sure if we have an assembly with multiple extensions present, + // we insert only one version of it. + if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) + { + addedAssemblies.insert(filenameWithoutExt); + + tpaList.append(directory); + tpaList.append("/"); + tpaList.append(filename); + tpaList.append(":"); + } + } + + // Rewind the directory stream to be able to iterate over it for the next extension + rewinddir(dir); } + + closedir(dir); + + // strip any trailing : from the tpaList + if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':') + tpaList.resize(tpaList.size()-1); } diff --git a/host/common/coreclrutil.h b/host/common/coreclrutil.h index fe0ad77fc..e1a481c56 100644 --- a/host/common/coreclrutil.h +++ b/host/common/coreclrutil.h @@ -1,49 +1,51 @@ #pragma once +#ifdef __cplusplus #include +#endif -namespace CoreCLRUtil +extern "C" { - extern "C" { - int startCoreClr( - // Paths of expected things - const char* clrAbsolutePath, - // Passed to propertyValues - const char* tpaList, - const char* appPath, - const char* nativeDllSearchDirs, - // Passed to InitializeCoreCLRFunction - const char* appDomainFriendlyName, - void** hostHandle, - unsigned int* domainId); + int startCoreClr( + // Paths of expected things + const char* clrAbsolutePath, + // Passed to propertyValues + const char* tpaList, + const char* appPath, + const char* nativeDllSearchDirs, + // Passed to InitializeCoreCLRFunction + const char* appDomainFriendlyName, + void** hostHandle, + unsigned int* domainId); - int stopCoreClr(void* hostHandle, unsigned int domainId); + int stopCoreClr(void* hostHandle, unsigned int domainId); - // Prototype of the coreclr_execute_assembly function from the libcoreclr.so - typedef int (*ExecuteAssemblyFunction)( - void* hostHandle, - unsigned int domainId, - int argc, - const char** argv, - const char* managedAssemblyPath, - unsigned int* exitCode); + // Prototype of the coreclr_execute_assembly function from the libcoreclr.so + typedef int (*ExecuteAssemblyFunction)( + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); - extern ExecuteAssemblyFunction executeAssembly; + extern ExecuteAssemblyFunction executeAssembly; - // Prototype of coreclr_create_delegate function from the libcoreclr.so - typedef int (*CreateDelegateFunction)( - void* hostHandle, - unsigned int domainId, - const char* entryPointAssemblyName, - const char* entryPointTypeName, - const char* entryPointMethodName, - void** delegate); + // Prototype of coreclr_create_delegate function from the libcoreclr.so + typedef int (*CreateDelegateFunction)( + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate); - extern CreateDelegateFunction createDelegate; - } - - bool GetAbsolutePath(const char* path, std::string& absolutePath); - bool GetDirectory(const char* absolutePath, std::string& directory); - bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); - void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); + extern CreateDelegateFunction createDelegate; } + +#ifdef __cplusplus +bool GetAbsolutePath(const char* path, std::string& absolutePath); +bool GetDirectory(const char* absolutePath, std::string& directory); +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); +#endif diff --git a/host/common/hostutil.h b/host/common/hostutil.h index 60bec5519..6a07469c0 100644 --- a/host/common/hostutil.h +++ b/host/common/hostutil.h @@ -23,7 +23,7 @@ namespace HostUtil if (token != "") { std::string absolutePath; - if (CoreCLRUtil::GetAbsolutePath(token.c_str(),absolutePath)) + if (GetAbsolutePath(token.c_str(),absolutePath)) { // add colons correctly if (result.size() == 0) From bdb06b08d6549972ea501a406cb1430880ae66bd Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 13:31:22 -0700 Subject: [PATCH 194/342] Rename to (start|stop)CoreCLR() --- src/host/cmdline/main.cpp | 4 ++-- src/host/common/coreclrutil.cpp | 8 +++----- src/host/common/coreclrutil.h | 4 ++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index f89f1a18c..2443df623 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -285,7 +285,7 @@ int main(int argc, char** argv) void* hostHandle; unsigned int domainId; - int status = startCoreClr( + int status = startCoreCLR( clrAbsolutePath.c_str(), tpaList.c_str(), appPath.c_str(), @@ -318,7 +318,7 @@ int main(int argc, char** argv) (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), &exitCode); - status = stopCoreClr(hostHandle, domainId); + status = stopCoreCLR(hostHandle, domainId); return exitCode; } diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index 3e80623bf..ed2d64453 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -27,19 +27,17 @@ typedef int (*InitializeCoreCLRFunction)( void** hostHandle, unsigned int* domainId); -InitializeCoreCLRFunction initializeCoreCLR; - // Prototype of the coreclr_shutdown function from the libcoreclr.so typedef int (*ShutdownCoreCLRFunction)( void* hostHandle, unsigned int domainId); +InitializeCoreCLRFunction initializeCoreCLR; ShutdownCoreCLRFunction shutdownCoreCLR; - ExecuteAssemblyFunction executeAssembly; CreateDelegateFunction createDelegate; -int startCoreClr( +int startCoreCLR( // Paths of expected things const char* clrAbsolutePath, // Passed to propertyValues @@ -141,7 +139,7 @@ int startCoreClr( return status; } -int stopCoreClr(void* hostHandle, unsigned int domainId) +int stopCoreCLR(void* hostHandle, unsigned int domainId) { // shutdown CoreCLR int status = shutdownCoreCLR(hostHandle, domainId); diff --git a/src/host/common/coreclrutil.h b/src/host/common/coreclrutil.h index e1a481c56..5e9768325 100644 --- a/src/host/common/coreclrutil.h +++ b/src/host/common/coreclrutil.h @@ -6,8 +6,8 @@ extern "C" { - int startCoreClr( // Paths of expected things + int startCoreCLR( const char* clrAbsolutePath, // Passed to propertyValues const char* tpaList, @@ -18,7 +18,7 @@ extern "C" void** hostHandle, unsigned int* domainId); - int stopCoreClr(void* hostHandle, unsigned int domainId); + int stopCoreCLR(void* hostHandle, unsigned int domainId); // Prototype of the coreclr_execute_assembly function from the libcoreclr.so typedef int (*ExecuteAssemblyFunction)( From 80c68707aa422d986f3141c110ac59b89f632921 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 13:31:22 -0700 Subject: [PATCH 195/342] Rename to (start|stop)CoreCLR() --- host/cmdline/main.cpp | 4 ++-- host/common/coreclrutil.cpp | 8 +++----- host/common/coreclrutil.h | 4 ++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index f89f1a18c..2443df623 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -285,7 +285,7 @@ int main(int argc, char** argv) void* hostHandle; unsigned int domainId; - int status = startCoreClr( + int status = startCoreCLR( clrAbsolutePath.c_str(), tpaList.c_str(), appPath.c_str(), @@ -318,7 +318,7 @@ int main(int argc, char** argv) (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), &exitCode); - status = stopCoreClr(hostHandle, domainId); + status = stopCoreCLR(hostHandle, domainId); return exitCode; } diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index 3e80623bf..ed2d64453 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -27,19 +27,17 @@ typedef int (*InitializeCoreCLRFunction)( void** hostHandle, unsigned int* domainId); -InitializeCoreCLRFunction initializeCoreCLR; - // Prototype of the coreclr_shutdown function from the libcoreclr.so typedef int (*ShutdownCoreCLRFunction)( void* hostHandle, unsigned int domainId); +InitializeCoreCLRFunction initializeCoreCLR; ShutdownCoreCLRFunction shutdownCoreCLR; - ExecuteAssemblyFunction executeAssembly; CreateDelegateFunction createDelegate; -int startCoreClr( +int startCoreCLR( // Paths of expected things const char* clrAbsolutePath, // Passed to propertyValues @@ -141,7 +139,7 @@ int startCoreClr( return status; } -int stopCoreClr(void* hostHandle, unsigned int domainId) +int stopCoreCLR(void* hostHandle, unsigned int domainId) { // shutdown CoreCLR int status = shutdownCoreCLR(hostHandle, domainId); diff --git a/host/common/coreclrutil.h b/host/common/coreclrutil.h index e1a481c56..5e9768325 100644 --- a/host/common/coreclrutil.h +++ b/host/common/coreclrutil.h @@ -6,8 +6,8 @@ extern "C" { - int startCoreClr( // Paths of expected things + int startCoreCLR( const char* clrAbsolutePath, // Passed to propertyValues const char* tpaList, @@ -18,7 +18,7 @@ extern "C" void** hostHandle, unsigned int* domainId); - int stopCoreClr(void* hostHandle, unsigned int domainId); + int stopCoreCLR(void* hostHandle, unsigned int domainId); // Prototype of the coreclr_execute_assembly function from the libcoreclr.so typedef int (*ExecuteAssemblyFunction)( From 4fd752cee63e06b35ac0ae0b5e0840dfe31663c1 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 13:35:00 -0700 Subject: [PATCH 196/342] Reconcile with coreruncommon.cpp --- src/host/common/coreclrutil.cpp | 14 +++++++------- src/host/common/coreclrutil.h | 34 ++++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index ed2d64453..29c039d47 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -157,6 +157,10 @@ int stopCoreCLR(void* hostHandle, unsigned int domainId) return status; } +// +// Below is from unixcoreruncommon/coreruncommon.cpp +// + bool GetAbsolutePath(const char* path, std::string& absolutePath) { bool result = false; @@ -223,7 +227,7 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) ".ni.exe", ".exe", }; - + DIR* dir = opendir(directory); if (dir == nullptr) { @@ -300,14 +304,10 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) tpaList.append(":"); } } - + // Rewind the directory stream to be able to iterate over it for the next extension rewinddir(dir); } - - closedir(dir); - // strip any trailing : from the tpaList - if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':') - tpaList.resize(tpaList.size()-1); + closedir(dir); } diff --git a/src/host/common/coreclrutil.h b/src/host/common/coreclrutil.h index 5e9768325..ca055df73 100644 --- a/src/host/common/coreclrutil.h +++ b/src/host/common/coreclrutil.h @@ -4,23 +4,30 @@ #include #endif +/* PowerShell on Linux custom host interface + * + * startCoreCLR() and stopCoreCLR() wrap the initialization of CoreCLR + * and use of ExecuteAssemblyFunction() and CreateDelegateFunction() + * should be sandwiched in between them + * + */ extern "C" { - // Paths of expected things int startCoreCLR( + /* Paths of expected things */ const char* clrAbsolutePath, - // Passed to propertyValues + /* Passed to propertyValues */ const char* tpaList, const char* appPath, const char* nativeDllSearchDirs, - // Passed to InitializeCoreCLRFunction + /* Passed to InitializeCoreCLRFunction */ const char* appDomainFriendlyName, void** hostHandle, unsigned int* domainId); int stopCoreCLR(void* hostHandle, unsigned int domainId); - // Prototype of the coreclr_execute_assembly function from the libcoreclr.so + /* Prototype of the coreclr_execute_assembly function from the libcoreclr.so */ typedef int (*ExecuteAssemblyFunction)( void* hostHandle, unsigned int domainId, @@ -29,9 +36,7 @@ extern "C" const char* managedAssemblyPath, unsigned int* exitCode); - extern ExecuteAssemblyFunction executeAssembly; - - // Prototype of coreclr_create_delegate function from the libcoreclr.so + /* Prototype of coreclr_create_delegate function from the libcoreclr.so */ typedef int (*CreateDelegateFunction)( void* hostHandle, unsigned int domainId, @@ -40,12 +45,27 @@ extern "C" const char* entryPointMethodName, void** delegate); + extern ExecuteAssemblyFunction executeAssembly; extern CreateDelegateFunction createDelegate; } #ifdef __cplusplus +// Get absolute path from the specified path. +// Return true in case of a success, false otherwise. bool GetAbsolutePath(const char* path, std::string& absolutePath); + +// Get directory of the specified path. +// Return true in case of a success, false otherwise. bool GetDirectory(const char* absolutePath, std::string& directory); + +// +// Get the absolute path to use to locate libcoreclr.so and the CLR assemblies are stored. If clrFilesPath is provided, +// this function will return the absolute path to it. Otherwise, the directory of the current executable is used. +// +// Return true in case of a success, false otherwise. +// bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); + +// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); #endif From 2c4b99455ad9cd5ee5c4098a30a43abab9c47a3b Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 13:35:00 -0700 Subject: [PATCH 197/342] Reconcile with coreruncommon.cpp --- host/common/coreclrutil.cpp | 14 +++++++------- host/common/coreclrutil.h | 34 +++++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index ed2d64453..29c039d47 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -157,6 +157,10 @@ int stopCoreCLR(void* hostHandle, unsigned int domainId) return status; } +// +// Below is from unixcoreruncommon/coreruncommon.cpp +// + bool GetAbsolutePath(const char* path, std::string& absolutePath) { bool result = false; @@ -223,7 +227,7 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) ".ni.exe", ".exe", }; - + DIR* dir = opendir(directory); if (dir == nullptr) { @@ -300,14 +304,10 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) tpaList.append(":"); } } - + // Rewind the directory stream to be able to iterate over it for the next extension rewinddir(dir); } - - closedir(dir); - // strip any trailing : from the tpaList - if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':') - tpaList.resize(tpaList.size()-1); + closedir(dir); } diff --git a/host/common/coreclrutil.h b/host/common/coreclrutil.h index 5e9768325..ca055df73 100644 --- a/host/common/coreclrutil.h +++ b/host/common/coreclrutil.h @@ -4,23 +4,30 @@ #include #endif +/* PowerShell on Linux custom host interface + * + * startCoreCLR() and stopCoreCLR() wrap the initialization of CoreCLR + * and use of ExecuteAssemblyFunction() and CreateDelegateFunction() + * should be sandwiched in between them + * + */ extern "C" { - // Paths of expected things int startCoreCLR( + /* Paths of expected things */ const char* clrAbsolutePath, - // Passed to propertyValues + /* Passed to propertyValues */ const char* tpaList, const char* appPath, const char* nativeDllSearchDirs, - // Passed to InitializeCoreCLRFunction + /* Passed to InitializeCoreCLRFunction */ const char* appDomainFriendlyName, void** hostHandle, unsigned int* domainId); int stopCoreCLR(void* hostHandle, unsigned int domainId); - // Prototype of the coreclr_execute_assembly function from the libcoreclr.so + /* Prototype of the coreclr_execute_assembly function from the libcoreclr.so */ typedef int (*ExecuteAssemblyFunction)( void* hostHandle, unsigned int domainId, @@ -29,9 +36,7 @@ extern "C" const char* managedAssemblyPath, unsigned int* exitCode); - extern ExecuteAssemblyFunction executeAssembly; - - // Prototype of coreclr_create_delegate function from the libcoreclr.so + /* Prototype of coreclr_create_delegate function from the libcoreclr.so */ typedef int (*CreateDelegateFunction)( void* hostHandle, unsigned int domainId, @@ -40,12 +45,27 @@ extern "C" const char* entryPointMethodName, void** delegate); + extern ExecuteAssemblyFunction executeAssembly; extern CreateDelegateFunction createDelegate; } #ifdef __cplusplus +// Get absolute path from the specified path. +// Return true in case of a success, false otherwise. bool GetAbsolutePath(const char* path, std::string& absolutePath); + +// Get directory of the specified path. +// Return true in case of a success, false otherwise. bool GetDirectory(const char* absolutePath, std::string& directory); + +// +// Get the absolute path to use to locate libcoreclr.so and the CLR assemblies are stored. If clrFilesPath is provided, +// this function will return the absolute path to it. Otherwise, the directory of the current executable is used. +// +// Return true in case of a success, false otherwise. +// bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); + +// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); #endif From f81aec00b3064d902488420dc540b398f0a8b44d Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 13:57:37 -0700 Subject: [PATCH 198/342] Move start/stop functions --- src/host/common/coreclrutil.cpp | 244 ++++++++++++++++---------------- 1 file changed, 124 insertions(+), 120 deletions(-) diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index 29c039d47..47ff418b2 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -37,126 +37,6 @@ ShutdownCoreCLRFunction shutdownCoreCLR; ExecuteAssemblyFunction executeAssembly; CreateDelegateFunction createDelegate; -int startCoreCLR( - // Paths of expected things - const char* clrAbsolutePath, - // Passed to propertyValues - const char* tpaList, - const char* appPath, - const char* nativeDllSearchDirs, - // Passed to InitializeCoreCLRFunction - const char* appDomainFriendlyName, - void** hostHandle, - unsigned int* domainId) -{ - // the path to the CoreCLR library - // - // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac - std::string coreClrDllPath = clrAbsolutePath; - coreClrDllPath += "/"; - coreClrDllPath += coreClrDll; - - if (coreClrDllPath.size() >= PATH_MAX) - { - std::cerr << "Absolute path to CoreCLR library too long" << std::endl; - return 1; - } - - // open the shared library - coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); - if (coreclrLib == nullptr) - { - char* error = dlerror(); - std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; - return 2; - } - - // query the function pointers - initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); - shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); - - executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); - createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); - - if (initializeCoreCLR == nullptr) - { - std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; - return 3; - } - if (executeAssembly == nullptr) - { - std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; - return 3; - } - if (shutdownCoreCLR == nullptr) - { - std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; - return 3; - } - if (createDelegate == nullptr) - { - std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; - return 3; - } - - // create list of properties to initialize CoreCLR - const char* propertyKeys[] = { - "TRUSTED_PLATFORM_ASSEMBLIES", - "APP_PATHS", - "APP_NI_PATHS", - "NATIVE_DLL_SEARCH_DIRECTORIES", - "AppDomainCompatSwitch" - }; - - const char* propertyValues[] = { - tpaList, - appPath, - appPath, - nativeDllSearchDirs, - "UseLatestBehaviorWhenTFMNotSpecified" - }; - - // get path to current executable - char exePath[PATH_MAX] = { 0 }; - readlink("/proc/self/exe", exePath, PATH_MAX); - - // initialize CoreCLR - int status = initializeCoreCLR( - exePath, - appDomainFriendlyName, - sizeof(propertyKeys)/sizeof(propertyKeys[0]), - propertyKeys, - propertyValues, - hostHandle, - domainId); - - if (0 > status) - { - std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; - return 4; - } - - return status; -} - -int stopCoreCLR(void* hostHandle, unsigned int domainId) -{ - // shutdown CoreCLR - int status = shutdownCoreCLR(hostHandle, domainId); - if (0 > status) - { - std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; - } - - // close the dynamic library - if (0 != dlclose(coreclrLib)) - { - std::cerr << "failed to close CoreCLR library" << std::endl; - } - - return status; -} - // // Below is from unixcoreruncommon/coreruncommon.cpp // @@ -311,3 +191,127 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) closedir(dir); } + +// +// Below is our custom start/stop interface +// + +int startCoreCLR( + // Paths of expected things + const char* clrAbsolutePath, + // Passed to propertyValues + const char* tpaList, + const char* appPath, + const char* nativeDllSearchDirs, + // Passed to InitializeCoreCLRFunction + const char* appDomainFriendlyName, + void** hostHandle, + unsigned int* domainId) +{ + // the path to the CoreCLR library + // + // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac + std::string coreClrDllPath = clrAbsolutePath; + coreClrDllPath += "/"; + coreClrDllPath += coreClrDll; + + if (coreClrDllPath.size() >= PATH_MAX) + { + std::cerr << "Absolute path to CoreCLR library too long" << std::endl; + return 1; + } + + // open the shared library + coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); + if (coreclrLib == nullptr) + { + char* error = dlerror(); + std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; + return 2; + } + + // query the function pointers + initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); + shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); + + executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); + createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); + + if (initializeCoreCLR == nullptr) + { + std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; + return 3; + } + if (executeAssembly == nullptr) + { + std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; + return 3; + } + if (shutdownCoreCLR == nullptr) + { + std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; + return 3; + } + if (createDelegate == nullptr) + { + std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; + return 3; + } + + // create list of properties to initialize CoreCLR + const char* propertyKeys[] = { + "TRUSTED_PLATFORM_ASSEMBLIES", + "APP_PATHS", + "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", + "AppDomainCompatSwitch" + }; + + const char* propertyValues[] = { + tpaList, + appPath, + appPath, + nativeDllSearchDirs, + "UseLatestBehaviorWhenTFMNotSpecified" + }; + + // get path to current executable + char exePath[PATH_MAX] = { 0 }; + readlink("/proc/self/exe", exePath, PATH_MAX); + + // initialize CoreCLR + int status = initializeCoreCLR( + exePath, + appDomainFriendlyName, + sizeof(propertyKeys)/sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + hostHandle, + domainId); + + if (0 > status) + { + std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; + return 4; + } + + return status; +} + +int stopCoreCLR(void* hostHandle, unsigned int domainId) +{ + // shutdown CoreCLR + int status = shutdownCoreCLR(hostHandle, domainId); + if (0 > status) + { + std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; + } + + // close the dynamic library + if (0 != dlclose(coreclrLib)) + { + std::cerr << "failed to close CoreCLR library" << std::endl; + } + + return status; +} From 4e6b7a8e6e270b43bfa2c5b2a97eb9e7117c6e74 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 13:57:37 -0700 Subject: [PATCH 199/342] Move start/stop functions --- host/common/coreclrutil.cpp | 244 ++++++++++++++++++------------------ 1 file changed, 124 insertions(+), 120 deletions(-) diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index 29c039d47..47ff418b2 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -37,126 +37,6 @@ ShutdownCoreCLRFunction shutdownCoreCLR; ExecuteAssemblyFunction executeAssembly; CreateDelegateFunction createDelegate; -int startCoreCLR( - // Paths of expected things - const char* clrAbsolutePath, - // Passed to propertyValues - const char* tpaList, - const char* appPath, - const char* nativeDllSearchDirs, - // Passed to InitializeCoreCLRFunction - const char* appDomainFriendlyName, - void** hostHandle, - unsigned int* domainId) -{ - // the path to the CoreCLR library - // - // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac - std::string coreClrDllPath = clrAbsolutePath; - coreClrDllPath += "/"; - coreClrDllPath += coreClrDll; - - if (coreClrDllPath.size() >= PATH_MAX) - { - std::cerr << "Absolute path to CoreCLR library too long" << std::endl; - return 1; - } - - // open the shared library - coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); - if (coreclrLib == nullptr) - { - char* error = dlerror(); - std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; - return 2; - } - - // query the function pointers - initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); - shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); - - executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); - createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); - - if (initializeCoreCLR == nullptr) - { - std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; - return 3; - } - if (executeAssembly == nullptr) - { - std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; - return 3; - } - if (shutdownCoreCLR == nullptr) - { - std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; - return 3; - } - if (createDelegate == nullptr) - { - std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; - return 3; - } - - // create list of properties to initialize CoreCLR - const char* propertyKeys[] = { - "TRUSTED_PLATFORM_ASSEMBLIES", - "APP_PATHS", - "APP_NI_PATHS", - "NATIVE_DLL_SEARCH_DIRECTORIES", - "AppDomainCompatSwitch" - }; - - const char* propertyValues[] = { - tpaList, - appPath, - appPath, - nativeDllSearchDirs, - "UseLatestBehaviorWhenTFMNotSpecified" - }; - - // get path to current executable - char exePath[PATH_MAX] = { 0 }; - readlink("/proc/self/exe", exePath, PATH_MAX); - - // initialize CoreCLR - int status = initializeCoreCLR( - exePath, - appDomainFriendlyName, - sizeof(propertyKeys)/sizeof(propertyKeys[0]), - propertyKeys, - propertyValues, - hostHandle, - domainId); - - if (0 > status) - { - std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; - return 4; - } - - return status; -} - -int stopCoreCLR(void* hostHandle, unsigned int domainId) -{ - // shutdown CoreCLR - int status = shutdownCoreCLR(hostHandle, domainId); - if (0 > status) - { - std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; - } - - // close the dynamic library - if (0 != dlclose(coreclrLib)) - { - std::cerr << "failed to close CoreCLR library" << std::endl; - } - - return status; -} - // // Below is from unixcoreruncommon/coreruncommon.cpp // @@ -311,3 +191,127 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) closedir(dir); } + +// +// Below is our custom start/stop interface +// + +int startCoreCLR( + // Paths of expected things + const char* clrAbsolutePath, + // Passed to propertyValues + const char* tpaList, + const char* appPath, + const char* nativeDllSearchDirs, + // Passed to InitializeCoreCLRFunction + const char* appDomainFriendlyName, + void** hostHandle, + unsigned int* domainId) +{ + // the path to the CoreCLR library + // + // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac + std::string coreClrDllPath = clrAbsolutePath; + coreClrDllPath += "/"; + coreClrDllPath += coreClrDll; + + if (coreClrDllPath.size() >= PATH_MAX) + { + std::cerr << "Absolute path to CoreCLR library too long" << std::endl; + return 1; + } + + // open the shared library + coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); + if (coreclrLib == nullptr) + { + char* error = dlerror(); + std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; + return 2; + } + + // query the function pointers + initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); + shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); + + executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); + createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); + + if (initializeCoreCLR == nullptr) + { + std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; + return 3; + } + if (executeAssembly == nullptr) + { + std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; + return 3; + } + if (shutdownCoreCLR == nullptr) + { + std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; + return 3; + } + if (createDelegate == nullptr) + { + std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; + return 3; + } + + // create list of properties to initialize CoreCLR + const char* propertyKeys[] = { + "TRUSTED_PLATFORM_ASSEMBLIES", + "APP_PATHS", + "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", + "AppDomainCompatSwitch" + }; + + const char* propertyValues[] = { + tpaList, + appPath, + appPath, + nativeDllSearchDirs, + "UseLatestBehaviorWhenTFMNotSpecified" + }; + + // get path to current executable + char exePath[PATH_MAX] = { 0 }; + readlink("/proc/self/exe", exePath, PATH_MAX); + + // initialize CoreCLR + int status = initializeCoreCLR( + exePath, + appDomainFriendlyName, + sizeof(propertyKeys)/sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + hostHandle, + domainId); + + if (0 > status) + { + std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; + return 4; + } + + return status; +} + +int stopCoreCLR(void* hostHandle, unsigned int domainId) +{ + // shutdown CoreCLR + int status = shutdownCoreCLR(hostHandle, domainId); + if (0 > status) + { + std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; + } + + // close the dynamic library + if (0 != dlclose(coreclrLib)) + { + std::cerr << "failed to close CoreCLR library" << std::endl; + } + + return status; +} From 684c849c4b37289bc75eb83bbd4523ec4ecb7594 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 14:23:48 -0700 Subject: [PATCH 200/342] Remove coreclr_path Obtained via CORE_ROOT, like on Windows. --- src/host/cmdline/main.cpp | 34 +++++++----------------- src/host/common/coreclrutil.cpp | 46 +++++++++++++++++++-------------- src/host/common/coreclrutil.h | 10 ------- 3 files changed, 35 insertions(+), 55 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 2443df623..f23107250 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -13,13 +13,12 @@ namespace Cmdline void printHelp() { std::cerr << "PS CoreCLR host" << std::endl - << "Usage: host_cmdline [-c coreclr_path] [-alc load_context_assembly] [-s search_paths]" << std::endl + << "Usage: host_cmdline [-alc load_context_assembly] [-s search_paths]" << std::endl << " [-b base_path] assembly [...]" << std::endl << std::endl << "What it does:" << std::endl << "- by default the host assumes that CoreCLR is located in the same folder" << std::endl << " as host_cmdline" << std::endl - << " + this behavior can be overridden with the -c command line argument" << std::endl << "- by default the host assumes that the assembly named" << std::endl << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl << " platform assemblies" << std::endl @@ -31,7 +30,6 @@ namespace Cmdline << " + this assembly has to be located in the search path" << std::endl << "- by default the host will add the current working directory to the assembly search path" << std::endl << " + this can be overridden with the -s command line argument" << std::endl - << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl << "- by default the host assumes the PS base path for the assembly load context is the current" << std::endl << " working directory" << std::endl << " + this can be overridden with the -b command line argument" << std::endl @@ -39,7 +37,6 @@ namespace Cmdline << " static void Main(string[] args)" << std::endl << std::endl << "Options:" << std::endl - << "-c, --clr-path path to libcoreclr.so and the managed CLR assemblies" << std::endl << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl << "-s a list of assembly search paths, separated by :" << std::endl << "-b the powershell assembly base path" << std::endl @@ -51,7 +48,7 @@ namespace Cmdline << "assembly the path of the assembly to execute relative to current directory" << std::endl << std::endl << "Example:" << std::endl - << "./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; + << "CORE_ROOT=/test/coreclr ./host_cmdline -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 @@ -63,7 +60,6 @@ namespace Cmdline { } - std::string clrPath; std::string assemblyLoadContextFilePath; std::string searchPaths; std::string basePath; @@ -76,7 +72,6 @@ namespace Cmdline void debugPrint() const { std::cerr << "Args:" << std::endl - << "- clrPath " << clrPath << std::endl << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl << "- searchPaths " << searchPaths << std::endl << "- basePath " << basePath << std::endl @@ -103,12 +98,7 @@ namespace Cmdline const bool hasNextArg = i+1 < argc; const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); - if (hasNextArg && (arg == "-c" || arg == "--clr-path")) - { - args.clrPath = nextArg; - ++i; - } - else if (hasNextArg && arg == "-alc") + if (hasNextArg && arg == "-alc") { args.assemblyLoadContextFilePath = nextArg; ++i; @@ -180,15 +170,10 @@ int main(int argc, char** argv) if (args.verbose) std::cerr << "currentExeAbsolutePath=" << currentExeAbsolutePath << std::endl; - // CLR absolute folder path - // - // This path is created from the location of this executable or a path - // specified with the -c command line argument std::string clrAbsolutePath; - const char* clrPathArg = args.clrPath == "" ? nullptr : args.clrPath.c_str(); - if (!GetClrFilesAbsolutePath(currentExeAbsolutePath.c_str(),clrPathArg,clrAbsolutePath)) + if (!GetAbsolutePath(std::getenv("CORE_ROOT"), clrAbsolutePath)) { - std::cerr << "could not find absolute CLR path" << std::endl; + std::cerr << "could not get absolute path of CoreCLR" << std::endl; return 1; } if (args.verbose) @@ -237,12 +222,12 @@ int main(int argc, char** argv) // assembly search paths // - // add the current directory, and optionally the CoreCLR directory if -c was specified - // and anything specified with the -s option + // add the current directory, the CoreCLR directory, and anything + // specified with the -s option std::string appPath = currentDirAbsolutePath; - if (args.clrPath != "") - appPath += ":" + clrAbsolutePath; + + appPath += ":" + clrAbsolutePath; if (args.searchPaths != "") { std::string searchAbsolutePathList = HostUtil::getAbsolutePathList(args.searchPaths); @@ -286,7 +271,6 @@ int main(int argc, char** argv) void* hostHandle; unsigned int domainId; int status = startCoreCLR( - clrAbsolutePath.c_str(), tpaList.c_str(), appPath.c_str(), nativeDllSearchDirs.c_str(), diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index 47ff418b2..96b432625 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -71,23 +72,28 @@ bool GetDirectory(const char* absolutePath, std::string& directory) return false; } -bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) +// Modified to use CORE_ROOT environment variable + +// +// Get the absolute path to use to locate libcoreclr.so and the CLR assemblies are stored. If clrFilesPath is provided, +// this function will return the absolute path to it. Otherwise, the directory of the current executable is used. +// +// Return true in case of a success, false otherwise. +// +bool GetClrFilesAbsolutePath(const char* currentExePath, std::string& clrFilesAbsolutePath) { std::string clrFilesRelativePath; - const char* clrFilesPathLocal = clrFilesPath; + const char* clrFilesPathLocal = std::getenv("CORE_ROOT");; if (clrFilesPathLocal == nullptr) { - // There was no CLR files path specified, use the folder of the corerun/coreconsole + // There was no CLR files path specified, use the folder of the host if (!GetDirectory(currentExePath, clrFilesRelativePath)) { - perror("Failed to get directory from argv[0]"); + std::cerr << "Failed to get directory from currentExePath" << std::endl; return false; } clrFilesPathLocal = clrFilesRelativePath.c_str(); - - // TODO: consider using an env variable (if defined) as a fall-back. - // The windows version of the corerun uses core_root env variable } if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) @@ -195,10 +201,7 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) // // Below is our custom start/stop interface // - int startCoreCLR( - // Paths of expected things - const char* clrAbsolutePath, // Passed to propertyValues const char* tpaList, const char* appPath, @@ -208,12 +211,19 @@ int startCoreCLR( void** hostHandle, unsigned int* domainId) { - // the path to the CoreCLR library - // - // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac - std::string coreClrDllPath = clrAbsolutePath; - coreClrDllPath += "/"; - coreClrDllPath += coreClrDll; + // get path to current executable + char exePath[PATH_MAX] = { 0 }; + readlink("/proc/self/exe", exePath, PATH_MAX); + + std::string clrFilesAbsolutePath; + if(!GetClrFilesAbsolutePath(exePath, clrFilesAbsolutePath)) + { + return -1; + } + + std::string coreClrDllPath(clrFilesAbsolutePath); + coreClrDllPath.append("/"); + coreClrDllPath.append(coreClrDll); if (coreClrDllPath.size() >= PATH_MAX) { @@ -275,10 +285,6 @@ int startCoreCLR( "UseLatestBehaviorWhenTFMNotSpecified" }; - // get path to current executable - char exePath[PATH_MAX] = { 0 }; - readlink("/proc/self/exe", exePath, PATH_MAX); - // initialize CoreCLR int status = initializeCoreCLR( exePath, diff --git a/src/host/common/coreclrutil.h b/src/host/common/coreclrutil.h index ca055df73..c48270743 100644 --- a/src/host/common/coreclrutil.h +++ b/src/host/common/coreclrutil.h @@ -14,8 +14,6 @@ extern "C" { int startCoreCLR( - /* Paths of expected things */ - const char* clrAbsolutePath, /* Passed to propertyValues */ const char* tpaList, const char* appPath, @@ -58,14 +56,6 @@ bool GetAbsolutePath(const char* path, std::string& absolutePath); // Return true in case of a success, false otherwise. bool GetDirectory(const char* absolutePath, std::string& directory); -// -// Get the absolute path to use to locate libcoreclr.so and the CLR assemblies are stored. If clrFilesPath is provided, -// this function will return the absolute path to it. Otherwise, the directory of the current executable is used. -// -// Return true in case of a success, false otherwise. -// -bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); - // Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); #endif From 6b1f0d98479fa6b5c99c1f1ff9781efca765df0c Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 14:23:48 -0700 Subject: [PATCH 201/342] Remove coreclr_path Obtained via CORE_ROOT, like on Windows. --- host/cmdline/main.cpp | 34 ++++++++------------------- host/common/coreclrutil.cpp | 46 +++++++++++++++++++++---------------- host/common/coreclrutil.h | 10 -------- 3 files changed, 35 insertions(+), 55 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 2443df623..f23107250 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -13,13 +13,12 @@ namespace Cmdline void printHelp() { std::cerr << "PS CoreCLR host" << std::endl - << "Usage: host_cmdline [-c coreclr_path] [-alc load_context_assembly] [-s search_paths]" << std::endl + << "Usage: host_cmdline [-alc load_context_assembly] [-s search_paths]" << std::endl << " [-b base_path] assembly [...]" << std::endl << std::endl << "What it does:" << std::endl << "- by default the host assumes that CoreCLR is located in the same folder" << std::endl << " as host_cmdline" << std::endl - << " + this behavior can be overridden with the -c command line argument" << std::endl << "- by default the host assumes that the assembly named" << std::endl << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl << " platform assemblies" << std::endl @@ -31,7 +30,6 @@ namespace Cmdline << " + this assembly has to be located in the search path" << std::endl << "- by default the host will add the current working directory to the assembly search path" << std::endl << " + this can be overridden with the -s command line argument" << std::endl - << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl << "- by default the host assumes the PS base path for the assembly load context is the current" << std::endl << " working directory" << std::endl << " + this can be overridden with the -b command line argument" << std::endl @@ -39,7 +37,6 @@ namespace Cmdline << " static void Main(string[] args)" << std::endl << std::endl << "Options:" << std::endl - << "-c, --clr-path path to libcoreclr.so and the managed CLR assemblies" << std::endl << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl << "-s a list of assembly search paths, separated by :" << std::endl << "-b the powershell assembly base path" << std::endl @@ -51,7 +48,7 @@ namespace Cmdline << "assembly the path of the assembly to execute relative to current directory" << std::endl << std::endl << "Example:" << std::endl - << "./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; + << "CORE_ROOT=/test/coreclr ./host_cmdline -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 @@ -63,7 +60,6 @@ namespace Cmdline { } - std::string clrPath; std::string assemblyLoadContextFilePath; std::string searchPaths; std::string basePath; @@ -76,7 +72,6 @@ namespace Cmdline void debugPrint() const { std::cerr << "Args:" << std::endl - << "- clrPath " << clrPath << std::endl << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl << "- searchPaths " << searchPaths << std::endl << "- basePath " << basePath << std::endl @@ -103,12 +98,7 @@ namespace Cmdline const bool hasNextArg = i+1 < argc; const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); - if (hasNextArg && (arg == "-c" || arg == "--clr-path")) - { - args.clrPath = nextArg; - ++i; - } - else if (hasNextArg && arg == "-alc") + if (hasNextArg && arg == "-alc") { args.assemblyLoadContextFilePath = nextArg; ++i; @@ -180,15 +170,10 @@ int main(int argc, char** argv) if (args.verbose) std::cerr << "currentExeAbsolutePath=" << currentExeAbsolutePath << std::endl; - // CLR absolute folder path - // - // This path is created from the location of this executable or a path - // specified with the -c command line argument std::string clrAbsolutePath; - const char* clrPathArg = args.clrPath == "" ? nullptr : args.clrPath.c_str(); - if (!GetClrFilesAbsolutePath(currentExeAbsolutePath.c_str(),clrPathArg,clrAbsolutePath)) + if (!GetAbsolutePath(std::getenv("CORE_ROOT"), clrAbsolutePath)) { - std::cerr << "could not find absolute CLR path" << std::endl; + std::cerr << "could not get absolute path of CoreCLR" << std::endl; return 1; } if (args.verbose) @@ -237,12 +222,12 @@ int main(int argc, char** argv) // assembly search paths // - // add the current directory, and optionally the CoreCLR directory if -c was specified - // and anything specified with the -s option + // add the current directory, the CoreCLR directory, and anything + // specified with the -s option std::string appPath = currentDirAbsolutePath; - if (args.clrPath != "") - appPath += ":" + clrAbsolutePath; + + appPath += ":" + clrAbsolutePath; if (args.searchPaths != "") { std::string searchAbsolutePathList = HostUtil::getAbsolutePathList(args.searchPaths); @@ -286,7 +271,6 @@ int main(int argc, char** argv) void* hostHandle; unsigned int domainId; int status = startCoreCLR( - clrAbsolutePath.c_str(), tpaList.c_str(), appPath.c_str(), nativeDllSearchDirs.c_str(), diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index 47ff418b2..96b432625 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -71,23 +72,28 @@ bool GetDirectory(const char* absolutePath, std::string& directory) return false; } -bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) +// Modified to use CORE_ROOT environment variable + +// +// Get the absolute path to use to locate libcoreclr.so and the CLR assemblies are stored. If clrFilesPath is provided, +// this function will return the absolute path to it. Otherwise, the directory of the current executable is used. +// +// Return true in case of a success, false otherwise. +// +bool GetClrFilesAbsolutePath(const char* currentExePath, std::string& clrFilesAbsolutePath) { std::string clrFilesRelativePath; - const char* clrFilesPathLocal = clrFilesPath; + const char* clrFilesPathLocal = std::getenv("CORE_ROOT");; if (clrFilesPathLocal == nullptr) { - // There was no CLR files path specified, use the folder of the corerun/coreconsole + // There was no CLR files path specified, use the folder of the host if (!GetDirectory(currentExePath, clrFilesRelativePath)) { - perror("Failed to get directory from argv[0]"); + std::cerr << "Failed to get directory from currentExePath" << std::endl; return false; } clrFilesPathLocal = clrFilesRelativePath.c_str(); - - // TODO: consider using an env variable (if defined) as a fall-back. - // The windows version of the corerun uses core_root env variable } if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) @@ -195,10 +201,7 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) // // Below is our custom start/stop interface // - int startCoreCLR( - // Paths of expected things - const char* clrAbsolutePath, // Passed to propertyValues const char* tpaList, const char* appPath, @@ -208,12 +211,19 @@ int startCoreCLR( void** hostHandle, unsigned int* domainId) { - // the path to the CoreCLR library - // - // This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac - std::string coreClrDllPath = clrAbsolutePath; - coreClrDllPath += "/"; - coreClrDllPath += coreClrDll; + // get path to current executable + char exePath[PATH_MAX] = { 0 }; + readlink("/proc/self/exe", exePath, PATH_MAX); + + std::string clrFilesAbsolutePath; + if(!GetClrFilesAbsolutePath(exePath, clrFilesAbsolutePath)) + { + return -1; + } + + std::string coreClrDllPath(clrFilesAbsolutePath); + coreClrDllPath.append("/"); + coreClrDllPath.append(coreClrDll); if (coreClrDllPath.size() >= PATH_MAX) { @@ -275,10 +285,6 @@ int startCoreCLR( "UseLatestBehaviorWhenTFMNotSpecified" }; - // get path to current executable - char exePath[PATH_MAX] = { 0 }; - readlink("/proc/self/exe", exePath, PATH_MAX); - // initialize CoreCLR int status = initializeCoreCLR( exePath, diff --git a/host/common/coreclrutil.h b/host/common/coreclrutil.h index ca055df73..c48270743 100644 --- a/host/common/coreclrutil.h +++ b/host/common/coreclrutil.h @@ -14,8 +14,6 @@ extern "C" { int startCoreCLR( - /* Paths of expected things */ - const char* clrAbsolutePath, /* Passed to propertyValues */ const char* tpaList, const char* appPath, @@ -58,14 +56,6 @@ bool GetAbsolutePath(const char* path, std::string& absolutePath); // Return true in case of a success, false otherwise. bool GetDirectory(const char* absolutePath, std::string& directory); -// -// Get the absolute path to use to locate libcoreclr.so and the CLR assemblies are stored. If clrFilesPath is provided, -// this function will return the absolute path to it. Otherwise, the directory of the current executable is used. -// -// Return true in case of a success, false otherwise. -// -bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); - // Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); #endif From e55277d2d6d0efb7bd84544f53e1829ca1de0f39 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 14:24:53 -0700 Subject: [PATCH 202/342] Fix warning in GetDirectory() --- src/host/common/coreclrutil.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index 96b432625..8e26cf624 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -59,6 +59,7 @@ bool GetAbsolutePath(const char* path, std::string& absolutePath) return result; } +// TODO use dirname bool GetDirectory(const char* absolutePath, std::string& directory) { directory.assign(absolutePath); @@ -124,7 +125,7 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) // Walk the directory for each extension separately so that we first get files with .ni.dll extension, // then files with .dll extension, etc. - for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + for (unsigned int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) { const char* ext = tpaExtensions[extIndex]; int extLength = strlen(ext); From b4b0f70ad111261a877cb0de11436f5ddb1c05d4 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 14:24:53 -0700 Subject: [PATCH 203/342] Fix warning in GetDirectory() --- host/common/coreclrutil.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index 96b432625..8e26cf624 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -59,6 +59,7 @@ bool GetAbsolutePath(const char* path, std::string& absolutePath) return result; } +// TODO use dirname bool GetDirectory(const char* absolutePath, std::string& directory) { directory.assign(absolutePath); @@ -124,7 +125,7 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) // Walk the directory for each extension separately so that we first get files with .ni.dll extension, // then files with .dll extension, etc. - for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + for (unsigned int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) { const char* ext = tpaExtensions[extIndex]; int extLength = strlen(ext); From 33a09baf03b986d02322f48765a05bfd57ad7cb1 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 14:25:38 -0700 Subject: [PATCH 204/342] Remove currentExeAbsolutePath --- src/host/cmdline/main.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index f23107250..e77e1d7f3 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -160,16 +160,6 @@ int main(int argc, char** argv) if (args.verbose) args.debugPrint(); - // get the absolute path of the current executable - std::string currentExeAbsolutePath; - if (!GetAbsolutePath(argv[0],currentExeAbsolutePath)) - { - std::cerr << "could not get absolute path of current executable" << std::endl; - return 1; - } - if (args.verbose) - std::cerr << "currentExeAbsolutePath=" << currentExeAbsolutePath << std::endl; - std::string clrAbsolutePath; if (!GetAbsolutePath(std::getenv("CORE_ROOT"), clrAbsolutePath)) { From cb3fe8d16eec1420527f9a2fc3951a8528083969 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 14:25:38 -0700 Subject: [PATCH 205/342] Remove currentExeAbsolutePath --- host/cmdline/main.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index f23107250..e77e1d7f3 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -160,16 +160,6 @@ int main(int argc, char** argv) if (args.verbose) args.debugPrint(); - // get the absolute path of the current executable - std::string currentExeAbsolutePath; - if (!GetAbsolutePath(argv[0],currentExeAbsolutePath)) - { - std::cerr << "could not get absolute path of current executable" << std::endl; - return 1; - } - if (args.verbose) - std::cerr << "currentExeAbsolutePath=" << currentExeAbsolutePath << std::endl; - std::string clrAbsolutePath; if (!GetAbsolutePath(std::getenv("CORE_ROOT"), clrAbsolutePath)) { From e30f05983884c9ab870b954ad8d5dafcbc5d50f6 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 15:18:21 -0700 Subject: [PATCH 206/342] Refactor into GetEnvAbsolutePath() --- src/host/common/coreclrutil.cpp | 35 +++++++++++---------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index 8e26cf624..79e753fd0 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -73,33 +73,23 @@ bool GetDirectory(const char* absolutePath, std::string& directory) return false; } -// Modified to use CORE_ROOT environment variable - // -// Get the absolute path to use to locate libcoreclr.so and the CLR assemblies are stored. If clrFilesPath is provided, -// this function will return the absolute path to it. Otherwise, the directory of the current executable is used. +// Get the absolute path given the environment variable. // // Return true in case of a success, false otherwise. // -bool GetClrFilesAbsolutePath(const char* currentExePath, std::string& clrFilesAbsolutePath) +bool GetEnvAbsolutePath(const char* env_var, std::string& absolutePath) { - std::string clrFilesRelativePath; - const char* clrFilesPathLocal = std::getenv("CORE_ROOT");; - if (clrFilesPathLocal == nullptr) + const char* filesPathLocal = std::getenv(env_var);; + if (filesPathLocal == nullptr) { - // There was no CLR files path specified, use the folder of the host - if (!GetDirectory(currentExePath, clrFilesRelativePath)) - { - std::cerr << "Failed to get directory from currentExePath" << std::endl; - return false; - } - - clrFilesPathLocal = clrFilesRelativePath.c_str(); + std::cerr << "$" << env_var << " was empty" << std::endl; + return false; } - if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) + if (!GetAbsolutePath(filesPathLocal, absolutePath)) { - perror("Failed to convert CLR files path to absolute path"); + std::cerr << "Failed to get absolute path for " << env_var << std::endl; return false; } @@ -203,11 +193,9 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) // Below is our custom start/stop interface // int startCoreCLR( - // Passed to propertyValues const char* tpaList, const char* appPath, const char* nativeDllSearchDirs, - // Passed to InitializeCoreCLRFunction const char* appDomainFriendlyName, void** hostHandle, unsigned int* domainId) @@ -216,12 +204,14 @@ int startCoreCLR( char exePath[PATH_MAX] = { 0 }; readlink("/proc/self/exe", exePath, PATH_MAX); + // get the CoreCLR root path std::string clrFilesAbsolutePath; - if(!GetClrFilesAbsolutePath(exePath, clrFilesAbsolutePath)) + if(!GetEnvAbsolutePath("CORE_ROOT", clrFilesAbsolutePath)) { return -1; } + // get the CoreCLR shared library path std::string coreClrDllPath(clrFilesAbsolutePath); coreClrDllPath.append("/"); coreClrDllPath.append(coreClrDll); @@ -241,10 +231,9 @@ int startCoreCLR( return 2; } - // query the function pointers + // query and verify the function pointers initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); - executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); From e570c2a0a8b3cccd2461a317e06b060141322323 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 15:18:21 -0700 Subject: [PATCH 207/342] Refactor into GetEnvAbsolutePath() --- host/common/coreclrutil.cpp | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index 8e26cf624..79e753fd0 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -73,33 +73,23 @@ bool GetDirectory(const char* absolutePath, std::string& directory) return false; } -// Modified to use CORE_ROOT environment variable - // -// Get the absolute path to use to locate libcoreclr.so and the CLR assemblies are stored. If clrFilesPath is provided, -// this function will return the absolute path to it. Otherwise, the directory of the current executable is used. +// Get the absolute path given the environment variable. // // Return true in case of a success, false otherwise. // -bool GetClrFilesAbsolutePath(const char* currentExePath, std::string& clrFilesAbsolutePath) +bool GetEnvAbsolutePath(const char* env_var, std::string& absolutePath) { - std::string clrFilesRelativePath; - const char* clrFilesPathLocal = std::getenv("CORE_ROOT");; - if (clrFilesPathLocal == nullptr) + const char* filesPathLocal = std::getenv(env_var);; + if (filesPathLocal == nullptr) { - // There was no CLR files path specified, use the folder of the host - if (!GetDirectory(currentExePath, clrFilesRelativePath)) - { - std::cerr << "Failed to get directory from currentExePath" << std::endl; - return false; - } - - clrFilesPathLocal = clrFilesRelativePath.c_str(); + std::cerr << "$" << env_var << " was empty" << std::endl; + return false; } - if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) + if (!GetAbsolutePath(filesPathLocal, absolutePath)) { - perror("Failed to convert CLR files path to absolute path"); + std::cerr << "Failed to get absolute path for " << env_var << std::endl; return false; } @@ -203,11 +193,9 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) // Below is our custom start/stop interface // int startCoreCLR( - // Passed to propertyValues const char* tpaList, const char* appPath, const char* nativeDllSearchDirs, - // Passed to InitializeCoreCLRFunction const char* appDomainFriendlyName, void** hostHandle, unsigned int* domainId) @@ -216,12 +204,14 @@ int startCoreCLR( char exePath[PATH_MAX] = { 0 }; readlink("/proc/self/exe", exePath, PATH_MAX); + // get the CoreCLR root path std::string clrFilesAbsolutePath; - if(!GetClrFilesAbsolutePath(exePath, clrFilesAbsolutePath)) + if(!GetEnvAbsolutePath("CORE_ROOT", clrFilesAbsolutePath)) { return -1; } + // get the CoreCLR shared library path std::string coreClrDllPath(clrFilesAbsolutePath); coreClrDllPath.append("/"); coreClrDllPath.append(coreClrDll); @@ -241,10 +231,9 @@ int startCoreCLR( return 2; } - // query the function pointers + // query and verify the function pointers initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); - executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); From 4ba2ac196aeb7d6760378196bdf9758ce5bb22b5 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 18:17:15 -0700 Subject: [PATCH 208/342] Refactor tpaList into libpshost --- src/host/cmdline/main.cpp | 48 ++------------------------------- src/host/common/coreclrutil.cpp | 21 +++++++++++++-- src/host/common/coreclrutil.h | 4 --- 3 files changed, 21 insertions(+), 52 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index e77e1d7f3..b29935cc1 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -40,15 +40,11 @@ namespace Cmdline << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl << "-s a list of assembly search paths, separated by :" << std::endl << "-b the powershell assembly base path" << std::endl - << "-v verbose output, show paths" << std::endl - << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl - << " separated by :" << std::endl - << " unless part of the same folder as CoreCLR, the main assembly referenced with the assembly_name" << std::endl - << " argument, must always be added to the TPA list with this parameter" << std::endl + << "-v verbose output" << std::endl << "assembly the path of the assembly to execute relative to current directory" << std::endl << std::endl << "Example:" << std::endl - << "CORE_ROOT=/test/coreclr ./host_cmdline -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; + << "CORE_ROOT=/test/coreclr PWRSH_ROOT=/test/powershell ./host_cmdline -alc /test/ps/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll -s /test/ps -b /test/ps powershell-simple 'get-process'" << std::endl; } struct Args @@ -63,7 +59,6 @@ namespace Cmdline std::string assemblyLoadContextFilePath; std::string searchPaths; std::string basePath; - std::string tpaList; std::string entryAssemblyPath; int argc; char** argv; @@ -75,7 +70,6 @@ namespace Cmdline << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl << "- searchPaths " << searchPaths << std::endl << "- basePath " << basePath << std::endl - << "- tpaList " << tpaList << std::endl << "- entryAssemblyPath " << entryAssemblyPath << std::endl << "- argc " << argc << std::endl << "- verbose " << (verbose ? "true" : "false") << std::endl; @@ -113,11 +107,6 @@ namespace Cmdline args.basePath = nextArg; ++i; } - else if (hasNextArg && arg == "-tpa") - { - args.tpaList = nextArg; - ++i; - } else if (arg == "-v") { args.verbose = true; @@ -169,38 +158,6 @@ int main(int argc, char** argv) if (args.verbose) std::cerr << "clrAbsolutePath=" << clrAbsolutePath << std::endl; - // TPA list - // - // The list of platform assemblies must include all CoreCLR assemblies - // and the Microsoft.PowerShell.CoreCLR.AssemblyLoadContext - // - // if the -alc parameter was specified, add it to the TPA list here - - std::string tpaList; - AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); - - if (args.assemblyLoadContextFilePath != "") - { - std::string assemblyLoadContextAbsoluteFilePath; - if (!GetAbsolutePath(args.assemblyLoadContextFilePath.c_str(),assemblyLoadContextAbsoluteFilePath)) - { - std::cerr << "Failed to get absolute file path for assembly load context" << std::endl; - return 1; - } - tpaList += ":" + assemblyLoadContextAbsoluteFilePath; - } - - // add the -tpa command line argument - if (args.tpaList != "") - { - std::string tpaAbsolutePathList = HostUtil::getAbsolutePathList(args.tpaList); - if (tpaAbsolutePathList != "") - tpaList += ":" + tpaAbsolutePathList; - } - - if (args.verbose) - std::cerr << "tpaList: " << tpaList << std::endl; - // get the absolute path of the current directory std::string currentDirAbsolutePath; @@ -261,7 +218,6 @@ int main(int argc, char** argv) void* hostHandle; unsigned int domainId; int status = startCoreCLR( - tpaList.c_str(), appPath.c_str(), nativeDllSearchDirs.c_str(), "ps_cmdline_host", diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index 79e753fd0..cccd0efd3 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -96,6 +96,7 @@ bool GetEnvAbsolutePath(const char* env_var, std::string& absolutePath) return true; } +// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) { const char * const tpaExtensions[] = { @@ -193,7 +194,6 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) // Below is our custom start/stop interface // int startCoreCLR( - const char* tpaList, const char* appPath, const char* nativeDllSearchDirs, const char* appDomainFriendlyName, @@ -258,6 +258,23 @@ int startCoreCLR( return 3; } + // generate the Trusted Platform Assemblies list + std::string tpaList; + + // add assemblies in the CoreCLR root path + AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath.c_str(), tpaList); + + // get path to AssemblyLoadContext.dll + std::string psFilesAbsolutePath; + if(!GetEnvAbsolutePath("PWRSH_ROOT", psFilesAbsolutePath)) + { + return -1; + } + std::string assemblyLoadContextAbsoluteFilePath(psFilesAbsolutePath + "/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"); + + // add AssemblyLoadContext + tpaList.append(assemblyLoadContextAbsoluteFilePath); + // create list of properties to initialize CoreCLR const char* propertyKeys[] = { "TRUSTED_PLATFORM_ASSEMBLIES", @@ -268,7 +285,7 @@ int startCoreCLR( }; const char* propertyValues[] = { - tpaList, + tpaList.c_str(), appPath, appPath, nativeDllSearchDirs, diff --git a/src/host/common/coreclrutil.h b/src/host/common/coreclrutil.h index c48270743..018f5a5f5 100644 --- a/src/host/common/coreclrutil.h +++ b/src/host/common/coreclrutil.h @@ -15,7 +15,6 @@ extern "C" { int startCoreCLR( /* Passed to propertyValues */ - const char* tpaList, const char* appPath, const char* nativeDllSearchDirs, /* Passed to InitializeCoreCLRFunction */ @@ -55,7 +54,4 @@ bool GetAbsolutePath(const char* path, std::string& absolutePath); // Get directory of the specified path. // Return true in case of a success, false otherwise. bool GetDirectory(const char* absolutePath, std::string& directory); - -// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. -void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); #endif From da69d4a8c7d75365c94dd8f08ea624c322273cb1 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 18:17:15 -0700 Subject: [PATCH 209/342] Refactor tpaList into libpshost --- host/cmdline/main.cpp | 48 ++----------------------------------- host/common/coreclrutil.cpp | 21 ++++++++++++++-- host/common/coreclrutil.h | 4 ---- 3 files changed, 21 insertions(+), 52 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index e77e1d7f3..b29935cc1 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -40,15 +40,11 @@ namespace Cmdline << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl << "-s a list of assembly search paths, separated by :" << std::endl << "-b the powershell assembly base path" << std::endl - << "-v verbose output, show paths" << std::endl - << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl - << " separated by :" << std::endl - << " unless part of the same folder as CoreCLR, the main assembly referenced with the assembly_name" << std::endl - << " argument, must always be added to the TPA list with this parameter" << std::endl + << "-v verbose output" << std::endl << "assembly the path of the assembly to execute relative to current directory" << std::endl << std::endl << "Example:" << std::endl - << "CORE_ROOT=/test/coreclr ./host_cmdline -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; + << "CORE_ROOT=/test/coreclr PWRSH_ROOT=/test/powershell ./host_cmdline -alc /test/ps/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll -s /test/ps -b /test/ps powershell-simple 'get-process'" << std::endl; } struct Args @@ -63,7 +59,6 @@ namespace Cmdline std::string assemblyLoadContextFilePath; std::string searchPaths; std::string basePath; - std::string tpaList; std::string entryAssemblyPath; int argc; char** argv; @@ -75,7 +70,6 @@ namespace Cmdline << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl << "- searchPaths " << searchPaths << std::endl << "- basePath " << basePath << std::endl - << "- tpaList " << tpaList << std::endl << "- entryAssemblyPath " << entryAssemblyPath << std::endl << "- argc " << argc << std::endl << "- verbose " << (verbose ? "true" : "false") << std::endl; @@ -113,11 +107,6 @@ namespace Cmdline args.basePath = nextArg; ++i; } - else if (hasNextArg && arg == "-tpa") - { - args.tpaList = nextArg; - ++i; - } else if (arg == "-v") { args.verbose = true; @@ -169,38 +158,6 @@ int main(int argc, char** argv) if (args.verbose) std::cerr << "clrAbsolutePath=" << clrAbsolutePath << std::endl; - // TPA list - // - // The list of platform assemblies must include all CoreCLR assemblies - // and the Microsoft.PowerShell.CoreCLR.AssemblyLoadContext - // - // if the -alc parameter was specified, add it to the TPA list here - - std::string tpaList; - AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList); - - if (args.assemblyLoadContextFilePath != "") - { - std::string assemblyLoadContextAbsoluteFilePath; - if (!GetAbsolutePath(args.assemblyLoadContextFilePath.c_str(),assemblyLoadContextAbsoluteFilePath)) - { - std::cerr << "Failed to get absolute file path for assembly load context" << std::endl; - return 1; - } - tpaList += ":" + assemblyLoadContextAbsoluteFilePath; - } - - // add the -tpa command line argument - if (args.tpaList != "") - { - std::string tpaAbsolutePathList = HostUtil::getAbsolutePathList(args.tpaList); - if (tpaAbsolutePathList != "") - tpaList += ":" + tpaAbsolutePathList; - } - - if (args.verbose) - std::cerr << "tpaList: " << tpaList << std::endl; - // get the absolute path of the current directory std::string currentDirAbsolutePath; @@ -261,7 +218,6 @@ int main(int argc, char** argv) void* hostHandle; unsigned int domainId; int status = startCoreCLR( - tpaList.c_str(), appPath.c_str(), nativeDllSearchDirs.c_str(), "ps_cmdline_host", diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index 79e753fd0..cccd0efd3 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -96,6 +96,7 @@ bool GetEnvAbsolutePath(const char* env_var, std::string& absolutePath) return true; } +// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) { const char * const tpaExtensions[] = { @@ -193,7 +194,6 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) // Below is our custom start/stop interface // int startCoreCLR( - const char* tpaList, const char* appPath, const char* nativeDllSearchDirs, const char* appDomainFriendlyName, @@ -258,6 +258,23 @@ int startCoreCLR( return 3; } + // generate the Trusted Platform Assemblies list + std::string tpaList; + + // add assemblies in the CoreCLR root path + AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath.c_str(), tpaList); + + // get path to AssemblyLoadContext.dll + std::string psFilesAbsolutePath; + if(!GetEnvAbsolutePath("PWRSH_ROOT", psFilesAbsolutePath)) + { + return -1; + } + std::string assemblyLoadContextAbsoluteFilePath(psFilesAbsolutePath + "/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"); + + // add AssemblyLoadContext + tpaList.append(assemblyLoadContextAbsoluteFilePath); + // create list of properties to initialize CoreCLR const char* propertyKeys[] = { "TRUSTED_PLATFORM_ASSEMBLIES", @@ -268,7 +285,7 @@ int startCoreCLR( }; const char* propertyValues[] = { - tpaList, + tpaList.c_str(), appPath, appPath, nativeDllSearchDirs, diff --git a/host/common/coreclrutil.h b/host/common/coreclrutil.h index c48270743..018f5a5f5 100644 --- a/host/common/coreclrutil.h +++ b/host/common/coreclrutil.h @@ -15,7 +15,6 @@ extern "C" { int startCoreCLR( /* Passed to propertyValues */ - const char* tpaList, const char* appPath, const char* nativeDllSearchDirs, /* Passed to InitializeCoreCLRFunction */ @@ -55,7 +54,4 @@ bool GetAbsolutePath(const char* path, std::string& absolutePath); // Get directory of the specified path. // Return true in case of a success, false otherwise. bool GetDirectory(const char* absolutePath, std::string& directory); - -// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. -void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); #endif From 6fb372c72a88c99db1ef868358b1d9f2be9eb688 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 18:17:27 -0700 Subject: [PATCH 210/342] Remove base_path and load_context_assembly - libpshost resolves the absolute path to the PowerShell binaries from the environment variable PWRSH_ROOT - libpshost assumes that PowerShell's AssemblyLoadContext.dll exists in PWRSH_ROOT and loads during `startCoreCLR()` - libicu is now only used by libpshost; note that an icu::UnicodeString is UTF-16, and endianness does not matter (see http://userguide.icu-project.org/strings#TOC-ICU:-16-bit-Unicode-strings) --- src/CMakeLists.txt | 2 +- src/host/cmdline/main.cpp | 88 +++++---------------------------- src/host/common/coreclrutil.cpp | 28 +++++++++-- 3 files changed, 38 insertions(+), 80 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8db93c175..9d568377f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,7 +26,7 @@ find_package(Threads) target_link_libraries(ps icuuc) target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps pshost) target_link_libraries(pshost dl icuuc) -target_link_libraries(host_cmdline pshost icuuc) +target_link_libraries(host_cmdline pshost) # target specific include directories target_include_directories(monad_native PRIVATE host) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index b29935cc1..ac9df809e 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -13,38 +13,29 @@ namespace Cmdline void printHelp() { std::cerr << "PS CoreCLR host" << std::endl - << "Usage: host_cmdline [-alc load_context_assembly] [-s search_paths]" << std::endl - << " [-b base_path] assembly [...]" << std::endl + << "Usage: host_cmdline [-s search_paths] assembly [...]" << std::endl << std::endl << "What it does:" << std::endl - << "- by default the host assumes that CoreCLR is located in the same folder" << std::endl - << " as host_cmdline" << std::endl + << "- the host assumes that CoreCLR is located $CORE_ROOT" << std::endl << "- by default the host assumes that the assembly named" << std::endl - << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl - << " platform assemblies" << std::endl - << " + a custom assembly containing the PowerShellAssemblyLoadContext can" << std::endl - << " be provided with the -alc command line argument" << std::endl + << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is " << std::endl + << " located in $PWRSH_ROOT" << std::endl << "- all additional parameters at the end of the command line are forwarded" << std::endl << " to the Main function in the assembly" << std::endl << "- the host will execute the Main function in the specified assembly" << std::endl << " + this assembly has to be located in the search path" << std::endl << "- by default the host will add the current working directory to the assembly search path" << std::endl << " + this can be overridden with the -s command line argument" << std::endl - << "- by default the host assumes the PS base path for the assembly load context is the current" << std::endl - << " working directory" << std::endl - << " + this can be overridden with the -b command line argument" << std::endl << "- the function signature of the Main function that gets executed must be:" << std::endl << " static void Main(string[] args)" << std::endl << std::endl << "Options:" << std::endl - << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl << "-s a list of assembly search paths, separated by :" << std::endl - << "-b the powershell assembly base path" << std::endl << "-v verbose output" << std::endl << "assembly the path of the assembly to execute relative to current directory" << std::endl << std::endl << "Example:" << std::endl - << "CORE_ROOT=/test/coreclr PWRSH_ROOT=/test/powershell ./host_cmdline -alc /test/ps/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll -s /test/ps -b /test/ps powershell-simple 'get-process'" << std::endl; + << "CORE_ROOT=/test/coreclr PWRSH_ROOT=/test/powershell ./host_cmdline -s /test/ps powershell-simple 'get-process'" << std::endl; } struct Args @@ -56,9 +47,7 @@ namespace Cmdline { } - std::string assemblyLoadContextFilePath; std::string searchPaths; - std::string basePath; std::string entryAssemblyPath; int argc; char** argv; @@ -67,9 +56,7 @@ namespace Cmdline void debugPrint() const { std::cerr << "Args:" << std::endl - << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl << "- searchPaths " << searchPaths << std::endl - << "- basePath " << basePath << std::endl << "- entryAssemblyPath " << entryAssemblyPath << std::endl << "- argc " << argc << std::endl << "- verbose " << (verbose ? "true" : "false") << std::endl; @@ -92,21 +79,11 @@ namespace Cmdline const bool hasNextArg = i+1 < argc; const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); - if (hasNextArg && arg == "-alc") - { - args.assemblyLoadContextFilePath = nextArg; - ++i; - } - else if (hasNextArg && arg == "-s") + if (hasNextArg && arg == "-s") { args.searchPaths = nextArg; ++i; } - else if (hasNextArg && arg == "-b") - { - args.basePath = nextArg; - ++i; - } else if (arg == "-v") { args.verbose = true; @@ -190,31 +167,6 @@ int main(int argc, char** argv) // Add both the CoreCLR directory and the regular search paths to this list std::string nativeDllSearchDirs = appPath + ":" + clrAbsolutePath; - // convert the app base to utf-16 - // - // this is needed as a utf-16 LE string by CoreCLR/PS's assembly load context interface - // it is either: - // - the current dir's absolute path - // - the path specified through the -b argument - std::string psBasePath = currentDirAbsolutePath; - if (args.basePath != "") - { - if (!GetAbsolutePath(args.basePath.c_str(),psBasePath)) - { - std::cerr << "failed to get the absolute path from the base_path argument" << std::endl; - return 1; - } - } - if (args.verbose) - std::cerr << "psBasePath=" << psBasePath << std::endl; - - // make sure to leave 1 byte at the end for null termination - std::basic_string psBasePath16(PATH_MAX+1,0); - - UnicodeString u8str = UnicodeString(psBasePath.c_str(),"UTF-8"); - int32_t targetSize = u8str.extract(0,u8str.length(),(char*)&psBasePath16[0],(psBasePath16.size()-1)*sizeof(char16_t),"UTF-16LE"); - psBasePath16.resize(targetSize/sizeof(char16_t)+1); - void* hostHandle; unsigned int domainId; int status = startCoreCLR( @@ -224,29 +176,13 @@ int main(int argc, char** argv) &hostHandle, &domainId); - // initialize the PS's custom assembly load context - typedef void (*LoaderRunHelperFp)(const char16_t* appPath); - LoaderRunHelperFp loaderDelegate = nullptr; - status = createDelegate( - hostHandle, - domainId, - "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", - "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", - "SetPowerShellAssemblyLoadContext", - (void**)&loaderDelegate); - if (0 > status) - { - std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; - return 4; - } - loaderDelegate(psBasePath16.c_str()); - - // call into Main of powershell-simple.exe + // call into Main of assembly unsigned int exitCode; - executeAssembly(hostHandle, domainId, args.argc, - (const char**)args.argv, - (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), - &exitCode); + executeAssembly( + hostHandle, domainId, args.argc, + (const char**)args.argv, + (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), + &exitCode); status = stopCoreCLR(hostHandle, domainId); diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index cccd0efd3..95af993fe 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -8,6 +8,7 @@ #include #include #include +#include // The name of the CoreCLR native runtime DLL #if defined(__APPLE__) @@ -265,12 +266,12 @@ int startCoreCLR( AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath.c_str(), tpaList); // get path to AssemblyLoadContext.dll - std::string psFilesAbsolutePath; - if(!GetEnvAbsolutePath("PWRSH_ROOT", psFilesAbsolutePath)) + std::string psAbsolutePath; + if(!GetEnvAbsolutePath("PWRSH_ROOT", psAbsolutePath)) { return -1; } - std::string assemblyLoadContextAbsoluteFilePath(psFilesAbsolutePath + "/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"); + std::string assemblyLoadContextAbsoluteFilePath(psAbsolutePath + "/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"); // add AssemblyLoadContext tpaList.append(assemblyLoadContextAbsoluteFilePath); @@ -308,6 +309,27 @@ int startCoreCLR( return 4; } + // initialize PowerShell's custom assembly load context + typedef void (*LoaderRunHelperFp)(const char16_t* appPath); + LoaderRunHelperFp loaderDelegate = nullptr; + status = createDelegate( + *hostHandle, + *domainId, + "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", + "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", + "SetPowerShellAssemblyLoadContext", + (void**)&loaderDelegate); + + if (status < 0) + { + std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; + return 4; + } + + icu::UnicodeString psUnicodeAbsolutePath = icu::UnicodeString::fromUTF8(psAbsolutePath.c_str()); + + loaderDelegate((const char16_t*)psUnicodeAbsolutePath.getTerminatedBuffer()); + return status; } From b897e08d217d7d87e98361669512b15c1caf163e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 22 Oct 2015 18:17:27 -0700 Subject: [PATCH 211/342] Remove base_path and load_context_assembly - libpshost resolves the absolute path to the PowerShell binaries from the environment variable PWRSH_ROOT - libpshost assumes that PowerShell's AssemblyLoadContext.dll exists in PWRSH_ROOT and loads during `startCoreCLR()` - libicu is now only used by libpshost; note that an icu::UnicodeString is UTF-16, and endianness does not matter (see http://userguide.icu-project.org/strings#TOC-ICU:-16-bit-Unicode-strings) --- CMakeLists.txt | 2 +- host/cmdline/main.cpp | 88 +++++-------------------------------- host/common/coreclrutil.cpp | 28 ++++++++++-- 3 files changed, 38 insertions(+), 80 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8db93c175..9d568377f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ find_package(Threads) target_link_libraries(ps icuuc) target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps pshost) target_link_libraries(pshost dl icuuc) -target_link_libraries(host_cmdline pshost icuuc) +target_link_libraries(host_cmdline pshost) # target specific include directories target_include_directories(monad_native PRIVATE host) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index b29935cc1..ac9df809e 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -13,38 +13,29 @@ namespace Cmdline void printHelp() { std::cerr << "PS CoreCLR host" << std::endl - << "Usage: host_cmdline [-alc load_context_assembly] [-s search_paths]" << std::endl - << " [-b base_path] assembly [...]" << std::endl + << "Usage: host_cmdline [-s search_paths] assembly [...]" << std::endl << std::endl << "What it does:" << std::endl - << "- by default the host assumes that CoreCLR is located in the same folder" << std::endl - << " as host_cmdline" << std::endl + << "- the host assumes that CoreCLR is located $CORE_ROOT" << std::endl << "- by default the host assumes that the assembly named" << std::endl - << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl - << " platform assemblies" << std::endl - << " + a custom assembly containing the PowerShellAssemblyLoadContext can" << std::endl - << " be provided with the -alc command line argument" << std::endl + << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is " << std::endl + << " located in $PWRSH_ROOT" << std::endl << "- all additional parameters at the end of the command line are forwarded" << std::endl << " to the Main function in the assembly" << std::endl << "- the host will execute the Main function in the specified assembly" << std::endl << " + this assembly has to be located in the search path" << std::endl << "- by default the host will add the current working directory to the assembly search path" << std::endl << " + this can be overridden with the -s command line argument" << std::endl - << "- by default the host assumes the PS base path for the assembly load context is the current" << std::endl - << " working directory" << std::endl - << " + this can be overridden with the -b command line argument" << std::endl << "- the function signature of the Main function that gets executed must be:" << std::endl << " static void Main(string[] args)" << std::endl << std::endl << "Options:" << std::endl - << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl << "-s a list of assembly search paths, separated by :" << std::endl - << "-b the powershell assembly base path" << std::endl << "-v verbose output" << std::endl << "assembly the path of the assembly to execute relative to current directory" << std::endl << std::endl << "Example:" << std::endl - << "CORE_ROOT=/test/coreclr PWRSH_ROOT=/test/powershell ./host_cmdline -alc /test/ps/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll -s /test/ps -b /test/ps powershell-simple 'get-process'" << std::endl; + << "CORE_ROOT=/test/coreclr PWRSH_ROOT=/test/powershell ./host_cmdline -s /test/ps powershell-simple 'get-process'" << std::endl; } struct Args @@ -56,9 +47,7 @@ namespace Cmdline { } - std::string assemblyLoadContextFilePath; std::string searchPaths; - std::string basePath; std::string entryAssemblyPath; int argc; char** argv; @@ -67,9 +56,7 @@ namespace Cmdline void debugPrint() const { std::cerr << "Args:" << std::endl - << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl << "- searchPaths " << searchPaths << std::endl - << "- basePath " << basePath << std::endl << "- entryAssemblyPath " << entryAssemblyPath << std::endl << "- argc " << argc << std::endl << "- verbose " << (verbose ? "true" : "false") << std::endl; @@ -92,21 +79,11 @@ namespace Cmdline const bool hasNextArg = i+1 < argc; const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); - if (hasNextArg && arg == "-alc") - { - args.assemblyLoadContextFilePath = nextArg; - ++i; - } - else if (hasNextArg && arg == "-s") + if (hasNextArg && arg == "-s") { args.searchPaths = nextArg; ++i; } - else if (hasNextArg && arg == "-b") - { - args.basePath = nextArg; - ++i; - } else if (arg == "-v") { args.verbose = true; @@ -190,31 +167,6 @@ int main(int argc, char** argv) // Add both the CoreCLR directory and the regular search paths to this list std::string nativeDllSearchDirs = appPath + ":" + clrAbsolutePath; - // convert the app base to utf-16 - // - // this is needed as a utf-16 LE string by CoreCLR/PS's assembly load context interface - // it is either: - // - the current dir's absolute path - // - the path specified through the -b argument - std::string psBasePath = currentDirAbsolutePath; - if (args.basePath != "") - { - if (!GetAbsolutePath(args.basePath.c_str(),psBasePath)) - { - std::cerr << "failed to get the absolute path from the base_path argument" << std::endl; - return 1; - } - } - if (args.verbose) - std::cerr << "psBasePath=" << psBasePath << std::endl; - - // make sure to leave 1 byte at the end for null termination - std::basic_string psBasePath16(PATH_MAX+1,0); - - UnicodeString u8str = UnicodeString(psBasePath.c_str(),"UTF-8"); - int32_t targetSize = u8str.extract(0,u8str.length(),(char*)&psBasePath16[0],(psBasePath16.size()-1)*sizeof(char16_t),"UTF-16LE"); - psBasePath16.resize(targetSize/sizeof(char16_t)+1); - void* hostHandle; unsigned int domainId; int status = startCoreCLR( @@ -224,29 +176,13 @@ int main(int argc, char** argv) &hostHandle, &domainId); - // initialize the PS's custom assembly load context - typedef void (*LoaderRunHelperFp)(const char16_t* appPath); - LoaderRunHelperFp loaderDelegate = nullptr; - status = createDelegate( - hostHandle, - domainId, - "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", - "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", - "SetPowerShellAssemblyLoadContext", - (void**)&loaderDelegate); - if (0 > status) - { - std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; - return 4; - } - loaderDelegate(psBasePath16.c_str()); - - // call into Main of powershell-simple.exe + // call into Main of assembly unsigned int exitCode; - executeAssembly(hostHandle, domainId, args.argc, - (const char**)args.argv, - (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), - &exitCode); + executeAssembly( + hostHandle, domainId, args.argc, + (const char**)args.argv, + (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), + &exitCode); status = stopCoreCLR(hostHandle, domainId); diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index cccd0efd3..95af993fe 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -8,6 +8,7 @@ #include #include #include +#include // The name of the CoreCLR native runtime DLL #if defined(__APPLE__) @@ -265,12 +266,12 @@ int startCoreCLR( AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath.c_str(), tpaList); // get path to AssemblyLoadContext.dll - std::string psFilesAbsolutePath; - if(!GetEnvAbsolutePath("PWRSH_ROOT", psFilesAbsolutePath)) + std::string psAbsolutePath; + if(!GetEnvAbsolutePath("PWRSH_ROOT", psAbsolutePath)) { return -1; } - std::string assemblyLoadContextAbsoluteFilePath(psFilesAbsolutePath + "/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"); + std::string assemblyLoadContextAbsoluteFilePath(psAbsolutePath + "/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"); // add AssemblyLoadContext tpaList.append(assemblyLoadContextAbsoluteFilePath); @@ -308,6 +309,27 @@ int startCoreCLR( return 4; } + // initialize PowerShell's custom assembly load context + typedef void (*LoaderRunHelperFp)(const char16_t* appPath); + LoaderRunHelperFp loaderDelegate = nullptr; + status = createDelegate( + *hostHandle, + *domainId, + "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", + "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", + "SetPowerShellAssemblyLoadContext", + (void**)&loaderDelegate); + + if (status < 0) + { + std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; + return 4; + } + + icu::UnicodeString psUnicodeAbsolutePath = icu::UnicodeString::fromUTF8(psAbsolutePath.c_str()); + + loaderDelegate((const char16_t*)psUnicodeAbsolutePath.getTerminatedBuffer()); + return status; } From 54a4a2ae6ca8dfbaace2f5a4ad1ba3a95c1d5c3b Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 00:01:48 -0700 Subject: [PATCH 212/342] Clean up error codes --- src/host/cmdline/main.cpp | 11 +++++++++++ src/host/common/coreclrutil.cpp | 26 ++++++++++---------------- src/host/common/coreclrutil.h | 2 ++ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index ac9df809e..9e61b31ee 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -176,6 +176,12 @@ int main(int argc, char** argv) &hostHandle, &domainId); + if (!SUCCEEDED(status)) + { + std::cerr << "could not start CoreCLR" << std::endl; + return -1; + } + // call into Main of assembly unsigned int exitCode; executeAssembly( @@ -185,6 +191,11 @@ int main(int argc, char** argv) &exitCode); status = stopCoreCLR(hostHandle, domainId); + if (!SUCCEEDED(status)) + { + std::cerr << "could not stop CoreCLR" << std::endl; + return -1; + } return exitCode; } diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index 95af993fe..65d187b36 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -217,19 +217,13 @@ int startCoreCLR( coreClrDllPath.append("/"); coreClrDllPath.append(coreClrDll); - if (coreClrDllPath.size() >= PATH_MAX) - { - std::cerr << "Absolute path to CoreCLR library too long" << std::endl; - return 1; - } - // open the shared library coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); if (coreclrLib == nullptr) { char* error = dlerror(); std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; - return 2; + return -1; } // query and verify the function pointers @@ -241,22 +235,22 @@ int startCoreCLR( if (initializeCoreCLR == nullptr) { std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; - return 3; + return -1; } if (executeAssembly == nullptr) { std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; - return 3; + return -1; } if (shutdownCoreCLR == nullptr) { std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; - return 3; + return -1; } if (createDelegate == nullptr) { std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; - return 3; + return -1; } // generate the Trusted Platform Assemblies list @@ -303,10 +297,10 @@ int startCoreCLR( hostHandle, domainId); - if (0 > status) + if (!SUCCEEDED(status)) { std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; - return 4; + return -1; } // initialize PowerShell's custom assembly load context @@ -320,10 +314,10 @@ int startCoreCLR( "SetPowerShellAssemblyLoadContext", (void**)&loaderDelegate); - if (status < 0) + if (!SUCCEEDED(status)) { std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; - return 4; + return -1; } icu::UnicodeString psUnicodeAbsolutePath = icu::UnicodeString::fromUTF8(psAbsolutePath.c_str()); @@ -337,7 +331,7 @@ int stopCoreCLR(void* hostHandle, unsigned int domainId) { // shutdown CoreCLR int status = shutdownCoreCLR(hostHandle, domainId); - if (0 > status) + if (!SUCCEEDED(status)) { std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; } diff --git a/src/host/common/coreclrutil.h b/src/host/common/coreclrutil.h index 018f5a5f5..b01844e95 100644 --- a/src/host/common/coreclrutil.h +++ b/src/host/common/coreclrutil.h @@ -4,6 +4,8 @@ #include #endif +#define SUCCEEDED(Status) ((Status) >= 0) + /* PowerShell on Linux custom host interface * * startCoreCLR() and stopCoreCLR() wrap the initialization of CoreCLR From 5573c58a75b7a4f04dab1bdad90ab0efd9b126fb Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 00:01:48 -0700 Subject: [PATCH 213/342] Clean up error codes --- host/cmdline/main.cpp | 11 +++++++++++ host/common/coreclrutil.cpp | 26 ++++++++++---------------- host/common/coreclrutil.h | 2 ++ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index ac9df809e..9e61b31ee 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -176,6 +176,12 @@ int main(int argc, char** argv) &hostHandle, &domainId); + if (!SUCCEEDED(status)) + { + std::cerr << "could not start CoreCLR" << std::endl; + return -1; + } + // call into Main of assembly unsigned int exitCode; executeAssembly( @@ -185,6 +191,11 @@ int main(int argc, char** argv) &exitCode); status = stopCoreCLR(hostHandle, domainId); + if (!SUCCEEDED(status)) + { + std::cerr << "could not stop CoreCLR" << std::endl; + return -1; + } return exitCode; } diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index 95af993fe..65d187b36 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -217,19 +217,13 @@ int startCoreCLR( coreClrDllPath.append("/"); coreClrDllPath.append(coreClrDll); - if (coreClrDllPath.size() >= PATH_MAX) - { - std::cerr << "Absolute path to CoreCLR library too long" << std::endl; - return 1; - } - // open the shared library coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); if (coreclrLib == nullptr) { char* error = dlerror(); std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; - return 2; + return -1; } // query and verify the function pointers @@ -241,22 +235,22 @@ int startCoreCLR( if (initializeCoreCLR == nullptr) { std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; - return 3; + return -1; } if (executeAssembly == nullptr) { std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; - return 3; + return -1; } if (shutdownCoreCLR == nullptr) { std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; - return 3; + return -1; } if (createDelegate == nullptr) { std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; - return 3; + return -1; } // generate the Trusted Platform Assemblies list @@ -303,10 +297,10 @@ int startCoreCLR( hostHandle, domainId); - if (0 > status) + if (!SUCCEEDED(status)) { std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; - return 4; + return -1; } // initialize PowerShell's custom assembly load context @@ -320,10 +314,10 @@ int startCoreCLR( "SetPowerShellAssemblyLoadContext", (void**)&loaderDelegate); - if (status < 0) + if (!SUCCEEDED(status)) { std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; - return 4; + return -1; } icu::UnicodeString psUnicodeAbsolutePath = icu::UnicodeString::fromUTF8(psAbsolutePath.c_str()); @@ -337,7 +331,7 @@ int stopCoreCLR(void* hostHandle, unsigned int domainId) { // shutdown CoreCLR int status = shutdownCoreCLR(hostHandle, domainId); - if (0 > status) + if (!SUCCEEDED(status)) { std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; } diff --git a/host/common/coreclrutil.h b/host/common/coreclrutil.h index 018f5a5f5..b01844e95 100644 --- a/host/common/coreclrutil.h +++ b/host/common/coreclrutil.h @@ -4,6 +4,8 @@ #include #endif +#define SUCCEEDED(Status) ((Status) >= 0) + /* PowerShell on Linux custom host interface * * startCoreCLR() and stopCoreCLR() wrap the initialization of CoreCLR From 9abf5d276eef4eae21a9b510b3c987c811bcfcdc Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 00:36:47 -0700 Subject: [PATCH 214/342] Move appPath and nativeDllSearchDirs to libpshost - for PowerShell, the `appPath` is the path to the PowerShell libraries and consoles, i.e., `PWRSH_ROOT` - the `nativeDllSearchDirs` is just `appPath` plus `CORE_ROOT` - probably should parse and add `LD_LIBRARY_PATH` to `appPath` This refactors the last vestiges of command line arguments out of the command-line host and into libpshost, where all necessary questions are answered either automatically or through the two introduced environment variables (`CORE_ROOT` and `PWRSH_ROOT`). --- src/host/cmdline/main.cpp | 51 ++++----------------------------- src/host/common/coreclrutil.cpp | 16 +++++++---- src/host/common/coreclrutil.h | 4 --- 3 files changed, 17 insertions(+), 54 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 9e61b31ee..80a1f700a 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -13,24 +13,22 @@ namespace Cmdline void printHelp() { std::cerr << "PS CoreCLR host" << std::endl - << "Usage: host_cmdline [-s search_paths] assembly [...]" << std::endl + << "Usage: host_cmdline assembly [...]" << std::endl << std::endl << "What it does:" << std::endl << "- the host assumes that CoreCLR is located $CORE_ROOT" << std::endl - << "- by default the host assumes that the assembly named" << std::endl + << "- the host assumes that the assembly named" << std::endl << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is " << std::endl << " located in $PWRSH_ROOT" << std::endl << "- all additional parameters at the end of the command line are forwarded" << std::endl << " to the Main function in the assembly" << std::endl << "- the host will execute the Main function in the specified assembly" << std::endl << " + this assembly has to be located in the search path" << std::endl - << "- by default the host will add the current working directory to the assembly search path" << std::endl - << " + this can be overridden with the -s command line argument" << std::endl + << "- the host will add $PWRSH_ROOT to the assembly search path" << std::endl << "- the function signature of the Main function that gets executed must be:" << std::endl << " static void Main(string[] args)" << std::endl << std::endl << "Options:" << std::endl - << "-s a list of assembly search paths, separated by :" << std::endl << "-v verbose output" << std::endl << "assembly the path of the assembly to execute relative to current directory" << std::endl << std::endl @@ -56,7 +54,6 @@ namespace Cmdline void debugPrint() const { std::cerr << "Args:" << std::endl - << "- searchPaths " << searchPaths << std::endl << "- entryAssemblyPath " << entryAssemblyPath << std::endl << "- argc " << argc << std::endl << "- verbose " << (verbose ? "true" : "false") << std::endl; @@ -79,9 +76,9 @@ namespace Cmdline const bool hasNextArg = i+1 < argc; const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); - if (hasNextArg && arg == "-s") + if (hasNextArg && arg == "--File") { - args.searchPaths = nextArg; + std::cerr << "TODO: should launch script " << nextArg << std::endl; ++i; } else if (arg == "-v") @@ -126,52 +123,17 @@ int main(int argc, char** argv) if (args.verbose) args.debugPrint(); - std::string clrAbsolutePath; - if (!GetAbsolutePath(std::getenv("CORE_ROOT"), clrAbsolutePath)) - { - std::cerr << "could not get absolute path of CoreCLR" << std::endl; - return 1; - } - if (args.verbose) - std::cerr << "clrAbsolutePath=" << clrAbsolutePath << std::endl; - // get the absolute path of the current directory - std::string currentDirAbsolutePath; - if (!GetAbsolutePath(".",currentDirAbsolutePath)) + if (!GetAbsolutePath(".", currentDirAbsolutePath)) { std::cerr << "failed to get the absolute path from current working directory" << std::endl; return 1; } - // assembly search paths - // - // add the current directory, the CoreCLR directory, and anything - // specified with the -s option - - std::string appPath = currentDirAbsolutePath; - - appPath += ":" + clrAbsolutePath; - if (args.searchPaths != "") - { - std::string searchAbsolutePathList = HostUtil::getAbsolutePathList(args.searchPaths); - if (searchAbsolutePathList != "") - appPath += ":" + searchAbsolutePathList; - } - - if (args.verbose) - std::cerr << "appPath: " << appPath << std::endl; - - // search paths for native dlls - // - // Add both the CoreCLR directory and the regular search paths to this list - std::string nativeDllSearchDirs = appPath + ":" + clrAbsolutePath; - void* hostHandle; unsigned int domainId; int status = startCoreCLR( - appPath.c_str(), - nativeDllSearchDirs.c_str(), "ps_cmdline_host", &hostHandle, &domainId); @@ -199,4 +161,3 @@ int main(int argc, char** argv) return exitCode; } - diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index 65d187b36..597e3fd75 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -195,8 +195,6 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) // Below is our custom start/stop interface // int startCoreCLR( - const char* appPath, - const char* nativeDllSearchDirs, const char* appDomainFriendlyName, void** hostHandle, unsigned int* domainId) @@ -270,6 +268,14 @@ int startCoreCLR( // add AssemblyLoadContext tpaList.append(assemblyLoadContextAbsoluteFilePath); + // generate the assembly search paths + std::string appPath(psAbsolutePath); + // TODO: add LD_LIBRARY_PATH? + + std::string nativeDllSearchDirs(appPath); + nativeDllSearchDirs.append(":"); + nativeDllSearchDirs.append(clrFilesAbsolutePath); + // create list of properties to initialize CoreCLR const char* propertyKeys[] = { "TRUSTED_PLATFORM_ASSEMBLIES", @@ -281,9 +287,9 @@ int startCoreCLR( const char* propertyValues[] = { tpaList.c_str(), - appPath, - appPath, - nativeDllSearchDirs, + appPath.c_str(), + appPath.c_str(), + nativeDllSearchDirs.c_str(), "UseLatestBehaviorWhenTFMNotSpecified" }; diff --git a/src/host/common/coreclrutil.h b/src/host/common/coreclrutil.h index b01844e95..f31da19aa 100644 --- a/src/host/common/coreclrutil.h +++ b/src/host/common/coreclrutil.h @@ -16,10 +16,6 @@ extern "C" { int startCoreCLR( - /* Passed to propertyValues */ - const char* appPath, - const char* nativeDllSearchDirs, - /* Passed to InitializeCoreCLRFunction */ const char* appDomainFriendlyName, void** hostHandle, unsigned int* domainId); From 762930f61eba34a53d8706a603fe21345b3f978c Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 00:36:47 -0700 Subject: [PATCH 215/342] Move appPath and nativeDllSearchDirs to libpshost - for PowerShell, the `appPath` is the path to the PowerShell libraries and consoles, i.e., `PWRSH_ROOT` - the `nativeDllSearchDirs` is just `appPath` plus `CORE_ROOT` - probably should parse and add `LD_LIBRARY_PATH` to `appPath` This refactors the last vestiges of command line arguments out of the command-line host and into libpshost, where all necessary questions are answered either automatically or through the two introduced environment variables (`CORE_ROOT` and `PWRSH_ROOT`). --- host/cmdline/main.cpp | 51 +++++-------------------------------- host/common/coreclrutil.cpp | 16 ++++++++---- host/common/coreclrutil.h | 4 --- 3 files changed, 17 insertions(+), 54 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 9e61b31ee..80a1f700a 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -13,24 +13,22 @@ namespace Cmdline void printHelp() { std::cerr << "PS CoreCLR host" << std::endl - << "Usage: host_cmdline [-s search_paths] assembly [...]" << std::endl + << "Usage: host_cmdline assembly [...]" << std::endl << std::endl << "What it does:" << std::endl << "- the host assumes that CoreCLR is located $CORE_ROOT" << std::endl - << "- by default the host assumes that the assembly named" << std::endl + << "- the host assumes that the assembly named" << std::endl << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is " << std::endl << " located in $PWRSH_ROOT" << std::endl << "- all additional parameters at the end of the command line are forwarded" << std::endl << " to the Main function in the assembly" << std::endl << "- the host will execute the Main function in the specified assembly" << std::endl << " + this assembly has to be located in the search path" << std::endl - << "- by default the host will add the current working directory to the assembly search path" << std::endl - << " + this can be overridden with the -s command line argument" << std::endl + << "- the host will add $PWRSH_ROOT to the assembly search path" << std::endl << "- the function signature of the Main function that gets executed must be:" << std::endl << " static void Main(string[] args)" << std::endl << std::endl << "Options:" << std::endl - << "-s a list of assembly search paths, separated by :" << std::endl << "-v verbose output" << std::endl << "assembly the path of the assembly to execute relative to current directory" << std::endl << std::endl @@ -56,7 +54,6 @@ namespace Cmdline void debugPrint() const { std::cerr << "Args:" << std::endl - << "- searchPaths " << searchPaths << std::endl << "- entryAssemblyPath " << entryAssemblyPath << std::endl << "- argc " << argc << std::endl << "- verbose " << (verbose ? "true" : "false") << std::endl; @@ -79,9 +76,9 @@ namespace Cmdline const bool hasNextArg = i+1 < argc; const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); - if (hasNextArg && arg == "-s") + if (hasNextArg && arg == "--File") { - args.searchPaths = nextArg; + std::cerr << "TODO: should launch script " << nextArg << std::endl; ++i; } else if (arg == "-v") @@ -126,52 +123,17 @@ int main(int argc, char** argv) if (args.verbose) args.debugPrint(); - std::string clrAbsolutePath; - if (!GetAbsolutePath(std::getenv("CORE_ROOT"), clrAbsolutePath)) - { - std::cerr << "could not get absolute path of CoreCLR" << std::endl; - return 1; - } - if (args.verbose) - std::cerr << "clrAbsolutePath=" << clrAbsolutePath << std::endl; - // get the absolute path of the current directory - std::string currentDirAbsolutePath; - if (!GetAbsolutePath(".",currentDirAbsolutePath)) + if (!GetAbsolutePath(".", currentDirAbsolutePath)) { std::cerr << "failed to get the absolute path from current working directory" << std::endl; return 1; } - // assembly search paths - // - // add the current directory, the CoreCLR directory, and anything - // specified with the -s option - - std::string appPath = currentDirAbsolutePath; - - appPath += ":" + clrAbsolutePath; - if (args.searchPaths != "") - { - std::string searchAbsolutePathList = HostUtil::getAbsolutePathList(args.searchPaths); - if (searchAbsolutePathList != "") - appPath += ":" + searchAbsolutePathList; - } - - if (args.verbose) - std::cerr << "appPath: " << appPath << std::endl; - - // search paths for native dlls - // - // Add both the CoreCLR directory and the regular search paths to this list - std::string nativeDllSearchDirs = appPath + ":" + clrAbsolutePath; - void* hostHandle; unsigned int domainId; int status = startCoreCLR( - appPath.c_str(), - nativeDllSearchDirs.c_str(), "ps_cmdline_host", &hostHandle, &domainId); @@ -199,4 +161,3 @@ int main(int argc, char** argv) return exitCode; } - diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index 65d187b36..597e3fd75 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -195,8 +195,6 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) // Below is our custom start/stop interface // int startCoreCLR( - const char* appPath, - const char* nativeDllSearchDirs, const char* appDomainFriendlyName, void** hostHandle, unsigned int* domainId) @@ -270,6 +268,14 @@ int startCoreCLR( // add AssemblyLoadContext tpaList.append(assemblyLoadContextAbsoluteFilePath); + // generate the assembly search paths + std::string appPath(psAbsolutePath); + // TODO: add LD_LIBRARY_PATH? + + std::string nativeDllSearchDirs(appPath); + nativeDllSearchDirs.append(":"); + nativeDllSearchDirs.append(clrFilesAbsolutePath); + // create list of properties to initialize CoreCLR const char* propertyKeys[] = { "TRUSTED_PLATFORM_ASSEMBLIES", @@ -281,9 +287,9 @@ int startCoreCLR( const char* propertyValues[] = { tpaList.c_str(), - appPath, - appPath, - nativeDllSearchDirs, + appPath.c_str(), + appPath.c_str(), + nativeDllSearchDirs.c_str(), "UseLatestBehaviorWhenTFMNotSpecified" }; diff --git a/host/common/coreclrutil.h b/host/common/coreclrutil.h index b01844e95..f31da19aa 100644 --- a/host/common/coreclrutil.h +++ b/host/common/coreclrutil.h @@ -16,10 +16,6 @@ extern "C" { int startCoreCLR( - /* Passed to propertyValues */ - const char* appPath, - const char* nativeDllSearchDirs, - /* Passed to InitializeCoreCLRFunction */ const char* appDomainFriendlyName, void** hostHandle, unsigned int* domainId); From 6fffdd341e4498cba2ca372d971819f54eb91f0b Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 00:40:26 -0700 Subject: [PATCH 216/342] fixup! Clean up error codes --- src/host/common/coreclrutil.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index 597e3fd75..eb4a0017d 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -45,19 +45,17 @@ CreateDelegateFunction createDelegate; bool GetAbsolutePath(const char* path, std::string& absolutePath) { - bool result = false; - char realPath[PATH_MAX]; if (realpath(path, realPath) != nullptr && realPath[0] != '\0') { absolutePath.assign(realPath); // realpath should return canonicalized path without the trailing slash assert(absolutePath.back() != '/'); - - result = true; + return true; } - return result; + std::cerr << "failed to get absolute path for " << path << std::endl; + return false; } // TODO use dirname @@ -71,6 +69,7 @@ bool GetDirectory(const char* absolutePath, std::string& directory) return true; } + std::cerr << "failed to get directory for " << absolutePath << std::endl; return false; } @@ -84,13 +83,13 @@ bool GetEnvAbsolutePath(const char* env_var, std::string& absolutePath) const char* filesPathLocal = std::getenv(env_var);; if (filesPathLocal == nullptr) { - std::cerr << "$" << env_var << " was empty" << std::endl; + std::cerr << "failed because $" << env_var << " was empty" << std::endl; return false; } if (!GetAbsolutePath(filesPathLocal, absolutePath)) { - std::cerr << "Failed to get absolute path for " << env_var << std::endl; + std::cerr << "failed to get absolute path for " << env_var << std::endl; return false; } From cfb8f2e59f0cfaed4feb1e79d5a7cf6730f392f1 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 00:40:26 -0700 Subject: [PATCH 217/342] fixup! Clean up error codes --- host/common/coreclrutil.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index 597e3fd75..eb4a0017d 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -45,19 +45,17 @@ CreateDelegateFunction createDelegate; bool GetAbsolutePath(const char* path, std::string& absolutePath) { - bool result = false; - char realPath[PATH_MAX]; if (realpath(path, realPath) != nullptr && realPath[0] != '\0') { absolutePath.assign(realPath); // realpath should return canonicalized path without the trailing slash assert(absolutePath.back() != '/'); - - result = true; + return true; } - return result; + std::cerr << "failed to get absolute path for " << path << std::endl; + return false; } // TODO use dirname @@ -71,6 +69,7 @@ bool GetDirectory(const char* absolutePath, std::string& directory) return true; } + std::cerr << "failed to get directory for " << absolutePath << std::endl; return false; } @@ -84,13 +83,13 @@ bool GetEnvAbsolutePath(const char* env_var, std::string& absolutePath) const char* filesPathLocal = std::getenv(env_var);; if (filesPathLocal == nullptr) { - std::cerr << "$" << env_var << " was empty" << std::endl; + std::cerr << "failed because $" << env_var << " was empty" << std::endl; return false; } if (!GetAbsolutePath(filesPathLocal, absolutePath)) { - std::cerr << "Failed to get absolute path for " << env_var << std::endl; + std::cerr << "failed to get absolute path for " << env_var << std::endl; return false; } From aeacd0f047b282f1cd600d55c6b3cc430a7c8a21 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 00:49:25 -0700 Subject: [PATCH 218/342] Rename variables and reorganize --- src/host/common/coreclrutil.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/host/common/coreclrutil.cpp b/src/host/common/coreclrutil.cpp index eb4a0017d..d53433e3b 100644 --- a/src/host/common/coreclrutil.cpp +++ b/src/host/common/coreclrutil.cpp @@ -198,19 +198,15 @@ int startCoreCLR( void** hostHandle, unsigned int* domainId) { - // get path to current executable - char exePath[PATH_MAX] = { 0 }; - readlink("/proc/self/exe", exePath, PATH_MAX); - // get the CoreCLR root path - std::string clrFilesAbsolutePath; - if(!GetEnvAbsolutePath("CORE_ROOT", clrFilesAbsolutePath)) + std::string clrAbsolutePath; + if(!GetEnvAbsolutePath("CORE_ROOT", clrAbsolutePath)) { return -1; } // get the CoreCLR shared library path - std::string coreClrDllPath(clrFilesAbsolutePath); + std::string coreClrDllPath(clrAbsolutePath); coreClrDllPath.append("/"); coreClrDllPath.append(coreClrDll); @@ -254,7 +250,7 @@ int startCoreCLR( std::string tpaList; // add assemblies in the CoreCLR root path - AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath.c_str(), tpaList); + AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(), tpaList); // get path to AssemblyLoadContext.dll std::string psAbsolutePath; @@ -262,10 +258,12 @@ int startCoreCLR( { return -1; } - std::string assemblyLoadContextAbsoluteFilePath(psAbsolutePath + "/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"); + std::string alcAbsolutePath(psAbsolutePath); + alcAbsolutePath.append("/"); + alcAbsolutePath.append("Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"); // add AssemblyLoadContext - tpaList.append(assemblyLoadContextAbsoluteFilePath); + tpaList.append(alcAbsolutePath); // generate the assembly search paths std::string appPath(psAbsolutePath); @@ -273,7 +271,7 @@ int startCoreCLR( std::string nativeDllSearchDirs(appPath); nativeDllSearchDirs.append(":"); - nativeDllSearchDirs.append(clrFilesAbsolutePath); + nativeDllSearchDirs.append(clrAbsolutePath); // create list of properties to initialize CoreCLR const char* propertyKeys[] = { @@ -292,6 +290,10 @@ int startCoreCLR( "UseLatestBehaviorWhenTFMNotSpecified" }; + // get path to current executable + char exePath[PATH_MAX] = { 0 }; + readlink("/proc/self/exe", exePath, PATH_MAX); + // initialize CoreCLR int status = initializeCoreCLR( exePath, From 9b308fa600e064dd95ecab6019059cff1135829f Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 00:49:25 -0700 Subject: [PATCH 219/342] Rename variables and reorganize --- host/common/coreclrutil.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/host/common/coreclrutil.cpp b/host/common/coreclrutil.cpp index eb4a0017d..d53433e3b 100644 --- a/host/common/coreclrutil.cpp +++ b/host/common/coreclrutil.cpp @@ -198,19 +198,15 @@ int startCoreCLR( void** hostHandle, unsigned int* domainId) { - // get path to current executable - char exePath[PATH_MAX] = { 0 }; - readlink("/proc/self/exe", exePath, PATH_MAX); - // get the CoreCLR root path - std::string clrFilesAbsolutePath; - if(!GetEnvAbsolutePath("CORE_ROOT", clrFilesAbsolutePath)) + std::string clrAbsolutePath; + if(!GetEnvAbsolutePath("CORE_ROOT", clrAbsolutePath)) { return -1; } // get the CoreCLR shared library path - std::string coreClrDllPath(clrFilesAbsolutePath); + std::string coreClrDllPath(clrAbsolutePath); coreClrDllPath.append("/"); coreClrDllPath.append(coreClrDll); @@ -254,7 +250,7 @@ int startCoreCLR( std::string tpaList; // add assemblies in the CoreCLR root path - AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath.c_str(), tpaList); + AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(), tpaList); // get path to AssemblyLoadContext.dll std::string psAbsolutePath; @@ -262,10 +258,12 @@ int startCoreCLR( { return -1; } - std::string assemblyLoadContextAbsoluteFilePath(psAbsolutePath + "/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"); + std::string alcAbsolutePath(psAbsolutePath); + alcAbsolutePath.append("/"); + alcAbsolutePath.append("Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"); // add AssemblyLoadContext - tpaList.append(assemblyLoadContextAbsoluteFilePath); + tpaList.append(alcAbsolutePath); // generate the assembly search paths std::string appPath(psAbsolutePath); @@ -273,7 +271,7 @@ int startCoreCLR( std::string nativeDllSearchDirs(appPath); nativeDllSearchDirs.append(":"); - nativeDllSearchDirs.append(clrFilesAbsolutePath); + nativeDllSearchDirs.append(clrAbsolutePath); // create list of properties to initialize CoreCLR const char* propertyKeys[] = { @@ -292,6 +290,10 @@ int startCoreCLR( "UseLatestBehaviorWhenTFMNotSpecified" }; + // get path to current executable + char exePath[PATH_MAX] = { 0 }; + readlink("/proc/self/exe", exePath, PATH_MAX); + // initialize CoreCLR int status = initializeCoreCLR( exePath, From 6432bb94b8dbca376a2e3296bb894978b604c3b1 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 00:57:17 -0700 Subject: [PATCH 220/342] Remove deprecated hostutil and tests --- src/CMakeLists.txt | 3 +-- src/host/cmdline/main.cpp | 1 - src/host/common/hostutil.h | 44 -------------------------------- src/tests/host/test-hostutil.cpp | 35 ------------------------- 4 files changed, 1 insertion(+), 82 deletions(-) delete mode 100644 src/host/common/hostutil.h delete mode 100644 src/tests/host/test-hostutil.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9d568377f..e2b1cad53 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,8 +10,7 @@ link_directories(${monad_native_BINARY_DIR}) # source file definitions 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-getusername.cpp tests/test-getcomputername.cpp tests/test-getcpinfo.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}) set(SOURCE_FILES main.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) set(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 80a1f700a..7ce3b36de 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -1,7 +1,6 @@ #include #include #include "common/coreclrutil.h" -#include "common/hostutil.h" #include #include #include diff --git a/src/host/common/hostutil.h b/src/host/common/hostutil.h deleted file mode 100644 index 6a07469c0..000000000 --- a/src/host/common/hostutil.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include "common/coreclrutil.h" - -namespace HostUtil -{ - //!\brief get a list of absolute paths separated by : from a list of relative/absolute paths separated by : - std::string getAbsolutePathList(const std::string& paths) - { - //std::cerr << "getAbsolutePathList: paths=" << paths << std::endl; - std::string result; - - // split by : - size_t lastPos = 0; - size_t curPos = paths.find(':',lastPos); - do - { - const std::string token = paths.substr(lastPos,curPos-lastPos); - //std::cerr << "curPos=" << curPos << " lastPos=" << lastPos << " token=" << token << std::endl; - - // skip empty tokens - if (token != "") - { - std::string absolutePath; - if (GetAbsolutePath(token.c_str(),absolutePath)) - { - // add colons correctly - if (result.size() == 0) - result += absolutePath; - else - result += ":" + absolutePath; - } - } - - // increment lastPos to skip the : - lastPos += token.size() + 1; - curPos = paths.find(':',lastPos); - } - while (lastPos < paths.size()); - - return result; - } -} diff --git a/src/tests/host/test-hostutil.cpp b/src/tests/host/test-hostutil.cpp deleted file mode 100644 index 7a8b6b473..000000000 --- a/src/tests/host/test-hostutil.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include "common/hostutil.h" - -TEST(HostUtilTest,simple) -{ - // syntactical corner cases - ASSERT_EQ("",HostUtil::getAbsolutePathList("")); - ASSERT_EQ("",HostUtil::getAbsolutePathList(":")); - ASSERT_EQ("",HostUtil::getAbsolutePathList("::")); - ASSERT_EQ("",HostUtil::getAbsolutePathList(":::::")); - - // current directory - char* cwd = get_current_dir_name(); - ASSERT_EQ(std::string(cwd),HostUtil::getAbsolutePathList(".")); - - // relative and absolute paths that don't exist - ASSERT_EQ("",HostUtil::getAbsolutePathList("/something/that/does/not/exist")); - ASSERT_EQ("",HostUtil::getAbsolutePathList(":/something/that/does/not/exist:")); - ASSERT_EQ("",HostUtil::getAbsolutePathList("something/relative/that/does/not/exist")); - ASSERT_EQ("",HostUtil::getAbsolutePathList(":something/relative/that/does/not/exist:")); - - // absolute existing paths - ASSERT_EQ("/tmp",HostUtil::getAbsolutePathList("/tmp")); - ASSERT_EQ("/tmp:/tmp",HostUtil::getAbsolutePathList("/tmp:/tmp")); - - // relative paths - chdir("/"); - ASSERT_EQ("/tmp",HostUtil::getAbsolutePathList("tmp")); - ASSERT_EQ("/tmp:/tmp",HostUtil::getAbsolutePathList("/tmp:tmp:")); - chdir(cwd); - - // cleanup - free(cwd); -} - From 556f423aa7e60a3e99fb611987fb9b1b4f66e769 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 00:57:17 -0700 Subject: [PATCH 221/342] Remove deprecated hostutil and tests --- CMakeLists.txt | 3 +-- host/cmdline/main.cpp | 1 - host/common/hostutil.h | 44 ------------------------------------ tests/host/test-hostutil.cpp | 35 ---------------------------- 4 files changed, 1 insertion(+), 82 deletions(-) delete mode 100644 host/common/hostutil.h delete mode 100644 tests/host/test-hostutil.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d568377f..e2b1cad53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,7 @@ link_directories(${monad_native_BINARY_DIR}) # source file definitions 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-getusername.cpp tests/test-getcomputername.cpp tests/test-getcpinfo.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}) set(SOURCE_FILES main.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc) set(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 80a1f700a..7ce3b36de 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -1,7 +1,6 @@ #include #include #include "common/coreclrutil.h" -#include "common/hostutil.h" #include #include #include diff --git a/host/common/hostutil.h b/host/common/hostutil.h deleted file mode 100644 index 6a07469c0..000000000 --- a/host/common/hostutil.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include "common/coreclrutil.h" - -namespace HostUtil -{ - //!\brief get a list of absolute paths separated by : from a list of relative/absolute paths separated by : - std::string getAbsolutePathList(const std::string& paths) - { - //std::cerr << "getAbsolutePathList: paths=" << paths << std::endl; - std::string result; - - // split by : - size_t lastPos = 0; - size_t curPos = paths.find(':',lastPos); - do - { - const std::string token = paths.substr(lastPos,curPos-lastPos); - //std::cerr << "curPos=" << curPos << " lastPos=" << lastPos << " token=" << token << std::endl; - - // skip empty tokens - if (token != "") - { - std::string absolutePath; - if (GetAbsolutePath(token.c_str(),absolutePath)) - { - // add colons correctly - if (result.size() == 0) - result += absolutePath; - else - result += ":" + absolutePath; - } - } - - // increment lastPos to skip the : - lastPos += token.size() + 1; - curPos = paths.find(':',lastPos); - } - while (lastPos < paths.size()); - - return result; - } -} diff --git a/tests/host/test-hostutil.cpp b/tests/host/test-hostutil.cpp deleted file mode 100644 index 7a8b6b473..000000000 --- a/tests/host/test-hostutil.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include "common/hostutil.h" - -TEST(HostUtilTest,simple) -{ - // syntactical corner cases - ASSERT_EQ("",HostUtil::getAbsolutePathList("")); - ASSERT_EQ("",HostUtil::getAbsolutePathList(":")); - ASSERT_EQ("",HostUtil::getAbsolutePathList("::")); - ASSERT_EQ("",HostUtil::getAbsolutePathList(":::::")); - - // current directory - char* cwd = get_current_dir_name(); - ASSERT_EQ(std::string(cwd),HostUtil::getAbsolutePathList(".")); - - // relative and absolute paths that don't exist - ASSERT_EQ("",HostUtil::getAbsolutePathList("/something/that/does/not/exist")); - ASSERT_EQ("",HostUtil::getAbsolutePathList(":/something/that/does/not/exist:")); - ASSERT_EQ("",HostUtil::getAbsolutePathList("something/relative/that/does/not/exist")); - ASSERT_EQ("",HostUtil::getAbsolutePathList(":something/relative/that/does/not/exist:")); - - // absolute existing paths - ASSERT_EQ("/tmp",HostUtil::getAbsolutePathList("/tmp")); - ASSERT_EQ("/tmp:/tmp",HostUtil::getAbsolutePathList("/tmp:/tmp")); - - // relative paths - chdir("/"); - ASSERT_EQ("/tmp",HostUtil::getAbsolutePathList("tmp")); - ASSERT_EQ("/tmp:/tmp",HostUtil::getAbsolutePathList("/tmp:tmp:")); - chdir(cwd); - - // cleanup - free(cwd); -} - From 6a1b9f3e598d1fe686c8e3f5124d63851ea06134 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 00:57:55 -0700 Subject: [PATCH 222/342] Remove deprecated functions from coreclrutil Using `getcwd()` in main for resolving relative to the current working directory removed the last public use of `GetAbsolutePath()`, so `coreclrutil.h` is now stricly `extern "C"`. --- src/host/cmdline/main.cpp | 15 +++------------ src/host/common/coreclrutil.h | 14 -------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/src/host/cmdline/main.cpp b/src/host/cmdline/main.cpp index 7ce3b36de..938a02275 100644 --- a/src/host/cmdline/main.cpp +++ b/src/host/cmdline/main.cpp @@ -1,11 +1,7 @@ +#include #include #include #include "common/coreclrutil.h" -#include -#include -#include -#include -#include namespace Cmdline { @@ -123,12 +119,7 @@ int main(int argc, char** argv) args.debugPrint(); // get the absolute path of the current directory - std::string currentDirAbsolutePath; - if (!GetAbsolutePath(".", currentDirAbsolutePath)) - { - std::cerr << "failed to get the absolute path from current working directory" << std::endl; - return 1; - } + std::string cwd(getcwd(nullptr, 0)); void* hostHandle; unsigned int domainId; @@ -148,7 +139,7 @@ int main(int argc, char** argv) executeAssembly( hostHandle, domainId, args.argc, (const char**)args.argv, - (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), + (cwd + "/" + args.entryAssemblyPath).c_str(), &exitCode); status = stopCoreCLR(hostHandle, domainId); diff --git a/src/host/common/coreclrutil.h b/src/host/common/coreclrutil.h index f31da19aa..17e3537eb 100644 --- a/src/host/common/coreclrutil.h +++ b/src/host/common/coreclrutil.h @@ -1,9 +1,5 @@ #pragma once -#ifdef __cplusplus -#include -#endif - #define SUCCEEDED(Status) ((Status) >= 0) /* PowerShell on Linux custom host interface @@ -43,13 +39,3 @@ extern "C" extern ExecuteAssemblyFunction executeAssembly; extern CreateDelegateFunction createDelegate; } - -#ifdef __cplusplus -// Get absolute path from the specified path. -// Return true in case of a success, false otherwise. -bool GetAbsolutePath(const char* path, std::string& absolutePath); - -// Get directory of the specified path. -// Return true in case of a success, false otherwise. -bool GetDirectory(const char* absolutePath, std::string& directory); -#endif From 8d399e84c242b503856b9a69e3af1556cdc3974a Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 00:57:55 -0700 Subject: [PATCH 223/342] Remove deprecated functions from coreclrutil Using `getcwd()` in main for resolving relative to the current working directory removed the last public use of `GetAbsolutePath()`, so `coreclrutil.h` is now stricly `extern "C"`. --- host/cmdline/main.cpp | 15 +++------------ host/common/coreclrutil.h | 14 -------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/host/cmdline/main.cpp b/host/cmdline/main.cpp index 7ce3b36de..938a02275 100644 --- a/host/cmdline/main.cpp +++ b/host/cmdline/main.cpp @@ -1,11 +1,7 @@ +#include #include #include #include "common/coreclrutil.h" -#include -#include -#include -#include -#include namespace Cmdline { @@ -123,12 +119,7 @@ int main(int argc, char** argv) args.debugPrint(); // get the absolute path of the current directory - std::string currentDirAbsolutePath; - if (!GetAbsolutePath(".", currentDirAbsolutePath)) - { - std::cerr << "failed to get the absolute path from current working directory" << std::endl; - return 1; - } + std::string cwd(getcwd(nullptr, 0)); void* hostHandle; unsigned int domainId; @@ -148,7 +139,7 @@ int main(int argc, char** argv) executeAssembly( hostHandle, domainId, args.argc, (const char**)args.argv, - (currentDirAbsolutePath+"/"+args.entryAssemblyPath).c_str(), + (cwd + "/" + args.entryAssemblyPath).c_str(), &exitCode); status = stopCoreCLR(hostHandle, domainId); diff --git a/host/common/coreclrutil.h b/host/common/coreclrutil.h index f31da19aa..17e3537eb 100644 --- a/host/common/coreclrutil.h +++ b/host/common/coreclrutil.h @@ -1,9 +1,5 @@ #pragma once -#ifdef __cplusplus -#include -#endif - #define SUCCEEDED(Status) ((Status) >= 0) /* PowerShell on Linux custom host interface @@ -43,13 +39,3 @@ extern "C" extern ExecuteAssemblyFunction executeAssembly; extern CreateDelegateFunction createDelegate; } - -#ifdef __cplusplus -// Get absolute path from the specified path. -// Return true in case of a success, false otherwise. -bool GetAbsolutePath(const char* path, std::string& absolutePath); - -// Get directory of the specified path. -// Return true in case of a success, false otherwise. -bool GetDirectory(const char* absolutePath, std::string& directory); -#endif From 4767d46b389c7a062aacfc97559637529b0f3f54 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 01:04:45 -0700 Subject: [PATCH 224/342] Update libpshost comments --- src/host/common/coreclrutil.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/host/common/coreclrutil.h b/src/host/common/coreclrutil.h index 17e3537eb..f00b6519d 100644 --- a/src/host/common/coreclrutil.h +++ b/src/host/common/coreclrutil.h @@ -4,11 +4,19 @@ /* PowerShell on Linux custom host interface * - * startCoreCLR() and stopCoreCLR() wrap the initialization of CoreCLR - * and use of ExecuteAssemblyFunction() and CreateDelegateFunction() - * should be sandwiched in between them + * startCoreCLR() takes a friendly name, e.g. "powershell", and a + * writable pointer and identifier * + * executeAssmbly() will be made available after starting CoreCLR, and + * is used to launch assemblies with a main function + * + * createDelegate() works similarly but provides a reverse P/Invoke + * given an assembly, type, and method; note that on Linux, + * PublicKeyToken must be null + * + * stopCoreCLR() will deinitialize given the handle and identifier */ + extern "C" { int startCoreCLR( From 460f51fa7f45dd87062d178ebbb8ca80af5adfe6 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 01:04:45 -0700 Subject: [PATCH 225/342] Update libpshost comments --- host/common/coreclrutil.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/host/common/coreclrutil.h b/host/common/coreclrutil.h index 17e3537eb..f00b6519d 100644 --- a/host/common/coreclrutil.h +++ b/host/common/coreclrutil.h @@ -4,11 +4,19 @@ /* PowerShell on Linux custom host interface * - * startCoreCLR() and stopCoreCLR() wrap the initialization of CoreCLR - * and use of ExecuteAssemblyFunction() and CreateDelegateFunction() - * should be sandwiched in between them + * startCoreCLR() takes a friendly name, e.g. "powershell", and a + * writable pointer and identifier * + * executeAssmbly() will be made available after starting CoreCLR, and + * is used to launch assemblies with a main function + * + * createDelegate() works similarly but provides a reverse P/Invoke + * given an assembly, type, and method; note that on Linux, + * PublicKeyToken must be null + * + * stopCoreCLR() will deinitialize given the handle and identifier */ + extern "C" { int startCoreCLR( From 43c7bdd137c7bde591727ceea621f8746d9bf026 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Fri, 23 Oct 2015 10:55:55 -0700 Subject: [PATCH 226/342] New GetLinkCount() --- CMakeLists.txt | 2 +- impl/getlinkcount.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++ impl/getlinkcount.h | 9 ++++ impl/pal.h | 7 +++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 impl/getlinkcount.cpp create mode 100644 impl/getlinkcount.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b534ebb94..6b8b426dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ 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/getcomputername.cpp impl/getcpinfo.cpp) +set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp impl/getcomputername.cpp impl/getcpinfo.cpp impl/getlinkcount.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-getusername.cpp tests/test-getcomputername.cpp tests/test-getcpinfo.cpp ${HOST_COMMON_SOURCE_FILES} ${HOST_COMMON_TEST_SOURCE_FILES}) diff --git a/impl/getlinkcount.cpp b/impl/getlinkcount.cpp new file mode 100644 index 000000000..1af39b69c --- /dev/null +++ b/impl/getlinkcount.cpp @@ -0,0 +1,120 @@ +//! @file getlinkcount.cpp +//! @author George FLeming +//! @brief Retrieve link count of a file + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "getlinkcount.h" + +//! @brief GetLinkCount retrieves the file link count (number of hard links) +//! for the given file +//! +//! GetLinkCountW is the Unicode variation. See [MSDN documentation]. +//! +//! @param[in] fileName +//! @parblock +//! A pointer to the buffer that contains the file name +//! +//! WCHAR_T* is a Unicode [LPTSTR]. +//! @endparblock +//! +//! @param[out] count +//! @parblock +//! This function returns the number of hard links associated with this file +//! +//! TCHAR is a Unicode 16-bit [WCHAR]. +//! +//! @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_FILE_NOT_FOUND: file does not exist +//! - ERROR_ACCESS_DENIED: access is denied +//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified +//! - ERROR_INVALID_ADDRESS: attempt to access invalid address +//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link +//! - ERROR_GEN_FAILURE: device attached to the system is not functioning +//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file +//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect +//! - ERROR_BUFFER_OVERFLOW: file name is too long +//! - ERROR_INVALID_FUNCTION: incorrect function +//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters +//! +//! @retval TRUE If the function succeeds, the return value is a nonzero +//! value, and the variable pointed to by buffer contains infomation about the files +//! @retval FALSE If the function fails, the return value is zero. To get +//! extended error information, call GetLastError. +//! + +BOOL GetLinkCountW(char* fileName, LPDWORD count) +{ + errno = 0; + + // Check parameters + if (!fileName) + { + 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; + } + + struct stat statBuf; + + int returnCode = lstat(fileName, &statBuf); + + if (returnCode != 0) + { + switch(errno) + { + case EACCES: + errno = ERROR_ACCESS_DENIED; + break; + case EBADF: + errno = ERROR_FILE_NOT_FOUND; + break; + case EFAULT: + errno = ERROR_INVALID_ADDRESS; + break; + case ELOOP: + errno = ERROR_STOPPED_ON_SYMLINK; + break; + case ENAMETOOLONG: + errno = ERROR_GEN_FAILURE; + break; + case ENOENT: + errno = ERROR_FILE_NOT_FOUND; + break; + case ENOMEM: + errno = ERROR_NO_SUCH_USER; + break; + case ENOTDIR: + errno = ERROR_INVALID_NAME; + break; + case EOVERFLOW: + errno = ERROR_BUFFER_OVERFLOW; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return FALSE; + } + + *count = statBuf.st_nlink; + return TRUE; + +} + diff --git a/impl/getlinkcount.h b/impl/getlinkcount.h new file mode 100644 index 000000000..47243c969 --- /dev/null +++ b/impl/getlinkcount.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +BOOL GetLinkCountW(char* fileName, LPDWORD count); + +PAL_END_EXTERNC diff --git a/impl/pal.h b/impl/pal.h index 944336ab0..c53c985a8 100644 --- a/impl/pal.h +++ b/impl/pal.h @@ -82,6 +82,13 @@ #define MAX_PATH 0x00000104 #define ERROR_INVALID_ADDRESS 0x000001e7 #define ERROR_GEN_FAILURE 0x0000001F + #define ERROR_ACCESS_DENIED 0x00000005 + #define ERROR_INVALID_NAME 0x0000007B + #define ERROR_STOPPED_ON_SYMLINK 0x000002A9 + #define ERROR_BUFFER_OVERFLOW 0x0000006F + #define ERROR_FILE_NOT_FOUND 0x00000002 + #define ERROR_BAD_PATH_NAME 0x000000A1 + typedef unsigned long long uint64; #endif From cf9b390faaddb2306030bb2cfdcef15b27b3f722 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Fri, 23 Oct 2015 15:48:48 -0700 Subject: [PATCH 227/342] Adding native tests --- CMakeLists.txt | 2 +- tests/test-getlinkcount.cpp | 90 +++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 tests/test-getlinkcount.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b8b426dd..034bb2a89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ link_directories(${monad_native_BINARY_DIR}) set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp impl/getcomputername.cpp impl/getcpinfo.cpp impl/getlinkcount.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-getusername.cpp tests/test-getcomputername.cpp tests/test-getcpinfo.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 tests/test-getlinkcount.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) diff --git a/tests/test-getlinkcount.cpp b/tests/test-getlinkcount.cpp new file mode 100644 index 000000000..081b0474e --- /dev/null +++ b/tests/test-getlinkcount.cpp @@ -0,0 +1,90 @@ +//! @file test-getlinkcount.cpp +//! @author George Fleming +//! @brief Implements test for getLinkCount() + +#include +#include +#include +#include +#include +#include +#include +#include "getlinkcount.h" + +class getLinkCountTest : public ::testing::Test +{ + protected: + + std::string file; + const std::string fileTemplate = "/tmp/createFile.XXXXXXX"; + ulong count; + + getLinkCountTest() + { + file = fileTemplate; + file = mktemp(const_cast(file.c_str())); + std::ifstream fileCondition(file); + EXPECT_EQ(0, fileCondition.good()); + } + + void createFileForTesting(std::string theFile) + { + std::ofstream ofs; + ofs.open(theFile, std::ofstream::out); + ofs << "hi there, ms ostc!"; + ofs.close(); + } + + std::string createHardLink(std::string origFile) + { + std::string newFile = origFile + "_link"; + int ret = link(const_cast(origFile.c_str()), const_cast(newFile.c_str())); + EXPECT_EQ(0, ret); + + return newFile; + } + + void removeFile(std::string fileName) + { + int ret = unlink(const_cast(fileName.c_str())); + EXPECT_EQ(0, ret); + } +}; + +TEST_F(getLinkCountTest, FilePathNameIsNull) +{ + bool retVal = GetLinkCountW(NULL, &count ); + ASSERT_FALSE(retVal); + EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); +} + +TEST_F(getLinkCountTest, FilePathNameDoesNotExist) +{ + std::string invalidFile = "/tmp/createFile"; + bool retVal = GetLinkCountW(const_cast(invalidFile.c_str()), &count); + ASSERT_FALSE(retVal); + EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno); +} + +TEST_F(getLinkCountTest, LinkCountOfSinglyLinkedFile) +{ + createFileForTesting(file); + bool retVal = GetLinkCountW(const_cast(file.c_str()), &count); + ASSERT_TRUE(retVal); + EXPECT_EQ(1, count); + + removeFile(file); +} + +TEST_F(getLinkCountTest, LinkCountOfMultipliLinkedFile) +{ + createFileForTesting(file); + std::string newFile = createHardLink(file); + bool retVal = GetLinkCountW(const_cast(file.c_str()), &count); + ASSERT_TRUE(retVal); + EXPECT_EQ(2, count); + + removeFile(file); + removeFile(newFile); +} + From 6af36478fd564bf99f6b4385c20fff641b892ba2 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 15:59:06 -0700 Subject: [PATCH 228/342] Conditionalize extern "C" --- host/common/coreclrutil.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/host/common/coreclrutil.h b/host/common/coreclrutil.h index f00b6519d..d34487310 100644 --- a/host/common/coreclrutil.h +++ b/host/common/coreclrutil.h @@ -17,8 +17,10 @@ * stopCoreCLR() will deinitialize given the handle and identifier */ +#ifdef __cplusplus extern "C" { +#endif int startCoreCLR( const char* appDomainFriendlyName, void** hostHandle, @@ -46,4 +48,6 @@ extern "C" extern ExecuteAssemblyFunction executeAssembly; extern CreateDelegateFunction createDelegate; +#ifdef __cplusplus } +#endif From a3a3e2b5c985e9cb19368d5146c54e6165bb224e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 23 Oct 2015 15:59:06 -0700 Subject: [PATCH 229/342] Conditionalize extern "C" --- src/host/common/coreclrutil.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/host/common/coreclrutil.h b/src/host/common/coreclrutil.h index f00b6519d..d34487310 100644 --- a/src/host/common/coreclrutil.h +++ b/src/host/common/coreclrutil.h @@ -17,8 +17,10 @@ * stopCoreCLR() will deinitialize given the handle and identifier */ +#ifdef __cplusplus extern "C" { +#endif int startCoreCLR( const char* appDomainFriendlyName, void** hostHandle, @@ -46,4 +48,6 @@ extern "C" extern ExecuteAssemblyFunction executeAssembly; extern CreateDelegateFunction createDelegate; +#ifdef __cplusplus } +#endif From b91c1173137881f7cb478e758f31388569d04af8 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sat, 24 Oct 2015 21:30:42 -0700 Subject: [PATCH 230/342] GetLinkCount is not Unicode --- impl/getlinkcount.cpp | 10 ++++------ impl/getlinkcount.h | 2 +- tests/test-getlinkcount.cpp | 8 ++++---- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/impl/getlinkcount.cpp b/impl/getlinkcount.cpp index 1af39b69c..2dde56bba 100644 --- a/impl/getlinkcount.cpp +++ b/impl/getlinkcount.cpp @@ -16,20 +16,19 @@ //! @brief GetLinkCount retrieves the file link count (number of hard links) //! for the given file //! -//! GetLinkCountW is the Unicode variation. See [MSDN documentation]. +//! GetLinkCount //! //! @param[in] fileName //! @parblock //! A pointer to the buffer that contains the file name //! -//! WCHAR_T* is a Unicode [LPTSTR]. +//! char* is marshaled as an LPStr, which on Linux is UTF-8. //! @endparblock //! //! @param[out] count //! @parblock //! This function returns the number of hard links associated with this file -//! -//! TCHAR is a Unicode 16-bit [WCHAR]. +//! @endparblock //! //! @exception errno Passes these errors via errno to GetLastError: //! - ERROR_INVALID_PARAMETER: parameter is not valid @@ -52,7 +51,7 @@ //! extended error information, call GetLastError. //! -BOOL GetLinkCountW(char* fileName, LPDWORD count) +BOOL GetLinkCount(char* fileName, LPDWORD count) { errno = 0; @@ -117,4 +116,3 @@ BOOL GetLinkCountW(char* fileName, LPDWORD count) return TRUE; } - diff --git a/impl/getlinkcount.h b/impl/getlinkcount.h index 47243c969..738a606c6 100644 --- a/impl/getlinkcount.h +++ b/impl/getlinkcount.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetLinkCountW(char* fileName, LPDWORD count); +BOOL GetLinkCount(char* fileName, LPDWORD count); PAL_END_EXTERNC diff --git a/tests/test-getlinkcount.cpp b/tests/test-getlinkcount.cpp index 081b0474e..0c7a3d0c5 100644 --- a/tests/test-getlinkcount.cpp +++ b/tests/test-getlinkcount.cpp @@ -53,7 +53,7 @@ class getLinkCountTest : public ::testing::Test TEST_F(getLinkCountTest, FilePathNameIsNull) { - bool retVal = GetLinkCountW(NULL, &count ); + bool retVal = GetLinkCount(NULL, &count ); ASSERT_FALSE(retVal); EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); } @@ -61,7 +61,7 @@ TEST_F(getLinkCountTest, FilePathNameIsNull) TEST_F(getLinkCountTest, FilePathNameDoesNotExist) { std::string invalidFile = "/tmp/createFile"; - bool retVal = GetLinkCountW(const_cast(invalidFile.c_str()), &count); + bool retVal = GetLinkCount(const_cast(invalidFile.c_str()), &count); ASSERT_FALSE(retVal); EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno); } @@ -69,7 +69,7 @@ TEST_F(getLinkCountTest, FilePathNameDoesNotExist) TEST_F(getLinkCountTest, LinkCountOfSinglyLinkedFile) { createFileForTesting(file); - bool retVal = GetLinkCountW(const_cast(file.c_str()), &count); + bool retVal = GetLinkCount(const_cast(file.c_str()), &count); ASSERT_TRUE(retVal); EXPECT_EQ(1, count); @@ -80,7 +80,7 @@ TEST_F(getLinkCountTest, LinkCountOfMultipliLinkedFile) { createFileForTesting(file); std::string newFile = createHardLink(file); - bool retVal = GetLinkCountW(const_cast(file.c_str()), &count); + bool retVal = GetLinkCount(const_cast(file.c_str()), &count); ASSERT_TRUE(retVal); EXPECT_EQ(2, count); From 5ed81a0a41b7cf51c137730bdebafcf7395e6780 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sat, 24 Oct 2015 22:12:05 -0700 Subject: [PATCH 231/342] Return char* for GetUserName The UTF-8 char* is marshaled to a UTF-16 string automatically. It must be allocated on the heap as the CLR will free the returned memory. This removes entire classes of possible errors, greatly reducing the code complexity and number of tests. --- impl/getusername.cpp | 81 +++------------------- impl/getusername.h | 2 +- tests/test-getusername.cpp | 136 ++----------------------------------- 3 files changed, 15 insertions(+), 204 deletions(-) diff --git a/impl/getusername.cpp b/impl/getusername.cpp index ee14d8651..a4590bfde 100644 --- a/impl/getusername.cpp +++ b/impl/getusername.cpp @@ -1,6 +1,6 @@ //! @file getusername.cpp //! @author Andrew Schwartzmeyer -//! @brief Implements GetUserName Win32 API +//! @brief Implements GetUserName for Linux #include #include @@ -14,56 +14,16 @@ //! @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_INSUFFICIENT_BUFFER: buffer not large enough to hold username string //! - ERROR_NO_SUCH_USER: there was no corresponding user //! - ERROR_GEN_FAILURE: sysconf() or getpwuid() failed for unknown reasons //! -//! @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/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) +//! @retval username as UTF-8 string, or null if unsuccessful +char* GetUserName() { - // Check parameters - if (!lpBuffer || !lpnSize) - { - errno = ERROR_INVALID_PARAMETER; - return FALSE; - } + errno = 0; // Select locale from environment setlocale(LC_ALL, ""); @@ -71,7 +31,7 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) if (nl_langinfo(CODESET) != std::string("UTF-8")) { errno = ERROR_BAD_ENVIRONMENT; - return FALSE; + return NULL; } struct passwd pwd; @@ -86,7 +46,6 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) std::string buf(buflen, 0); // geteuid() gets the effective user ID of the calling process, and is always successful - errno = 0; int ret = getpwuid_r(geteuid(), &pwd, &buf[0], buflen, &result); // Map errno to Win32 Error Codes @@ -103,38 +62,16 @@ BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) default: errno = ERROR_GEN_FAILURE; } - return FALSE; + return NULL; } // Check if no user matched if (result == NULL) { errno = ERROR_NO_SUCH_USER; - return FALSE; + return NULL; } - std::string username(result->pw_name); - - // Convert to UnicodeString - auto username16 = icu::UnicodeString::fromUTF8(username.c_str()); - // Terminate string with null - username16.append('\0'); - - // Size in WCHARs including null - const DWORD size = username16.length(); - 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 - username16.extract(0, size, reinterpret_cast(lpBuffer), "UTF-16LE"); - - *lpnSize = size; - - return TRUE; + // allocate copy on heap so CLR can free it + return strdup(result->pw_name); } diff --git a/impl/getusername.h b/impl/getusername.h index 6083078bc..1326298f4 100644 --- a/impl/getusername.h +++ b/impl/getusername.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetUserNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize); +char* GetUserName(); PAL_END_EXTERNC diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index 9d238f538..50c2d1fea 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -10,144 +10,18 @@ #include #include "getusername.h" -//! Test fixture for GetUserNameW +//! Test fixture for GetUserName class GetUserNameTest : public ::testing::Test { protected: - DWORD lpnSize; - std::vector lpBuffer; - BOOL result; - std::string expectedUsername; - DWORD expectedSize; + std::string UserName; - GetUserNameTest(): expectedUsername(std::string(getpwuid(geteuid())->pw_name)), - expectedSize(expectedUsername.length()+1) + GetUserNameTest(): UserName(std::string(getpwuid(geteuid())->pw_name)) { } - - //! 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); - } - - //! Checks the effects of GetUserNameW for success. - 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(&lpBuffer[0]); - icu::UnicodeString username16(begin, (lpnSize-1)*sizeof(UChar), "UTF-16LE"); - ASSERT_EQ(expectedUsername.length(), username16.length()); - // Convert to UTF-8 for comparison - std::string username; - username16.toUTF8String(username); - ASSERT_EQ(expectedUsername.length(), username.length()); - - //! Returned username (after conversion) is what was expected. - EXPECT_EQ(expectedUsername, username); - } - - //! Checks the effects of GetUserNameW on failure with invalid parameters. - void TestInvalidParameter() - { - SCOPED_TRACE(""); - - //! 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). - EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); - } - - //! Checks the effects of GetUserNameW on failure with a buffer that is too small. - 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 plus null. - EXPECT_EQ(expectedSize, lpnSize); - } }; -TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) +TEST_F(GetUserNameTest, Success) { - lpnSize = 1; - result = GetUserNameW(NULL, &lpnSize); - - TestInvalidParameter(); - // does not reset lpnSize - EXPECT_EQ(1, lpnSize); -} - -TEST_F(GetUserNameTest, BufferSizeAsNullButNotBuffer) -{ - lpBuffer.push_back('\0'); - result = GetUserNameW(&lpBuffer[0], NULL); - - TestInvalidParameter(); -} - -TEST_F(GetUserNameTest, BufferSizeAsZero) -{ - TestWithSize(0); - TestInvalidParameter(); - // does not reset lpnSize - EXPECT_EQ(0, lpnSize); -} - -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 it does not account for null - TestWithSize(expectedUsername.length()); - TestInsufficientBuffer(); -} - -TEST_F(GetUserNameTest, BufferSizeAsUsernamePlusOne) -{ - // includes null and so should be sufficient - TestWithSize(expectedUsername.length()+1); - TestSuccess(); -} - -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, including null - TestWithSize(LOGIN_NAME_MAX); - TestSuccess(); + ASSERT_EQ(GetUserName(), UserName); } From 81984534b8514ad5f9258b13cf26cf4109497976 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sun, 25 Oct 2015 12:03:49 -0700 Subject: [PATCH 232/342] Refactor CMake build system and host files Use CMakeLists.txt file for each directory. Setup to be consumed by monad-linux's CMake. Utilize GoogleTest's CMake. Refactor host files layout. --- CMakeLists.txt | 35 +++++-------------------------- host/CMakeLists.txt | 5 +++++ host/{common => }/coreclrutil.cpp | 0 host/{common => }/coreclrutil.h | 0 host/{cmdline => }/main.cpp | 2 +- impl/CMakeLists.txt | 8 +++++++ tests/CMakeLists.txt | 12 +++++++++++ tests/googletest | 1 + main.cpp => tests/main.cpp | 2 +- 9 files changed, 33 insertions(+), 32 deletions(-) create mode 100644 host/CMakeLists.txt rename host/{common => }/coreclrutil.cpp (100%) rename host/{common => }/coreclrutil.h (100%) rename host/{cmdline => }/main.cpp (99%) create mode 100644 impl/CMakeLists.txt create mode 100644 tests/CMakeLists.txt create mode 160000 tests/googletest rename main.cpp => tests/main.cpp (98%) diff --git a/CMakeLists.txt b/CMakeLists.txt index e2b1cad53..07c663219 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,32 +1,7 @@ -cmake_minimum_required(VERSION 2.8.4) -project(monad_native) +project(MONAD_NATIVE) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") +add_compile_options(-std=c++11 -Wall) -#include gtest -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/getcomputername.cpp impl/getcpinfo.cpp) -set(HOST_COMMON_SOURCE_FILES host/common/coreclrutil.cpp) -set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp tests/test-getusername.cpp tests/test-getcomputername.cpp tests/test-getcpinfo.cpp ${HOST_COMMON_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) - -# target definitions -add_library(ps SHARED ${LIB_SOURCE_FILES}) -add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES}) -add_library(pshost STATIC ${HOST_COMMON_SOURCE_FILES}) -add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES}) - -# add pthread and other libs -find_package(Threads) -target_link_libraries(ps icuuc) -target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps pshost) -target_link_libraries(pshost dl icuuc) -target_link_libraries(host_cmdline pshost) - -# target specific include directories -target_include_directories(monad_native PRIVATE host) -target_include_directories(host_cmdline PRIVATE host) +add_subdirectory(impl) +add_subdirectory(host) +add_subdirectory(tests) diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt new file mode 100644 index 000000000..0ddbf88f7 --- /dev/null +++ b/host/CMakeLists.txt @@ -0,0 +1,5 @@ +add_library(pshost STATIC coreclrutil.cpp) +target_link_libraries(pshost dl icuuc) + +add_executable(host_cmdline main.cpp) +target_link_libraries(host_cmdline pshost) diff --git a/host/common/coreclrutil.cpp b/host/coreclrutil.cpp similarity index 100% rename from host/common/coreclrutil.cpp rename to host/coreclrutil.cpp diff --git a/host/common/coreclrutil.h b/host/coreclrutil.h similarity index 100% rename from host/common/coreclrutil.h rename to host/coreclrutil.h diff --git a/host/cmdline/main.cpp b/host/main.cpp similarity index 99% rename from host/cmdline/main.cpp rename to host/main.cpp index 938a02275..06e7ad040 100644 --- a/host/cmdline/main.cpp +++ b/host/main.cpp @@ -1,7 +1,7 @@ #include #include #include -#include "common/coreclrutil.h" +#include "coreclrutil.h" namespace Cmdline { diff --git a/impl/CMakeLists.txt b/impl/CMakeLists.txt new file mode 100644 index 000000000..0eeb2e8fa --- /dev/null +++ b/impl/CMakeLists.txt @@ -0,0 +1,8 @@ +add_library(ps SHARED + getcurrentprocessorid.cpp + getusername.cpp + getcomputername.cpp + terminal.cpp) + +target_link_libraries(ps icuuc) +target_include_directories (ps PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 000000000..396e121c5 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,12 @@ +add_subdirectory(googletest) + +add_executable(monad_native + main.cpp + test-getcurrentprocessid.cpp + test-getusername.cpp + test-getcomputername.cpp) + +target_include_directories(monad_native PRIVATE ${gtest_SOURCE_DIR}/include) + +find_package(Threads) +target_link_libraries(monad_native ps gtest) diff --git a/tests/googletest b/tests/googletest new file mode 160000 index 000000000..c99458533 --- /dev/null +++ b/tests/googletest @@ -0,0 +1 @@ +Subproject commit c99458533a9b4c743ed51537e25989ea55944908 diff --git a/main.cpp b/tests/main.cpp similarity index 98% rename from main.cpp rename to tests/main.cpp index e59bea057..9bb465e02 100644 --- a/main.cpp +++ b/tests/main.cpp @@ -4,4 +4,4 @@ int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} From 807760f06dcaf98d68ae02d516889791e032acca Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sun, 25 Oct 2015 12:06:47 -0700 Subject: [PATCH 233/342] Remove deprecated GetCPInfo code --- impl/getcpinfo.cpp | 118 --------------------------------------- impl/getcpinfo.h | 27 --------- tests/test-getcpinfo.cpp | 34 ----------- 3 files changed, 179 deletions(-) delete mode 100644 impl/getcpinfo.cpp delete mode 100644 impl/getcpinfo.h delete mode 100644 tests/test-getcpinfo.cpp diff --git a/impl/getcpinfo.cpp b/impl/getcpinfo.cpp deleted file mode 100644 index 79f39ea25..000000000 --- a/impl/getcpinfo.cpp +++ /dev/null @@ -1,118 +0,0 @@ -//! @file getcpinfo.cpp -//! @author Aaron Ktaz -//! @brief Implements GetCpInfoW Win32 API - -#include -#include -#include -#include "getcpinfo.h" - -//! @brief GetCPInfoW retrieves the name of the code page associated with -//! the current thread. -//! -//! GetCpInfoW the Unicode variation. See [MSDN documentation]. -//! -//! @param[in] codepage -//! @parblock -//! An UINT Identifier for the code page for which to retrieve information. -//! See Code Page Identifiers for details -//! 65001 in the number for UTF8. It is the only valid input parameter -//!because Linux and Unix only use UTF8 for codepage -//! -//! @endparblock -//! -//! @param[out] cpinfo -//! @parblock -//! Pointer to a CPINFO structure that receives information about the code page -//! -//! LPCPINFO is a pointer to the structure _cpinfo used to contain the information -//! about a code page -//! -//! -//! typedef struct _cpinfo { -//! UINT MaxCharSize; -//! BYTE DefaultChar[MAX_DEFAULTCHAR]; -//! BYTE LeadByte[MAX_LEADBYTES]; -//! } CPINFO, *LPCPINFO; -//! -//! _cpinfo is a struct that comprises -//! -//! UINT MaxCharSize; -//! Maximum length, in bytes, of a character in the code page. -//! The length can be 1 for a single-byte character set (SBCS), -//! 2 for a double-byte character set (DBCS), or a value larger -//! than 2 for other character set types. The function cannot -//! use the size to distinguish an SBCS or a DBCS from other -//! character sets because of other factors, for example, -//! the use of ISCII or ISO-2022-xx code pages. -//! -//! BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; -//! Default character used when translating character -//! strings to the specific code page. This character is used by -//! the WideCharToMultiByte function if an explicit default -//! character is not specified. The default is usually the "?" -//! character for the code page -//! -//! BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; -//! A fixed-length array of lead byte ranges, for which the number -//! of lead byte ranges is variable. If the code page has no lead -//! bytes, every element of the array is set to NULL. If the code -//! page has lead bytes, the array specifies a starting value and -//! an ending value for each range. Ranges are inclusive, and the -//! maximum number of ranges for any code page is five. The array -//! uses two bytes to describe each range, with two null bytes as -//! a terminator after the last range. -//! -//! MAX_DEFAULTCHAR is an int of size 2 -//! MAX_LEADBYTES is an int of size 12 -//! -//! -//! @exception errno Passes these errors via errno to GetLastError: -//! - ERROR_INVALID_PARAMETER: parameter is not valid -//! -//! @retval TRUE If the function succeeds, the return value is a nonzero -//! value, and cpinfo is population with information about the code page -//! -//! @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/dd318078%28v=vs.85%29.aspx -//! [_cpinfo]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317780(v=vs.85).aspx -//! [CodePageIdentifiers] https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx - -BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo) -{ - errno = 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; - } - - if (codepage != const_cpinfo::UTF8) - { - //If other value is used return error because Linux and Unix only used UTF-8 for codepage - errno = ERROR_INVALID_PARAMETER; - return FALSE; - } - - // UTF-8 uses the default char for DefaultChar[0] which is '?' - cpinfo->DefaultChar[0] = '?'; - cpinfo->DefaultChar[1] = '0'; - cpinfo->MaxCharSize = 4; - - for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++ ) - { - // UTF-8 uses the default has no LeadByte as result LeadByte is '0' - cpinfo->LeadByte[i] = '0'; - } - - return TRUE; - -} - diff --git a/impl/getcpinfo.h b/impl/getcpinfo.h deleted file mode 100644 index cd0883d7b..000000000 --- a/impl/getcpinfo.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "pal.h" - -//!* NameSpace - -namespace const_cpinfo -{ - constexpr int MAX_DEFAULTCHAR = 2; - constexpr int MAX_LEADBYTES = 12; - constexpr int UTF8 = 65001; -} - -//!* Structs - -typedef struct _cpinfo -{ - UINT MaxCharSize; - BYTE DefaultChar[const_cpinfo::MAX_DEFAULTCHAR]; - BYTE LeadByte[const_cpinfo::MAX_LEADBYTES]; -} CPINFO; - -PAL_BEGIN_EXTERNC - -BOOL GetCPInfoW(UINT codepage, CPINFO* cpinfo); - -PAL_END_EXTERNC diff --git a/tests/test-getcpinfo.cpp b/tests/test-getcpinfo.cpp deleted file mode 100644 index 0c8a33960..000000000 --- a/tests/test-getcpinfo.cpp +++ /dev/null @@ -1,34 +0,0 @@ -//! @file test-getcpinfo.cpp -//! @author Aaron Ktaz -//! @brief Implements Unit test for GetCPInfoW - -#include -#include "getcpinfo.h" - -TEST(GetCPInfo, CodePageIsUTF8) -{ - CPINFO cpinfo; - BOOL result = GetCPInfoW(const_cpinfo::UTF8, &cpinfo); - - // first make sure that the function worked - ASSERT_EQ(TRUE, result); - - // now compare the actual values - EXPECT_EQ(cpinfo.DefaultChar[0], '?'); - EXPECT_EQ(cpinfo.DefaultChar[1], '0'); - EXPECT_EQ(cpinfo.MaxCharSize, 4); - - for (int i = 0; i < const_cpinfo::MAX_LEADBYTES; i++) - { - EXPECT_EQ(cpinfo.LeadByte[i], '0'); - } -} - -TEST(GetCPInfo, CodePageIsNotUTF8) -{ - CPINFO cpinfo; - BOOL result = GetCPInfoW(const_cpinfo::UTF8+1, &cpinfo); - - ASSERT_EQ(FALSE, result); - ASSERT_EQ(ERROR_INVALID_PARAMETER, errno); -} From a548455918df5bf3f33508f466c124352bd0fa00 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sun, 25 Oct 2015 12:09:49 -0700 Subject: [PATCH 234/342] Rename host_cmdline to powershell --- host/CMakeLists.txt | 4 ++-- host/main.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 0ddbf88f7..a44effc5f 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -1,5 +1,5 @@ add_library(pshost STATIC coreclrutil.cpp) target_link_libraries(pshost dl icuuc) -add_executable(host_cmdline main.cpp) -target_link_libraries(host_cmdline pshost) +add_executable(powershell main.cpp) +target_link_libraries(powershell pshost) diff --git a/host/main.cpp b/host/main.cpp index 06e7ad040..04ad61ea9 100644 --- a/host/main.cpp +++ b/host/main.cpp @@ -7,8 +7,8 @@ namespace Cmdline { void printHelp() { - std::cerr << "PS CoreCLR host" << std::endl - << "Usage: host_cmdline assembly [...]" << std::endl + std::cerr << "PowerShell on Linux host" << std::endl + << "Usage: powershell assembly [...]" << std::endl << std::endl << "What it does:" << std::endl << "- the host assumes that CoreCLR is located $CORE_ROOT" << std::endl From c1a5e9fb533006a70b0723a7148f986512d02af2 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sun, 25 Oct 2015 12:15:21 -0700 Subject: [PATCH 235/342] Resurrect .gitmodules after subtree split Removed src intermediate directory --- .gitmodules | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..44d6d26f4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "tests/googletest"] + path = tests/googletest + url = https://github.com/google/googletest.git + ignore = dirty From 569de14c1e59ba8194fd46eebcbec7a4d57885f3 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sun, 25 Oct 2015 12:16:34 -0700 Subject: [PATCH 236/342] Rename libps to libpsnative And impl to native --- CMakeLists.txt | 2 +- impl/CMakeLists.txt | 9 --------- native/CMakeLists.txt | 9 +++++++++ {impl => native}/getcomputername.cpp | 0 {impl => native}/getcomputername.h | 0 {impl => native}/getcurrentprocessorid.cpp | 0 {impl => native}/getcurrentprocessorid.h | 0 {impl => native}/getcurrentthreadid.cpp | 0 {impl => native}/getcurrentthreadid.h | 0 {impl => native}/getlinkcount.cpp | 0 {impl => native}/getlinkcount.h | 0 {impl => native}/getusername.cpp | 0 {impl => native}/getusername.h | 0 {impl => native}/pal.h | 0 {impl => native}/terminal.cpp | 0 {impl => native}/terminal.h | 0 tests/CMakeLists.txt | 2 +- 17 files changed, 11 insertions(+), 11 deletions(-) delete mode 100644 impl/CMakeLists.txt create mode 100644 native/CMakeLists.txt rename {impl => native}/getcomputername.cpp (100%) rename {impl => native}/getcomputername.h (100%) rename {impl => native}/getcurrentprocessorid.cpp (100%) rename {impl => native}/getcurrentprocessorid.h (100%) rename {impl => native}/getcurrentthreadid.cpp (100%) rename {impl => native}/getcurrentthreadid.h (100%) rename {impl => native}/getlinkcount.cpp (100%) rename {impl => native}/getlinkcount.h (100%) rename {impl => native}/getusername.cpp (100%) rename {impl => native}/getusername.h (100%) rename {impl => native}/pal.h (100%) rename {impl => native}/terminal.cpp (100%) rename {impl => native}/terminal.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 07c663219..5de641170 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,6 @@ project(MONAD_NATIVE) add_compile_options(-std=c++11 -Wall) -add_subdirectory(impl) +add_subdirectory(native) add_subdirectory(host) add_subdirectory(tests) diff --git a/impl/CMakeLists.txt b/impl/CMakeLists.txt deleted file mode 100644 index 5b9c123fb..000000000 --- a/impl/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -add_library(ps SHARED - getcurrentprocessorid.cpp - getusername.cpp - getcomputername.cpp - getlinkcount.cpp - terminal.cpp) - -target_link_libraries(ps icuuc) -target_include_directories (ps PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt new file mode 100644 index 000000000..c2523c3a3 --- /dev/null +++ b/native/CMakeLists.txt @@ -0,0 +1,9 @@ +add_library(psnative SHARED + getcurrentprocessorid.cpp + getusername.cpp + getcomputername.cpp + getlinkcount.cpp + terminal.cpp) + +target_link_libraries(psnative icuuc) +target_include_directories (psnative PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/impl/getcomputername.cpp b/native/getcomputername.cpp similarity index 100% rename from impl/getcomputername.cpp rename to native/getcomputername.cpp diff --git a/impl/getcomputername.h b/native/getcomputername.h similarity index 100% rename from impl/getcomputername.h rename to native/getcomputername.h diff --git a/impl/getcurrentprocessorid.cpp b/native/getcurrentprocessorid.cpp similarity index 100% rename from impl/getcurrentprocessorid.cpp rename to native/getcurrentprocessorid.cpp diff --git a/impl/getcurrentprocessorid.h b/native/getcurrentprocessorid.h similarity index 100% rename from impl/getcurrentprocessorid.h rename to native/getcurrentprocessorid.h diff --git a/impl/getcurrentthreadid.cpp b/native/getcurrentthreadid.cpp similarity index 100% rename from impl/getcurrentthreadid.cpp rename to native/getcurrentthreadid.cpp diff --git a/impl/getcurrentthreadid.h b/native/getcurrentthreadid.h similarity index 100% rename from impl/getcurrentthreadid.h rename to native/getcurrentthreadid.h diff --git a/impl/getlinkcount.cpp b/native/getlinkcount.cpp similarity index 100% rename from impl/getlinkcount.cpp rename to native/getlinkcount.cpp diff --git a/impl/getlinkcount.h b/native/getlinkcount.h similarity index 100% rename from impl/getlinkcount.h rename to native/getlinkcount.h diff --git a/impl/getusername.cpp b/native/getusername.cpp similarity index 100% rename from impl/getusername.cpp rename to native/getusername.cpp diff --git a/impl/getusername.h b/native/getusername.h similarity index 100% rename from impl/getusername.h rename to native/getusername.h diff --git a/impl/pal.h b/native/pal.h similarity index 100% rename from impl/pal.h rename to native/pal.h diff --git a/impl/terminal.cpp b/native/terminal.cpp similarity index 100% rename from impl/terminal.cpp rename to native/terminal.cpp diff --git a/impl/terminal.h b/native/terminal.h similarity index 100% rename from impl/terminal.h rename to native/terminal.h diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4ff914ae0..53580614d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,4 +10,4 @@ add_executable(monad_native target_include_directories(monad_native PRIVATE ${gtest_SOURCE_DIR}/include) find_package(Threads) -target_link_libraries(monad_native ps gtest) +target_link_libraries(monad_native psnative gtest) From 523279f6e2afb97daed064505400e8dea4eafed8 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sun, 25 Oct 2015 12:19:28 -0700 Subject: [PATCH 237/342] Resurrect .gitignore --- .gitignore | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..280941f2a --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.idea +src/.kdev4/ +src/CMakeFiles/ +src/build/ +src/monad_native +src/src.kdev4 +libps.so +CMakeCache.txt +CMakeFiles/ +Makefile +cmake_install.cmake +host_cmdline +monad_native From af813b9a08e60ab54ecdb270cb0ef199d8b4a62e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sun, 25 Oct 2015 12:49:19 -0700 Subject: [PATCH 238/342] Enable unit testing via CMake --- tests/CMakeLists.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 53580614d..96d06674d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,13 +1,16 @@ add_subdirectory(googletest) -add_executable(monad_native +add_executable(psnative-test test-getcurrentprocessid.cpp test-getusername.cpp test-getcomputername.cpp test-getlinkcount.cpp main.cpp) -target_include_directories(monad_native PRIVATE ${gtest_SOURCE_DIR}/include) +# manually include gtest headers +target_include_directories(psnative-test PRIVATE ${gtest_SOURCE_DIR}/include) -find_package(Threads) -target_link_libraries(monad_native psnative gtest) +target_link_libraries(psnative-test psnative gtest) + +add_test(NAME psnative-test + COMMAND psnative-test --gtest_output=xml:${MONAD_LINUX_SOURCE_DIR}/native-tests.xml) From 1c247171bd9a7430ac58ae23214a2a9fe276d8d5 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sun, 25 Oct 2015 12:49:49 -0700 Subject: [PATCH 239/342] Update gitignore --- .gitignore | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 280941f2a..2afa8a81f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,8 @@ -.idea -src/.kdev4/ -src/CMakeFiles/ -src/build/ -src/monad_native -src/src.kdev4 -libps.so CMakeCache.txt -CMakeFiles/ +CMakeFiles +CMakeScripts Makefile cmake_install.cmake -host_cmdline -monad_native +install_manifest.txt +CTestTestfile.cmake +Testing/ \ No newline at end of file From c6ca4db6a448db8a279815f78b1021c66741949a Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sun, 25 Oct 2015 17:59:14 -0700 Subject: [PATCH 240/342] Output psnative and pshost to monad-linux/bin But leave test artifacts in monad-native. --- .gitignore | 3 ++- CMakeLists.txt | 14 +++++++++++++- tests/CMakeLists.txt | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 2afa8a81f..b4b9d1249 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ Makefile cmake_install.cmake install_manifest.txt CTestTestfile.cmake -Testing/ \ No newline at end of file +Testing/ +tests/psnative-test diff --git a/CMakeLists.txt b/CMakeLists.txt index 5de641170..51d4665de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,19 @@ +cmake_minimum_required(VERSION 2.8.4) project(MONAD_NATIVE) add_compile_options(-std=c++11 -Wall) +# resolve superproject directory +set(MONAD ${CMAKE_SOURCE_DIR}/../../) + +# test in BUILD_DIR +enable_testing() +add_subdirectory(tests) + +# output psnative and pshost to superproject +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${MONAD}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${MONAD}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${MONAD}/lib) + add_subdirectory(native) add_subdirectory(host) -add_subdirectory(tests) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 96d06674d..c9630dda1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,4 +13,4 @@ target_include_directories(psnative-test PRIVATE ${gtest_SOURCE_DIR}/include) target_link_libraries(psnative-test psnative gtest) add_test(NAME psnative-test - COMMAND psnative-test --gtest_output=xml:${MONAD_LINUX_SOURCE_DIR}/native-tests.xml) + COMMAND psnative-test --gtest_output=xml:${MONAD}/native-tests.xml) From 28dfd36a58dce69a5ab21fd6a89e3ba04986521b Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sun, 25 Oct 2015 20:32:42 -0700 Subject: [PATCH 241/342] Require absolute path to assembly Rather than assuming that it's in the current directory. Later this will be refactoring to choose the appropriate host assembly (for an interactive shell, script, command list, or self-test) from the `PWRSH_ROOT` path. --- host/main.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/host/main.cpp b/host/main.cpp index 04ad61ea9..79539603a 100644 --- a/host/main.cpp +++ b/host/main.cpp @@ -18,14 +18,12 @@ namespace Cmdline << "- all additional parameters at the end of the command line are forwarded" << std::endl << " to the Main function in the assembly" << std::endl << "- the host will execute the Main function in the specified assembly" << std::endl - << " + this assembly has to be located in the search path" << std::endl - << "- the host will add $PWRSH_ROOT to the assembly search path" << std::endl + << " + this must be an absolute path to the assembly" << std::endl << "- the function signature of the Main function that gets executed must be:" << std::endl << " static void Main(string[] args)" << std::endl << std::endl << "Options:" << std::endl << "-v verbose output" << std::endl - << "assembly the path of the assembly to execute relative to current directory" << std::endl << std::endl << "Example:" << std::endl << "CORE_ROOT=/test/coreclr PWRSH_ROOT=/test/powershell ./host_cmdline -s /test/ps powershell-simple 'get-process'" << std::endl; @@ -40,7 +38,6 @@ namespace Cmdline { } - std::string searchPaths; std::string entryAssemblyPath; int argc; char** argv; @@ -118,9 +115,6 @@ int main(int argc, char** argv) if (args.verbose) args.debugPrint(); - // get the absolute path of the current directory - std::string cwd(getcwd(nullptr, 0)); - void* hostHandle; unsigned int domainId; int status = startCoreCLR( @@ -139,7 +133,7 @@ int main(int argc, char** argv) executeAssembly( hostHandle, domainId, args.argc, (const char**)args.argv, - (cwd + "/" + args.entryAssemblyPath).c_str(), + args.entryAssemblyPath.c_str(), &exitCode); status = stopCoreCLR(hostHandle, domainId); From 18a047408def7e86e45473c33c9e15160222c12d Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 26 Oct 2015 12:08:16 -0700 Subject: [PATCH 242/342] Compile pshost with -fPIC So that libpshost can be linked with shared libraries (like the OMI provider). --- host/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index a44effc5f..7d472915d 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -1,5 +1,6 @@ add_library(pshost STATIC coreclrutil.cpp) target_link_libraries(pshost dl icuuc) +target_compile_options(pshost PRIVATE -fPIC) add_executable(powershell main.cpp) target_link_libraries(powershell pshost) From 845c4483b64d1939a6f93340554b6bc44df36661 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Tue, 27 Oct 2015 09:19:41 -0700 Subject: [PATCH 243/342] Simpliefied GetComputerName --- native/getcomputername.cpp | 82 +++-------------------- native/getcomputername.h | 4 +- tests/test-getcomputername.cpp | 117 ++------------------------------- 3 files changed, 16 insertions(+), 187 deletions(-) diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 818623ddf..6c5f8853a 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -7,69 +7,24 @@ #include #include #include -#include +#include #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 +//! - ERROR_INVALID_ADDRESS: buffer is an invalid address +//! - ERROR_GEN_FAILURE: buffer not large enough //! -//! @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) +//! @retval username as UTF-8 string, or null if unsuccessful + +char* GetComputerNameW() { 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 @@ -99,29 +54,8 @@ BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize) 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(lpBuffer), "UTF-16LE"); - - *lpnSize = size; - return TRUE; + std::cerr << "GetComputerName: " << computername.c_str() << std::endl; + return strdup(computername.c_str()); } diff --git a/native/getcomputername.h b/native/getcomputername.h index 8d39d3f9f..b760b6c5a 100644 --- a/native/getcomputername.h +++ b/native/getcomputername.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetComputerNameW(WCHAR_T* lpBuffer, LPDWORD lpnSize); +char* GetComputerNameW(); -PAL_END_EXTERNC \ No newline at end of file +PAL_END_EXTERNC diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index 51ebd0ccc..9ee3a6f82 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -3,132 +3,27 @@ //! @brief Unit tests for GetComputerNameW #include -#include -#include #include #include -#include #include "getcomputername.h" //! Test fixture for GetComputerNameTest class GetComputerNameTest : public ::testing::Test { protected: - DWORD lpnSize; - std::vector lpBuffer; - BOOL result; - std::string expectedComputerName; - DWORD expectedSize; + char expectedComputerName[HOST_NAME_MAX]; //Get expected result from using linux call GetComputerNameTest() { - expectedComputerName.resize(HOST_NAME_MAX); - BOOL ret = gethostname(&expectedComputerName[0], expectedComputerName.length()); + BOOL ret = gethostname(expectedComputerName, HOST_NAME_MAX); 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(&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); + std::cout << "Expected Name:" << expectedComputerName << std::endl; } }; -TEST_F(GetComputerNameTest, BufferAsNullButNotBufferSize) +TEST_F(GetComputerNameTest, Success) { - lpnSize = 1; - result = GetComputerNameW(NULL, &lpnSize); - TestInvalidParameter(); - // does not reset lpnSize - EXPECT_EQ(1, lpnSize); + std::cout << "Actual Name:" << GetComputerNameW() << std::endl; + ASSERT_STREQ(GetComputerNameW(), expectedComputerName); } - -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(); -} \ No newline at end of file From 9718cd02abad03143711fa56979c33e8691e2276 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Tue, 27 Oct 2015 10:48:31 -0700 Subject: [PATCH 244/342] Remove W suffix of native function --- native/getcomputername.cpp | 2 +- native/getcomputername.h | 2 +- tests/test-getcomputername.cpp | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 6c5f8853a..47fc634d3 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -21,7 +21,7 @@ //! //! @retval username as UTF-8 string, or null if unsuccessful -char* GetComputerNameW() +char* GetComputerName() { errno = 0; diff --git a/native/getcomputername.h b/native/getcomputername.h index b760b6c5a..66b0c352b 100644 --- a/native/getcomputername.h +++ b/native/getcomputername.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -char* GetComputerNameW(); +char* GetComputerName(); PAL_END_EXTERNC diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index 9ee3a6f82..961cee796 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -18,12 +18,10 @@ protected: { BOOL ret = gethostname(expectedComputerName, HOST_NAME_MAX); EXPECT_EQ(0, ret); - std::cout << "Expected Name:" << expectedComputerName << std::endl; } }; TEST_F(GetComputerNameTest, Success) { - std::cout << "Actual Name:" << GetComputerNameW() << std::endl; - ASSERT_STREQ(GetComputerNameW(), expectedComputerName); + ASSERT_STREQ(GetComputerName(), expectedComputerName); } From b7260951f1b2066885d738a0098ffa5b55be3154 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Tue, 27 Oct 2015 10:55:27 -0700 Subject: [PATCH 245/342] Remove debug output --- native/getcomputername.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 47fc634d3..68fd89953 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -54,7 +54,6 @@ char* GetComputerName() return FALSE; } - std::cerr << "GetComputerName: " << computername.c_str() << std::endl; return strdup(computername.c_str()); } From 81f833cf2531d81c5ce2511570a3b338fd0b911b Mon Sep 17 00:00:00 2001 From: George Fleming Date: Tue, 27 Oct 2015 10:57:02 -0700 Subject: [PATCH 246/342] Remove --- native/getcomputername.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 68fd89953..0c8ac06a0 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include "getcomputername.h" //! @brief GetComputerName retrieves the name of the host associated with From 7f6a494bf0103bd43d66315ed7ca35d972bab1de Mon Sep 17 00:00:00 2001 From: George Fleming Date: Tue, 27 Oct 2015 14:21:25 -0700 Subject: [PATCH 247/342] Modify return value --- native/getcomputername.cpp | 4 ++-- native/getusername.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 0c8ac06a0..51f1cf5bf 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -30,7 +30,7 @@ char* GetComputerName() if (nl_langinfo(CODESET) != std::string("UTF-8")) { errno = ERROR_BAD_ENVIRONMENT; - return FALSE; + return NULL; } // Get computername from system in a thread-safe manner @@ -50,7 +50,7 @@ char* GetComputerName() default: errno = ERROR_INVALID_FUNCTION; } - return FALSE; + return NULL; } return strdup(computername.c_str()); diff --git a/native/getusername.cpp b/native/getusername.cpp index a4590bfde..30c2b8a14 100644 --- a/native/getusername.cpp +++ b/native/getusername.cpp @@ -41,7 +41,7 @@ char* GetUserName() if (buflen == -1) { errno = ERROR_GEN_FAILURE; - return FALSE; + return NULL; } std::string buf(buflen, 0); From 11bcfb06d38fd743f535ade424ce4b0d43cf3953 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Tue, 27 Oct 2015 14:56:57 -0700 Subject: [PATCH 248/342] Add GetFullyQualifiedName() --- native/CMakeLists.txt | 1 + native/getfullyqualifiedname.cpp | 57 ++++++++++++++++++++++++++++++++ native/getfullyqualifiedname.h | 9 +++++ native/pal.h | 1 + 4 files changed, 68 insertions(+) create mode 100644 native/getfullyqualifiedname.cpp create mode 100644 native/getfullyqualifiedname.h diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index c2523c3a3..76682aa84 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -3,6 +3,7 @@ add_library(psnative SHARED getusername.cpp getcomputername.cpp getlinkcount.cpp + getfullyqualifiedname.cpp terminal.cpp) target_link_libraries(psnative icuuc) diff --git a/native/getfullyqualifiedname.cpp b/native/getfullyqualifiedname.cpp new file mode 100644 index 000000000..936127f46 --- /dev/null +++ b/native/getfullyqualifiedname.cpp @@ -0,0 +1,57 @@ +//! @file getfullyqualifiedname.cpp +//! @author George Fleming +//! @brief Implements GetFullyQualifiedName on Linux + +#include +#include +#include +#include +#include "getfullyqualifiedname.h" + +extern char* GetComputerName(); + +//! @brief GetFullyQualifiedName retrieves the full name of the host associated with +//! the current thread. +//! +//! @exception errno Passes these errors via errno to GetLastError: +//! - ERROR_BAD_ENVIRONMENT: locale is not UTF-8 +//! - ERROR_INVALID_FUNCTION: getlogin_r() returned an unrecognized error code +//! - ERROR_INVALID_ADDRESS: buffer is an invalid address +//! - ERROR_GEN_FAILURE: buffer not large enough +//! - ERROR_BAD_NET_NAME: Cannot determine network short name +//! +//! @retval username as UTF-8 string, or null if unsuccessful + +char* GetFullyQualifiedName() +{ + errno = 0; + + char *computerName = GetComputerName(); + if (NULL == computerName) + { + return NULL; + } + + struct addrinfo hints, *info; + int gai_result; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; /*either IPV4 or IPV6*/ + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + + if ((gai_result = getaddrinfo(computerName, "http", &hints, &info)) != 0) + { + errno = ERROR_BAD_NET_NAME; + return NULL; + } + + // info is actually a link-list. We'll just return the first full name + + char *fullName = strdup(info->ai_canonname); + + freeaddrinfo(info); + free(computerName); + return fullName; +} + diff --git a/native/getfullyqualifiedname.h b/native/getfullyqualifiedname.h new file mode 100644 index 000000000..4db1fd2e7 --- /dev/null +++ b/native/getfullyqualifiedname.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +char* GetFullyQualifiedName(); + +PAL_END_EXTERNC diff --git a/native/pal.h b/native/pal.h index c53c985a8..d74f52d71 100644 --- a/native/pal.h +++ b/native/pal.h @@ -88,6 +88,7 @@ #define ERROR_BUFFER_OVERFLOW 0x0000006F #define ERROR_FILE_NOT_FOUND 0x00000002 #define ERROR_BAD_PATH_NAME 0x000000A1 + #define ERROR_BAD_NET_NAME 0x00000043 typedef unsigned long long uint64; #endif From 1759f9a2f6d7c3b83acfd8aff5163a8529e6d124 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Tue, 27 Oct 2015 15:33:25 -0700 Subject: [PATCH 249/342] Changes per Zack comments --- native/getcomputername.cpp | 2 +- tests/test-getcomputername.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 51f1cf5bf..3d4e7eda3 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -1,5 +1,5 @@ //! @file getcomputername.cpp -//! @author Aaron Katz +//! @author George Fleming //! @brief Implements GetComputerName Win32 API #include diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index 961cee796..c783ff003 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -1,6 +1,6 @@ //! @file test-getcomputername.cpp -//! @author Aaron Katz -//! @brief Unit tests for GetComputerNameW +//! @author George Fleming +//! @brief Unit tests for GetComputerName #include #include @@ -21,7 +21,7 @@ protected: } }; -TEST_F(GetComputerNameTest, Success) +TEST_F(GetComputerNameTest, ValidateLinuxGetHostnameSystemCall) { ASSERT_STREQ(GetComputerName(), expectedComputerName); } From e776d01cc8f4e9b1297f527c0e27c3f3a4f2125c Mon Sep 17 00:00:00 2001 From: George Fleming Date: Tue, 27 Oct 2015 16:43:43 -0700 Subject: [PATCH 250/342] Change reference of GetComputerName --- native/getfullyqualifiedname.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/native/getfullyqualifiedname.cpp b/native/getfullyqualifiedname.cpp index 936127f46..a4e98a664 100644 --- a/native/getfullyqualifiedname.cpp +++ b/native/getfullyqualifiedname.cpp @@ -6,10 +6,9 @@ #include #include #include +#include "getcomputername.h" #include "getfullyqualifiedname.h" -extern char* GetComputerName(); - //! @brief GetFullyQualifiedName retrieves the full name of the host associated with //! the current thread. //! From 4d2b184892793b3a1849ac1265b27a6d89a2104d Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 27 Oct 2015 23:21:44 -0700 Subject: [PATCH 251/342] Add sensible defaults for powershell and coreclr --- host/coreclrutil.cpp | 53 ++++++++++++++++++++++++++++++++++---------- host/main.cpp | 7 +++--- 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/host/coreclrutil.cpp b/host/coreclrutil.cpp index d53433e3b..eabd73f04 100644 --- a/host/coreclrutil.cpp +++ b/host/coreclrutil.cpp @@ -18,6 +18,7 @@ constexpr char coreClrDll[] = "libcoreclr.so"; #endif void* coreclrLib; +char exePath[PATH_MAX]; // Prototype of the coreclr_initialize function from the libcoreclr.so typedef int (*InitializeCoreCLRFunction)( @@ -78,24 +79,53 @@ bool GetDirectory(const char* absolutePath, std::string& directory) // // Return true in case of a success, false otherwise. // -bool GetEnvAbsolutePath(const char* env_var, std::string& absolutePath) +bool GetEnvAbsolutePath(const char* envVar, std::string& absolutePath) { - const char* filesPathLocal = std::getenv(env_var);; + const char* filesPathLocal = std::getenv(envVar);; if (filesPathLocal == nullptr) { - std::cerr << "failed because $" << env_var << " was empty" << std::endl; return false; } - if (!GetAbsolutePath(filesPathLocal, absolutePath)) + return GetAbsolutePath(filesPathLocal, absolutePath); +} + +// +// Get the a root path given an environment variable and default +// relative to exePath +// +bool GetRootPath(const char* envVar, + const char* relativePath, + std::string& absolutePath) +{ + if (!GetEnvAbsolutePath(envVar, absolutePath)) { - std::cerr << "failed to get absolute path for " << env_var << std::endl; - return false; + // Default to bin/relativePath + std::string path; + if (!GetDirectory(exePath, path)) + { + return false; + } + path.append("/"); + path.append(relativePath); + return GetAbsolutePath(path.c_str(), absolutePath); } return true; } +// Get the PowerShell root path, with sensible default +bool GetPwrshRoot(std::string& absolutePath) +{ + return GetRootPath("PWRSH_ROOT", "../lib/powershell", absolutePath); +} + +// Get the CoreCLR root path, with sensible default +bool GetCoreRoot(std::string& absolutePath) +{ + return GetRootPath("CORE_ROOT", "../lib/coreclr", absolutePath); +} + // Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) { @@ -198,9 +228,12 @@ int startCoreCLR( void** hostHandle, unsigned int* domainId) { + // get path to current executable + readlink("/proc/self/exe", exePath, PATH_MAX); + // get the CoreCLR root path std::string clrAbsolutePath; - if(!GetEnvAbsolutePath("CORE_ROOT", clrAbsolutePath)) + if(!GetCoreRoot(clrAbsolutePath)) { return -1; } @@ -254,7 +287,7 @@ int startCoreCLR( // get path to AssemblyLoadContext.dll std::string psAbsolutePath; - if(!GetEnvAbsolutePath("PWRSH_ROOT", psAbsolutePath)) + if(!GetPwrshRoot(psAbsolutePath)) { return -1; } @@ -290,10 +323,6 @@ int startCoreCLR( "UseLatestBehaviorWhenTFMNotSpecified" }; - // get path to current executable - char exePath[PATH_MAX] = { 0 }; - readlink("/proc/self/exe", exePath, PATH_MAX); - // initialize CoreCLR int status = initializeCoreCLR( exePath, diff --git a/host/main.cpp b/host/main.cpp index 79539603a..0b7728d4e 100644 --- a/host/main.cpp +++ b/host/main.cpp @@ -11,10 +11,11 @@ namespace Cmdline << "Usage: powershell assembly [...]" << std::endl << std::endl << "What it does:" << std::endl - << "- the host assumes that CoreCLR is located $CORE_ROOT" << std::endl + << "- the host assumes that CoreCLR is located $CORE_ROOT," << std::endl + << " else in lib/coreclr" << "- the host assumes that the assembly named" << std::endl << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is " << std::endl - << " located in $PWRSH_ROOT" << std::endl + << " located in $PWRSH_ROOT, else in lib/powershell" << std::endl << "- all additional parameters at the end of the command line are forwarded" << std::endl << " to the Main function in the assembly" << std::endl << "- the host will execute the Main function in the specified assembly" << std::endl @@ -26,7 +27,7 @@ namespace Cmdline << "-v verbose output" << std::endl << std::endl << "Example:" << std::endl - << "CORE_ROOT=/test/coreclr PWRSH_ROOT=/test/powershell ./host_cmdline -s /test/ps powershell-simple 'get-process'" << std::endl; + << "CORE_ROOT=/test/coreclr PWRSH_ROOT=/test/powershell ./powershell powershell-simple 'get-process'" << std::endl; } struct Args From 29d496e3ac26030ee06d2661d6fc695910546a89 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Wed, 28 Oct 2015 10:24:43 -0700 Subject: [PATCH 252/342] Adding additional comments --- native/getfullyqualifiedname.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/native/getfullyqualifiedname.cpp b/native/getfullyqualifiedname.cpp index a4e98a664..7e5831e6d 100644 --- a/native/getfullyqualifiedname.cpp +++ b/native/getfullyqualifiedname.cpp @@ -9,17 +9,20 @@ #include "getcomputername.h" #include "getfullyqualifiedname.h" -//! @brief GetFullyQualifiedName retrieves the full name of the host associated with -//! the current thread. +//! @brief GetFullyQualifiedName retrieves the fully qualifed dns name of the host //! //! @exception errno Passes these errors via errno to GetLastError: -//! - ERROR_BAD_ENVIRONMENT: locale is not UTF-8 -//! - ERROR_INVALID_FUNCTION: getlogin_r() returned an unrecognized error code -//! - ERROR_INVALID_ADDRESS: buffer is an invalid address -//! - ERROR_GEN_FAILURE: buffer not large enough +//! - ERROR_BAD_ENVIRONMENT: locale is not UTF-8 (from GetComputerName) +//! - ERROR_INVALID_FUNCTION: getlogin_r() returned an unrecognized error code (from GetComputerName) +//! - ERROR_INVALID_ADDRESS: buffer is an invalid address (from GetComputerName) +//! - ERROR_GEN_FAILURE: buffer not large enough (from GetComputerName) //! - ERROR_BAD_NET_NAME: Cannot determine network short name //! //! @retval username as UTF-8 string, or null if unsuccessful +//! +//! Note on testing: Since there's no easy way to override the domain name, no unit testing will be +//! provided. Instead, manual end-to-end testing should be done to verify domain name matches expected +//! value. char* GetFullyQualifiedName() { @@ -39,6 +42,12 @@ char* GetFullyQualifiedName() hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_CANONNAME; + /* There are several ways to get the domain name: + * uname(2), gethostbyname(3), resolver(3), getdomainname(2), + * and getaddrinfo(3). Some of these are not portable, some aren't + * POSIX compliant, and some are being deprecated. Getaddrinfo seems + * to be the best choice right now. + */ if ((gai_result = getaddrinfo(computerName, "http", &hints, &info)) != 0) { errno = ERROR_BAD_NET_NAME; From 2d442eb73279a24638e63c4a82344de5717e5a70 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Wed, 28 Oct 2015 16:41:24 -0700 Subject: [PATCH 253/342] Skip getaddrinfo if hostname is already FQDN --- native/getfullyqualifiedname.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/native/getfullyqualifiedname.cpp b/native/getfullyqualifiedname.cpp index 7e5831e6d..5d711c2f3 100644 --- a/native/getfullyqualifiedname.cpp +++ b/native/getfullyqualifiedname.cpp @@ -20,9 +20,6 @@ //! //! @retval username as UTF-8 string, or null if unsuccessful //! -//! Note on testing: Since there's no easy way to override the domain name, no unit testing will be -//! provided. Instead, manual end-to-end testing should be done to verify domain name matches expected -//! value. char* GetFullyQualifiedName() { @@ -34,6 +31,11 @@ char* GetFullyQualifiedName() return NULL; } + if (strchr(computerName, '.') != NULL) + { + return computerName; + } + struct addrinfo hints, *info; int gai_result; From 2eaf911346212bd4fdec64d64ea2a562fa2a8d18 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Wed, 28 Oct 2015 16:42:15 -0700 Subject: [PATCH 254/342] Add new getfullyqualifiedname test --- tests/CMakeLists.txt | 1 + tests/test-getfullyqualifiedname.cpp | 35 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/test-getfullyqualifiedname.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c9630dda1..3dfb4fdd4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(psnative-test test-getusername.cpp test-getcomputername.cpp test-getlinkcount.cpp + test-getfullyqualifiedname.cpp main.cpp) # manually include gtest headers diff --git a/tests/test-getfullyqualifiedname.cpp b/tests/test-getfullyqualifiedname.cpp new file mode 100644 index 000000000..484fd8d65 --- /dev/null +++ b/tests/test-getfullyqualifiedname.cpp @@ -0,0 +1,35 @@ +//! @file test-getfullyqualifiedname.cpp +//! @author George Fleming +//! @brief Unit tests for GetFullyQualifiedName + +#include +#include +#include "getfullyqualifiedname.h" + +//! Test fixture for GetComputerNameTest +class GetFullyQualifiedNameTest : public ::testing::Test +{ +}; + +TEST_F(GetFullyQualifiedNameTest, ValidateLinuxGetFullyQualifiedDomainName) +{ + char expectedComputerName[HOST_NAME_MAX]; + + //Get expected result from using linux command + + FILE *fPtr = popen("/bin/hostname --fqdn", "r"); + ASSERT_TRUE(fPtr != NULL); + + char *linePtr = fgets(expectedComputerName, sizeof(expectedComputerName), fPtr); + ASSERT_TRUE(linePtr != NULL); + + // There's a tendency to have \n at end of fgets string, so remove it before compare + size_t sz = strlen(expectedComputerName); + if (sz > 0 && expectedComputerName[sz - 1] == '\n') + { + expectedComputerName[sz - 1] = '\0'; + } + pclose(fPtr); + + ASSERT_STREQ(GetFullyQualifiedName(), expectedComputerName); +} From 3a02f1b3a00dc0b3764d77f429825559fcf0ecc0 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Thu, 29 Oct 2015 08:47:36 -0700 Subject: [PATCH 255/342] Change /bin/hostname to just hostname, and let sh figure out the path --- tests/test-getfullyqualifiedname.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-getfullyqualifiedname.cpp b/tests/test-getfullyqualifiedname.cpp index 484fd8d65..9ec01e27f 100644 --- a/tests/test-getfullyqualifiedname.cpp +++ b/tests/test-getfullyqualifiedname.cpp @@ -17,7 +17,7 @@ TEST_F(GetFullyQualifiedNameTest, ValidateLinuxGetFullyQualifiedDomainName) //Get expected result from using linux command - FILE *fPtr = popen("/bin/hostname --fqdn", "r"); + FILE *fPtr = popen("hostname --fqdn", "r"); ASSERT_TRUE(fPtr != NULL); char *linePtr = fgets(expectedComputerName, sizeof(expectedComputerName), fPtr); From 2de4fe9be6ad791a5e406bf98efd7ec3d5258c01 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Fri, 30 Oct 2015 11:47:44 -0700 Subject: [PATCH 256/342] Adding new isSymLink() function --- native/CMakeLists.txt | 1 + native/issymlink.cpp | 108 +++++++++++++++++++++++++++++++++++++++ native/issymlink.h | 9 ++++ tests/CMakeLists.txt | 1 + tests/test-issymlink.cpp | 104 +++++++++++++++++++++++++++++++++++++ 5 files changed, 223 insertions(+) create mode 100644 native/issymlink.cpp create mode 100644 native/issymlink.h create mode 100644 tests/test-issymlink.cpp diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index 76682aa84..1b57c13d2 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -4,6 +4,7 @@ add_library(psnative SHARED getcomputername.cpp getlinkcount.cpp getfullyqualifiedname.cpp + issymlink.cpp terminal.cpp) target_link_libraries(psnative icuuc) diff --git a/native/issymlink.cpp b/native/issymlink.cpp new file mode 100644 index 000000000..0d3a1f387 --- /dev/null +++ b/native/issymlink.cpp @@ -0,0 +1,108 @@ +//! @file isSymLink.cpp +//! @author George FLeming +//! @brief returns whether a path is a symbolic link + +#include +#include +#include +#include +#include +#include +#include +#include +#include "issymlink.h" + +//! @brief IsSymLink determines if path is a symbolic link +//! +//! IsSymLink +//! +//! @param[in] fileName +//! @parblock +//! A pointer to the buffer that contains the file name +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @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_FILE_NOT_FOUND: file does not exist +//! - ERROR_ACCESS_DENIED: access is denied +//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified +//! - ERROR_INVALID_ADDRESS: attempt to access invalid address +//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link +//! - ERROR_GEN_FAILURE: device attached to the system is not functioning +//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file +//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect +//! - ERROR_BUFFER_OVERFLOW: file name is too long +//! - ERROR_INVALID_FUNCTION: incorrect function +//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters +//! +//! @retval 1 if path is a symbolic link +//! @retval 0 if path is not a symbolic link +//! @retval -1 If the function fails.. To get extended error information, call GetLastError. +//! + +long IsSymLink(const char* fileName) +{ + errno = 0; + + // Check parameters + if (!fileName) + { + errno = ERROR_INVALID_PARAMETER; + return -1; + } + + // 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 -1; + } + + struct stat statBuf; + + int returnCode = lstat(fileName, &statBuf); + + if (returnCode != 0) + { + switch(errno) + { + case EACCES: + errno = ERROR_ACCESS_DENIED; + break; + case EBADF: + errno = ERROR_FILE_NOT_FOUND; + break; + case EFAULT: + errno = ERROR_INVALID_ADDRESS; + break; + case ELOOP: + errno = ERROR_STOPPED_ON_SYMLINK; + break; + case ENAMETOOLONG: + errno = ERROR_GEN_FAILURE; + break; + case ENOENT: + errno = ERROR_FILE_NOT_FOUND; + break; + case ENOMEM: + errno = ERROR_NO_SUCH_USER; + break; + case ENOTDIR: + errno = ERROR_INVALID_NAME; + break; + case EOVERFLOW: + errno = ERROR_BUFFER_OVERFLOW; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return -1; + } + + return S_ISLNK(statBuf.st_mode) ? 1 : 0; +} diff --git a/native/issymlink.h b/native/issymlink.h new file mode 100644 index 000000000..3ba5e48ac --- /dev/null +++ b/native/issymlink.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +long IsSymLink(const char* fileName); + +PAL_END_EXTERNC diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3dfb4fdd4..b9bba62a2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable(psnative-test test-getcomputername.cpp test-getlinkcount.cpp test-getfullyqualifiedname.cpp + test-issymlink.cpp main.cpp) # manually include gtest headers diff --git a/tests/test-issymlink.cpp b/tests/test-issymlink.cpp new file mode 100644 index 000000000..41515fbc3 --- /dev/null +++ b/tests/test-issymlink.cpp @@ -0,0 +1,104 @@ +//! @file test-issymlink.cpp +//! @author George Fleming +//! @brief Implements test for isSymLink() + +#include +#include +#include +#include "issymlink.h" + +using namespace std; + +class isSymLinkTest : public ::testing::Test +{ +protected: + + static const int bufSize = 64; + const string fileTemplate = "/tmp/symlinktest.fXXXXXXX"; + const string dirTemplate = "/tmp/symlinktest.dXXXXXXX"; + const string fileSymLink = "/tmp/symlinktest.flink"; + const string dirSymLink = "/tmp/symlinktest.dlink"; + char *file, *dir; + char fileTemplateBuf[bufSize], dirTemplateBuf[bufSize]; + + isSymLinkTest() + { + // since mkstemp and mkdtemp modifies the template string, let's give them writable buffers + strcpy(fileTemplateBuf, fileTemplate.c_str()); + strcpy(dirTemplateBuf, dirTemplate.c_str()); + + // First create a file + int fd = mkstemp(fileTemplateBuf); + EXPECT_TRUE(fd != -1); + file = fileTemplateBuf; + + // Create a temp directory + dir = mkdtemp(dirTemplateBuf); + EXPECT_TRUE(dir != NULL); + + // Create symbolic link to file + int ret1 = symlink(file, fileSymLink.c_str()); + EXPECT_EQ(ret1, 0); + + // Create symbolic link to directory + int ret2 = symlink(dir, dirSymLink.c_str()); + EXPECT_EQ(ret2, 0); + } + + ~isSymLinkTest() + { + int ret; + + ret = unlink(fileSymLink.c_str()); + EXPECT_EQ(0, ret); + + ret = unlink(dirSymLink.c_str()); + EXPECT_EQ(0, ret); + + ret = unlink(file); + EXPECT_EQ(0, ret); + + ret = rmdir(dir); + EXPECT_EQ(0, ret); + } +}; + +TEST_F(isSymLinkTest, FilePathNameIsNull) +{ + int retVal = IsSymLink(NULL); + EXPECT_EQ(retVal, -1); + EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); +} + +TEST_F(isSymLinkTest, FilePathNameDoesNotExist) +{ + std::string invalidFile = "/tmp/symlinktest_invalidFile"; + int retVal = IsSymLink(invalidFile.c_str()); + EXPECT_EQ(retVal, -1); + EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno); +} + +TEST_F(isSymLinkTest, NormalFileIsNotSymLink) +{ + int retVal = IsSymLink(file); + EXPECT_EQ(0, retVal); +} + +TEST_F(isSymLinkTest, SymLinkToFile) +{ + int retVal = IsSymLink(fileSymLink.c_str()); + EXPECT_EQ(1, retVal); +} + +TEST_F(isSymLinkTest, NormalDirectoryIsNotSymbLink) +{ + int retVal = IsSymLink(dir); + EXPECT_EQ(0, retVal); +} + +TEST_F(isSymLinkTest, SymLinkToDirectory) +{ + int retVal = IsSymLink(dirSymLink.c_str()); + EXPECT_EQ(1, retVal); +} + From 9bb5b7e52c3f1a18cac367c7fb7579406c6786fc Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 27 Oct 2015 17:01:23 -0700 Subject: [PATCH 257/342] Use `make install` target Instead of manually and always resolving to monad-linux/{bin,lib}, we use the CMake `install()` command to generate a `make install` target which places powershell, libpshost, and libpsnative in ${CMAKE_INSTALL_PREFIX}/{bin,lib} respectively. CMAKE_INSTALL_PREFIX defaults to `/usr/local` which we will want upon actual package installation. During development, we will override this to be the path to monad-linux in the superproject's Makefile. Also move test output so monad-native Jenkins job can pick it up. --- .gitignore | 4 ++++ CMakeLists.txt | 9 --------- host/CMakeLists.txt | 4 ++++ native/CMakeLists.txt | 3 +++ tests/CMakeLists.txt | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index b4b9d1249..45177e796 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ install_manifest.txt CTestTestfile.cmake Testing/ tests/psnative-test +host/powershell +host/libpshost.a +native/libpsnative.so +tests/native-tests.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index 51d4665de..b61395b0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,17 +3,8 @@ project(MONAD_NATIVE) add_compile_options(-std=c++11 -Wall) -# resolve superproject directory -set(MONAD ${CMAKE_SOURCE_DIR}/../../) - # test in BUILD_DIR enable_testing() add_subdirectory(tests) - -# output psnative and pshost to superproject -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${MONAD}/bin) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${MONAD}/lib) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${MONAD}/lib) - add_subdirectory(native) add_subdirectory(host) diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 7d472915d..cdca0049d 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -4,3 +4,7 @@ target_compile_options(pshost PRIVATE -fPIC) add_executable(powershell main.cpp) target_link_libraries(powershell pshost) + +install(TARGETS powershell pshost + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib) diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index 1b57c13d2..73a1dcdfe 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -9,3 +9,6 @@ add_library(psnative SHARED target_link_libraries(psnative icuuc) target_include_directories (psnative PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +install(TARGETS psnative + LIBRARY DESTINATION lib) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b9bba62a2..43918bee1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -15,4 +15,4 @@ target_include_directories(psnative-test PRIVATE ${gtest_SOURCE_DIR}/include) target_link_libraries(psnative-test psnative gtest) add_test(NAME psnative-test - COMMAND psnative-test --gtest_output=xml:${MONAD}/native-tests.xml) + COMMAND psnative-test --gtest_output=xml:native-tests.xml) From 43f2d476f5027f9aa986def8af5f8a4749f4ff7b Mon Sep 17 00:00:00 2001 From: George Fleming Date: Mon, 2 Nov 2015 15:23:29 -0800 Subject: [PATCH 258/342] New IsExecutable function --- native/CMakeLists.txt | 1 + native/isexecutable.cpp | 99 +++++++++++++++++++++++++++++++++++++ native/isexecutable.h | 9 ++++ native/pal.h | 2 +- tests/CMakeLists.txt | 1 + tests/test-isexecutable.cpp | 94 +++++++++++++++++++++++++++++++++++ 6 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 native/isexecutable.cpp create mode 100644 native/isexecutable.h create mode 100644 tests/test-isexecutable.cpp diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index 73a1dcdfe..9efaec93c 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -5,6 +5,7 @@ add_library(psnative SHARED getlinkcount.cpp getfullyqualifiedname.cpp issymlink.cpp + isexecutable.cpp terminal.cpp) target_link_libraries(psnative icuuc) diff --git a/native/isexecutable.cpp b/native/isexecutable.cpp new file mode 100644 index 000000000..dab536295 --- /dev/null +++ b/native/isexecutable.cpp @@ -0,0 +1,99 @@ +//! @file isExecutable.cpp +//! @author George FLeming +//! @brief returns whether a path is executable + +#include +#include +#include +#include +#include +#include "isexecutable.h" + +//! @brief IsExecutable determines if path is executable +//! +//! IsExecutable +//! +//! @param[in] fileName +//! @parblock +//! A pointer to the buffer that contains the file name +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @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_FILE_NOT_FOUND: file does not exist +//! - ERROR_ACCESS_DENIED: access is denied +//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified +//! - ERROR_INVALID_ADDRESS: attempt to access invalid address +//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link +//! - ERROR_GEN_FAILURE: device attached to the system is not functioning +//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file +//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect +//! - ERROR_BUFFER_OVERFLOW: file name is too long +//! - ERROR_INVALID_FUNCTION: incorrect function +//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters +//! +//! @retval 1 if path is an executable +//! @retval 0 if path is not a executable +//! @retval -1 If the function fails.. To get extended error information, call GetLastError. +//! + +int32_t IsExecutable(const char* fileName) +{ + errno = 0; + + // Check parameters + if (!fileName) + { + errno = ERROR_INVALID_PARAMETER; + return -1; + } + + // 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 -1; + } + + int returnCode = access(fileName, X_OK); + + if (returnCode == 0) + { + return 1; + } + + switch(errno) + { + case EACCES: + return 0; + case EBADF: + case ENOENT: + errno = ERROR_FILE_NOT_FOUND; + break; + case EFAULT: + errno = ERROR_INVALID_ADDRESS; + break; + case ELOOP: + errno = ERROR_STOPPED_ON_SYMLINK; + break; + case EIO: + case ENOMEM: + errno = ERROR_GEN_FAILURE; + break; + case ENOTDIR: + case ENAMETOOLONG: + errno = ERROR_INVALID_NAME; + break; + case EINVAL: + errno = ERROR_INVALID_PARAMETER; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return -1; +} diff --git a/native/isexecutable.h b/native/isexecutable.h new file mode 100644 index 000000000..da4e9f8f3 --- /dev/null +++ b/native/isexecutable.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +int32_t IsExecutable(const char* fileName); + +PAL_END_EXTERNC diff --git a/native/pal.h b/native/pal.h index d74f52d71..7df0b32bb 100644 --- a/native/pal.h +++ b/native/pal.h @@ -30,7 +30,7 @@ #include #include #include -#include +#include #ifndef NAME_MAX # define NAME_MAX 255 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 43918bee1..a065c66c1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,6 +7,7 @@ add_executable(psnative-test test-getlinkcount.cpp test-getfullyqualifiedname.cpp test-issymlink.cpp + test-isexecutable.cpp main.cpp) # manually include gtest headers diff --git a/tests/test-isexecutable.cpp b/tests/test-isexecutable.cpp new file mode 100644 index 000000000..36955912f --- /dev/null +++ b/tests/test-isexecutable.cpp @@ -0,0 +1,94 @@ +//! @file test-isexecutable.cpp +//! @author George Fleming +//! @brief Implements test for isexecutable() + +#include +#include +#include +#include +#include "isexecutable.h" + +using namespace std; + +class IsExecutableTest : public ::testing::Test +{ +protected: + + static const int bufSize = 64; + const string fileTemplate = "/tmp/isexecutabletest.fXXXXXXX"; + const mode_t mode_700 = S_IRUSR | S_IWUSR | S_IXUSR; + const mode_t mode_070 = S_IRGRP | S_IWGRP | S_IXGRP; + const mode_t mode_007 = S_IROTH | S_IWOTH | S_IXOTH; + const mode_t mode_777 = mode_700 | mode_070 | mode_007; + const mode_t mode_444 = S_IRUSR | S_IRGRP | S_IROTH; + + char *file; + char fileTemplateBuf[bufSize]; + + IsExecutableTest() + { + // since mkstemp modifies the template string, let's give it writable buffers + strcpy(fileTemplateBuf, fileTemplate.c_str()); + + // First create a file + int fd = mkstemp(fileTemplateBuf); + EXPECT_TRUE(fd != -1); + file = fileTemplateBuf; + } + + ~IsExecutableTest() + { + int ret; + + ret = unlink(file); + EXPECT_EQ(0, ret); + } + + void ChangeFilePermission(const char* file, mode_t mode) + { + int ret = chmod(file, mode); + EXPECT_EQ(ret, 0); + } +}; + +TEST_F(IsExecutableTest, FilePathNameIsNull) +{ + int32_t retVal = IsExecutable(NULL); + EXPECT_EQ(retVal, -1); + EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); +} + +TEST_F(IsExecutableTest, FilePathNameDoesNotExist) +{ + std::string invalidFile = "/tmp/isexecutabletest_invalidFile"; + int32_t retVal = IsExecutable(invalidFile.c_str()); + EXPECT_EQ(retVal, -1); + EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno); +} + +TEST_F(IsExecutableTest, NormalFileIsNotIsexecutable) +{ + int32_t retVal = IsExecutable(file); + EXPECT_EQ(0, retVal); + + ChangeFilePermission(file, mode_444); + + retVal = IsExecutable(file); + EXPECT_EQ(0, retVal); +} + +TEST_F(IsExecutableTest, FilePermission_700) +{ + ChangeFilePermission(file, mode_700); + + int32_t retVal = IsExecutable(file); + EXPECT_EQ(1, retVal); +} + +TEST_F(IsExecutableTest, FilePermission_777) +{ + ChangeFilePermission(file, mode_777); + + int32_t retVal = IsExecutable(file); + EXPECT_EQ(1, retVal); +} From 8747ba1e4775565c28a1192ad2161b93510127ba Mon Sep 17 00:00:00 2001 From: George Fleming Date: Mon, 2 Nov 2015 16:40:28 -0800 Subject: [PATCH 259/342] Clean up of pal.h --- native/getcomputername.cpp | 2 +- native/getcurrentprocessorid.cpp | 6 +- native/getcurrentprocessorid.h | 2 +- native/getlinkcount.cpp | 13 +- native/getlinkcount.h | 2 +- native/issymlink.cpp | 2 +- native/pal.h | 577 +-------------------------- native/terminal.cpp | 4 +- native/terminal.h | 4 +- tests/test-getcomputername.cpp | 29 +- tests/test-getcurrentprocessid.cpp | 6 +- tests/test-getfullyqualifiedname.cpp | 3 +- tests/test-getlinkcount.cpp | 37 +- tests/test-issymlink.cpp | 4 +- 14 files changed, 81 insertions(+), 610 deletions(-) diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 3d4e7eda3..67e3d870d 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -34,7 +34,7 @@ char* GetComputerName() } // Get computername from system in a thread-safe manner - std::string computername(HOST_NAME_MAX, 0); + std::string computername(NAME_MAX, 0); int err = gethostname(&computername[0], computername.length()); // Map errno to Win32 Error Codes if (err != 0) diff --git a/native/getcurrentprocessorid.cpp b/native/getcurrentprocessorid.cpp index 409f2c258..eea80937b 100644 --- a/native/getcurrentprocessorid.cpp +++ b/native/getcurrentprocessorid.cpp @@ -1,9 +1,9 @@ #include "getcurrentprocessorid.h" #include -HANDLE GetCurrentProcessId() +int32_t GetCurrentProcessId() { - pid_t pid = getpid(); - return reinterpret_cast(pid); + pid_t pid = getpid(); + return static_cast(pid); } diff --git a/native/getcurrentprocessorid.h b/native/getcurrentprocessorid.h index fa3f35534..3c768e72e 100644 --- a/native/getcurrentprocessorid.h +++ b/native/getcurrentprocessorid.h @@ -4,7 +4,7 @@ PAL_BEGIN_EXTERNC -HANDLE GetCurrentProcessId(); +int32_t GetCurrentProcessId(); PAL_END_EXTERNC diff --git a/native/getlinkcount.cpp b/native/getlinkcount.cpp index 50e7263a8..dd9ffbb02 100644 --- a/native/getlinkcount.cpp +++ b/native/getlinkcount.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include "getlinkcount.h" //! @brief GetLinkCount retrieves the file link count (number of hard links) @@ -45,13 +44,13 @@ //! - ERROR_INVALID_FUNCTION: incorrect function //! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters //! -//! @retval TRUE If the function succeeds, the return value is a nonzero -//! value, and the variable pointed to by buffer contains infomation about the files -//! @retval FALSE If the function fails, the return value is zero. To get +//! @retval 1 If the function succeeds, and the variable pointed to by buffer contains +//! infomation about the files +//! @retval 0 If the function fails, the return value is zero. To get //! extended error information, call GetLastError. //! -BOOL GetLinkCount(char* fileName, LPDWORD count) +int32_t GetLinkCount(const char* fileName, int32_t *count) { errno = 0; @@ -109,10 +108,10 @@ BOOL GetLinkCount(char* fileName, LPDWORD count) default: errno = ERROR_INVALID_FUNCTION; } - return FALSE; + return 0; } *count = statBuf.st_nlink; - return TRUE; + return 1; } diff --git a/native/getlinkcount.h b/native/getlinkcount.h index 738a606c6..6a3c8b8e4 100644 --- a/native/getlinkcount.h +++ b/native/getlinkcount.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -BOOL GetLinkCount(char* fileName, LPDWORD count); +int32_t GetLinkCount(const char* fileName, int32_t *count); PAL_END_EXTERNC diff --git a/native/issymlink.cpp b/native/issymlink.cpp index 0d3a1f387..4a4ae5448 100644 --- a/native/issymlink.cpp +++ b/native/issymlink.cpp @@ -43,7 +43,7 @@ //! @retval -1 If the function fails.. To get extended error information, call GetLastError. //! -long IsSymLink(const char* fileName) +int32_t IsSymLink(const char* fileName) { errno = 0; diff --git a/native/pal.h b/native/pal.h index 7df0b32bb..421bbf0a8 100644 --- a/native/pal.h +++ b/native/pal.h @@ -1,57 +1,14 @@ -/* -**============================================================================== -** -** Open Management Infrastructure (OMI) -** -** Copyright (c) Microsoft Corporation -** -** Licensed under the Apache License, Version 2.0 (the "License"); you may not -** use this file except in compliance with the License. You may obtain a copy -** of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -** MERCHANTABLITY OR NON-INFRINGEMENT. -** -** See the Apache 2 License for the specific language governing permissions -** and limitations under the License. -** -**============================================================================== -*/ - #pragma once -#include -#include #include #include -#include -#include #include #ifndef NAME_MAX # define NAME_MAX 255 #endif -/* -**============================================================================== -** -** Windows-specific types. Defined here for PAL on Non-Windows platforms. -** -**============================================================================== -*/ - -#ifdef _MSC_VER - #ifndef WIN32_FROM_HRESULT - #define WIN32_FROM_HRESULT(hr) (HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : hr) - #endif -#else - #define WIN32_FROM_HRESULT(hr) hr - #define HRESULT_FROM_WIN32(error) error - typedef unsigned long DWORD, *LPDWORD; +/* typedef unsigned long DWORD, *LPDWORD; typedef char BOOL; typedef unsigned short WCHAR_T; typedef unsigned int UINT32; @@ -71,110 +28,26 @@ #define S_OK 0 #define TRUE 1 #define FALSE 0 - #define ERROR_INVALID_PARAMETER 87 - #define ERROR_OUTOFMEMORY 14 - #define ERROR_BAD_ENVIRONMENT 0x0000000A - #define ERROR_TOO_MANY_OPEN_FILES 0x00000004 - #define ERROR_INSUFFICIENT_BUFFER 0x0000007A - #define ERROR_NO_ASSOCIATION 0x00000483 - #define ERROR_NO_SUCH_USER 0x00000525 - #define ERROR_INVALID_FUNCTION 0x00000001 - #define MAX_PATH 0x00000104 - #define ERROR_INVALID_ADDRESS 0x000001e7 - #define ERROR_GEN_FAILURE 0x0000001F - #define ERROR_ACCESS_DENIED 0x00000005 - #define ERROR_INVALID_NAME 0x0000007B - #define ERROR_STOPPED_ON_SYMLINK 0x000002A9 - #define ERROR_BUFFER_OVERFLOW 0x0000006F - #define ERROR_FILE_NOT_FOUND 0x00000002 - #define ERROR_BAD_PATH_NAME 0x000000A1 - #define ERROR_BAD_NET_NAME 0x00000043 - - typedef unsigned long long uint64; -#endif - -/* -**============================================================================== -** -** __FUNCTION__ -** -**============================================================================== */ -#if !defined(CONFIG_HAVE_FUNCTION_MACRO) -# if !defined(_MSC_VER) && !defined(__FUNCTION__) -# define __FUNCTION__ "" -# endif -#endif - -/* -**============================================================================== -** -** PAL_32BIT -** PAL_64BIT -** -**============================================================================== -*/ -#if defined(__GNUC__) -# if defined(__i386__) -# define PAL_32BIT -# elif defined(__x86_64__) -# define PAL_64BIT -# elif defined(__ppc__) -# define PAL_32BIT -# elif defined(__ppc64__) -# define PAL_64BIT -# elif ((ULONG_MAX) == (UINT_MAX) && (ULONG_MAX == 0xFFFFFFFF)) -# define PAL_32BIT -# else -# define PAL_64BIT -# endif -#elif defined(_MSC_VER) -# if defined(_WIN64) -# define PAL_64BIT -# else -# define PAL_32BIT -# endif -#elif ((ULONG_MAX) == (UINT_MAX) && (ULONG_MAX == 0xFFFFFFFF)) -# define PAL_32BIT -#else -# define PAL_64BIT -#endif - -/* -**============================================================================== -** -** PAL_CALL macro -** -**============================================================================== -*/ -#ifdef _MSC_VER -# define PAL_CALL __stdcall -#else -# define PAL_CALL -#endif - -/* -**============================================================================== -** -** PAL_EXPORT_API, PAL_IMPORT_API macros -** -**============================================================================== -*/ - -#if defined(_MSC_VER) -# define PAL_EXPORT_API __declspec(dllexport) -# define PAL_IMPORT_API __declspec(dllimport) -#elif defined(__GNUC__) -# define PAL_EXPORT_API __attribute__((visibility("default"))) -# define PAL_IMPORT_API /* empty */ -#elif defined(sun) -# define PAL_EXPORT_API __global -# define PAL_IMPORT_API /* empty */ -#else -# define PAL_EXPORT_API /* empty */ -# define PAL_IMPORT_API /* empty */ -#endif +#define ERROR_INVALID_PARAMETER 87 +#define ERROR_OUTOFMEMORY 14 +#define ERROR_BAD_ENVIRONMENT 0x0000000A +#define ERROR_TOO_MANY_OPEN_FILES 0x00000004 +#define ERROR_INSUFFICIENT_BUFFER 0x0000007A +#define ERROR_NO_ASSOCIATION 0x00000483 +#define ERROR_NO_SUCH_USER 0x00000525 +#define ERROR_INVALID_FUNCTION 0x00000001 +#define MAX_PATH 0x00000104 +#define ERROR_INVALID_ADDRESS 0x000001e7 +#define ERROR_GEN_FAILURE 0x0000001F +#define ERROR_ACCESS_DENIED 0x00000005 +#define ERROR_INVALID_NAME 0x0000007B +#define ERROR_STOPPED_ON_SYMLINK 0x000002A9 +#define ERROR_BUFFER_OVERFLOW 0x0000006F +#define ERROR_FILE_NOT_FOUND 0x00000002 +#define ERROR_BAD_PATH_NAME 0x000000A1 +#define ERROR_BAD_NET_NAME 0x00000043 /* **============================================================================== @@ -193,415 +66,3 @@ # define PAL_END_EXTERNC #endif -/* -**============================================================================== -** -** PAL_EXTERN_C -** -**============================================================================== -*/ -#ifdef __cplusplus -# define PAL_EXTERN_C extern "C" -#else -# define PAL_EXTERN_C extern -#endif /* __cplusplus */ - -/* -**============================================================================== -** -** PAL_INLINE macro -** -**============================================================================== -*/ - -#if defined(_MSC_VER) -# define PAL_INLINE static __inline -#elif defined(__GNUC__) -# define PAL_INLINE static __inline -#elif defined(sun) -# define PAL_INLINE static inline -#elif defined(__PPC) -# define PAL_INLINE __inline__ -#else -# define PAL_INLINE static __inline -#endif - -/* -**============================================================================== -** -** PAL string -** -**============================================================================== -*/ - -#if defined(CONFIG_ENABLE_WCHAR) -typedef wchar_t PAL_Char; -#else -typedef char PAL_Char; -#endif - -typedef PAL_Char TChar; - -/* -**============================================================================== -** -** PAL_T() -** -**============================================================================== -*/ - -#if defined(CONFIG_ENABLE_WCHAR) -# define __PAL_T(STR) L ## STR -# define PAL_T(STR) __PAL_T(STR) -#else -# define PAL_T(STR) STR -#endif - -/* -**============================================================================== -** -** PAL_UNUSED -** -**============================================================================== -*/ - -#define PAL_UNUSED(X) ((void)X) - -/* -**============================================================================== -** -** PAL_HAVE_POSIX -** -**============================================================================== -*/ - -#if defined(linux) || defined(sun) || defined(hpux) || defined(aix) -# define PAL_HAVE_POSIX -#endif - -/* -**============================================================================== -** -** PAL_HAVE_PTHREADS -** -**============================================================================== -*/ - -#if defined(linux) | defined(sun) | defined(hpux) | defined(aix) -# define PAL_HAVE_PTHREADS -#endif - -/* -**============================================================================== -** -** Basic types -** -**============================================================================== -*/ - -typedef unsigned char PAL_Uint8; -#define PAL_UINT8_MAX (UCHAR_MAX) - -typedef signed char PAL_Sint8; -#define PAL_SINT8_MIN (SCHAR_MIN) -#define PAL_SINT8_MAX (SCHAR_MAX) - -typedef unsigned short PAL_Uint16; -#define PAL_UINT16_MAX (USHRT_MAX) - -typedef signed short PAL_Sint16; -#define PAL_SINT16_MIN (SHRT_MIN) -#define PAL_SINT16_MAX (SHRT_MAX) - -typedef unsigned int PAL_Uint32; -#define PAL_UINT32_MAX (UINT_MAX) - -typedef signed int PAL_Sint32; -#define PAL_SINT32_MIN (INT_MIN) -#define PAL_SINT32_MAX (INT_MAX) - -#if defined(_MSC_VER) -typedef unsigned __int64 PAL_Uint64; -typedef signed __int64 PAL_Sint64; -#else -typedef unsigned long long PAL_Uint64; -typedef signed long long PAL_Sint64; -#endif -#define PAL_UINT64_MIN ((PAL_Uint64) 0ULL) -#define PAL_UINT64_MAX ((PAL_Uint64) 18446744073709551615ULL) -#define PAL_SINT64_MIN ((PAL_Sint64) (-9223372036854775807LL - 1LL)) -#define PAL_SINT64_MAX ((PAL_Sint64) 9223372036854775807LL ) - -typedef unsigned char PAL_Boolean; - -#define PAL_TRUE ((PAL_Boolean)1) -#define PAL_FALSE ((PAL_Boolean)0) - -/* -**============================================================================== -** -** Function calling conventions -** -**============================================================================== -*/ - -#ifdef _MSC_VER -# define PAL_CDECLAPI __cdecl -#else -# define PAL_CDECLAPI -#endif - -#define ATEXIT_API PAL_CDECLAPI - -/* -**============================================================================== -** -** SAL Notation for non-Windows platforms -** -**============================================================================== -*/ - -#if !defined(_MSC_VER) - -# ifndef _In_ -# define _In_ -# endif - -# ifndef _Out_ -# define _Out_ -# endif - -# ifndef _Inout_ -# define _Inout_ -# endif - -# ifndef _Return_type_success_ -# define _Return_type_success_(x) -# endif - -# ifndef _Acquires_lock_ -# define _Acquires_lock_(x) -# endif - -# ifndef _Releases_lock_ -# define _Releases_lock_(x) -# endif - -# ifndef _In_z_ -# define _In_z_ -# endif - -# ifndef _Post_z_ -# define _Post_z_ -# endif - -# ifndef _Out_writes_ -# define _Out_writes_(size) -# endif - -# ifndef _Out_writes_z_ -# define _Out_writes_z_(size) -# endif - -# ifndef _Null_terminated_ -# define _Null_terminated_ -# endif - -# ifndef _Use_decl_annotations_ -# define _Use_decl_annotations_ -# endif - -# ifndef _Out_opt_ -# define _Out_opt_ -# endif - -# ifndef _Deref_post_z_ -# define _Deref_post_z_ -# endif - -# ifndef _Inout_updates_z_ -# define _Inout_updates_z_(count) -# endif - -# ifndef _Inout_opt_z_ -# define _Inout_opt_z_ -# endif - -# ifndef _Deref_prepost_opt_z_ -# define _Deref_prepost_opt_z_ -# endif - -# ifndef _In_opt_ -# define _In_opt_ -# endif - -# ifndef _In_opt_z_ -# define _In_opt_z_ -# endif - -# ifndef _Ret_maybenull_ -# define _Ret_maybenull_ -# endif - -# ifndef _Check_return_ -# define _Check_return_ -# endif - -# ifndef _Must_inspect_result_ -# define _Must_inspect_result_ -# endif - -# ifndef _Frees_ptr_opt_ -# define _Frees_ptr_opt_ -# endif - -# ifndef _Frees_ptr_ -# define _Frees_ptr_ -# endif - -# ifndef _Const_ -# define _Const_ -# endif - -# ifndef _Post_writable_byte_size -# define _Post_writable_byte_size(size) -# endif - -# ifndef _Analysis_assume_ -# define _Analysis_assume_(expr) -# endif - -# ifndef _Always_ -# define _Always_(expr) -# endif - -# ifndef _Outptr_ -# define _Outptr_ -# endif - -# ifndef _Outptr_result_buffer_ -# define _Outptr_result_buffer_(size) -# endif - -# ifndef _Outptr_result_nullonfailure_ -# define _Outptr_result_nullonfailure_ -# endif - -# ifndef _Maybenull_ -# define _Maybenull_ -# endif - -# ifndef _Notnull_ -# define _Notnull_ -# endif - -# ifndef _Valid_ -# define _Valid_ -# endif - -# ifndef _Analysis_noreturn_ -# define _Analysis_noreturn_ -# endif - -# ifndef _Ret_writes_maybenull_z_ -# define _Ret_writes_maybenull_z_(count) -# endif - -# ifndef _String_length_ -# define _String_length_(str) -# endif - -# ifndef _Success_ -# define _Success_ -# endif - -# ifndef _Field_range_ -# define _Field_range_(min, max) -# endif - -# ifndef _In_range_ -# define _In_range_(min, max) -# endif - -# ifndef _Field_size_ -# define _Field_size_(count) -# endif - -# ifndef _Field_size_opt_ -# define _Field_size_opt_(count) -# endif - -# ifndef _Field_size_full_opt_ -# define _Field_size_full_opt_(count) -# endif - -# ifndef _Field_size_bytes_opt_ -# define _Field_size_bytes_opt_(size) -# endif - -# ifndef _Readable_elements_ -# define _Readable_elements_(count) -# endif - -# ifndef _Writable_elements_ -# define _Writable_elements_(count) -# endif - -# ifndef _Struct_size_bytes_ -# define _Struct_size_bytes_(size) -# endif - -# ifndef _At_ -# define _At_(target, annotation) -# endif - -# ifndef _Pre_satisfies_ -# define _Pre_satisfies_(expr) -# endif - -# ifndef _On_failure_ -# define _On_failure_(expr) -# endif - -# ifndef _In_bytecount_ -# define _In_bytecount_(size) -# endif - -# ifndef _Out_writes_bytes_to_opt_ -# define _Out_writes_bytes_to_opt_(buffLen, bufferNeeded) -# endif - -# ifndef _When_ -# define _When_(expr, annotation) -# endif - -# ifndef _Analysis_assume_nullterminated_ -# define _Analysis_assume_nullterminated_(expr) -# endif - - -#endif /* !defined(_MSC_VER) */ - -/* -**============================================================================== -** -** PAL_MAX_PATH_SIZE -** -**============================================================================== -*/ - -#define PAL_MAX_PATH_SIZE 1024 - -/* -**============================================================================== -** -** PAL_COUNT -** -**============================================================================== -*/ - -#ifdef _MSC_VER -# define PAL_COUNT(ARR) _countof(ARR) -#else -# define PAL_COUNT(ARR) (sizeof(ARR) / sizeof(ARR[0])) -#endif diff --git a/native/terminal.cpp b/native/terminal.cpp index c32192802..44fadd084 100644 --- a/native/terminal.cpp +++ b/native/terminal.cpp @@ -1,7 +1,7 @@ #include "terminal.h" #include -INT32 GetTerminalWidth() +int32_t GetTerminalWidth() { struct winsize ws; if (-1 == ioctl(0,TIOCGWINSZ,&ws)) @@ -10,7 +10,7 @@ INT32 GetTerminalWidth() return ws.ws_col; } -INT32 GetTerminalHeight() +int32_t GetTerminalHeight() { struct winsize ws; if (-1 == ioctl(0,TIOCGWINSZ,&ws)) diff --git a/native/terminal.h b/native/terminal.h index 00332e9bf..e036bc849 100644 --- a/native/terminal.h +++ b/native/terminal.h @@ -4,8 +4,8 @@ PAL_BEGIN_EXTERNC -INT32 GetTerminalWidth(); -INT32 GetTerminalHeight(); +int32_t GetTerminalWidth(); +int32_t GetTerminalHeight(); PAL_END_EXTERNC diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index c783ff003..2a6bf5e0f 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -2,26 +2,33 @@ //! @author George Fleming //! @brief Unit tests for GetComputerName -#include -#include #include #include "getcomputername.h" //! Test fixture for GetComputerNameTest class GetComputerNameTest : public ::testing::Test { -protected: - char expectedComputerName[HOST_NAME_MAX]; - - //Get expected result from using linux call - GetComputerNameTest() - { - BOOL ret = gethostname(expectedComputerName, HOST_NAME_MAX); - EXPECT_EQ(0, ret); - } }; TEST_F(GetComputerNameTest, ValidateLinuxGetHostnameSystemCall) { + char expectedComputerName[NAME_MAX]; + + //Get expected result from using linux command + + FILE *fPtr = popen("hostname -s", "r"); + ASSERT_TRUE(fPtr != NULL); + + char *linePtr = fgets(expectedComputerName, sizeof(expectedComputerName), fPtr); + ASSERT_TRUE(linePtr != NULL); + + // There's a tendency to have \n at end of fgets string, so remove it before compare + size_t sz = strlen(expectedComputerName); + if (sz > 0 && expectedComputerName[sz - 1] == '\n') + { + expectedComputerName[sz - 1] = '\0'; + } + pclose(fPtr); + ASSERT_STREQ(GetComputerName(), expectedComputerName); } diff --git a/tests/test-getcurrentprocessid.cpp b/tests/test-getcurrentprocessid.cpp index 9803b6612..a1d10a0be 100644 --- a/tests/test-getcurrentprocessid.cpp +++ b/tests/test-getcurrentprocessid.cpp @@ -4,13 +4,13 @@ // This is a very simple test case to show how tests can be written TEST(GetCurrentProcessId,simple) { - const HANDLE currentProcessId = GetCurrentProcessId(); + const int32_t currentProcessId = GetCurrentProcessId(); const pid_t pid = getpid(); // first make sure that on this platform those types are of the same size - ASSERT_TRUE(sizeof(HANDLE) >= sizeof(pid_t)); + ASSERT_TRUE(sizeof(int32_t) >= sizeof(pid_t)); // now compare the actual values - ASSERT_EQ(currentProcessId,reinterpret_cast(pid)); + ASSERT_EQ(currentProcessId,static_cast(pid)); } diff --git a/tests/test-getfullyqualifiedname.cpp b/tests/test-getfullyqualifiedname.cpp index 9ec01e27f..dc49114d0 100644 --- a/tests/test-getfullyqualifiedname.cpp +++ b/tests/test-getfullyqualifiedname.cpp @@ -2,7 +2,6 @@ //! @author George Fleming //! @brief Unit tests for GetFullyQualifiedName -#include #include #include "getfullyqualifiedname.h" @@ -13,7 +12,7 @@ class GetFullyQualifiedNameTest : public ::testing::Test TEST_F(GetFullyQualifiedNameTest, ValidateLinuxGetFullyQualifiedDomainName) { - char expectedComputerName[HOST_NAME_MAX]; + char expectedComputerName[NAME_MAX]; //Get expected result from using linux command diff --git a/tests/test-getlinkcount.cpp b/tests/test-getlinkcount.cpp index b01ddbbee..fbe1a001f 100644 --- a/tests/test-getlinkcount.cpp +++ b/tests/test-getlinkcount.cpp @@ -15,19 +15,24 @@ class getLinkCountTest : public ::testing::Test { protected: - std::string file; - const std::string fileTemplate = "/tmp/createFile.XXXXXXX"; - ulong count; + static const int bufSize = 64; + const std::string fileTemplate = "/tmp/createFile.XXXXXX"; + char fileTemplateBuf[bufSize]; + + int32_t count; + char *file; getLinkCountTest() { - file = fileTemplate; - file = mktemp(const_cast(file.c_str())); - std::ifstream fileCondition(file); - EXPECT_EQ(0, fileCondition.good()); + // since mkstemp modifies the template string, let's give it writable buffer + strcpy(fileTemplateBuf, fileTemplate.c_str()); + + int fd = mkstemp(fileTemplateBuf); + EXPECT_TRUE(fd != -1); + file = fileTemplateBuf; } - void createFileForTesting(std::string theFile) + void createFileForTesting(const std::string &theFile) { std::ofstream ofs; ofs.open(theFile, std::ofstream::out); @@ -35,25 +40,25 @@ protected: ofs.close(); } - std::string createHardLink(std::string origFile) + std::string createHardLink(const std::string &origFile) { std::string newFile = origFile + "_link"; - int ret = link(const_cast(origFile.c_str()), const_cast(newFile.c_str())); + int ret = link(origFile.c_str(), newFile.c_str()); EXPECT_EQ(0, ret); return newFile; } - void removeFile(std::string fileName) + void removeFile(const std::string &fileName) { - int ret = unlink(const_cast(fileName.c_str())); + int ret = unlink(fileName.c_str()); EXPECT_EQ(0, ret); } }; TEST_F(getLinkCountTest, FilePathNameIsNull) { - bool retVal = GetLinkCount(NULL, &count ); + int32_t retVal = GetLinkCount(NULL, &count ); ASSERT_FALSE(retVal); EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); } @@ -61,7 +66,7 @@ TEST_F(getLinkCountTest, FilePathNameIsNull) TEST_F(getLinkCountTest, FilePathNameDoesNotExist) { std::string invalidFile = "/tmp/createFile"; - bool retVal = GetLinkCount(const_cast(invalidFile.c_str()), &count); + int32_t retVal = GetLinkCount(invalidFile.c_str(), &count); ASSERT_FALSE(retVal); EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno); } @@ -69,7 +74,7 @@ TEST_F(getLinkCountTest, FilePathNameDoesNotExist) TEST_F(getLinkCountTest, LinkCountOfSinglyLinkedFile) { createFileForTesting(file); - bool retVal = GetLinkCount(const_cast(file.c_str()), &count); + int32_t retVal = GetLinkCount(file, &count); ASSERT_TRUE(retVal); EXPECT_EQ(1, count); @@ -80,7 +85,7 @@ TEST_F(getLinkCountTest, LinkCountOfMultipliLinkedFile) { createFileForTesting(file); std::string newFile = createHardLink(file); - bool retVal = GetLinkCount(const_cast(file.c_str()), &count); + int32_t retVal = GetLinkCount(file, &count); ASSERT_TRUE(retVal); EXPECT_EQ(2, count); diff --git a/tests/test-issymlink.cpp b/tests/test-issymlink.cpp index 41515fbc3..4aaa3eb54 100644 --- a/tests/test-issymlink.cpp +++ b/tests/test-issymlink.cpp @@ -14,8 +14,8 @@ class isSymLinkTest : public ::testing::Test protected: static const int bufSize = 64; - const string fileTemplate = "/tmp/symlinktest.fXXXXXXX"; - const string dirTemplate = "/tmp/symlinktest.dXXXXXXX"; + const string fileTemplate = "/tmp/symlinktest.fXXXXXX"; + const string dirTemplate = "/tmp/symlinktest.dXXXXXX"; const string fileSymLink = "/tmp/symlinktest.flink"; const string dirSymLink = "/tmp/symlinktest.dlink"; char *file, *dir; From 102f6163a17afec6e27107ec0fdfec5fd458c706 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Tue, 3 Nov 2015 08:26:36 -0800 Subject: [PATCH 260/342] Remove unnecessary code --- native/isexecutable.cpp | 10 ++-------- native/issymlink.h | 2 +- native/pal.h | 22 ---------------------- 3 files changed, 3 insertions(+), 31 deletions(-) diff --git a/native/isexecutable.cpp b/native/isexecutable.cpp index dab536295..be49afb3c 100644 --- a/native/isexecutable.cpp +++ b/native/isexecutable.cpp @@ -1,6 +1,6 @@ //! @file isExecutable.cpp //! @author George FLeming -//! @brief returns whether a path is executable +//! @brief returns whether a file is executable #include #include @@ -21,19 +21,13 @@ //! @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_FILE_NOT_FOUND: file does not exist -//! - ERROR_ACCESS_DENIED: access is denied //! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified //! - ERROR_INVALID_ADDRESS: attempt to access invalid address -//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link //! - ERROR_GEN_FAILURE: device attached to the system is not functioning -//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file //! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect -//! - ERROR_BUFFER_OVERFLOW: file name is too long //! - ERROR_INVALID_FUNCTION: incorrect function -//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters +//! - ERROR_INVALID_PARAMETER: parameter to access(2) call is incorrect //! //! @retval 1 if path is an executable //! @retval 0 if path is not a executable diff --git a/native/issymlink.h b/native/issymlink.h index 3ba5e48ac..066a4060c 100644 --- a/native/issymlink.h +++ b/native/issymlink.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -long IsSymLink(const char* fileName); +int32_t IsSymLink(const char* fileName); PAL_END_EXTERNC diff --git a/native/pal.h b/native/pal.h index 421bbf0a8..2b97aee1d 100644 --- a/native/pal.h +++ b/native/pal.h @@ -8,28 +8,6 @@ # define NAME_MAX 255 #endif -/* typedef unsigned long DWORD, *LPDWORD; - typedef char BOOL; - typedef unsigned short WCHAR_T; - typedef unsigned int UINT32; - typedef int INT32; - typedef unsigned long HRESULT; - typedef const wchar_t *PCWSTR; - typedef wchar_t *PWSTR; - typedef const char *PCSTR; - typedef char *PSTR; - typedef void *PVOID; - typedef PVOID HANDLE; - typedef uint32_t UINT; - typedef char BYTE; - #define NO_ERROR 0 - #define INFINITE 0xFFFFFFFF - #define WINAPI - #define S_OK 0 - #define TRUE 1 - #define FALSE 0 -*/ - #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 #define ERROR_BAD_ENVIRONMENT 0x0000000A From dfea2bf9274ecf42ae6f06714c65c17947a5426d Mon Sep 17 00:00:00 2001 From: George Fleming Date: Wed, 4 Nov 2015 08:53:54 -0800 Subject: [PATCH 261/342] Further cleanup of pal.h --- native/pal.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/native/pal.h b/native/pal.h index 2b97aee1d..d47b2845e 100644 --- a/native/pal.h +++ b/native/pal.h @@ -3,10 +3,7 @@ #include #include #include - -#ifndef NAME_MAX -# define NAME_MAX 255 -#endif +#include #define ERROR_INVALID_PARAMETER 87 #define ERROR_OUTOFMEMORY 14 @@ -16,7 +13,6 @@ #define ERROR_NO_ASSOCIATION 0x00000483 #define ERROR_NO_SUCH_USER 0x00000525 #define ERROR_INVALID_FUNCTION 0x00000001 -#define MAX_PATH 0x00000104 #define ERROR_INVALID_ADDRESS 0x000001e7 #define ERROR_GEN_FAILURE 0x0000001F #define ERROR_ACCESS_DENIED 0x00000005 From d5c0ad08cb3f8438ce599152c2fe3868046b67ee Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 4 Nov 2015 20:30:52 -0800 Subject: [PATCH 262/342] Fix test since gethostname gets the nodename The nodename is not necessarily the short name returned by hostname. --- native/getcomputername.cpp | 3 ++- tests/test-getcomputername.cpp | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 67e3d870d..70a52a684 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -33,7 +33,8 @@ char* GetComputerName() return NULL; } - // Get computername from system in a thread-safe manner + // Get computername from system, not that gethostname gets the + // nodename from uname std::string computername(NAME_MAX, 0); int err = gethostname(&computername[0], computername.length()); // Map errno to Win32 Error Codes diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index 2a6bf5e0f..5820d0565 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -10,13 +10,12 @@ class GetComputerNameTest : public ::testing::Test { }; -TEST_F(GetComputerNameTest, ValidateLinuxGetHostnameSystemCall) +TEST_F(GetComputerNameTest, Success) { char expectedComputerName[NAME_MAX]; - //Get expected result from using linux command - - FILE *fPtr = popen("hostname -s", "r"); + // the gethostname system call gets the nodename from uname + FILE *fPtr = popen("uname -n", "r"); ASSERT_TRUE(fPtr != NULL); char *linePtr = fgets(expectedComputerName, sizeof(expectedComputerName), fPtr); From 8c9c9b2284b4bbd79163a303548e2462e97e82b6 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 4 Nov 2015 20:47:28 -0800 Subject: [PATCH 263/342] Fix username tests by checking for null --- tests/test-getusername.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index 50c2d1fea..cab8cb98b 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -10,18 +10,9 @@ #include #include "getusername.h" -//! Test fixture for GetUserName -class GetUserNameTest : public ::testing::Test +TEST(GetUserName, Success) { -protected: - std::string UserName; - - GetUserNameTest(): UserName(std::string(getpwuid(geteuid())->pw_name)) - { - } -}; - -TEST_F(GetUserNameTest, Success) -{ - ASSERT_EQ(GetUserName(), UserName); + char* expected = getpwuid(geteuid())->pw_name; + ASSERT_TRUE(expected != NULL); + ASSERT_EQ(GetUserName(), std::string(expected)); } From 9c6edbc7a1432d993d82ac86f0d8a7daeff97e0e Mon Sep 17 00:00:00 2001 From: Alex Jordan Date: Fri, 6 Nov 2015 23:03:45 +0000 Subject: [PATCH 264/342] Added -Werror to treat all warnings as errors to monad-native CMake --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b61395b0c..e0e4a7ab9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.8.4) project(MONAD_NATIVE) -add_compile_options(-std=c++11 -Wall) +add_compile_options(-std=c++11 -Wall -Werror) # test in BUILD_DIR enable_testing() From 96cda45f342fd82adb4b9604892885b922bb7279 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 6 Nov 2015 19:55:19 -0800 Subject: [PATCH 265/342] Expose pshost's pwrshPath (PowerShell libraries) It's the determined path of the PowerShell libraries (whether specified via PWRSH_ROOT or found relative to the native bin/powershell executable). Like exePath, this is available only after a call to startCoreCLR. --- host/coreclrutil.cpp | 6 +++++- host/coreclrutil.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/host/coreclrutil.cpp b/host/coreclrutil.cpp index eabd73f04..0324105f4 100644 --- a/host/coreclrutil.cpp +++ b/host/coreclrutil.cpp @@ -19,6 +19,7 @@ constexpr char coreClrDll[] = "libcoreclr.so"; void* coreclrLib; char exePath[PATH_MAX]; +char pwrshPath[PATH_MAX]; // Prototype of the coreclr_initialize function from the libcoreclr.so typedef int (*InitializeCoreCLRFunction)( @@ -285,12 +286,15 @@ int startCoreCLR( // add assemblies in the CoreCLR root path AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(), tpaList); - // get path to AssemblyLoadContext.dll + // get path to PowerShell libraries std::string psAbsolutePath; if(!GetPwrshRoot(psAbsolutePath)) { return -1; } + psAbsolutePath.copy(pwrshPath, psAbsolutePath.size(), 0); + + // get path to AssemblyLoadContext.dll std::string alcAbsolutePath(psAbsolutePath); alcAbsolutePath.append("/"); alcAbsolutePath.append("Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"); diff --git a/host/coreclrutil.h b/host/coreclrutil.h index d34487310..843a440ad 100644 --- a/host/coreclrutil.h +++ b/host/coreclrutil.h @@ -48,6 +48,7 @@ extern "C" extern ExecuteAssemblyFunction executeAssembly; extern CreateDelegateFunction createDelegate; + extern char pwrshPath[]; #ifdef __cplusplus } #endif From 0e119de0c95e4a242982c18caadb314ebe89264f Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 6 Nov 2015 19:59:04 -0800 Subject: [PATCH 266/342] Refactor argument parsing for new interface Only one argument is accepted by the native host, which is an optional path to a managed host assembly (aka the PowerShell console). If not specified, lib/powershell/powershell.exe is used by default. All other arguments are forwarded as-is to the managed host. --- host/main.cpp | 102 ++++++++++++++++++-------------------------------- 1 file changed, 36 insertions(+), 66 deletions(-) diff --git a/host/main.cpp b/host/main.cpp index 0b7728d4e..1721b2a14 100644 --- a/host/main.cpp +++ b/host/main.cpp @@ -35,86 +35,48 @@ namespace Cmdline Args() : argc(0), argv(nullptr), - verbose(false) + assembly() { } - std::string entryAssemblyPath; int argc; char** argv; - bool verbose; - - void debugPrint() const - { - std::cerr << "Args:" << std::endl - << "- entryAssemblyPath " << entryAssemblyPath << std::endl - << "- argc " << argc << std::endl - << "- verbose " << (verbose ? "true" : "false") << std::endl; - } + std::string assembly; }; - // this is implemented without any 3rd party lib to keep the list - // of dependencies low - bool parseCmdline(const int argc, char** argv, Args& args) + // checks if string ends with ".exe" + bool isExe(std::string arg) { - if (argc <= 1) - { - std::cerr << "error: missing arguments" << std::endl; - return false; - } - - for (int i = 1; i < argc; ++i) - { - const std::string arg = argv[i]; - const bool hasNextArg = i+1 < argc; - const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string(""); - - if (hasNextArg && arg == "--File") - { - std::cerr << "TODO: should launch script " << nextArg << std::endl; - ++i; - } - else if (arg == "-v") - { - args.verbose = true; - } - else if (args.entryAssemblyPath == "") - { - args.entryAssemblyPath = arg; - } - else - { - // forward command line parameters - args.argc = argc-i; - args.argv = &argv[i]; - - // explicitly break here because the lines above consume all remaining arguments - break; - } - } - - // check for mandatory parameters - if (args.entryAssemblyPath == "") - { - std::cerr << "error: assembly_name argument missing" << std::endl; - } - - return true; + std::size_t dot = arg.find_last_of("."); + return dot == std::string::npos ? false : arg.substr(dot) == ".exe"; } + // simple extraction of assembly.exe so we can run other hosts + void parseCmdline(int argc, char** argv, Args& args) + { + // index of arguments to forward (skip zeroth) + int i = 1; + // if we have any arguments + if (argc > 1) + { + // check if the first is an assembly.exe + const std::string arg = argv[i]; + if (isExe(arg)) + { + args.assembly.assign(arg); + ++i; // don't forward the first argument + } + } + // forward arguments + args.argc = argc - i; + args.argv = &argv[i]; + } } int main(int argc, char** argv) { - // parse the command line arguments Cmdline::Args args; - if (!Cmdline::parseCmdline(argc,argv,args)) - { - Cmdline::printHelp(); - return 1; - } - if (args.verbose) - args.debugPrint(); + Cmdline::parseCmdline(argc, argv, args); void* hostHandle; unsigned int domainId; @@ -129,12 +91,20 @@ int main(int argc, char** argv) return -1; } + // default to powershell.exe if no host specified + if (args.assembly.empty()) + { + args.assembly.assign(pwrshPath); + args.assembly.append("/"); + args.assembly.append("powershell.exe"); + } + // call into Main of assembly unsigned int exitCode; executeAssembly( hostHandle, domainId, args.argc, (const char**)args.argv, - args.entryAssemblyPath.c_str(), + args.assembly.c_str(), &exitCode); status = stopCoreCLR(hostHandle, domainId); From 48af92c286572eb7bfc4552a9dbd3cded995b9b3 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 6 Nov 2015 20:01:29 -0800 Subject: [PATCH 267/342] Update usage text --- host/main.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/host/main.cpp b/host/main.cpp index 1721b2a14..8d76579ce 100644 --- a/host/main.cpp +++ b/host/main.cpp @@ -7,8 +7,8 @@ namespace Cmdline { void printHelp() { - std::cerr << "PowerShell on Linux host" << std::endl - << "Usage: powershell assembly [...]" << std::endl + std::cerr << "PowerShell on Linux native host" << std::endl + << "Usage: powershell [assembly] [...]" << std::endl << std::endl << "What it does:" << std::endl << "- the host assumes that CoreCLR is located $CORE_ROOT," << std::endl @@ -16,18 +16,14 @@ namespace Cmdline << "- the host assumes that the assembly named" << std::endl << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is " << std::endl << " located in $PWRSH_ROOT, else in lib/powershell" << std::endl + << "- the host will launch $PWRSH_ROOT/powershell.exe" << std::endl + << " if not given an explicit assembly.exe" << std::endl << "- all additional parameters at the end of the command line are forwarded" << std::endl << " to the Main function in the assembly" << std::endl << "- the host will execute the Main function in the specified assembly" << std::endl - << " + this must be an absolute path to the assembly" << std::endl - << "- the function signature of the Main function that gets executed must be:" << std::endl - << " static void Main(string[] args)" << std::endl - << std::endl - << "Options:" << std::endl - << "-v verbose output" << std::endl << std::endl << "Example:" << std::endl - << "CORE_ROOT=/test/coreclr PWRSH_ROOT=/test/powershell ./powershell powershell-simple 'get-process'" << std::endl; + << "CORE_ROOT=/test/coreclr PWRSH_ROOT=/test/powershell ./powershell get-process" << std::endl; } struct Args From 22cc11e2d96ae7cd9f131eb5e5e12c71b56fa27b Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 6 Nov 2015 20:01:41 -0800 Subject: [PATCH 268/342] Rename appDomainFriendlyName to psl_cmdline_host --- host/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/main.cpp b/host/main.cpp index 8d76579ce..36bee13da 100644 --- a/host/main.cpp +++ b/host/main.cpp @@ -77,7 +77,7 @@ int main(int argc, char** argv) void* hostHandle; unsigned int domainId; int status = startCoreCLR( - "ps_cmdline_host", + "psl_cmdline_host", &hostHandle, &domainId); From 3bdcf50465b78e781278b630b87dda282a04114a Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 9 Nov 2015 09:46:53 -0800 Subject: [PATCH 269/342] Use HOST_NAME_MAX as specified in gethostname(2) NAME_MAX is the "maximum number of bytes in a filename," which is irrelevant to the gethostname libc function. --- native/getcomputername.cpp | 2 +- tests/test-getcomputername.cpp | 2 +- tests/test-getfullyqualifiedname.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 67e3d870d..3d4e7eda3 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -34,7 +34,7 @@ char* GetComputerName() } // Get computername from system in a thread-safe manner - std::string computername(NAME_MAX, 0); + std::string computername(HOST_NAME_MAX, 0); int err = gethostname(&computername[0], computername.length()); // Map errno to Win32 Error Codes if (err != 0) diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index 2a6bf5e0f..1a170c67d 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -12,7 +12,7 @@ class GetComputerNameTest : public ::testing::Test TEST_F(GetComputerNameTest, ValidateLinuxGetHostnameSystemCall) { - char expectedComputerName[NAME_MAX]; + char expectedComputerName[HOST_NAME_MAX]; //Get expected result from using linux command diff --git a/tests/test-getfullyqualifiedname.cpp b/tests/test-getfullyqualifiedname.cpp index dc49114d0..c34419ab6 100644 --- a/tests/test-getfullyqualifiedname.cpp +++ b/tests/test-getfullyqualifiedname.cpp @@ -12,7 +12,7 @@ class GetFullyQualifiedNameTest : public ::testing::Test TEST_F(GetFullyQualifiedNameTest, ValidateLinuxGetFullyQualifiedDomainName) { - char expectedComputerName[NAME_MAX]; + char expectedComputerName[HOST_NAME_MAX]; //Get expected result from using linux command From f1c8f15fb5541a1a27e9d543bed24018fc4ed81c Mon Sep 17 00:00:00 2001 From: George Fleming Date: Thu, 12 Nov 2015 16:31:30 -0800 Subject: [PATCH 270/342] SetDate function --- native/CMakeLists.txt | 1 + native/setdate.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++ native/setdate.h | 22 +++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 native/setdate.cpp create mode 100644 native/setdate.h diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index 9efaec93c..e2841943d 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -6,6 +6,7 @@ add_library(psnative SHARED getfullyqualifiedname.cpp issymlink.cpp isexecutable.cpp + setdate.cpp terminal.cpp) target_link_libraries(psnative icuuc) diff --git a/native/setdate.cpp b/native/setdate.cpp new file mode 100644 index 000000000..cc9757815 --- /dev/null +++ b/native/setdate.cpp @@ -0,0 +1,73 @@ +//! @file setdate.cpp +//! @author George FLeming +//! @brief set local/system date and time + +#include +#include +#include +#include +#include +#include +#include "setdate.h" + +//! @brief SetDate sets the date and time on local computer. You must +//! be super-user to set the time. +//! +//! SetDate +//! +//! @param[in] info +//! @parblock +//! A struct that contains program to execute and its parameters +//! +//! @exception errno Passes these errors via errno to GetLastError: +//! - ERROR_BAD_ENVIRONMENT: locale is not UTF-8 +//! - ERROR_INVALID_PARAMETER: time was not passed in correctly +//! - ERROR_ACCESS_DENIED: you must be super-user to set the date +//! +//! @retval 0 process successfully started and finished (if we are waiting for process) +//! @retval -1 if failure occurred. To get extended error information, call GetLastError. +//! + + int32_t SetDate(const SetDateInfo &info) +{ + errno = 0; + + // 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 -1; + } + + struct tm bdTime; + struct timeval tv; + + bdTime.tm_year = info.Year - 1900; + bdTime.tm_mon = info.Month - 1; // This is zero-based + bdTime.tm_mday = info.Day; + bdTime.tm_hour = info.Hour; + bdTime.tm_min = info.Minute; + bdTime.tm_min = info.Second; + bdTime.tm_isdst = info.DST; + + time_t newTime = mktime(&bdTime); + if (newTime == -1) + { + errno = ERROR_INVALID_PARAMETER; + return -1; + } + + tv.tv_sec = newTime; + tv.tv_usec = info.Millisecond * 1000; + + int result = settimeofday(&tv, NULL); + if (result == -1) + { + errno = ERROR_ACCESS_DENIED; + return -1; + } + + return 0; +} diff --git a/native/setdate.h b/native/setdate.h new file mode 100644 index 000000000..b55a7d1e7 --- /dev/null +++ b/native/setdate.h @@ -0,0 +1,22 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +typedef struct setDateInfo +{ + // the order of members does matter here + int32_t Year; + int32_t Month; + int32_t Day; + int32_t Hour; + int32_t Minute; + int32_t Second; + int32_t Millisecond; + int32_t DST; +} SetDateInfo; + +int32_t SetDate(const SetDateInfo &info); + +PAL_END_EXTERNC From f2b70e32ba17ffc33a0df0d90c65c203ba644625 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Fri, 13 Nov 2015 10:05:55 -0800 Subject: [PATCH 271/342] Remove microsecond --- native/setdate.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/native/setdate.cpp b/native/setdate.cpp index cc9757815..81bfa3417 100644 --- a/native/setdate.cpp +++ b/native/setdate.cpp @@ -24,11 +24,11 @@ //! - ERROR_INVALID_PARAMETER: time was not passed in correctly //! - ERROR_ACCESS_DENIED: you must be super-user to set the date //! -//! @retval 0 process successfully started and finished (if we are waiting for process) +//! @retval 0 successfully set date //! @retval -1 if failure occurred. To get extended error information, call GetLastError. //! - int32_t SetDate(const SetDateInfo &info) +int32_t SetDate(const SetDateInfo &info) { errno = 0; @@ -49,7 +49,7 @@ bdTime.tm_mday = info.Day; bdTime.tm_hour = info.Hour; bdTime.tm_min = info.Minute; - bdTime.tm_min = info.Second; + bdTime.tm_sec = info.Second; bdTime.tm_isdst = info.DST; time_t newTime = mktime(&bdTime); @@ -60,7 +60,7 @@ } tv.tv_sec = newTime; - tv.tv_usec = info.Millisecond * 1000; + tv.tv_usec = 0; int result = settimeofday(&tv, NULL); if (result == -1) From 284f28f52b900534531134a2fee33982d36b44ad Mon Sep 17 00:00:00 2001 From: Alex Jordan Date: Tue, 24 Nov 2015 23:37:12 +0000 Subject: [PATCH 272/342] Removing explicit test of en_US.UTF-8 in native code and moving to a unit test --- native/getcomputername.cpp | 12 ------------ native/getlinkcount.cpp | 9 --------- native/getusername.cpp | 9 --------- native/isexecutable.cpp | 10 ---------- native/issymlink.cpp | 11 ----------- tests/CMakeLists.txt | 1 + tests/test-locale.cpp | 22 ++++++++++++++++++++++ 7 files changed, 23 insertions(+), 51 deletions(-) create mode 100644 tests/test-locale.cpp diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 9feecf01c..29094e490 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include "getcomputername.h" @@ -22,17 +21,6 @@ char* GetComputerName() { - errno = 0; - - // 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 NULL; - } - // Get computername from system, note that gethostname(2) gets the // nodename from uname std::string computername(HOST_NAME_MAX, 0); diff --git a/native/getlinkcount.cpp b/native/getlinkcount.cpp index dd9ffbb02..9a828216b 100644 --- a/native/getlinkcount.cpp +++ b/native/getlinkcount.cpp @@ -61,15 +61,6 @@ int32_t GetLinkCount(const char* fileName, int32_t *count) 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; - } - struct stat statBuf; int returnCode = lstat(fileName, &statBuf); diff --git a/native/getusername.cpp b/native/getusername.cpp index 30c2b8a14..ce2b865bd 100644 --- a/native/getusername.cpp +++ b/native/getusername.cpp @@ -25,15 +25,6 @@ char* GetUserName() { errno = 0; - // 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 NULL; - } - struct passwd pwd; struct passwd* result; // gets the initial suggested size for buf diff --git a/native/isexecutable.cpp b/native/isexecutable.cpp index be49afb3c..78ffea47b 100644 --- a/native/isexecutable.cpp +++ b/native/isexecutable.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include "isexecutable.h" @@ -45,15 +44,6 @@ int32_t IsExecutable(const char* fileName) return -1; } - // 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 -1; - } - int returnCode = access(fileName, X_OK); if (returnCode == 0) diff --git a/native/issymlink.cpp b/native/issymlink.cpp index 4a4ae5448..c0787ec6b 100644 --- a/native/issymlink.cpp +++ b/native/issymlink.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -45,7 +44,6 @@ int32_t IsSymLink(const char* fileName) { - errno = 0; // Check parameters if (!fileName) @@ -54,15 +52,6 @@ int32_t IsSymLink(const char* fileName) return -1; } - // 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 -1; - } - struct stat statBuf; int returnCode = lstat(fileName, &statBuf); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a065c66c1..b0216f88e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(googletest) add_executable(psnative-test + test-locale.cpp test-getcurrentprocessid.cpp test-getusername.cpp test-getcomputername.cpp diff --git a/tests/test-locale.cpp b/tests/test-locale.cpp new file mode 100644 index 000000000..8588fb494 --- /dev/null +++ b/tests/test-locale.cpp @@ -0,0 +1,22 @@ +//! @file test-locale.cpp +//! @author Alex Jordan +//! @brief Unit tests for linux locale + +#include +#include +#include +#include +#include +//! Test fixture for LocaleTest + +class LocaleTest : public ::testing::Test +{ +}; + +TEST_F(LocaleTest, Success) +{ + setlocale (LC_ALL, ""); + ASSERT_FALSE (nl_langinfo(CODESET) == NULL); + ASSERT_TRUE(nl_langinfo(CODESET) == std::string("UTF-8")); + ASSERT_FALSE(nl_langinfo(CODESET) != std::string("UTF-8")); +} From 6fd5d5d40eab24a4b6ad0ed79241c1c796d63a8c Mon Sep 17 00:00:00 2001 From: Alex Jordan Date: Wed, 25 Nov 2015 00:29:57 +0000 Subject: [PATCH 273/342] Removed LANG dependancies from native fns --- native/getcomputername.cpp | 1 - native/getlinkcount.cpp | 1 - native/getusername.cpp | 1 - native/isexecutable.cpp | 1 - native/issymlink.cpp | 1 - tests/test-locale.cpp | 1 - 6 files changed, 6 deletions(-) diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 29094e490..03ec03517 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -3,7 +3,6 @@ //! @brief Implements GetComputerName Win32 API #include -#include #include #include #include "getcomputername.h" diff --git a/native/getlinkcount.cpp b/native/getlinkcount.cpp index 9a828216b..aab533640 100644 --- a/native/getlinkcount.cpp +++ b/native/getlinkcount.cpp @@ -3,7 +3,6 @@ //! @brief Retrieve link count of a file #include -#include #include #include #include diff --git a/native/getusername.cpp b/native/getusername.cpp index ce2b865bd..923e76e75 100644 --- a/native/getusername.cpp +++ b/native/getusername.cpp @@ -3,7 +3,6 @@ //! @brief Implements GetUserName for Linux #include -#include #include #include #include diff --git a/native/isexecutable.cpp b/native/isexecutable.cpp index 78ffea47b..a243cbc4d 100644 --- a/native/isexecutable.cpp +++ b/native/isexecutable.cpp @@ -3,7 +3,6 @@ //! @brief returns whether a file is executable #include -#include #include #include #include "isexecutable.h" diff --git a/native/issymlink.cpp b/native/issymlink.cpp index c0787ec6b..537a4a160 100644 --- a/native/issymlink.cpp +++ b/native/issymlink.cpp @@ -3,7 +3,6 @@ //! @brief returns whether a path is a symbolic link #include -#include #include #include #include diff --git a/tests/test-locale.cpp b/tests/test-locale.cpp index 8588fb494..043e98910 100644 --- a/tests/test-locale.cpp +++ b/tests/test-locale.cpp @@ -18,5 +18,4 @@ TEST_F(LocaleTest, Success) setlocale (LC_ALL, ""); ASSERT_FALSE (nl_langinfo(CODESET) == NULL); ASSERT_TRUE(nl_langinfo(CODESET) == std::string("UTF-8")); - ASSERT_FALSE(nl_langinfo(CODESET) != std::string("UTF-8")); } From 2fd54306f94546385211c7d66ec716132037ac10 Mon Sep 17 00:00:00 2001 From: Alex Jordan Date: Wed, 25 Nov 2015 00:37:45 +0000 Subject: [PATCH 274/342] Removed BAD_ENVIRONMENT from comments and added errno back to several fns --- native/getcomputername.cpp | 2 +- native/getlinkcount.cpp | 1 - native/getusername.cpp | 1 - native/isexecutable.cpp | 1 - native/issymlink.cpp | 3 ++- 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 03ec03517..0906aa5af 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -11,7 +11,6 @@ //! the current thread. //! //! @exception errno Passes these errors via errno to GetLastError: -//! - ERROR_BAD_ENVIRONMENT: locale is not UTF-8 //! - ERROR_INVALID_FUNCTION: getlogin_r() returned an unrecognized error code //! - ERROR_INVALID_ADDRESS: buffer is an invalid address //! - ERROR_GEN_FAILURE: buffer not large enough @@ -20,6 +19,7 @@ char* GetComputerName() { + errno = 0; // Get computername from system, note that gethostname(2) gets the // nodename from uname std::string computername(HOST_NAME_MAX, 0); diff --git a/native/getlinkcount.cpp b/native/getlinkcount.cpp index aab533640..3d8061876 100644 --- a/native/getlinkcount.cpp +++ b/native/getlinkcount.cpp @@ -30,7 +30,6 @@ //! //! @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_FILE_NOT_FOUND: file does not exist //! - ERROR_ACCESS_DENIED: access is denied //! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified diff --git a/native/getusername.cpp b/native/getusername.cpp index 923e76e75..505291593 100644 --- a/native/getusername.cpp +++ b/native/getusername.cpp @@ -15,7 +15,6 @@ //! //! @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_NO_SUCH_USER: there was no corresponding user //! - ERROR_GEN_FAILURE: sysconf() or getpwuid() failed for unknown reasons //! diff --git a/native/isexecutable.cpp b/native/isexecutable.cpp index a243cbc4d..38f6ad184 100644 --- a/native/isexecutable.cpp +++ b/native/isexecutable.cpp @@ -19,7 +19,6 @@ //! @endparblock //! //! @exception errno Passes these errors via errno to GetLastError: -//! - ERROR_BAD_ENVIRONMENT: locale is not UTF-8 //! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified //! - ERROR_INVALID_ADDRESS: attempt to access invalid address //! - ERROR_GEN_FAILURE: device attached to the system is not functioning diff --git a/native/issymlink.cpp b/native/issymlink.cpp index 537a4a160..a48a9935b 100644 --- a/native/issymlink.cpp +++ b/native/issymlink.cpp @@ -23,7 +23,6 @@ //! //! @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_FILE_NOT_FOUND: file does not exist //! - ERROR_ACCESS_DENIED: access is denied //! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified @@ -44,6 +43,8 @@ int32_t IsSymLink(const char* fileName) { + errno = 0; + // Check parameters if (!fileName) { From d0960b3cf22ccf2aab89ded4d8a40426d0578112 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 7 Dec 2015 15:59:53 -0800 Subject: [PATCH 275/342] Refactor host for dotnet-cli - Now uses Boost - No longer uses libicu --- host/CMakeLists.txt | 13 ++-- host/coreclrutil.cpp | 162 ++++++------------------------------------- host/coreclrutil.h | 2 +- host/main.cpp | 16 ++--- 4 files changed, 37 insertions(+), 156 deletions(-) diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index cdca0049d..985bc8bb7 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -1,10 +1,11 @@ add_library(pshost STATIC coreclrutil.cpp) -target_link_libraries(pshost dl icuuc) +target_link_libraries(pshost dl ${Boost_LIBRARIES}) +target_include_directories(pshost PRIVATE ${Boost_INCLUDE_DIRS}) target_compile_options(pshost PRIVATE -fPIC) -add_executable(powershell main.cpp) -target_link_libraries(powershell pshost) +set(Boost_USE_STATIC_LIBS ON) +find_package(Boost 1.54.0 REQUIRED COMPONENTS filesystem system) -install(TARGETS powershell pshost - RUNTIME DESTINATION bin - ARCHIVE DESTINATION lib) +# simple native host executable test +add_executable(powershell main.cpp) +target_link_libraries(powershell pshost ${Boost_LIBRARIES}) diff --git a/host/coreclrutil.cpp b/host/coreclrutil.cpp index 0324105f4..daffd4cc0 100644 --- a/host/coreclrutil.cpp +++ b/host/coreclrutil.cpp @@ -1,14 +1,12 @@ #include "coreclrutil.h" #include #include -#include -#include #include -#include -#include #include #include -#include + +#include +using namespace boost; // The name of the CoreCLR native runtime DLL #if defined(__APPLE__) @@ -18,8 +16,7 @@ constexpr char coreClrDll[] = "libcoreclr.so"; #endif void* coreclrLib; -char exePath[PATH_MAX]; -char pwrshPath[PATH_MAX]; +char coreRoot[PATH_MAX]; // Prototype of the coreclr_initialize function from the libcoreclr.so typedef int (*InitializeCoreCLRFunction)( @@ -41,93 +38,22 @@ ShutdownCoreCLRFunction shutdownCoreCLR; ExecuteAssemblyFunction executeAssembly; CreateDelegateFunction createDelegate; -// -// Below is from unixcoreruncommon/coreruncommon.cpp -// - -bool GetAbsolutePath(const char* path, std::string& absolutePath) -{ - char realPath[PATH_MAX]; - if (realpath(path, realPath) != nullptr && realPath[0] != '\0') - { - absolutePath.assign(realPath); - // realpath should return canonicalized path without the trailing slash - assert(absolutePath.back() != '/'); - return true; - } - - std::cerr << "failed to get absolute path for " << path << std::endl; - return false; -} - -// TODO use dirname -bool GetDirectory(const char* absolutePath, std::string& directory) -{ - directory.assign(absolutePath); - size_t lastSlash = directory.rfind('/'); - if (lastSlash != std::string::npos) - { - directory.erase(lastSlash); - return true; - } - - std::cerr << "failed to get directory for " << absolutePath << std::endl; - return false; -} - // // Get the absolute path given the environment variable. // // Return true in case of a success, false otherwise. // -bool GetEnvAbsolutePath(const char* envVar, std::string& absolutePath) +filesystem::path GetEnvAbsolutePath(const char* env) { - const char* filesPathLocal = std::getenv(envVar);; - if (filesPathLocal == nullptr) - { - return false; - } + const char* local = std::getenv(env); + if (!local) + return nullptr; - return GetAbsolutePath(filesPathLocal, absolutePath); -} - -// -// Get the a root path given an environment variable and default -// relative to exePath -// -bool GetRootPath(const char* envVar, - const char* relativePath, - std::string& absolutePath) -{ - if (!GetEnvAbsolutePath(envVar, absolutePath)) - { - // Default to bin/relativePath - std::string path; - if (!GetDirectory(exePath, path)) - { - return false; - } - path.append("/"); - path.append(relativePath); - return GetAbsolutePath(path.c_str(), absolutePath); - } - - return true; -} - -// Get the PowerShell root path, with sensible default -bool GetPwrshRoot(std::string& absolutePath) -{ - return GetRootPath("PWRSH_ROOT", "../lib/powershell", absolutePath); -} - -// Get the CoreCLR root path, with sensible default -bool GetCoreRoot(std::string& absolutePath) -{ - return GetRootPath("CORE_ROOT", "../lib/coreclr", absolutePath); + return filesystem::canonical(local); } // Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. +// Note: copied from unixcorerun void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) { const char * const tpaExtensions[] = { @@ -229,27 +155,30 @@ int startCoreCLR( void** hostHandle, unsigned int* domainId) { + char exePath[PATH_MAX]; + // get path to current executable readlink("/proc/self/exe", exePath, PATH_MAX); // get the CoreCLR root path - std::string clrAbsolutePath; - if(!GetCoreRoot(clrAbsolutePath)) + auto clrAbsolutePath = GetEnvAbsolutePath("CORE_ROOT"); + if(!clrAbsolutePath.is_absolute()) { + std::cerr << "Failed to get CORE_ROOT path" << std::endl; return -1; } + // copy to shared buffer + clrAbsolutePath.native().copy(coreRoot, clrAbsolutePath.native().size(), 0); // get the CoreCLR shared library path - std::string coreClrDllPath(clrAbsolutePath); - coreClrDllPath.append("/"); - coreClrDllPath.append(coreClrDll); + filesystem::path coreClrDllPath(clrAbsolutePath); + coreClrDllPath /= coreClrDll; // open the shared library coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); if (coreclrLib == nullptr) { - char* error = dlerror(); - std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl; + std::cerr << "dlopen failed to open the CoreCLR library: " << dlerror() << std::endl; return -1; } @@ -286,30 +215,6 @@ int startCoreCLR( // add assemblies in the CoreCLR root path AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(), tpaList); - // get path to PowerShell libraries - std::string psAbsolutePath; - if(!GetPwrshRoot(psAbsolutePath)) - { - return -1; - } - psAbsolutePath.copy(pwrshPath, psAbsolutePath.size(), 0); - - // get path to AssemblyLoadContext.dll - std::string alcAbsolutePath(psAbsolutePath); - alcAbsolutePath.append("/"); - alcAbsolutePath.append("Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"); - - // add AssemblyLoadContext - tpaList.append(alcAbsolutePath); - - // generate the assembly search paths - std::string appPath(psAbsolutePath); - // TODO: add LD_LIBRARY_PATH? - - std::string nativeDllSearchDirs(appPath); - nativeDllSearchDirs.append(":"); - nativeDllSearchDirs.append(clrAbsolutePath); - // create list of properties to initialize CoreCLR const char* propertyKeys[] = { "TRUSTED_PLATFORM_ASSEMBLIES", @@ -321,9 +226,9 @@ int startCoreCLR( const char* propertyValues[] = { tpaList.c_str(), - appPath.c_str(), - appPath.c_str(), - nativeDllSearchDirs.c_str(), + clrAbsolutePath.c_str(), + clrAbsolutePath.c_str(), + clrAbsolutePath.c_str(), "UseLatestBehaviorWhenTFMNotSpecified" }; @@ -343,27 +248,6 @@ int startCoreCLR( return -1; } - // initialize PowerShell's custom assembly load context - typedef void (*LoaderRunHelperFp)(const char16_t* appPath); - LoaderRunHelperFp loaderDelegate = nullptr; - status = createDelegate( - *hostHandle, - *domainId, - "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", - "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", - "SetPowerShellAssemblyLoadContext", - (void**)&loaderDelegate); - - if (!SUCCEEDED(status)) - { - std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; - return -1; - } - - icu::UnicodeString psUnicodeAbsolutePath = icu::UnicodeString::fromUTF8(psAbsolutePath.c_str()); - - loaderDelegate((const char16_t*)psUnicodeAbsolutePath.getTerminatedBuffer()); - return status; } diff --git a/host/coreclrutil.h b/host/coreclrutil.h index 843a440ad..8fb99c79f 100644 --- a/host/coreclrutil.h +++ b/host/coreclrutil.h @@ -48,7 +48,7 @@ extern "C" extern ExecuteAssemblyFunction executeAssembly; extern CreateDelegateFunction createDelegate; - extern char pwrshPath[]; + extern char coreRoot[]; #ifdef __cplusplus } #endif diff --git a/host/main.cpp b/host/main.cpp index 36bee13da..dcb39be0e 100644 --- a/host/main.cpp +++ b/host/main.cpp @@ -11,19 +11,15 @@ namespace Cmdline << "Usage: powershell [assembly] [...]" << std::endl << std::endl << "What it does:" << std::endl - << "- the host assumes that CoreCLR is located $CORE_ROOT," << std::endl - << " else in lib/coreclr" - << "- the host assumes that the assembly named" << std::endl - << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is " << std::endl - << " located in $PWRSH_ROOT, else in lib/powershell" << std::endl - << "- the host will launch $PWRSH_ROOT/powershell.exe" << std::endl - << " if not given an explicit assembly.exe" << std::endl + << "- the host assumes that PSL has been published to $CORE_ROOT," << std::endl + << "- the host will launch $CORE_ROOT/Microsoft.PowerShell.Linux.Host.dll" << std::endl + << " if not given an explicit assembly" << std::endl << "- all additional parameters at the end of the command line are forwarded" << std::endl << " to the Main function in the assembly" << std::endl << "- the host will execute the Main function in the specified assembly" << std::endl << std::endl << "Example:" << std::endl - << "CORE_ROOT=/test/coreclr PWRSH_ROOT=/test/powershell ./powershell get-process" << std::endl; + << "CORE_ROOT=/test/coreclr ./powershell get-process" << std::endl; } struct Args @@ -90,9 +86,9 @@ int main(int argc, char** argv) // default to powershell.exe if no host specified if (args.assembly.empty()) { - args.assembly.assign(pwrshPath); + args.assembly.append(coreRoot); args.assembly.append("/"); - args.assembly.append("powershell.exe"); + args.assembly.append("Microsoft.PowerShell.Linux.Host.dll"); } // call into Main of assembly From 418b947f38ec5b2b35b3fd4707277e5e2b91aea2 Mon Sep 17 00:00:00 2001 From: Paul Allen Date: Mon, 7 Dec 2015 17:11:05 -0800 Subject: [PATCH 276/342] Null terminate exePath --- host/coreclrutil.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/host/coreclrutil.cpp b/host/coreclrutil.cpp index daffd4cc0..0ccbb9bd6 100644 --- a/host/coreclrutil.cpp +++ b/host/coreclrutil.cpp @@ -158,7 +158,10 @@ int startCoreCLR( char exePath[PATH_MAX]; // get path to current executable - readlink("/proc/self/exe", exePath, PATH_MAX); + ssize_t len = readlink("/proc/self/exe", exePath, PATH_MAX); + if (len == -1 || len == sizeof(exePath)) + len = 0; + exePath[len] = '\0'; // get the CoreCLR root path auto clrAbsolutePath = GetEnvAbsolutePath("CORE_ROOT"); From a33977edb26b22e0bf8ea9a3bf8f9d9464478fb4 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 9 Dec 2015 09:57:08 -0800 Subject: [PATCH 277/342] Resurrect PowerShell's AssemblyLoadContext --- host/CMakeLists.txt | 2 +- host/coreclrutil.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 985bc8bb7..94b132a3e 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -1,5 +1,5 @@ add_library(pshost STATIC coreclrutil.cpp) -target_link_libraries(pshost dl ${Boost_LIBRARIES}) +target_link_libraries(pshost dl icuuc ${Boost_LIBRARIES}) target_include_directories(pshost PRIVATE ${Boost_INCLUDE_DIRS}) target_compile_options(pshost PRIVATE -fPIC) diff --git a/host/coreclrutil.cpp b/host/coreclrutil.cpp index 0ccbb9bd6..679cecb15 100644 --- a/host/coreclrutil.cpp +++ b/host/coreclrutil.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include using namespace boost; @@ -251,6 +253,30 @@ int startCoreCLR( return -1; } + // initialize PowerShell's custom assembly load context + filesystem::path alcAbsolutePath(clrAbsolutePath); + alcAbsolutePath /= "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"; + + typedef void (*LoaderRunHelperFp)(const char16_t* appPath); + LoaderRunHelperFp loaderDelegate = nullptr; + status = createDelegate( + *hostHandle, + *domainId, + "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, PublicKeyToken=null", + "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", + "SetPowerShellAssemblyLoadContext", + (void**)&loaderDelegate); + + if (!SUCCEEDED(status)) + { + std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; + return -1; + } + + icu::UnicodeString psUnicodeAbsolutePath = icu::UnicodeString::fromUTF8(clrAbsolutePath.c_str()); + + loaderDelegate((const char16_t*)psUnicodeAbsolutePath.getTerminatedBuffer()); + return status; } From e2b2279fcb8e447926be8d71d747a82aa35a8432 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 15 Dec 2015 14:23:09 -0800 Subject: [PATCH 278/342] Remove icuuc dependency from host Broke this dependency by changing the `SetPowerShellAssemblyLoadContext()` function to expect an LPStr on Linux, instead of an LPWStr, which is easier to deal with because .NET can marshal an LPStr automatically. --- host/CMakeLists.txt | 2 +- host/coreclrutil.cpp | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 94b132a3e..985bc8bb7 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -1,5 +1,5 @@ add_library(pshost STATIC coreclrutil.cpp) -target_link_libraries(pshost dl icuuc ${Boost_LIBRARIES}) +target_link_libraries(pshost dl ${Boost_LIBRARIES}) target_include_directories(pshost PRIVATE ${Boost_INCLUDE_DIRS}) target_compile_options(pshost PRIVATE -fPIC) diff --git a/host/coreclrutil.cpp b/host/coreclrutil.cpp index 679cecb15..1a27d359f 100644 --- a/host/coreclrutil.cpp +++ b/host/coreclrutil.cpp @@ -5,8 +5,6 @@ #include #include -#include - #include using namespace boost; @@ -257,7 +255,7 @@ int startCoreCLR( filesystem::path alcAbsolutePath(clrAbsolutePath); alcAbsolutePath /= "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"; - typedef void (*LoaderRunHelperFp)(const char16_t* appPath); + typedef void (*LoaderRunHelperFp)(const char* appPath); LoaderRunHelperFp loaderDelegate = nullptr; status = createDelegate( *hostHandle, @@ -273,9 +271,7 @@ int startCoreCLR( return -1; } - icu::UnicodeString psUnicodeAbsolutePath = icu::UnicodeString::fromUTF8(clrAbsolutePath.c_str()); - - loaderDelegate((const char16_t*)psUnicodeAbsolutePath.getTerminatedBuffer()); + loaderDelegate(clrAbsolutePath.c_str()); return status; } From fc81606886fd659e18218097301a25ca4cd91643 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sat, 19 Dec 2015 11:52:30 -0800 Subject: [PATCH 279/342] Remove icuuc entirely While we no longer used it, we still linked to it and included its header. This is now gone. --- native/CMakeLists.txt | 1 - native/getlinkcount.cpp | 1 - native/getusername.cpp | 1 - native/issymlink.cpp | 1 - tests/test-getusername.cpp | 1 - 5 files changed, 5 deletions(-) diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index e2841943d..20e8e8b2d 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -9,7 +9,6 @@ add_library(psnative SHARED setdate.cpp terminal.cpp) -target_link_libraries(psnative icuuc) target_include_directories (psnative PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) install(TARGETS psnative diff --git a/native/getlinkcount.cpp b/native/getlinkcount.cpp index 3d8061876..e11ba7d20 100644 --- a/native/getlinkcount.cpp +++ b/native/getlinkcount.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include "getlinkcount.h" //! @brief GetLinkCount retrieves the file link count (number of hard links) diff --git a/native/getusername.cpp b/native/getusername.cpp index 505291593..0efab9668 100644 --- a/native/getusername.cpp +++ b/native/getusername.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include "getusername.h" diff --git a/native/issymlink.cpp b/native/issymlink.cpp index a48a9935b..d4ce011cb 100644 --- a/native/issymlink.cpp +++ b/native/issymlink.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include "issymlink.h" //! @brief IsSymLink determines if path is a symbolic link diff --git a/tests/test-getusername.cpp b/tests/test-getusername.cpp index cab8cb98b..2ccb29f68 100644 --- a/tests/test-getusername.cpp +++ b/tests/test-getusername.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include "getusername.h" From 262471958f5c89aab30ebaead9da9d3dea1e7f49 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sat, 19 Dec 2015 11:54:01 -0800 Subject: [PATCH 280/342] Fix Boost include dir variable Boost_INCLUDE_DIRS is only used intermittently by CMake, whereas Boost_INCLUDE_DIR (no S) is always populated correctly. --- host/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 985bc8bb7..51e9a0c5c 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -1,6 +1,6 @@ add_library(pshost STATIC coreclrutil.cpp) target_link_libraries(pshost dl ${Boost_LIBRARIES}) -target_include_directories(pshost PRIVATE ${Boost_INCLUDE_DIRS}) +target_include_directories(pshost PRIVATE ${Boost_INCLUDE_DIR}) target_compile_options(pshost PRIVATE -fPIC) set(Boost_USE_STATIC_LIBS ON) From 129bff77a2cdc4e29e310f28fb15c8deed59ce85 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sat, 19 Dec 2015 11:58:37 -0800 Subject: [PATCH 281/342] Return 0, not undefined FALSE --- native/getlinkcount.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/getlinkcount.cpp b/native/getlinkcount.cpp index e11ba7d20..9e8db3d65 100644 --- a/native/getlinkcount.cpp +++ b/native/getlinkcount.cpp @@ -55,7 +55,7 @@ int32_t GetLinkCount(const char* fileName, int32_t *count) if (!fileName) { errno = ERROR_INVALID_PARAMETER; - return FALSE; + return 0; } struct stat statBuf; From 5b1bc20618333c0a1509870549f4d7bf30056561 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 21 Dec 2015 10:15:13 -0800 Subject: [PATCH 282/342] Handle error in GetEnvAbsolutePath Can't return nullptr because its an invalid cast for the return type. --- host/coreclrutil.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/host/coreclrutil.cpp b/host/coreclrutil.cpp index 1a27d359f..ccf802386 100644 --- a/host/coreclrutil.cpp +++ b/host/coreclrutil.cpp @@ -47,7 +47,9 @@ filesystem::path GetEnvAbsolutePath(const char* env) { const char* local = std::getenv(env); if (!local) - return nullptr; + { + std::cerr << "Could not read environment variable " << env << std::endl; + } return filesystem::canonical(local); } From 3d52aa35dab5c478c4413b018f2769aee32c9250 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 21 Dec 2015 10:15:16 -0800 Subject: [PATCH 283/342] Use _POSIX_HOST_NAME_MAX instead of HOST_NAME_MAX For OS X compatibility. --- native/getcomputername.cpp | 2 +- tests/test-getcomputername.cpp | 2 +- tests/test-getfullyqualifiedname.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/native/getcomputername.cpp b/native/getcomputername.cpp index 0906aa5af..e363cf167 100644 --- a/native/getcomputername.cpp +++ b/native/getcomputername.cpp @@ -22,7 +22,7 @@ char* GetComputerName() errno = 0; // Get computername from system, note that gethostname(2) gets the // nodename from uname - std::string computername(HOST_NAME_MAX, 0); + std::string computername(_POSIX_HOST_NAME_MAX, 0); int err = gethostname(&computername[0], computername.length()); // Map errno to Win32 Error Codes if (err != 0) diff --git a/tests/test-getcomputername.cpp b/tests/test-getcomputername.cpp index e0e9ca17f..9c1d676cb 100644 --- a/tests/test-getcomputername.cpp +++ b/tests/test-getcomputername.cpp @@ -12,7 +12,7 @@ class GetComputerNameTest : public ::testing::Test TEST_F(GetComputerNameTest, Success) { - char expectedComputerName[HOST_NAME_MAX]; + char expectedComputerName[_POSIX_HOST_NAME_MAX]; // the gethostname system call gets the nodename from uname FILE *fPtr = popen("uname -n", "r"); diff --git a/tests/test-getfullyqualifiedname.cpp b/tests/test-getfullyqualifiedname.cpp index c34419ab6..974316562 100644 --- a/tests/test-getfullyqualifiedname.cpp +++ b/tests/test-getfullyqualifiedname.cpp @@ -12,7 +12,7 @@ class GetFullyQualifiedNameTest : public ::testing::Test TEST_F(GetFullyQualifiedNameTest, ValidateLinuxGetFullyQualifiedDomainName) { - char expectedComputerName[HOST_NAME_MAX]; + char expectedComputerName[_POSIX_HOST_NAME_MAX]; //Get expected result from using linux command From eb6099fb49242f21b01d41bdba1c22ea93898835 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 22 Dec 2015 12:55:46 -0800 Subject: [PATCH 284/342] Clean up native host CLI - Fix launching of specific assembly via --assembly - Fix displaying help via --native-help --- host/main.cpp | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/host/main.cpp b/host/main.cpp index dcb39be0e..8665c8042 100644 --- a/host/main.cpp +++ b/host/main.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -8,18 +9,18 @@ namespace Cmdline void printHelp() { std::cerr << "PowerShell on Linux native host" << std::endl - << "Usage: powershell [assembly] [...]" << std::endl + << "Usage: powershell [-a assembly] [...]" << std::endl << std::endl << "What it does:" << std::endl << "- the host assumes that PSL has been published to $CORE_ROOT," << std::endl << "- the host will launch $CORE_ROOT/Microsoft.PowerShell.Linux.Host.dll" << std::endl - << " if not given an explicit assembly" << std::endl + << " if not given an explicit assembly via -a (or --assembly)" << std::endl << "- all additional parameters at the end of the command line are forwarded" << std::endl << " to the Main function in the assembly" << std::endl << "- the host will execute the Main function in the specified assembly" << std::endl << std::endl << "Example:" << std::endl - << "CORE_ROOT=/test/coreclr ./powershell get-process" << std::endl; + << "CORE_ROOT=$(pwd)/bin ./powershell get-process" << std::endl; } struct Args @@ -36,14 +37,7 @@ namespace Cmdline std::string assembly; }; - // checks if string ends with ".exe" - bool isExe(std::string arg) - { - std::size_t dot = arg.find_last_of("."); - return dot == std::string::npos ? false : arg.substr(dot) == ".exe"; - } - - // simple extraction of assembly.exe so we can run other hosts + // simple CLI parsing so we can run other hosts void parseCmdline(int argc, char** argv, Args& args) { // index of arguments to forward (skip zeroth) @@ -51,12 +45,21 @@ namespace Cmdline // if we have any arguments if (argc > 1) { - // check if the first is an assembly.exe - const std::string arg = argv[i]; - if (isExe(arg)) + std::string arg(argv[i]); + + // handle help if first argument; note that this can't be --help + // because the managed hosts use it + if (arg == "--native-help") { - args.assembly.assign(arg); - ++i; // don't forward the first argument + printHelp(); + exit(0); + } + + // check if given an explicit assembly to launch + if (argc > 2 && (arg == "-a" || arg == "--assembly")) + { + args.assembly.assign(std::string(argv[i+1])); + i += 2; // don't forward the first two arguments } } // forward arguments From 5bcd7148939db50e586291f874f0002a2dd1886f Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 5 Jan 2016 17:37:03 -0800 Subject: [PATCH 285/342] Remove host code Moved to OMI provider as the local shell no longer depends on a custom native host. --- CMakeLists.txt | 1 - host/CMakeLists.txt | 11 - host/coreclrutil.cpp | 297 ------------------- host/coreclrutil.h | 54 ---- host/main.cpp | 113 -------- host/unixcoreruncommon/.gitmirror | 1 - host/unixcoreruncommon/coreruncommon.cpp | 346 ----------------------- host/unixcoreruncommon/coreruncommon.h | 46 --- 8 files changed, 869 deletions(-) delete mode 100644 host/CMakeLists.txt delete mode 100644 host/coreclrutil.cpp delete mode 100644 host/coreclrutil.h delete mode 100644 host/main.cpp delete mode 100644 host/unixcoreruncommon/.gitmirror delete mode 100644 host/unixcoreruncommon/coreruncommon.cpp delete mode 100644 host/unixcoreruncommon/coreruncommon.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e0e4a7ab9..e665428fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,4 +7,3 @@ add_compile_options(-std=c++11 -Wall -Werror) enable_testing() add_subdirectory(tests) add_subdirectory(native) -add_subdirectory(host) diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt deleted file mode 100644 index 51e9a0c5c..000000000 --- a/host/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_library(pshost STATIC coreclrutil.cpp) -target_link_libraries(pshost dl ${Boost_LIBRARIES}) -target_include_directories(pshost PRIVATE ${Boost_INCLUDE_DIR}) -target_compile_options(pshost PRIVATE -fPIC) - -set(Boost_USE_STATIC_LIBS ON) -find_package(Boost 1.54.0 REQUIRED COMPONENTS filesystem system) - -# simple native host executable test -add_executable(powershell main.cpp) -target_link_libraries(powershell pshost ${Boost_LIBRARIES}) diff --git a/host/coreclrutil.cpp b/host/coreclrutil.cpp deleted file mode 100644 index ccf802386..000000000 --- a/host/coreclrutil.cpp +++ /dev/null @@ -1,297 +0,0 @@ -#include "coreclrutil.h" -#include -#include -#include -#include -#include - -#include -using namespace boost; - -// The name of the CoreCLR native runtime DLL -#if defined(__APPLE__) -constexpr char coreClrDll[] = "libcoreclr.dylib"; -#else -constexpr char coreClrDll[] = "libcoreclr.so"; -#endif - -void* coreclrLib; -char coreRoot[PATH_MAX]; - -// Prototype of the coreclr_initialize function from the libcoreclr.so -typedef int (*InitializeCoreCLRFunction)( - const char* exePath, - const char* appDomainFriendlyName, - int propertyCount, - const char** propertyKeys, - const char** propertyValues, - void** hostHandle, - unsigned int* domainId); - -// Prototype of the coreclr_shutdown function from the libcoreclr.so -typedef int (*ShutdownCoreCLRFunction)( - void* hostHandle, - unsigned int domainId); - -InitializeCoreCLRFunction initializeCoreCLR; -ShutdownCoreCLRFunction shutdownCoreCLR; -ExecuteAssemblyFunction executeAssembly; -CreateDelegateFunction createDelegate; - -// -// Get the absolute path given the environment variable. -// -// Return true in case of a success, false otherwise. -// -filesystem::path GetEnvAbsolutePath(const char* env) -{ - const char* local = std::getenv(env); - if (!local) - { - std::cerr << "Could not read environment variable " << env << std::endl; - } - - return filesystem::canonical(local); -} - -// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. -// Note: copied from unixcorerun -void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) -{ - const char * const tpaExtensions[] = { - ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir - ".dll", - ".ni.exe", - ".exe", - }; - - DIR* dir = opendir(directory); - if (dir == nullptr) - { - return; - } - - std::set addedAssemblies; - - // Walk the directory for each extension separately so that we first get files with .ni.dll extension, - // then files with .dll extension, etc. - for (unsigned int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) - { - const char* ext = tpaExtensions[extIndex]; - int extLength = strlen(ext); - - struct dirent* entry; - - // For all entries in the directory - while ((entry = readdir(dir)) != nullptr) - { - // We are interested in files only - switch (entry->d_type) - { - case DT_REG: - break; - - // Handle symlinks and file systems that do not support d_type - case DT_LNK: - case DT_UNKNOWN: - { - std::string fullFilename; - - fullFilename.append(directory); - fullFilename.append("/"); - fullFilename.append(entry->d_name); - - struct stat sb; - if (stat(fullFilename.c_str(), &sb) == -1) - { - continue; - } - - if (!S_ISREG(sb.st_mode)) - { - continue; - } - } - break; - - default: - continue; - } - - std::string filename(entry->d_name); - - // Check if the extension matches the one we are looking for - int extPos = filename.length() - extLength; - if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) - { - continue; - } - - std::string filenameWithoutExt(filename.substr(0, extPos)); - - // Make sure if we have an assembly with multiple extensions present, - // we insert only one version of it. - if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) - { - addedAssemblies.insert(filenameWithoutExt); - - tpaList.append(directory); - tpaList.append("/"); - tpaList.append(filename); - tpaList.append(":"); - } - } - - // Rewind the directory stream to be able to iterate over it for the next extension - rewinddir(dir); - } - - closedir(dir); -} - -// -// Below is our custom start/stop interface -// -int startCoreCLR( - const char* appDomainFriendlyName, - void** hostHandle, - unsigned int* domainId) -{ - char exePath[PATH_MAX]; - - // get path to current executable - ssize_t len = readlink("/proc/self/exe", exePath, PATH_MAX); - if (len == -1 || len == sizeof(exePath)) - len = 0; - exePath[len] = '\0'; - - // get the CoreCLR root path - auto clrAbsolutePath = GetEnvAbsolutePath("CORE_ROOT"); - if(!clrAbsolutePath.is_absolute()) - { - std::cerr << "Failed to get CORE_ROOT path" << std::endl; - return -1; - } - // copy to shared buffer - clrAbsolutePath.native().copy(coreRoot, clrAbsolutePath.native().size(), 0); - - // get the CoreCLR shared library path - filesystem::path coreClrDllPath(clrAbsolutePath); - coreClrDllPath /= coreClrDll; - - // open the shared library - coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL); - if (coreclrLib == nullptr) - { - std::cerr << "dlopen failed to open the CoreCLR library: " << dlerror() << std::endl; - return -1; - } - - // query and verify the function pointers - initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize"); - shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown"); - executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly"); - createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate"); - - if (initializeCoreCLR == nullptr) - { - std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl; - return -1; - } - if (executeAssembly == nullptr) - { - std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl; - return -1; - } - if (shutdownCoreCLR == nullptr) - { - std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl; - return -1; - } - if (createDelegate == nullptr) - { - std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl; - return -1; - } - - // generate the Trusted Platform Assemblies list - std::string tpaList; - - // add assemblies in the CoreCLR root path - AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(), tpaList); - - // create list of properties to initialize CoreCLR - const char* propertyKeys[] = { - "TRUSTED_PLATFORM_ASSEMBLIES", - "APP_PATHS", - "APP_NI_PATHS", - "NATIVE_DLL_SEARCH_DIRECTORIES", - "AppDomainCompatSwitch" - }; - - const char* propertyValues[] = { - tpaList.c_str(), - clrAbsolutePath.c_str(), - clrAbsolutePath.c_str(), - clrAbsolutePath.c_str(), - "UseLatestBehaviorWhenTFMNotSpecified" - }; - - // initialize CoreCLR - int status = initializeCoreCLR( - exePath, - appDomainFriendlyName, - sizeof(propertyKeys)/sizeof(propertyKeys[0]), - propertyKeys, - propertyValues, - hostHandle, - domainId); - - if (!SUCCEEDED(status)) - { - std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl; - return -1; - } - - // initialize PowerShell's custom assembly load context - filesystem::path alcAbsolutePath(clrAbsolutePath); - alcAbsolutePath /= "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll"; - - typedef void (*LoaderRunHelperFp)(const char* appPath); - LoaderRunHelperFp loaderDelegate = nullptr; - status = createDelegate( - *hostHandle, - *domainId, - "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, PublicKeyToken=null", - "System.Management.Automation.PowerShellAssemblyLoadContextInitializer", - "SetPowerShellAssemblyLoadContext", - (void**)&loaderDelegate); - - if (!SUCCEEDED(status)) - { - std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl; - return -1; - } - - loaderDelegate(clrAbsolutePath.c_str()); - - return status; -} - -int stopCoreCLR(void* hostHandle, unsigned int domainId) -{ - // shutdown CoreCLR - int status = shutdownCoreCLR(hostHandle, domainId); - if (!SUCCEEDED(status)) - { - std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl; - } - - // close the dynamic library - if (0 != dlclose(coreclrLib)) - { - std::cerr << "failed to close CoreCLR library" << std::endl; - } - - return status; -} diff --git a/host/coreclrutil.h b/host/coreclrutil.h deleted file mode 100644 index 8fb99c79f..000000000 --- a/host/coreclrutil.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#define SUCCEEDED(Status) ((Status) >= 0) - -/* PowerShell on Linux custom host interface - * - * startCoreCLR() takes a friendly name, e.g. "powershell", and a - * writable pointer and identifier - * - * executeAssmbly() will be made available after starting CoreCLR, and - * is used to launch assemblies with a main function - * - * createDelegate() works similarly but provides a reverse P/Invoke - * given an assembly, type, and method; note that on Linux, - * PublicKeyToken must be null - * - * stopCoreCLR() will deinitialize given the handle and identifier - */ - -#ifdef __cplusplus -extern "C" -{ -#endif - int startCoreCLR( - const char* appDomainFriendlyName, - void** hostHandle, - unsigned int* domainId); - - int stopCoreCLR(void* hostHandle, unsigned int domainId); - - /* Prototype of the coreclr_execute_assembly function from the libcoreclr.so */ - typedef int (*ExecuteAssemblyFunction)( - void* hostHandle, - unsigned int domainId, - int argc, - const char** argv, - const char* managedAssemblyPath, - unsigned int* exitCode); - - /* Prototype of coreclr_create_delegate function from the libcoreclr.so */ - typedef int (*CreateDelegateFunction)( - void* hostHandle, - unsigned int domainId, - const char* entryPointAssemblyName, - const char* entryPointTypeName, - const char* entryPointMethodName, - void** delegate); - - extern ExecuteAssemblyFunction executeAssembly; - extern CreateDelegateFunction createDelegate; - extern char coreRoot[]; -#ifdef __cplusplus -} -#endif diff --git a/host/main.cpp b/host/main.cpp deleted file mode 100644 index 8665c8042..000000000 --- a/host/main.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include -#include -#include -#include -#include "coreclrutil.h" - -namespace Cmdline -{ - void printHelp() - { - std::cerr << "PowerShell on Linux native host" << std::endl - << "Usage: powershell [-a assembly] [...]" << std::endl - << std::endl - << "What it does:" << std::endl - << "- the host assumes that PSL has been published to $CORE_ROOT," << std::endl - << "- the host will launch $CORE_ROOT/Microsoft.PowerShell.Linux.Host.dll" << std::endl - << " if not given an explicit assembly via -a (or --assembly)" << std::endl - << "- all additional parameters at the end of the command line are forwarded" << std::endl - << " to the Main function in the assembly" << std::endl - << "- the host will execute the Main function in the specified assembly" << std::endl - << std::endl - << "Example:" << std::endl - << "CORE_ROOT=$(pwd)/bin ./powershell get-process" << std::endl; - } - - struct Args - { - Args() : - argc(0), - argv(nullptr), - assembly() - { - } - - int argc; - char** argv; - std::string assembly; - }; - - // simple CLI parsing so we can run other hosts - void parseCmdline(int argc, char** argv, Args& args) - { - // index of arguments to forward (skip zeroth) - int i = 1; - // if we have any arguments - if (argc > 1) - { - std::string arg(argv[i]); - - // handle help if first argument; note that this can't be --help - // because the managed hosts use it - if (arg == "--native-help") - { - printHelp(); - exit(0); - } - - // check if given an explicit assembly to launch - if (argc > 2 && (arg == "-a" || arg == "--assembly")) - { - args.assembly.assign(std::string(argv[i+1])); - i += 2; // don't forward the first two arguments - } - } - // forward arguments - args.argc = argc - i; - args.argv = &argv[i]; - } -} - -int main(int argc, char** argv) -{ - Cmdline::Args args; - Cmdline::parseCmdline(argc, argv, args); - - void* hostHandle; - unsigned int domainId; - int status = startCoreCLR( - "psl_cmdline_host", - &hostHandle, - &domainId); - - if (!SUCCEEDED(status)) - { - std::cerr << "could not start CoreCLR" << std::endl; - return -1; - } - - // default to powershell.exe if no host specified - if (args.assembly.empty()) - { - args.assembly.append(coreRoot); - args.assembly.append("/"); - args.assembly.append("Microsoft.PowerShell.Linux.Host.dll"); - } - - // call into Main of assembly - unsigned int exitCode; - executeAssembly( - hostHandle, domainId, args.argc, - (const char**)args.argv, - args.assembly.c_str(), - &exitCode); - - status = stopCoreCLR(hostHandle, domainId); - if (!SUCCEEDED(status)) - { - std::cerr << "could not stop CoreCLR" << std::endl; - return -1; - } - - return exitCode; -} diff --git a/host/unixcoreruncommon/.gitmirror b/host/unixcoreruncommon/.gitmirror deleted file mode 100644 index f507630f9..000000000 --- a/host/unixcoreruncommon/.gitmirror +++ /dev/null @@ -1 +0,0 @@ -Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file diff --git a/host/unixcoreruncommon/coreruncommon.cpp b/host/unixcoreruncommon/coreruncommon.cpp deleted file mode 100644 index ecbbf3929..000000000 --- a/host/unixcoreruncommon/coreruncommon.cpp +++ /dev/null @@ -1,346 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -// -// Code that is used by both the Unix corerun and coreconsole. -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// The name of the CoreCLR native runtime DLL -#if defined(__APPLE__) -static const char * const coreClrDll = "libcoreclr.dylib"; -#else -static const char * const coreClrDll = "libcoreclr.so"; -#endif - -#define SUCCEEDED(Status) ((Status) >= 0) - -// Prototype of the coreclr_initialize function from the libcoreclr.so -typedef int (*InitializeCoreCLRFunction)( - const char* exePath, - const char* appDomainFriendlyName, - int propertyCount, - const char** propertyKeys, - const char** propertyValues, - void** hostHandle, - unsigned int* domainId); - -// Prototype of the coreclr_shutdown function from the libcoreclr.so -typedef int (*ShutdownCoreCLRFunction)( - void* hostHandle, - unsigned int domainId); - -// Prototype of the coreclr_execute_assembly function from the libcoreclr.so -typedef int (*ExecuteAssemblyFunction)( - void* hostHandle, - unsigned int domainId, - int argc, - const char** argv, - const char* managedAssemblyPath, - unsigned int* exitCode); - -bool GetAbsolutePath(const char* path, std::string& absolutePath) -{ - bool result = false; - - char realPath[PATH_MAX]; - if (realpath(path, realPath) != nullptr && realPath[0] != '\0') - { - absolutePath.assign(realPath); - // realpath should return canonicalized path without the trailing slash - assert(absolutePath.back() != '/'); - - result = true; - } - - return result; -} - -bool GetDirectory(const char* absolutePath, std::string& directory) -{ - directory.assign(absolutePath); - size_t lastSlash = directory.rfind('/'); - if (lastSlash != std::string::npos) - { - directory.erase(lastSlash); - return true; - } - - return false; -} - -bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath) -{ - std::string clrFilesRelativePath; - const char* clrFilesPathLocal = clrFilesPath; - if (clrFilesPathLocal == nullptr) - { - // There was no CLR files path specified, use the folder of the corerun/coreconsole - if (!GetDirectory(currentExePath, clrFilesRelativePath)) - { - perror("Failed to get directory from argv[0]"); - return false; - } - - clrFilesPathLocal = clrFilesRelativePath.c_str(); - - // TODO: consider using an env variable (if defined) as a fall-back. - // The windows version of the corerun uses core_root env variable - } - - if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath)) - { - perror("Failed to convert CLR files path to absolute path"); - return false; - } - - return true; -} - -void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) -{ - const char * const tpaExtensions[] = { - ".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir - ".dll", - ".ni.exe", - ".exe", - }; - - DIR* dir = opendir(directory); - if (dir == nullptr) - { - return; - } - - std::set addedAssemblies; - - // Walk the directory for each extension separately so that we first get files with .ni.dll extension, - // then files with .dll extension, etc. - for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) - { - const char* ext = tpaExtensions[extIndex]; - int extLength = strlen(ext); - - struct dirent* entry; - - // For all entries in the directory - while ((entry = readdir(dir)) != nullptr) - { - // We are interested in files only - switch (entry->d_type) - { - case DT_REG: - break; - - // Handle symlinks and file systems that do not support d_type - case DT_LNK: - case DT_UNKNOWN: - { - std::string fullFilename; - - fullFilename.append(directory); - fullFilename.append("/"); - fullFilename.append(entry->d_name); - - struct stat sb; - if (stat(fullFilename.c_str(), &sb) == -1) - { - continue; - } - - if (!S_ISREG(sb.st_mode)) - { - continue; - } - } - break; - - default: - continue; - } - - std::string filename(entry->d_name); - - // Check if the extension matches the one we are looking for - int extPos = filename.length() - extLength; - if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0)) - { - continue; - } - - std::string filenameWithoutExt(filename.substr(0, extPos)); - - // Make sure if we have an assembly with multiple extensions present, - // we insert only one version of it. - if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) - { - addedAssemblies.insert(filenameWithoutExt); - - tpaList.append(directory); - tpaList.append("/"); - tpaList.append(filename); - tpaList.append(":"); - } - } - - // Rewind the directory stream to be able to iterate over it for the next extension - rewinddir(dir); - } - - closedir(dir); -} - -int ExecuteManagedAssembly( - const char* currentExeAbsolutePath, - const char* clrFilesAbsolutePath, - const char* managedAssemblyAbsolutePath, - int managedAssemblyArgc, - const char** managedAssemblyArgv) -{ - // Indicates failure - int exitCode = -1; - - std::string coreClrDllPath(clrFilesAbsolutePath); - coreClrDllPath.append("/"); - coreClrDllPath.append(coreClrDll); - - if (coreClrDllPath.length() >= PATH_MAX) - { - fprintf(stderr, "Absolute path to libcoreclr.so too long\n"); - return -1; - } - - // Get just the path component of the managed assembly path - std::string appPath; - GetDirectory(managedAssemblyAbsolutePath, appPath); - - std::string nativeDllSearchDirs(appPath); - nativeDllSearchDirs.append(":"); - nativeDllSearchDirs.append(clrFilesAbsolutePath); - - std::string tpaList; - AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath, tpaList); - - void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW | RTLD_LOCAL); - if (coreclrLib != nullptr) - { - InitializeCoreCLRFunction initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib, "coreclr_initialize"); - ExecuteAssemblyFunction executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib, "coreclr_execute_assembly"); - ShutdownCoreCLRFunction shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib, "coreclr_shutdown"); - - if (initializeCoreCLR == nullptr) - { - fprintf(stderr, "Function coreclr_initialize not found in the libcoreclr.so\n"); - } - else if (executeAssembly == nullptr) - { - fprintf(stderr, "Function coreclr_execute_assembly not found in the libcoreclr.so\n"); - } - else if (shutdownCoreCLR == nullptr) - { - fprintf(stderr, "Function coreclr_shutdown not found in the libcoreclr.so\n"); - } - else - { - // Allowed property names: - // APPBASE - // - The base path of the application from which the exe and other assemblies will be loaded - // - // TRUSTED_PLATFORM_ASSEMBLIES - // - The list of complete paths to each of the fully trusted assemblies - // - // APP_PATHS - // - The list of paths which will be probed by the assembly loader - // - // APP_NI_PATHS - // - The list of additional paths that the assembly loader will probe for ngen images - // - // NATIVE_DLL_SEARCH_DIRECTORIES - // - The list of paths that will be probed for native DLLs called by PInvoke - // - const char *propertyKeys[] = { - "TRUSTED_PLATFORM_ASSEMBLIES", - "APP_PATHS", - "APP_NI_PATHS", - "NATIVE_DLL_SEARCH_DIRECTORIES", - "AppDomainCompatSwitch" - }; - const char *propertyValues[] = { - // TRUSTED_PLATFORM_ASSEMBLIES - tpaList.c_str(), - // APP_PATHS - appPath.c_str(), - // APP_NI_PATHS - appPath.c_str(), - // NATIVE_DLL_SEARCH_DIRECTORIES - nativeDllSearchDirs.c_str(), - // AppDomainCompatSwitch - "UseLatestBehaviorWhenTFMNotSpecified" - }; - - void* hostHandle; - unsigned int domainId; - - int st = initializeCoreCLR( - currentExeAbsolutePath, - "unixcorerun", - sizeof(propertyKeys) / sizeof(propertyKeys[0]), - propertyKeys, - propertyValues, - &hostHandle, - &domainId); - - if (!SUCCEEDED(st)) - { - fprintf(stderr, "coreclr_initialize failed - status: 0x%08x\n", st); - exitCode = -1; - } - else - { - st = executeAssembly( - hostHandle, - domainId, - managedAssemblyArgc, - managedAssemblyArgv, - managedAssemblyAbsolutePath, - (unsigned int*)&exitCode); - - if (!SUCCEEDED(st)) - { - fprintf(stderr, "coreclr_execute_assembly failed - status: 0x%08x\n", st); - exitCode = -1; - } - - st = shutdownCoreCLR(hostHandle, domainId); - if (!SUCCEEDED(st)) - { - fprintf(stderr, "coreclr_shutdown failed - status: 0x%08x\n", st); - exitCode = -1; - } - } - } - - if (dlclose(coreclrLib) != 0) - { - fprintf(stderr, "Warning - dlclose failed\n"); - } - } - else - { - char* error = dlerror(); - fprintf(stderr, "dlopen failed to open the libcoreclr.so with error %s\n", error); - } - - return exitCode; -} diff --git a/host/unixcoreruncommon/coreruncommon.h b/host/unixcoreruncommon/coreruncommon.h deleted file mode 100644 index b587e407f..000000000 --- a/host/unixcoreruncommon/coreruncommon.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -#include - -// Get absolute path from the specified path. -// Return true in case of a success, false otherwise. -bool GetAbsolutePath(const char* path, std::string& absolutePath); - -// Get directory of the specified path. -// Return true in case of a success, false otherwise. -bool GetDirectory(const char* absolutePath, std::string& directory); - -// -// Get the absolute path to use to locate libcoreclr.so and the CLR assemblies are stored. If clrFilesPath is provided, -// this function will return the absolute path to it. Otherwise, the directory of the current executable is used. -// -// Return true in case of a success, false otherwise. -// -bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath); - -// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. -void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList); - -// -// Execute the specified managed assembly. -// -// Parameters: -// currentExePath - Path to the current executable -// clrFilesAbsolutePath - Absolute path to the folder where the libcoreclr.so and CLR managed assemblies are stored -// managedAssemblyPath - Path to the managed assembly to execute -// managedAssemblyArgc - Number of arguments passed to the executed assembly -// managedAssemblyArgv - Array of arguments passed to the executed assembly -// -// Returns: -// ExitCode of the assembly -// -int ExecuteManagedAssembly( - const char* currentExeAbsolutePath, - const char* clrFilesAbsolutePath, - const char* managedAssemblyAbsolutePath, - int managedAssemblyArgc, - const char** managedAssemblyArgv); - From 6e8ce797fc63e794c4a6934407ada12b7360364a Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 12 Jan 2016 13:52:50 -0800 Subject: [PATCH 286/342] Rename native to src With the removal of the host, this submodule is now just one thing: libpsnative, so it makes sense to have a `src` directory instead of a poorly named `monad-native/native`. --- CMakeLists.txt | 2 +- {native => src}/CMakeLists.txt | 0 {native => src}/getcomputername.cpp | 0 {native => src}/getcomputername.h | 0 {native => src}/getcurrentprocessorid.cpp | 0 {native => src}/getcurrentprocessorid.h | 0 {native => src}/getcurrentthreadid.cpp | 0 {native => src}/getcurrentthreadid.h | 0 {native => src}/getfullyqualifiedname.cpp | 0 {native => src}/getfullyqualifiedname.h | 0 {native => src}/getlinkcount.cpp | 0 {native => src}/getlinkcount.h | 0 {native => src}/getusername.cpp | 0 {native => src}/getusername.h | 0 {native => src}/isexecutable.cpp | 0 {native => src}/isexecutable.h | 0 {native => src}/issymlink.cpp | 0 {native => src}/issymlink.h | 0 {native => src}/pal.h | 0 {native => src}/setdate.cpp | 0 {native => src}/setdate.h | 0 {native => src}/terminal.cpp | 0 {native => src}/terminal.h | 0 23 files changed, 1 insertion(+), 1 deletion(-) rename {native => src}/CMakeLists.txt (100%) rename {native => src}/getcomputername.cpp (100%) rename {native => src}/getcomputername.h (100%) rename {native => src}/getcurrentprocessorid.cpp (100%) rename {native => src}/getcurrentprocessorid.h (100%) rename {native => src}/getcurrentthreadid.cpp (100%) rename {native => src}/getcurrentthreadid.h (100%) rename {native => src}/getfullyqualifiedname.cpp (100%) rename {native => src}/getfullyqualifiedname.h (100%) rename {native => src}/getlinkcount.cpp (100%) rename {native => src}/getlinkcount.h (100%) rename {native => src}/getusername.cpp (100%) rename {native => src}/getusername.h (100%) rename {native => src}/isexecutable.cpp (100%) rename {native => src}/isexecutable.h (100%) rename {native => src}/issymlink.cpp (100%) rename {native => src}/issymlink.h (100%) rename {native => src}/pal.h (100%) rename {native => src}/setdate.cpp (100%) rename {native => src}/setdate.h (100%) rename {native => src}/terminal.cpp (100%) rename {native => src}/terminal.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index e665428fd..a5ce4f40e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,5 +5,5 @@ add_compile_options(-std=c++11 -Wall -Werror) # test in BUILD_DIR enable_testing() +add_subdirectory(src) add_subdirectory(tests) -add_subdirectory(native) diff --git a/native/CMakeLists.txt b/src/CMakeLists.txt similarity index 100% rename from native/CMakeLists.txt rename to src/CMakeLists.txt diff --git a/native/getcomputername.cpp b/src/getcomputername.cpp similarity index 100% rename from native/getcomputername.cpp rename to src/getcomputername.cpp diff --git a/native/getcomputername.h b/src/getcomputername.h similarity index 100% rename from native/getcomputername.h rename to src/getcomputername.h diff --git a/native/getcurrentprocessorid.cpp b/src/getcurrentprocessorid.cpp similarity index 100% rename from native/getcurrentprocessorid.cpp rename to src/getcurrentprocessorid.cpp diff --git a/native/getcurrentprocessorid.h b/src/getcurrentprocessorid.h similarity index 100% rename from native/getcurrentprocessorid.h rename to src/getcurrentprocessorid.h diff --git a/native/getcurrentthreadid.cpp b/src/getcurrentthreadid.cpp similarity index 100% rename from native/getcurrentthreadid.cpp rename to src/getcurrentthreadid.cpp diff --git a/native/getcurrentthreadid.h b/src/getcurrentthreadid.h similarity index 100% rename from native/getcurrentthreadid.h rename to src/getcurrentthreadid.h diff --git a/native/getfullyqualifiedname.cpp b/src/getfullyqualifiedname.cpp similarity index 100% rename from native/getfullyqualifiedname.cpp rename to src/getfullyqualifiedname.cpp diff --git a/native/getfullyqualifiedname.h b/src/getfullyqualifiedname.h similarity index 100% rename from native/getfullyqualifiedname.h rename to src/getfullyqualifiedname.h diff --git a/native/getlinkcount.cpp b/src/getlinkcount.cpp similarity index 100% rename from native/getlinkcount.cpp rename to src/getlinkcount.cpp diff --git a/native/getlinkcount.h b/src/getlinkcount.h similarity index 100% rename from native/getlinkcount.h rename to src/getlinkcount.h diff --git a/native/getusername.cpp b/src/getusername.cpp similarity index 100% rename from native/getusername.cpp rename to src/getusername.cpp diff --git a/native/getusername.h b/src/getusername.h similarity index 100% rename from native/getusername.h rename to src/getusername.h diff --git a/native/isexecutable.cpp b/src/isexecutable.cpp similarity index 100% rename from native/isexecutable.cpp rename to src/isexecutable.cpp diff --git a/native/isexecutable.h b/src/isexecutable.h similarity index 100% rename from native/isexecutable.h rename to src/isexecutable.h diff --git a/native/issymlink.cpp b/src/issymlink.cpp similarity index 100% rename from native/issymlink.cpp rename to src/issymlink.cpp diff --git a/native/issymlink.h b/src/issymlink.h similarity index 100% rename from native/issymlink.h rename to src/issymlink.h diff --git a/native/pal.h b/src/pal.h similarity index 100% rename from native/pal.h rename to src/pal.h diff --git a/native/setdate.cpp b/src/setdate.cpp similarity index 100% rename from native/setdate.cpp rename to src/setdate.cpp diff --git a/native/setdate.h b/src/setdate.h similarity index 100% rename from native/setdate.h rename to src/setdate.h diff --git a/native/terminal.cpp b/src/terminal.cpp similarity index 100% rename from native/terminal.cpp rename to src/terminal.cpp diff --git a/native/terminal.h b/src/terminal.h similarity index 100% rename from native/terminal.h rename to src/terminal.h From e612ccb1e8b350e34d02805c71a3806e3cac0ef2 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 12 Jan 2016 13:58:25 -0800 Subject: [PATCH 287/342] Rename to psl-native The name `psnative` would have been confusing when this goes cross-platform; instead use the `psl` suffix for PowerShell on Linux. --- .gitignore | 6 ++---- CMakeLists.txt | 2 +- src/CMakeLists.txt | 7 ++----- tests/CMakeLists.txt | 10 +++++----- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 45177e796..0e33a4cd5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,6 @@ cmake_install.cmake install_manifest.txt CTestTestfile.cmake Testing/ -tests/psnative-test -host/powershell -host/libpshost.a -native/libpsnative.so +tests/psl-native-test +src/libpsl-native.so tests/native-tests.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index a5ce4f40e..1194d4b0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.8.4) -project(MONAD_NATIVE) +project(PSL-NATIVE) add_compile_options(-std=c++11 -Wall -Werror) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 20e8e8b2d..11b110f44 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(psnative SHARED +add_library(psl-native SHARED getcurrentprocessorid.cpp getusername.cpp getcomputername.cpp @@ -9,7 +9,4 @@ add_library(psnative SHARED setdate.cpp terminal.cpp) -target_include_directories (psnative PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) - -install(TARGETS psnative - LIBRARY DESTINATION lib) +target_include_directories(psl-native PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b0216f88e..bcdc0b459 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,6 @@ add_subdirectory(googletest) -add_executable(psnative-test +add_executable(psl-native-test test-locale.cpp test-getcurrentprocessid.cpp test-getusername.cpp @@ -12,9 +12,9 @@ add_executable(psnative-test main.cpp) # manually include gtest headers -target_include_directories(psnative-test PRIVATE ${gtest_SOURCE_DIR}/include) +target_include_directories(psl-native-test PRIVATE ${gtest_SOURCE_DIR}/include) -target_link_libraries(psnative-test psnative gtest) +target_link_libraries(psl-native-test psl-native gtest) -add_test(NAME psnative-test - COMMAND psnative-test --gtest_output=xml:native-tests.xml) +add_test(NAME psl-native-test + COMMAND psl-native-test --gtest_output=xml:native-tests.xml) From 494f08a16bdd1e0ea965b9595f2473a346712d6a Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 12 Jan 2016 14:00:25 -0800 Subject: [PATCH 288/342] Remove terminal queries Thanks to improvements in System.Console, we no longer rely on these. --- src/CMakeLists.txt | 3 +-- src/terminal.cpp | 21 --------------------- src/terminal.h | 11 ----------- 3 files changed, 1 insertion(+), 34 deletions(-) delete mode 100644 src/terminal.cpp delete mode 100644 src/terminal.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 11b110f44..acb732525 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,7 +6,6 @@ add_library(psl-native SHARED getfullyqualifiedname.cpp issymlink.cpp isexecutable.cpp - setdate.cpp - terminal.cpp) + setdate.cpp) target_include_directories(psl-native PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/terminal.cpp b/src/terminal.cpp deleted file mode 100644 index 44fadd084..000000000 --- a/src/terminal.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "terminal.h" -#include - -int32_t GetTerminalWidth() -{ - struct winsize ws; - if (-1 == ioctl(0,TIOCGWINSZ,&ws)) - return -1; - - return ws.ws_col; -} - -int32_t GetTerminalHeight() -{ - struct winsize ws; - if (-1 == ioctl(0,TIOCGWINSZ,&ws)) - return -1; - - return ws.ws_row; -} - diff --git a/src/terminal.h b/src/terminal.h deleted file mode 100644 index e036bc849..000000000 --- a/src/terminal.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "pal.h" - -PAL_BEGIN_EXTERNC - -int32_t GetTerminalWidth(); -int32_t GetTerminalHeight(); - -PAL_END_EXTERNC - From 6e8565967274f1b2ff6d29246e3aa5356639dd92 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jan 2016 10:14:40 -0800 Subject: [PATCH 289/342] Rename tests to test Requires moving a submodule, so its better to do it now when everything is moving. --- .gitignore | 4 ++-- .gitmodules | 4 ++-- CMakeLists.txt | 2 +- {tests => test}/CMakeLists.txt | 0 {tests => test}/googletest | 0 {tests => test}/main.cpp | 0 {tests => test}/test-getcomputername.cpp | 0 {tests => test}/test-getcurrentprocessid.cpp | 0 {tests => test}/test-getcurrentthreadid.cpp | 0 {tests => test}/test-getfullyqualifiedname.cpp | 0 {tests => test}/test-getlinkcount.cpp | 0 {tests => test}/test-getusername.cpp | 0 {tests => test}/test-isexecutable.cpp | 0 {tests => test}/test-issymlink.cpp | 0 {tests => test}/test-locale.cpp | 0 15 files changed, 5 insertions(+), 5 deletions(-) rename {tests => test}/CMakeLists.txt (100%) rename {tests => test}/googletest (100%) rename {tests => test}/main.cpp (100%) rename {tests => test}/test-getcomputername.cpp (100%) rename {tests => test}/test-getcurrentprocessid.cpp (100%) rename {tests => test}/test-getcurrentthreadid.cpp (100%) rename {tests => test}/test-getfullyqualifiedname.cpp (100%) rename {tests => test}/test-getlinkcount.cpp (100%) rename {tests => test}/test-getusername.cpp (100%) rename {tests => test}/test-isexecutable.cpp (100%) rename {tests => test}/test-issymlink.cpp (100%) rename {tests => test}/test-locale.cpp (100%) diff --git a/.gitignore b/.gitignore index 0e33a4cd5..798fa6c00 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,6 @@ cmake_install.cmake install_manifest.txt CTestTestfile.cmake Testing/ -tests/psl-native-test +test/psl-native-test src/libpsl-native.so -tests/native-tests.xml +test/native-tests.xml diff --git a/.gitmodules b/.gitmodules index 44d6d26f4..7cdedd847 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ -[submodule "tests/googletest"] - path = tests/googletest +[submodule "test/googletest"] + path = test/googletest url = https://github.com/google/googletest.git ignore = dirty diff --git a/CMakeLists.txt b/CMakeLists.txt index 1194d4b0e..f5778ed81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,4 +6,4 @@ add_compile_options(-std=c++11 -Wall -Werror) # test in BUILD_DIR enable_testing() add_subdirectory(src) -add_subdirectory(tests) +add_subdirectory(test) diff --git a/tests/CMakeLists.txt b/test/CMakeLists.txt similarity index 100% rename from tests/CMakeLists.txt rename to test/CMakeLists.txt diff --git a/tests/googletest b/test/googletest similarity index 100% rename from tests/googletest rename to test/googletest diff --git a/tests/main.cpp b/test/main.cpp similarity index 100% rename from tests/main.cpp rename to test/main.cpp diff --git a/tests/test-getcomputername.cpp b/test/test-getcomputername.cpp similarity index 100% rename from tests/test-getcomputername.cpp rename to test/test-getcomputername.cpp diff --git a/tests/test-getcurrentprocessid.cpp b/test/test-getcurrentprocessid.cpp similarity index 100% rename from tests/test-getcurrentprocessid.cpp rename to test/test-getcurrentprocessid.cpp diff --git a/tests/test-getcurrentthreadid.cpp b/test/test-getcurrentthreadid.cpp similarity index 100% rename from tests/test-getcurrentthreadid.cpp rename to test/test-getcurrentthreadid.cpp diff --git a/tests/test-getfullyqualifiedname.cpp b/test/test-getfullyqualifiedname.cpp similarity index 100% rename from tests/test-getfullyqualifiedname.cpp rename to test/test-getfullyqualifiedname.cpp diff --git a/tests/test-getlinkcount.cpp b/test/test-getlinkcount.cpp similarity index 100% rename from tests/test-getlinkcount.cpp rename to test/test-getlinkcount.cpp diff --git a/tests/test-getusername.cpp b/test/test-getusername.cpp similarity index 100% rename from tests/test-getusername.cpp rename to test/test-getusername.cpp diff --git a/tests/test-isexecutable.cpp b/test/test-isexecutable.cpp similarity index 100% rename from tests/test-isexecutable.cpp rename to test/test-isexecutable.cpp diff --git a/tests/test-issymlink.cpp b/test/test-issymlink.cpp similarity index 100% rename from tests/test-issymlink.cpp rename to test/test-issymlink.cpp diff --git a/tests/test-locale.cpp b/test/test-locale.cpp similarity index 100% rename from tests/test-locale.cpp rename to test/test-locale.cpp From 8650c6a6a1f782361d49191e935eef616f190155 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 15 Jan 2016 12:37:03 -0800 Subject: [PATCH 290/342] Add readme --- README.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..930ea3630 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# libpsl-native + +This library provides functionality missing from .NET Core via system calls, +that are called from from the `CorePsPlatform.cs` file of PowerShell. The +method to do this is a Platform Invoke, which is C#'s Foreign Function +Interface to C code (and C++ by way of `extern C`). + +## Build + +[CMake][] is used to build the project, which results in a `libpsl-native.so` +library on Linux, and `libpsl-native.dylib` on OS X. + +```sh +cmake -DCMAKE_BUILD_TYPE=Debug . +make -j +``` + +[CMake]: https://cmake.org/cmake/help/v2.8.12/cmake.html + +## Test + +The [Google Test][] framework is used for unit tests. + +Use either `make test` or `ctest --verbose` for more output. + +[Google Test]: https://github.com/google/googletest/tree/release-1.7.0 + +## Notes + +Marshalling data from native to managed code is much easier on Linux than it is +on Windows. For instance, to return a string, you simply return a copy of it on +the heap. Since only one memory allocator is used on Linux, the .NET runtime +has no problem later freeing the buffer. Additionally, .NET presumes that the +codepage "Ansi" on Linux is always UTF-8. So just marshal the string as +`UnmanagedType.LPStr`. + +### C# (Managed) + +```c# +[DllImport("libpsl-native", CharSet = CharSet.Ansi)] +[return: MarshalAs(UnmanagedType.LPStr)] +internal static extern string GetSomeString(); +``` + +### C (Native) + +```c +char *GetSomeString() +{ + return strdup("some string"); +} +``` + +The CoreFX team has an excellent guide for [UNIX Interop][]. + +[UNIX Interop]: https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/interop-guidelines.md#unix-shims From 4bfa1fa23173309168dd674dc05f9f3cd1d0ad8c Mon Sep 17 00:00:00 2001 From: George Fleming Date: Fri, 26 Feb 2016 14:31:17 -0800 Subject: [PATCH 291/342] Add new CreateSymLink function --- src/CMakeLists.txt | 3 +- src/createsymlink.cpp | 108 ++++++++++++++++++++++++++++++++++++++++++ src/createsymlink.h | 9 ++++ src/pal.h | 2 + 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 src/createsymlink.cpp create mode 100644 src/createsymlink.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index acb732525..b75ba8f16 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,6 +6,7 @@ add_library(psl-native SHARED getfullyqualifiedname.cpp issymlink.cpp isexecutable.cpp - setdate.cpp) + setdate.cpp + createsymlink.cpp) target_include_directories(psl-native PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/createsymlink.cpp b/src/createsymlink.cpp new file mode 100644 index 000000000..fcff5c25b --- /dev/null +++ b/src/createsymlink.cpp @@ -0,0 +1,108 @@ +//! @file createsymlink.cpp +//! @author George FLeming +//! @brief create new symbolic link + +#include +//#include +//#include +#include +#include +#include "createsymlink.h" + +//! @brief Createsymlink create new symbolic link +//! +//! Createsymlink +//! +//! @param[in] link +//! @parblock +//! A pointer to the buffer that contains the symbolic link to create +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @endparblock +//! +//! @param[in] target +//! @parblock +//! A pointer to the buffer that contains the existing file +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @endparblock +//! +//! @exception errno Passes these errors via errno to GetLastError: +//! - ERROR_INVALID_PARAMETER: parameter is not valid +//! - ERROR_FILE_NOT_FOUND: file does not exist +//! - ERROR_ACCESS_DENIED: access is denied +//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified +//! - ERROR_INVALID_ADDRESS: attempt to access invalid address +//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link +//! - ERROR_GEN_FAILURE: device attached to the system is not functioning +//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file +//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect +//! - ERROR_BUFFER_OVERFLOW: file name is too long +//! - ERROR_INVALID_FUNCTION: incorrect function +//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters +//! +//! @retval 1 if creation is successful +//! @retval 0 if createion failed +//! + +int32_t CreateSymLink(const char *link, const char *target) +{ + errno = 0; + + // Check parameters + if (!link || !target) + { + errno = ERROR_INVALID_PARAMETER; + return 0; + } + + int returnCode = symlink(target, link); + + if (returnCode == 0) + { + return 1; + } + + switch(errno) + { + case EACCES: + errno = ERROR_ACCESS_DENIED; + break; + case EDQUOT: + errno = ERROR_DISK_FULL; + break; + case EEXIST: + errno = ERROR_FILE_EXISTS; + break; + case EFAULT: + errno = ERROR_INVALID_ADDRESS; + break; + case EIO: + errno = ERROR_GEN_FAILURE; + break; + case ELOOP: + errno = ERROR_STOPPED_ON_SYMLINK; + break; + case ENAMETOOLONG: + errno = ERROR_BAD_PATH_NAME; + break; + case ENOENT: + errno = ERROR_FILE_NOT_FOUND; + break; + case ENOMEM: + errno = ERROR_OUTOFMEMORY; + break; + case ENOTDIR: + errno = ERROR_INVALID_NAME; + break; + case ENOSPC: + errno = ERROR_DISK_FULL; + break; + case EPERM: + errno = ERROR_GEN_FAILURE; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return 0; +} diff --git a/src/createsymlink.h b/src/createsymlink.h new file mode 100644 index 000000000..e47bce3fa --- /dev/null +++ b/src/createsymlink.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +int32_t CreateSymLink(const char *link, const char *target); + +PAL_END_EXTERNC diff --git a/src/pal.h b/src/pal.h index d47b2845e..754289776 100644 --- a/src/pal.h +++ b/src/pal.h @@ -22,6 +22,8 @@ #define ERROR_FILE_NOT_FOUND 0x00000002 #define ERROR_BAD_PATH_NAME 0x000000A1 #define ERROR_BAD_NET_NAME 0x00000043 +#define ERROR_DISK_FULL 0x00000070 +#define ERROR_FILE_EXISTS 0x00000050 /* **============================================================================== From 19dbaaf54cfa47c0673af6a3da2c4dad5fb56e8f Mon Sep 17 00:00:00 2001 From: George Fleming Date: Fri, 26 Feb 2016 15:16:42 -0800 Subject: [PATCH 292/342] Add native test for createSymLink --- src/createsymlink.cpp | 2 - test/CMakeLists.txt | 1 + test/test-createsymlink.cpp | 107 ++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 test/test-createsymlink.cpp diff --git a/src/createsymlink.cpp b/src/createsymlink.cpp index fcff5c25b..4ea8d6fd9 100644 --- a/src/createsymlink.cpp +++ b/src/createsymlink.cpp @@ -3,8 +3,6 @@ //! @brief create new symbolic link #include -//#include -//#include #include #include #include "createsymlink.h" diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bcdc0b459..cd9bf063d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -9,6 +9,7 @@ add_executable(psl-native-test test-getfullyqualifiedname.cpp test-issymlink.cpp test-isexecutable.cpp + test-createsymlink.cpp main.cpp) # manually include gtest headers diff --git a/test/test-createsymlink.cpp b/test/test-createsymlink.cpp new file mode 100644 index 000000000..1100d022c --- /dev/null +++ b/test/test-createsymlink.cpp @@ -0,0 +1,107 @@ +//! @file test-issymlink.cpp +//! @author George Fleming +//! @brief Implements test for isSymLink() + +#include +#include +#include +#include "issymlink.h" +#include "createsymlink.h" + +using namespace std; + +class CreateSymLinkTest : public ::testing::Test +{ +protected: + + static const int bufSize = 64; + const string fileTemplate = "/tmp/symlinktest.fXXXXXX"; + const string dirTemplate = "/tmp/symlinktest.dXXXXXX"; + const string fileSymLink = "/tmp/symlinktest.flink"; + const string dirSymLink = "/tmp/symlinktest.dlink"; + char *file, *dir; + char fileTemplateBuf[bufSize], dirTemplateBuf[bufSize]; + + CreateSymLinkTest() + { + // since mkstemp and mkdtemp modifies the template string, let's give them writable buffers + strcpy(fileTemplateBuf, fileTemplate.c_str()); + strcpy(dirTemplateBuf, dirTemplate.c_str()); + + // First create a temp file + int fd = mkstemp(fileTemplateBuf); + EXPECT_TRUE(fd != -1); + file = fileTemplateBuf; + + // Create a temp directory + dir = mkdtemp(dirTemplateBuf); + EXPECT_TRUE(dir != NULL); + + // Create symbolic link to file + int ret1 = CreateSymLink(fileSymLink.c_str(), file); + EXPECT_EQ(ret1, 1); + + // Create symbolic link to directory + int ret2 = CreateSymLink(dirSymLink.c_str(), dir); + EXPECT_EQ(ret2, 1); + } + + ~CreateSymLinkTest() + { + int ret; + + ret = unlink(fileSymLink.c_str()); + EXPECT_EQ(0, ret); + + ret = unlink(dirSymLink.c_str()); + EXPECT_EQ(0, ret); + + ret = unlink(file); + EXPECT_EQ(0, ret); + + ret = rmdir(dir); + EXPECT_EQ(0, ret); + } +}; + +TEST_F(CreateSymLinkTest, FilePathNameIsNull) +{ + int retVal = CreateSymLink(NULL, NULL); + EXPECT_EQ(retVal, 0); + EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); +} + +TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist) +{ + std::string invalidFile = "/tmp/symlinktest_invalidFile"; + std::string invalidLink = "/tmp/symlinktest_invalidLink"; + + // make sure neither exists + unlink(invalidFile.c_str()); + unlink(invalidLink.c_str()); + + // Linux allows creation of symbolic link that points to an invalid file + int retVal = CreateSymLink(invalidLink.c_str(), invalidFile.c_str()); + EXPECT_EQ(retVal, 1); + + unlink(invalidLink.c_str()); +} + +TEST_F(CreateSymLinkTest, SymLinkToFile) +{ + int retVal = IsSymLink(fileSymLink.c_str()); + EXPECT_EQ(1, retVal); +} + +TEST_F(CreateSymLinkTest, SymLinkToDirectory) +{ + int retVal = IsSymLink(dirSymLink.c_str()); + EXPECT_EQ(1, retVal); +} + +TEST_F(CreateSymLinkTest, SymLinkAgain) +{ + int retVal = CreateSymLink(fileSymLink.c_str(), file); + EXPECT_EQ(0, retVal); + EXPECT_EQ(ERROR_FILE_EXISTS, errno); +} From 5e0728e48e5c9317f35deeed4ac1493c2cf0639e Mon Sep 17 00:00:00 2001 From: George Fleming Date: Fri, 4 Mar 2016 15:59:32 -0800 Subject: [PATCH 293/342] New native code to support creation of hard links --- src/CMakeLists.txt | 1 + src/createhardlink.cpp | 115 +++++++++++++++++++++++++++++++++++ src/createhardlink.h | 9 +++ src/pal.h | 1 + test/CMakeLists.txt | 1 + test/test-createhardlink.cpp | 91 +++++++++++++++++++++++++++ 6 files changed, 218 insertions(+) create mode 100644 src/createhardlink.cpp create mode 100644 src/createhardlink.h create mode 100644 test/test-createhardlink.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b75ba8f16..cfd91e9fb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(psl-native SHARED issymlink.cpp isexecutable.cpp setdate.cpp + createhardlink.cpp createsymlink.cpp) target_include_directories(psl-native PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/createhardlink.cpp b/src/createhardlink.cpp new file mode 100644 index 000000000..2f131efaa --- /dev/null +++ b/src/createhardlink.cpp @@ -0,0 +1,115 @@ +//! @file createsymlink.cpp +//! @author George FLeming +//! @brief create new hard link + +#include +#include +#include +#include "createhardlink.h" + +//! @brief Createhardlink create new symbolic link +//! +//! Createhardlink +//! +//! @param[in] link +//! @parblock +//! A pointer to the buffer that contains the symbolic link to create +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @endparblock +//! +//! @param[in] target +//! @parblock +//! A pointer to the buffer that contains the existing file +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @endparblock +//! +//! @exception errno Passes these errors via errno to GetLastError: +//! - ERROR_INVALID_PARAMETER: parameter is not valid +//! - ERROR_FILE_NOT_FOUND: file does not exist +//! - ERROR_ACCESS_DENIED: access is denied +//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified +//! - ERROR_INVALID_ADDRESS: attempt to access invalid address +//! - ERROR_TOO_MANY_LINK: max number of hard links has been exceeded +//! - ERROR_GEN_FAILURE: device attached to the system is not functioning +//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file +//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect +//! - ERROR_BUFFER_OVERFLOW: file name is too long +//! - ERROR_INVALID_FUNCTION: incorrect function +//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters +//! +//! @retval 1 if creation is successful +//! @retval 0 if createion failed +//! + +int32_t CreateHardLink(const char *newlink, const char *target) +{ + errno = 0; + + // Check parameters + if (!newlink || !target) + { + errno = ERROR_INVALID_PARAMETER; + return 0; + } + + int returnCode = link(target, newlink); + + if (returnCode == 0) + { + return 1; + } + + switch(errno) + { + case EACCES: + errno = ERROR_ACCESS_DENIED; + break; + case EDQUOT: + errno = ERROR_DISK_FULL; + break; + case EEXIST: + errno = ERROR_FILE_EXISTS; + break; + case EFAULT: + errno = ERROR_INVALID_ADDRESS; + break; + case EIO: + errno = ERROR_GEN_FAILURE; + break; + case ELOOP: + errno = ERROR_TOO_MANY_LINKS; + break; + case EMLINK: + errno = ERROR_TOO_MANY_LINKS; + break; + case ENAMETOOLONG: + errno = ERROR_BAD_PATH_NAME; + break; + case ENOENT: + errno = ERROR_FILE_NOT_FOUND; + break; + case ENOMEM: + errno = ERROR_OUTOFMEMORY; + break; + case ENOTDIR: + errno = ERROR_INVALID_NAME; + break; + case ENOSPC: + errno = ERROR_DISK_FULL; + break; + case EPERM: + errno = ERROR_ACCESS_DENIED; + break; + case EROFS: + errno = ERROR_ACCESS_DENIED; + break; + case EXDEV: + errno = ERROR_GEN_FAILURE; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return 0; +} diff --git a/src/createhardlink.h b/src/createhardlink.h new file mode 100644 index 000000000..b8e62ddcc --- /dev/null +++ b/src/createhardlink.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +int32_t CreateHardLink(const char *link, const char *target); + +PAL_END_EXTERNC diff --git a/src/pal.h b/src/pal.h index 754289776..39fb6db82 100644 --- a/src/pal.h +++ b/src/pal.h @@ -24,6 +24,7 @@ #define ERROR_BAD_NET_NAME 0x00000043 #define ERROR_DISK_FULL 0x00000070 #define ERROR_FILE_EXISTS 0x00000050 +#define ERROR_TOO_MANY_LINKS 0x00000476 /* **============================================================================== diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cd9bf063d..4ddc53836 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable(psl-native-test test-issymlink.cpp test-isexecutable.cpp test-createsymlink.cpp + test-createhardlink.cpp main.cpp) # manually include gtest headers diff --git a/test/test-createhardlink.cpp b/test/test-createhardlink.cpp new file mode 100644 index 000000000..090864b9f --- /dev/null +++ b/test/test-createhardlink.cpp @@ -0,0 +1,91 @@ +//! @file test-createhardlink.cpp +//! @author George Fleming +//! @brief Implements test for CreateHardLink() + +#include +#include +#include +#include "getlinkcount.h" +#include "createhardlink.h" + +using namespace std; + +class CreateHardLinkTest : public ::testing::Test +{ +protected: + + static const int bufSize = 64; + const string fileTemplate = "/tmp/symlinktest.fXXXXXX"; + const string dirTemplate = "/tmp/symlinktest.dXXXXXX"; + const string fileHardLink = "/tmp/symlinktest.flink"; + const string dirHardLink = "/tmp/symlinktest.dlink"; + char *file, *dir; + char fileTemplateBuf[bufSize], dirTemplateBuf[bufSize]; + + CreateHardLinkTest() + { + // since mkstemp and mkdtemp modifies the template string, let's give them writable buffers + strcpy(fileTemplateBuf, fileTemplate.c_str()); + strcpy(dirTemplateBuf, dirTemplate.c_str()); + + // First create a temp file + int fd = mkstemp(fileTemplateBuf); + EXPECT_TRUE(fd != -1); + file = fileTemplateBuf; + + // Create a temp directory + dir = mkdtemp(dirTemplateBuf); + EXPECT_TRUE(dir != NULL); + + // Create hard link to file + int ret1 = CreateHardLink(fileHardLink.c_str(), file); + EXPECT_EQ(ret1, 1); + + // Create hard link to directory - should fail + int ret2 = CreateHardLink(dirHardLink.c_str(), dir); + EXPECT_EQ(ret2, 0); + } + + ~CreateHardLinkTest() + { + int ret; + + ret = unlink(fileHardLink.c_str()); + EXPECT_EQ(0, ret); + + ret = unlink(file); + EXPECT_EQ(0, ret); + + ret = rmdir(dir); + EXPECT_EQ(0, ret); + } +}; + +TEST_F(CreateHardLinkTest, FilePathNameIsNull) +{ + int retVal = CreateHardLink(NULL, NULL); + EXPECT_EQ(retVal, 0); + EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); +} + +TEST_F(CreateHardLinkTest, FilePathNameDoesNotExist) +{ + std::string invalidFile = "/tmp/symlinktest_invalidFile"; + std::string invalidLink = "/tmp/symlinktest_invalidLink"; + + // make sure neither exists + unlink(invalidFile.c_str()); + unlink(invalidLink.c_str()); + + int retVal = CreateHardLink(invalidLink.c_str(), invalidFile.c_str()); + EXPECT_EQ(retVal, 0); +} + +TEST_F(CreateHardLinkTest, VerifyLinkCount) +{ + int count = 0; + int retVal = GetLinkCount(fileHardLink.c_str(), &count); + EXPECT_EQ(1, retVal); + EXPECT_EQ(2, count); +} + From 7146cc0b860aa7c9401eaea8b807a86290c5061a Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 4 Mar 2016 19:52:03 -0800 Subject: [PATCH 294/342] Fix test of FQDN We can't use `hostname --fqdn` or any other shell tool because there is no POSIX compatible way to do this short of system calls. Unfortunately this means the test practically reimplements the original code, but oh well. --- test/test-getfullyqualifiedname.cpp | 36 +++++++++++++++++------------ 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/test/test-getfullyqualifiedname.cpp b/test/test-getfullyqualifiedname.cpp index 974316562..7c0353cd1 100644 --- a/test/test-getfullyqualifiedname.cpp +++ b/test/test-getfullyqualifiedname.cpp @@ -4,6 +4,10 @@ #include #include "getfullyqualifiedname.h" +#include +#include +#include +#include //! Test fixture for GetComputerNameTest class GetFullyQualifiedNameTest : public ::testing::Test @@ -12,23 +16,25 @@ class GetFullyQualifiedNameTest : public ::testing::Test TEST_F(GetFullyQualifiedNameTest, ValidateLinuxGetFullyQualifiedDomainName) { - char expectedComputerName[_POSIX_HOST_NAME_MAX]; - - //Get expected result from using linux command + std::string actual(GetFullyQualifiedName()); - FILE *fPtr = popen("hostname --fqdn", "r"); - ASSERT_TRUE(fPtr != NULL); + std::string hostname(_POSIX_HOST_NAME_MAX, 0); + ASSERT_FALSE(gethostname(&hostname[0], hostname.length())); + // trim null characters from string + hostname = std::string(hostname.c_str()); - char *linePtr = fgets(expectedComputerName, sizeof(expectedComputerName), fPtr); - ASSERT_TRUE(linePtr != NULL); + struct addrinfo hints, *info; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + ASSERT_FALSE(getaddrinfo(hostname.c_str(), "http", &hints, &info)); - // There's a tendency to have \n at end of fgets string, so remove it before compare - size_t sz = strlen(expectedComputerName); - if (sz > 0 && expectedComputerName[sz - 1] == '\n') - { - expectedComputerName[sz - 1] = '\0'; - } - pclose(fPtr); + // Compare hostname part of FQDN + ASSERT_EQ(hostname, actual.substr(0, hostname.length())); - ASSERT_STREQ(GetFullyQualifiedName(), expectedComputerName); + // Compare canonical name to FQDN + ASSERT_EQ(info->ai_canonname, actual); + + freeaddrinfo(info); } From 61667a43b58f34b3101bd388b8b822b7db404349 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 4 Mar 2016 19:52:59 -0800 Subject: [PATCH 295/342] Ignore built library on OS X --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 798fa6c00..0dff69372 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ CTestTestfile.cmake Testing/ test/psl-native-test src/libpsl-native.so +src/libpsl-native.dylib test/native-tests.xml From 86801f0457df8bd582cd861d656cb47313c65824 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 4 Mar 2016 19:53:16 -0800 Subject: [PATCH 296/342] Various code cleanups --- src/getcomputername.cpp | 4 +--- src/getcomputername.h | 2 +- src/getfullyqualifiedname.cpp | 21 +++++++++------------ src/getfullyqualifiedname.h | 2 +- src/getlinkcount.cpp | 1 - 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/getcomputername.cpp b/src/getcomputername.cpp index e363cf167..3e480b9ad 100644 --- a/src/getcomputername.cpp +++ b/src/getcomputername.cpp @@ -12,7 +12,7 @@ //! //! @exception errno Passes these errors via errno to GetLastError: //! - ERROR_INVALID_FUNCTION: getlogin_r() returned an unrecognized error code -//! - ERROR_INVALID_ADDRESS: buffer is an invalid address +//! - ERROR_INVALID_ADDRESS: buffer is an invalid address //! - ERROR_GEN_FAILURE: buffer not large enough //! //! @retval username as UTF-8 string, or null if unsuccessful @@ -42,6 +42,4 @@ char* GetComputerName() } return strdup(computername.c_str()); - } - diff --git a/src/getcomputername.h b/src/getcomputername.h index 66b0c352b..363210921 100644 --- a/src/getcomputername.h +++ b/src/getcomputername.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -char* GetComputerName(); +char *GetComputerName(); PAL_END_EXTERNC diff --git a/src/getfullyqualifiedname.cpp b/src/getfullyqualifiedname.cpp index 5d711c2f3..44178a0a5 100644 --- a/src/getfullyqualifiedname.cpp +++ b/src/getfullyqualifiedname.cpp @@ -12,7 +12,6 @@ //! @brief GetFullyQualifiedName retrieves the fully qualifed dns name of the host //! //! @exception errno Passes these errors via errno to GetLastError: -//! - ERROR_BAD_ENVIRONMENT: locale is not UTF-8 (from GetComputerName) //! - ERROR_INVALID_FUNCTION: getlogin_r() returned an unrecognized error code (from GetComputerName) //! - ERROR_INVALID_ADDRESS: buffer is an invalid address (from GetComputerName) //! - ERROR_GEN_FAILURE: buffer not large enough (from GetComputerName) @@ -21,12 +20,12 @@ //! @retval username as UTF-8 string, or null if unsuccessful //! -char* GetFullyQualifiedName() +char *GetFullyQualifiedName() { errno = 0; - + char *computerName = GetComputerName(); - if (NULL == computerName) + if (computerName == NULL) { return NULL; } @@ -37,7 +36,6 @@ char* GetFullyQualifiedName() } struct addrinfo hints, *info; - int gai_result; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; /*either IPV4 or IPV6*/ @@ -45,12 +43,12 @@ char* GetFullyQualifiedName() hints.ai_flags = AI_CANONNAME; /* There are several ways to get the domain name: - * uname(2), gethostbyname(3), resolver(3), getdomainname(2), - * and getaddrinfo(3). Some of these are not portable, some aren't - * POSIX compliant, and some are being deprecated. Getaddrinfo seems - * to be the best choice right now. + * uname(2), gethostbyname(3), resolver(3), getdomainname(2), + * and getaddrinfo(3). Some of these are not portable, some aren't + * POSIX compliant, and some are being deprecated. getaddrinfo seems + * to be the best choice. */ - if ((gai_result = getaddrinfo(computerName, "http", &hints, &info)) != 0) + if (getaddrinfo(computerName, "http", &hints, &info) != 0) { errno = ERROR_BAD_NET_NAME; return NULL; @@ -58,10 +56,9 @@ char* GetFullyQualifiedName() // info is actually a link-list. We'll just return the first full name - char *fullName = strdup(info->ai_canonname); + char *fullName = strndup(info->ai_canonname, strlen(info->ai_canonname)); freeaddrinfo(info); free(computerName); return fullName; } - diff --git a/src/getfullyqualifiedname.h b/src/getfullyqualifiedname.h index 4db1fd2e7..b44ab68fd 100644 --- a/src/getfullyqualifiedname.h +++ b/src/getfullyqualifiedname.h @@ -4,6 +4,6 @@ PAL_BEGIN_EXTERNC -char* GetFullyQualifiedName(); +char *GetFullyQualifiedName(); PAL_END_EXTERNC diff --git a/src/getlinkcount.cpp b/src/getlinkcount.cpp index 9e8db3d65..1b97a4167 100644 --- a/src/getlinkcount.cpp +++ b/src/getlinkcount.cpp @@ -101,5 +101,4 @@ int32_t GetLinkCount(const char* fileName, int32_t *count) *count = statBuf.st_nlink; return 1; - } From 454524cf7294021584a3005f2f3243c80b670a89 Mon Sep 17 00:00:00 2001 From: George Fleming Date: Fri, 25 Mar 2016 14:37:16 -0700 Subject: [PATCH 297/342] new native code and test for obtaining target of symlinks --- src/CMakeLists.txt | 3 +- src/followsymlink.cpp | 90 +++++++++++++++++++++++++++++++++++++ src/followsymlink.h | 9 ++++ test/test-createsymlink.cpp | 14 +++++- 4 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 src/followsymlink.cpp create mode 100644 src/followsymlink.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cfd91e9fb..5b2ec2419 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(psl-native SHARED isexecutable.cpp setdate.cpp createhardlink.cpp - createsymlink.cpp) + createsymlink.cpp + followsymlink.cpp) target_include_directories(psl-native PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/followsymlink.cpp b/src/followsymlink.cpp new file mode 100644 index 000000000..40e12b9b7 --- /dev/null +++ b/src/followsymlink.cpp @@ -0,0 +1,90 @@ +//! @file followSymLink.cpp +//! @author George FLeming +//! @brief returns whether a path is a symbolic link + +#include +#include +#include +#include +#include "followsymlink.h" + +//! @brief Followsymlink determines target path of a sym link +//! +//! Followsymlink +//! +//! @param[in] fileName +//! @parblock +//! A pointer to the buffer that contains the file name +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @endparblock +//! +//! @exception errno Passes these errors via errno to GetLastError: +//! - ERROR_INVALID_PARAMETER: parameter is not valid +//! - ERROR_FILE_NOT_FOUND: file does not exist +//! - ERROR_ACCESS_DENIED: access is denied +//! - ERROR_INVALID_ADDRESS: attempt to access invalid address +//! - ERROR_STOPPED_ON_SYMLINK: too many symbolic links +//! - ERROR_GEN_FAILURE: I/O error occurred +//! - ERROR_INVALID_NAME: file provided is not a symbolic link +//! - ERROR_INVALID_FUNCTION: incorrect function +//! - ERROR_BAD_PATH_NAME: pathname is too long +//! - ERROR_OUTOFMEMORY insufficient kernal memory +//! +//! @retval target path, or NULL if unsuccessful +//! + +char* FollowSymLink(const char* fileName) +{ + errno = 0; + + // Check parameters + if (!fileName) + { + errno = ERROR_INVALID_PARAMETER; + return NULL; + } + + char buffer[PATH_MAX]; + ssize_t sz = readlink(fileName, buffer, PATH_MAX); + + if (sz == -1) + { + switch(errno) + { + case EACCES: + errno = ERROR_ACCESS_DENIED; + break; + case EFAULT: + errno = ERROR_INVALID_ADDRESS; + break; + case EINVAL: + errno = ERROR_INVALID_NAME; + break; + case EIO: + errno = ERROR_GEN_FAILURE; + break; + case ELOOP: + errno = ERROR_STOPPED_ON_SYMLINK; + break; + case ENAMETOOLONG: + errno = ERROR_BAD_PATH_NAME; + break; + case ENOENT: + errno = ERROR_FILE_NOT_FOUND; + break; + case ENOMEM: + errno = ERROR_OUTOFMEMORY; + break; + case ENOTDIR: + errno = ERROR_BAD_PATH_NAME; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return NULL; + } + + buffer[sz] = '\0'; + return strndup(buffer, sz + 1); +} diff --git a/src/followsymlink.h b/src/followsymlink.h new file mode 100644 index 000000000..fac7f5244 --- /dev/null +++ b/src/followsymlink.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +char* FollowSymLink(const char* fileName); + +PAL_END_EXTERNC diff --git a/test/test-createsymlink.cpp b/test/test-createsymlink.cpp index 1100d022c..abc0646c6 100644 --- a/test/test-createsymlink.cpp +++ b/test/test-createsymlink.cpp @@ -1,12 +1,13 @@ -//! @file test-issymlink.cpp +//! @file test-createsymlink.cpp //! @author George Fleming -//! @brief Implements test for isSymLink() +//! @brief Implements test for CreateSymLink() and FollowSymLink() #include #include #include #include "issymlink.h" #include "createsymlink.h" +#include "followsymlink.h" using namespace std; @@ -84,6 +85,9 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist) int retVal = CreateSymLink(invalidLink.c_str(), invalidFile.c_str()); EXPECT_EQ(retVal, 1); + std::string target = FollowSymLink(invalidLink.c_str()); + EXPECT_EQ(target, invalidFile); + unlink(invalidLink.c_str()); } @@ -91,12 +95,18 @@ TEST_F(CreateSymLinkTest, SymLinkToFile) { int retVal = IsSymLink(fileSymLink.c_str()); EXPECT_EQ(1, retVal); + + std::string target = FollowSymLink(fileSymLink.c_str()); + EXPECT_EQ(target, file); } TEST_F(CreateSymLinkTest, SymLinkToDirectory) { int retVal = IsSymLink(dirSymLink.c_str()); EXPECT_EQ(1, retVal); + + std::string target = FollowSymLink(dirSymLink.c_str()); + EXPECT_EQ(target, dir); } TEST_F(CreateSymLinkTest, SymLinkAgain) From 4bb241ad11c54985617343fbeb8700cfdcdf7ae0 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 28 Mar 2016 14:04:36 -0700 Subject: [PATCH 298/342] Output libraries to host directory --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f5778ed81..d0e83e6bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 2.8.4) project(PSL-NATIVE) add_compile_options(-std=c++11 -Wall -Werror) +set(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/../Microsoft.PowerShell.Linux.Host") # test in BUILD_DIR enable_testing() From 646d234d1ff44080b38a27df6814a5620f6096eb Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 10:32:32 -0700 Subject: [PATCH 299/342] Revert "Remove runtimes sections from projects" This reverts commit 47fd1a45bc40095bf2c31d7c1bbdacac504d65bc. Per dotnet/cli#2029, RID inference is no longer supported by NuGet, and so the runtimes section needs to exist again. --- src/Microsoft.PowerShell.Linux.Host/project.json | 9 +++++++++ src/TypeCatalogParser/project.json | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/Microsoft.PowerShell.Linux.Host/project.json b/src/Microsoft.PowerShell.Linux.Host/project.json index 0bdce2016..98d8943ad 100644 --- a/src/Microsoft.PowerShell.Linux.Host/project.json +++ b/src/Microsoft.PowerShell.Linux.Host/project.json @@ -28,5 +28,14 @@ "netstandardapp1.5": { "imports": [ "dnxcore50", "portable-net45+win8" ] } + }, + + "runtimes": { + "ubuntu.14.04-x64": { }, + "centos.7.1-x64": { }, + "win7-x64": { }, + "win10-x64": { }, + "osx.10.10-x64": { }, + "osx.10.11-x64": { } } } diff --git a/src/TypeCatalogParser/project.json b/src/TypeCatalogParser/project.json index f3e2050da..ed52514f4 100644 --- a/src/TypeCatalogParser/project.json +++ b/src/TypeCatalogParser/project.json @@ -13,5 +13,14 @@ "netstandardapp1.5": { "imports": [ "dnxcore50", "portable-net45+win8" ] } + }, + + "runtimes": { + "ubuntu.14.04-x64": { }, + "centos.7.1-x64": { }, + "win7-x64": { }, + "win10-x64": { }, + "osx.10.10-x64": { }, + "osx.10.11-x64": { } } } From c128bbfe629b717459892b289a16115dff7629fb Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 12:11:50 -0700 Subject: [PATCH 300/342] Add COREHOST_TRACE debugging note --- docs/debugging/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/debugging/README.md b/docs/debugging/README.md index e1aaee6d7..4c5c17b91 100644 --- a/docs/debugging/README.md +++ b/docs/debugging/README.md @@ -42,3 +42,9 @@ provide a PID. (Please be careful not to commit such a change). [vscode]: https://code.visualstudio.com/ [OmniSharp]: https://github.com/OmniSharp/omnisharp-vscode [vscclrdebugger]: http://aka.ms/vscclrdebugger + +corehost +-------- + +The native executable prouduced by .NET CLI will produce trace output +if launched with `COREHOST_TRACE=1 ./powershell`. From 6ad880722c84736746f1dcfe67f8c52a8582aafc Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 12:12:00 -0700 Subject: [PATCH 301/342] Add PAL_DBG_CHANNELS note --- docs/debugging/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/debugging/README.md b/docs/debugging/README.md index 4c5c17b91..2994048d1 100644 --- a/docs/debugging/README.md +++ b/docs/debugging/README.md @@ -48,3 +48,13 @@ corehost The native executable prouduced by .NET CLI will produce trace output if launched with `COREHOST_TRACE=1 ./powershell`. + +CoreCLR PAL +----------- + +The native code in the CLR has debug channels to selectively output +information to the console. These are controlled by the +`PAL_DBG_CHANNELS`, e.g., `export PAL_DBG_CHANNELS="+all.all"`, as +detailed in the `dbgmsg.h` [header][]. + +[header]: https://github.com/dotnet/coreclr/blob/release/1.0.0-rc2/src/pal/src/include/pal/dbgmsg.h From b9232256fb798cb84f2b9cf2f4432d4b9cf6aff1 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 12:12:29 -0700 Subject: [PATCH 302/342] Remove duplicate #if CORECLR from SMA/CoreCLR --- src/System.Management.Automation/CoreCLR/CorePsExtensions.cs | 4 ---- src/System.Management.Automation/CoreCLR/CorePsStub.cs | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs index f6fb21d0b..ec69e4fa4 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs @@ -3,8 +3,6 @@ Copyright (c) Microsoft Corporation. All rights reserved. --********************************************************************/ -#if CORECLR - using System.Globalization; using System.Linq; using System.Reflection; @@ -1679,5 +1677,3 @@ namespace Microsoft.PowerShell.CoreCLR } #endif - -#endif diff --git a/src/System.Management.Automation/CoreCLR/CorePsStub.cs b/src/System.Management.Automation/CoreCLR/CorePsStub.cs index e17511684..319e359ff 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsStub.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsStub.cs @@ -12,8 +12,6 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.Win32; using System.Management.Automation.Remoting; -#if CORECLR - #pragma warning disable 1591, 1572, 1571, 1573, 1587, 1570, 0067 #region CLR_STUBS @@ -1874,5 +1872,3 @@ namespace System #pragma warning restore 1591, 1572, 1571, 1573, 1587, 1570, 0067 #endif - -#endif From 5c1e295e9a1deb8fefc57ff6baa022dd398e6bba Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 12:14:09 -0700 Subject: [PATCH 303/342] Remove -Output switch from PowerShellGitHubDev This is a breaking that stops publishing PowerShell by default, and instead relies on `dotnet build`. Thus the artifacts will be output to a new (RID, framework, and project dependent) location. Publishing will still be needed to produce packages, but this logic will be moved into `Start-PSPackage`. --- PowerShellGitHubDev.psm1 | 37 +++++++------------------------------ 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index fa22c2fe2..a7b916aff 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -23,7 +23,6 @@ function Start-PSBuild param( [switch]$Restore, [switch]$Clean, - [string]$Output, # These runtimes must match those in project.json # We do not use ValidateScript since we want tab completion @@ -67,17 +66,12 @@ function Start-PSBuild Write-Host -Foreground Green $message } - # simplify ParameterSetNames, set output + # simplify ParameterSetNames if ($PSCmdlet.ParameterSetName -eq 'FullCLR') { $FullCLR = $true } - if (-not $Output) - { - if ($FullCLR) { $Output = "$PSScriptRoot/binFull" } else { $Output = "$PSScriptRoot/bin" } - } - # verify we have all tools in place to do the build $precheck = precheck 'dotnet' "Build dependency 'dotnet' not found in PATH! See: https://dotnet.github.io/getting-started/" if ($FullCLR) @@ -97,13 +91,6 @@ function Start-PSBuild if (-not $precheck) { return } - # handle clean - if ($Clean) { - Remove-Item -Force -Recurse $Output -ErrorAction SilentlyContinue - } - - New-Item -Force -Type Directory $Output | Out-Null - # define key build variables if ($FullCLR) { @@ -182,38 +169,28 @@ function Start-PSBuild cmake ..\src\powershell-native } msbuild powershell.vcxproj /p:Configuration=$msbuildConfiguration - cp -rec $msbuildConfiguration\* $Output + # cp -rec $msbuildConfiguration\* $Output } finally { Pop-Location } } log "Building PowerShell" - $Arguments = "--framework", $framework, "--output", $Output + $Arguments = "--framework", $framework if ($IsLinux -Or $IsOSX) { $Arguments += "--configuration", "Linux" } if ($Runtime) { $Arguments += "--runtime", $Runtime } - if ($FullCLR) - { - # there is a problem with code signing: - # AssemblyKeyFileAttribute file path cannot be correctly located, if `dotnet publish $TOP` syntax is used - # we workaround it with calling `dotnet publish` from $TOP directory instead. - Push-Location $Top - } - else - { - $Arguments += $Top - } - Write-Verbose "Run dotnet publish $Arguments from $pwd" # this try-finally is part of workaround about AssemblyKeyFileAttribute issue try { - dotnet publish $Arguments + # Relative paths do not work well if cwd is not changed to project + Push-Location $Top + dotnet build $Arguments } finally { - if ($FullCLR) { Pop-Location } + Pop-Location } } From 34f6b44d9998f74ce72d4cd36a20910f4caf0ea3 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 12:14:24 -0700 Subject: [PATCH 304/342] Remove --runtime argument to `dotnet restore` --- PowerShellGitHubDev.psm1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index a7b916aff..da56aa800 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -111,8 +111,6 @@ function Start-PSBuild if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { $Arguments += "Info" } else { $Arguments += "Warning" } - if ($Runtime) { $Arguments += "--runtime", $Runtime } - $Arguments += "$PSScriptRoot" dotnet restore $Arguments From aa5c30d42ed2d6fbbdb8a1b65d5cb525dbf19357 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 14:41:13 -0700 Subject: [PATCH 305/342] Whitespace and style cleanups --- PowerShellGitHubDev.psm1 | 105 +++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 59 deletions(-) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index da56aa800..5e2d0519d 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -17,8 +17,7 @@ try { $IsWindows = $true } -function Start-PSBuild -{ +function Start-PSBuild { [CmdletBinding(DefaultParameterSetName='CoreCLR')] param( [switch]$Restore, @@ -43,63 +42,55 @@ function Start-PSBuild [Parameter(ParameterSetName='FullCLR')] [ValidateSet("Debug", - "Release")] - [string]$msbuildConfiguration = "Release" + "Release")] + [string]$msbuildConfiguration = "Release" ) - function precheck([string]$command, [string]$missedMessage) - { + function precheck([string]$command, [string]$missedMessage) { $c = Get-Command $command -ErrorAction SilentlyContinue - if (-not $c) - { + if (-not $c) { Write-Warning $missedMessage return $false - } - else - { - return $true + } else { + return $true } } - function log([string]$message) - { + function log([string]$message) { Write-Host -Foreground Green $message } # simplify ParameterSetNames - if ($PSCmdlet.ParameterSetName -eq 'FullCLR') - { + if ($PSCmdlet.ParameterSetName -eq 'FullCLR') { $FullCLR = $true } # verify we have all tools in place to do the build $precheck = precheck 'dotnet' "Build dependency 'dotnet' not found in PATH! See: https://dotnet.github.io/getting-started/" - if ($FullCLR) - { + if ($FullCLR) { # cmake is needed to build powershell.exe $precheck = $precheck -and (precheck 'cmake' 'cmake not found. You can install it from https://chocolatey.org/packages/cmake.portable') - + # msbuild is needed to build powershell.exe # msbuild is part of .NET Framework, we can try to get it from well-known location. - if (-not (Get-Command -Name msbuild -ErrorAction Ignore)) - { + if (-not (Get-Command -Name msbuild -ErrorAction Ignore)) { $env:path += ";${env:SystemRoot}\Microsoft.Net\Framework\v4.0.30319" } $precheck = $precheck -and (precheck 'msbuild' 'msbuild not found. Install Visual Studio 2015.') } - - if (-not $precheck) { return } + + # Abort if any precheck failed + if (-not $precheck) { + return + } # define key build variables - if ($FullCLR) - { + if ($FullCLR) { $Top = "$PSScriptRoot\src\Microsoft.PowerShell.ConsoleHost" $framework = 'net451' - } - else - { - $Top = "$PSScriptRoot/src/Microsoft.PowerShell.Linux.Host" + } else { + $Top = "$PSScriptRoot/src/Microsoft.PowerShell.Linux.Host" $framework = 'netstandardapp1.5' } @@ -109,7 +100,10 @@ function Start-PSBuild $Arguments = @("--verbosity") if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { - $Arguments += "Info" } else { $Arguments += "Warning" } + $Arguments += "Info" + } else { + $Arguments += "Warning" + } $Arguments += "$PSScriptRoot" @@ -154,46 +148,39 @@ function Start-PSBuild } mkdir $build -ErrorAction SilentlyContinue - try - { + try { Push-Location $build - if ($cmakeGenerator) - { + if ($cmakeGenerator) { cmake -G $cmakeGenerator ..\src\powershell-native - } - else - { + } else { cmake ..\src\powershell-native } msbuild powershell.vcxproj /p:Configuration=$msbuildConfiguration # cp -rec $msbuildConfiguration\* $Output + } finally { + Pop-Location } - finally { Pop-Location } } log "Building PowerShell" + $Arguments = "--framework", $framework if ($IsLinux -Or $IsOSX) { $Arguments += "--configuration", "Linux" } if ($Runtime) { $Arguments += "--runtime", $Runtime } - - Write-Verbose "Run dotnet publish $Arguments from $pwd" - # this try-finally is part of workaround about AssemblyKeyFileAttribute issue - try - { + log "Run dotnet build $Arguments from $pwd" + + try { # Relative paths do not work well if cwd is not changed to project Push-Location $Top dotnet build $Arguments - } - finally - { + } finally { Pop-Location } } -function Start-PSPackage -{ +function Start-PSPackage { # PowerShell packages use Semantic Versioning http://semver.org/ # # Ubuntu and OS X packages are supported. @@ -363,14 +350,14 @@ function Convert-PSObjectToHashtable .EXAMPLE Copy-SubmoduleFiles -ToSubmodule # copy files FROM src/ folders TO submodule #> function Copy-SubmoduleFiles { - + [CmdletBinding()] param( [string]$mappingFilePath = "$PSScriptRoot/mapping.json", [switch]$ToSubmodule ) - + if (-not (Test-Path $mappingFilePath)) { throw "Mapping file not found in $mappingFilePath" @@ -388,10 +375,10 @@ function Copy-SubmoduleFiles { { cp $_.Value $_.Key -Verbose:$Verbose } - else + else { mkdir (Split-Path $_.Value) -ErrorAction SilentlyContinue > $null - cp $_.Key $_.Value -Verbose:$Verbose + cp $_.Key $_.Value -Verbose:$Verbose } } } @@ -418,7 +405,7 @@ function New-MappingFile { return Split-Path $path -Leaf } - + if ($project -match 'Microsoft.Management.Infrastructure') { return Split-Path $path -Leaf @@ -487,7 +474,7 @@ function Get-InvertedOrderedMap } <# -.EXAMPLE Send-GitDiffToSd -diffArg1 45555786714d656bd31cbce67dbccb89c433b9cb -diffArg2 45555786714d656bd31cbce67dbccb89c433b9cb~1 -pathToAdmin d:\e\ps_dev\admin +.EXAMPLE Send-GitDiffToSd -diffArg1 45555786714d656bd31cbce67dbccb89c433b9cb -diffArg2 45555786714d656bd31cbce67dbccb89c433b9cb~1 -pathToAdmin d:\e\ps_dev\admin Apply a signle commit to admin folder #> function Send-GitDiffToSd @@ -521,19 +508,19 @@ function Send-GitDiffToSd Write-Host -Foreground Green "Patch content" cat $env:TEMP\diff } - else + else { - & $patchPath --binary -p1 $sdFilePath $env:TEMP\diff + & $patchPath --binary -p1 $sdFilePath $env:TEMP\diff } } - else + else { Write-Host -Foreground Green "No changes in $file" } } - else + else { Write-Host -Foreground Green "Ignore changes in $file, because there is no mapping for it" } - } + } } From 6cf8e39d1a010583ff7447bcb3d72277025e0f83 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 14:42:40 -0700 Subject: [PATCH 306/342] Refactor native build steps Move dependency checks to precheck section and make conditional more sensible. --- PowerShellGitHubDev.psm1 | 63 ++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index 5e2d0519d..a25a9510d 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -78,6 +78,17 @@ function Start-PSBuild { } $precheck = $precheck -and (precheck 'msbuild' 'msbuild not found. Install Visual Studio 2015.') + } elseif ($IsLinux -Or $IsOSX) { + $InstallCommand = if ($IsLinux) { + 'apt-get' + } elseif ($IsOSX) { + 'brew' + } + + foreach ($Dependency in 'cmake', 'make', 'g++') { + $precheck = $precheck -and (precheck $Dependency "Build dependency '$Dependency' not found. Run '$InstallCommand install $Dependency'") + } + } } # Abort if any precheck failed @@ -111,36 +122,30 @@ function Start-PSBuild { } # Build native components - if (-not $FullCLR) - { - if ($IsLinux -Or $IsOSX) { - log "Start building native components" - $InstallCommand = if ($IsLinux) { "apt-get" } elseif ($IsOSX) { "brew" } - foreach ($Dependency in "cmake", "g++") { - if (-Not (Get-Command $Dependency -ErrorAction SilentlyContinue)) { - throw "Build dependency '$Dependency' not found in PATH! Run '$InstallCommand install $Dependency'" - } - } - - $Ext = if ($IsLinux) { "so" } elseif ($IsOSX) { "dylib" } - $Native = "$PSScriptRoot/src/libpsl-native" - $Lib = "$Top/libpsl-native.$Ext" - Write-Verbose "Building $Lib" - - try { - Push-Location $Native - cmake -DCMAKE_BUILD_TYPE=Debug . - make -j - make test - } finally { - Pop-Location - } - - if (-Not (Test-Path $Lib)) { throw "Compilation of $Lib failed" } + if ($IsLinux -Or $IsOSX) { + $Ext = if ($IsLinux) { + "so" + } elseif ($IsOSX) { + "dylib" } - } - else - { + + $Native = "$PSScriptRoot/src/libpsl-native" + $Lib = "$Top/libpsl-native.$Ext" + log "Start building $Lib" + + try { + Push-Location $Native + cmake -DCMAKE_BUILD_TYPE=Debug . + make -j + make test + } finally { + Pop-Location + } + + if (-Not (Test-Path $Lib)) { + throw "Compilation of $Lib failed" + } + } elseif ($FullCLR) { log "Start building native powershell.exe" $build = "$PSScriptRoot/build" if ($Clean) { From bf470de5ca39849c81be5719acdc93e0b1e0df29 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 14:43:18 -0700 Subject: [PATCH 307/342] Obtain runtime from dotnet --info This is a breaking change that requires developers to update their version of .NET CLI. In order to stop specifying where dotnet should output the artifacts, we need to be able to guess their location correctly, which requires knowing the current RID (and framework). --- PowerShellGitHubDev.psm1 | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index a25a9510d..e14cf531a 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -89,6 +89,20 @@ function Start-PSBuild { $precheck = $precheck -and (precheck $Dependency "Build dependency '$Dependency' not found. Run '$InstallCommand install $Dependency'") } } + + if (-Not $Runtime) { + $Runtime = dotnet --info | % { + if ($_ -match "RID") { + $_ -split "\s+" | Select-Object -Last 1 + } + } + + if (-Not $Runtime) { + Write-Warning "Could not determine Runtime Identifier, please update dotnet" + $precheck = $false + } else { + log "Runtime not specified, using $Runtime" + } } # Abort if any precheck failed @@ -171,8 +185,12 @@ function Start-PSBuild { log "Building PowerShell" $Arguments = "--framework", $framework - if ($IsLinux -Or $IsOSX) { $Arguments += "--configuration", "Linux" } - if ($Runtime) { $Arguments += "--runtime", $Runtime } + + if ($IsLinux -Or $IsOSX) { + $Arguments += "--configuration", "Linux" + } + + $Arguments += "--runtime", $Runtime log "Run dotnet build $Arguments from $pwd" From 1293c632898fa5398f293e00845317bc9abd0432 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 16:48:16 -0700 Subject: [PATCH 308/342] Deploy powershell.exe as content for ConsoleHost CMake will now output the artifacts of the native build into the ConsoleHost project, where .NET CLI picks it up as content and deploys it automatically. --- PowerShellGitHubDev.psm1 | 1 - src/Microsoft.PowerShell.ConsoleHost/project.json | 4 ++++ src/powershell-native/CMakeLists.txt | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index e14cf531a..94c009c5c 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -176,7 +176,6 @@ function Start-PSBuild { cmake ..\src\powershell-native } msbuild powershell.vcxproj /p:Configuration=$msbuildConfiguration - # cp -rec $msbuildConfiguration\* $Output } finally { Pop-Location } diff --git a/src/Microsoft.PowerShell.ConsoleHost/project.json b/src/Microsoft.PowerShell.ConsoleHost/project.json index 0b99854b1..1a22616bb 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/project.json +++ b/src/Microsoft.PowerShell.ConsoleHost/project.json @@ -14,6 +14,10 @@ "Microsoft.PowerShell.Commands.Utility": "1.0.0-*" }, + "content": [ + "powershell.exe" + ], + "frameworks": { "net451": { } diff --git a/src/powershell-native/CMakeLists.txt b/src/powershell-native/CMakeLists.txt index 183988d69..738bcd033 100644 --- a/src/powershell-native/CMakeLists.txt +++ b/src/powershell-native/CMakeLists.txt @@ -3,6 +3,9 @@ project(PowerShell) add_compile_options() +# set the output path for `powershell.exe` +set(EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/../Microsoft.PowerShell.ConsoleHost") + # set these flags, so build does static linking for msvcr120.dll # otherwise this dll need to be present on the system set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") From 2ddf3e9ff0e156b65b0ffb56a2817c9f8baf883d Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 16:52:14 -0700 Subject: [PATCH 309/342] Bump .NET CLI version on AppVeyor --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index e10ecacea..0f458d711 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,7 +22,7 @@ install: - git config --global url.git@github.com:.insteadOf https://github.com/ - git submodule update --init --recursive -- src/windows-build src/Microsoft.PowerShell.Linux.Host/Modules/Pester - ps: Invoke-WebRequest -Uri https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/install.ps1 -OutFile install.ps1 - - ps: ./install.ps1 -version 1.0.0.001888 + - ps: ./install.ps1 -version 1.0.0-beta-002198 build_script: - ps: | From 540acd59d1c4a8aa73b18e8a7dfdf9203b36f547 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 16:59:29 -0700 Subject: [PATCH 310/342] Install latest .NET CLI packages on Travis --- .travis.yml | 7 ++----- bootstrap.sh | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) create mode 100755 bootstrap.sh diff --git a/.travis.yml b/.travis.yml index 8e78e7449..520ee5b24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,12 +10,9 @@ git: before_install: - git config --global url.git@github.com:.insteadOf https://github.com/ - git submodule update --init --recursive -- src/libpsl-native src/windows-build src/Microsoft.PowerShell.Linux.Host/Modules/Pester - - sudo sh -c 'echo "deb [arch=amd64] http://apt-mo.trafficmanager.net/repos/dotnet/ trusty main" > /etc/apt/sources.list.d/dotnetdev.list' - - sudo apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893 - - sudo apt-get -qq update - - sudo apt-get install -y dotnet=1.0.0.001675-1 + - ./bootstrap.sh - ./download.sh - - sudo dpkg -i powershell.deb + - sudo dpkg -i ./powershell.deb script: - powershell -c "Import-Module ./PowerShellGitHubDev.psm1; Start-PSBuild" - ./pester.sh diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 000000000..599321730 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +echo "Installing build dependencies" + +curl http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add - +echo "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.6 main" | sudo tee /etc/apt/sources.list.d/llvm.list +sudo apt-get update -qq + +sudo apt-get install -y wget make g++ cmake \ + libc6 libgcc1 libstdc++6 \ + libcurl3 libgssapi-krb5-2 libicu52 liblldb-3.6 liblttng-ust0 libssl1.0.0 libunwind8 libuuid1 zlib1g clang-3.5 + +wget -P /tmp https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-host-ubuntu-x64.latest.deb +sudo dpkg -i /tmp/dotnet-host-ubuntu-x64.latest.deb + +wget -P /tmp https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-sharedframework-ubuntu-x64.latest.deb +sudo dpkg -i /tmp/dotnet-sharedframework-ubuntu-x64.latest.deb + +wget -P /tmp https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-sdk-ubuntu-x64.latest.deb +sudo dpkg -i /tmp/dotnet-sdk-ubuntu-x64.latest.deb From fde63f4bc0c4c86d91b79364810eead5e6930d67 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 17:01:18 -0700 Subject: [PATCH 311/342] Add win81-x64 runtime It's what AppVeyor uses. --- PowerShellGitHubDev.psm1 | 1 + src/Microsoft.PowerShell.Linux.Host/project.json | 1 + 2 files changed, 2 insertions(+) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index 94c009c5c..35cc98c50 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -28,6 +28,7 @@ function Start-PSBuild { [ValidateSet("ubuntu.14.04-x64", "centos.7.1-x64", "win7-x64", + "win81-x64", "win10-x64", "osx.10.10-x64", "osx.10.11-x64")] diff --git a/src/Microsoft.PowerShell.Linux.Host/project.json b/src/Microsoft.PowerShell.Linux.Host/project.json index 98d8943ad..a70785c07 100644 --- a/src/Microsoft.PowerShell.Linux.Host/project.json +++ b/src/Microsoft.PowerShell.Linux.Host/project.json @@ -34,6 +34,7 @@ "ubuntu.14.04-x64": { }, "centos.7.1-x64": { }, "win7-x64": { }, + "win81-x64": { }, "win10-x64": { }, "osx.10.10-x64": { }, "osx.10.11-x64": { } From 2b46e0d5eb8a8bffb1e2ba8d32b5e50e54cb664d Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 17:51:38 -0700 Subject: [PATCH 312/342] Add $script:Output to store location of executable --- PowerShellGitHubDev.psm1 | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index 35cc98c50..cad22df76 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -114,12 +114,27 @@ function Start-PSBuild { # define key build variables if ($FullCLR) { $Top = "$PSScriptRoot\src\Microsoft.PowerShell.ConsoleHost" - $framework = 'net451' + $Framework = 'net451' } else { $Top = "$PSScriptRoot/src/Microsoft.PowerShell.Linux.Host" - $framework = 'netstandardapp1.5' + $Framework = 'netstandardapp1.5' } + if ($IsLinux -Or $IsOSX) { + $Configuration = "Linux" + $Executable = "powershell" + } else { + $Configuration = "Debug" + $Executable = "powershell.exe" + } + + $Arguments = @() + $Arguments += "--framework", $Framework + $Arguments += "--configuration", $Configuration + $Arguments += "--runtime", $Runtime + $script:Output = [IO.Path]::Combine($Top, "bin", $Configuration, $Framework, $Runtime, $Executable) + Write-Verbose "script:Output is $script:Output" + # handle Restore if ($Restore -Or -Not (Test-Path "$Top/project.lock.json")) { log "Run dotnet restore" @@ -182,25 +197,19 @@ function Start-PSBuild { } } - log "Building PowerShell" - - $Arguments = "--framework", $framework - - if ($IsLinux -Or $IsOSX) { - $Arguments += "--configuration", "Linux" - } - - $Arguments += "--runtime", $Runtime - - log "Run dotnet build $Arguments from $pwd" - try { # Relative paths do not work well if cwd is not changed to project + log "Run `dotnet build $Arguments` from $pwd" Push-Location $Top dotnet build $Arguments } finally { Pop-Location } + +} + +function Get-PSOutput { + $script:Output } function Start-PSPackage { From 2264613ae3b82b1286c55ccadfa926e7ce4da8e9 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 17:57:58 -0700 Subject: [PATCH 313/342] Remove libpsl-native submodule --- .gitmodules | 3 --- src/libpsl-native | 1 - 2 files changed, 4 deletions(-) delete mode 160000 src/libpsl-native diff --git a/.gitmodules b/.gitmodules index 8a49b569c..ad2f17c68 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "src/libpsl-native"] - path = src/libpsl-native - url = https://github.com/PowerShell/psl-native.git [submodule "src/omi"] path = src/omi url = https://github.com/Microsoft/omi.git diff --git a/src/libpsl-native b/src/libpsl-native deleted file mode 160000 index 4bb241ad1..000000000 --- a/src/libpsl-native +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4bb241ad11c54985617343fbeb8700cfdcdf7ae0 From 774dcb7996fcb999f76d49bae9e9d7581574a5dd Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 18:02:20 -0700 Subject: [PATCH 314/342] Migrate libpsl-native googletest submodule --- .gitmodules | 4 ++++ src/libpsl-native/.gitmodules | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 src/libpsl-native/.gitmodules diff --git a/.gitmodules b/.gitmodules index ad2f17c68..6c1c2e5f3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,7 @@ url = https://github.com/PowerShell/psl-pester.git branch = develop ignore = dirty +[submodule "src/libpsl-native/test/googletest"] + path = src/libpsl-native/test/googletest + url = https://github.com/google/googletest.git + ignore = dirty diff --git a/src/libpsl-native/.gitmodules b/src/libpsl-native/.gitmodules deleted file mode 100644 index 7cdedd847..000000000 --- a/src/libpsl-native/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "test/googletest"] - path = test/googletest - url = https://github.com/google/googletest.git - ignore = dirty From 9571b220b2c9d8456e2d2b8dd004545c06339ba6 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 18:04:25 -0700 Subject: [PATCH 315/342] Initialize googletest submodule on Travis --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 520ee5b24..7680f2faf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ git: submodules: false before_install: - git config --global url.git@github.com:.insteadOf https://github.com/ - - git submodule update --init --recursive -- src/libpsl-native src/windows-build src/Microsoft.PowerShell.Linux.Host/Modules/Pester + - git submodule update --init -- src/windows-build src/Microsoft.PowerShell.Linux.Host/Modules/Pester src/libpsl-native/test/googletest - ./bootstrap.sh - ./download.sh - sudo dpkg -i ./powershell.deb diff --git a/appveyor.yml b/appveyor.yml index 0f458d711..64a1438a3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,7 +20,7 @@ install: - ps: $fileContent += "`n-----END RSA PRIVATE KEY-----`n" - ps: Set-Content c:\users\appveyor\.ssh\id_rsa $fileContent - git config --global url.git@github.com:.insteadOf https://github.com/ - - git submodule update --init --recursive -- src/windows-build src/Microsoft.PowerShell.Linux.Host/Modules/Pester + - git submodule update --init -- src/windows-build src/Microsoft.PowerShell.Linux.Host/Modules/Pester - ps: Invoke-WebRequest -Uri https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/install.ps1 -OutFile install.ps1 - ps: ./install.ps1 -version 1.0.0-beta-002198 From ff73a5cd987d383a16c2ea9d6a1942882be45b6c Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 18:09:30 -0700 Subject: [PATCH 316/342] Move Pester to src/Modules --- .gitmodules | 4 ++-- src/{Microsoft.PowerShell.Linux.Host => }/Modules/Pester | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename src/{Microsoft.PowerShell.Linux.Host => }/Modules/Pester (100%) diff --git a/.gitmodules b/.gitmodules index 6c1c2e5f3..6fc1171a3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,8 +8,8 @@ [submodule "src/windows-build"] path = src/windows-build url = https://github.com/PowerShell/psl-windows-build.git -[submodule "src/Microsoft.PowerShell.Linux.Host/Modules/Pester"] - path = src/Microsoft.PowerShell.Linux.Host/Modules/Pester +[submodule "src/Modules/Pester"] + path = src/Modules/Pester url = https://github.com/PowerShell/psl-pester.git branch = develop ignore = dirty diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Pester b/src/Modules/Pester similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/Modules/Pester rename to src/Modules/Pester From a9f1603a97b50e29a5617182afed48e912a64440 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 18:14:55 -0700 Subject: [PATCH 317/342] Rename dotnet restore arguments variable --- PowerShellGitHubDev.psm1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index cad22df76..e2dfc192d 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -139,16 +139,16 @@ function Start-PSBuild { if ($Restore -Or -Not (Test-Path "$Top/project.lock.json")) { log "Run dotnet restore" - $Arguments = @("--verbosity") + $RestoreArguments = @("--verbosity") if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { - $Arguments += "Info" + $RestoreArguments += "Info" } else { - $Arguments += "Warning" + $RestoreArguments += "Warning" } - $Arguments += "$PSScriptRoot" + $RestoreArguments += "$PSScriptRoot" - dotnet restore $Arguments + dotnet restore $RestoreArguments } # Build native components From 61825110d07d7284efd557f4ea7bc265fe5b5523 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 18:51:31 -0700 Subject: [PATCH 318/342] Add Modules to mapping.json --- mapping.json | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/mapping.json b/mapping.json index 8311b1361..2f4ed0068 100644 --- a/mapping.json +++ b/mapping.json @@ -1180,5 +1180,26 @@ "src/monad/monad/nttargets/assemblies/nativemsh/pwrshcommon/WinSystemCallFacade.h": "src/powershell-native/nativemsh/pwrshcommon/WinSystemCallFacade.h", "src/monad/monad/nttargets/assemblies/nativemsh/pwrshexe/MainEntry.cpp": "src/powershell-native/nativemsh/pwrshexe/MainEntry.cpp", "src/monad/monad/nttargets/assemblies/nativemsh/pwrshexe/OutputWriter.h": "src/powershell-native/nativemsh/pwrshexe/OutputWriter.h", - "src/monad/monad/src/graphicalhost/visualstudiopublic.snk": "src/signing/visualstudiopublic.snk" + "src/monad/monad/src/graphicalhost/visualstudiopublic.snk": "src/signing/visualstudiopublic.snk", + "src/monad/monad/miscfiles/modules/AppxProvider/AppxProvider.psd1": "src/Modules/AppxProvider/AppxProvider.psd1", + "src/monad/monad/miscfiles/modules/AppxProvider/AppxProvider.psm1": "src/Modules/AppxProvider/AppxProvider.psm1", + "src/monad/monad/miscfiles/modules/AppxProvider/AppxProvider.Resource.psd1": "src/Modules/AppxProvider/AppxProvider.Resource.psd1", + "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Archive/ArchiveResources.psd1": "src/Modules/Microsoft.PowerShell.Archive/ArchiveResources.psd1", + "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1": "src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1", + "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1": "src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1", + "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Diagnostics/CoreClr/Microsoft.PowerShell.Diagnostics.psd1": "src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1", + "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1": "src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1", + "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1": "src/Modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1", + "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1": "src/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1", + "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1": "src/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1", + "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Utility/CoreClr/Microsoft.PowerShell.Utility.psd1": "src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1", + "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1": "src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1", + "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1": "src/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1", + "src/monad/monad/miscfiles/modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1": "src/Modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1", + "src/monad/monad/miscfiles/modules/PSDiagnostics/PSDiagnostics.psd1": "src/Modules/PSDiagnostics/PSDiagnostics.psd1", + "src/monad/monad/miscfiles/modules/PSDiagnostics/PSDiagnostics.psm1": "src/Modules/PSDiagnostics/PSDiagnostics.psm1", + "src/monad/monad/miscfiles/modules/PSGet/PSGet.Format.ps1xml": "src/Modules/PSGet/PSGet.Format.ps1xml", + "src/monad/monad/miscfiles/modules/PSGet/PSGet.psd1": "src/Modules/PSGet/PSGet.psd1", + "src/monad/monad/miscfiles/modules/PSGet/PSGet.Resource.psd1": "src/Modules/PSGet/PSGet.Resource.psd1", + "src/monad/monad/miscfiles/modules/PSGet/PSModule.psm1": "src/Modules/PSGet/PSModule.psm1" } From 5c1fb845c4f1ac6bf394318ffa320ead469b7679 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 18:51:56 -0700 Subject: [PATCH 319/342] Rename Linux.Host to Host --- .../.gitignore | 0 .../AssemblyInfo.cs | 0 .../Microsoft.PowerShell.Management.psd1 | 0 .../Microsoft.PowerShell.Platform.psd1 | Bin .../Microsoft.PowerShell.Platform.psm1 | 0 .../Microsoft.PowerShell.Security.psd1 | 0 .../Microsoft.PowerShell.Utility.psd1 | 0 .../Microsoft.PowerShell.Utility.psm1 | 0 .../Modules/PSDiagnostics/PSDiagnostics.psd1 | Bin .../Modules/PSDiagnostics/PSDiagnostics.psm1 | Bin .../PSL_profile.ps1 | 0 .../README.md | 0 .../host.cs | 0 .../main.cs | 0 .../project.json | 0 .../rawui.cs | 0 .../readline.cs | 0 .../ui.cs | 0 .../update-content.sh | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/.gitignore (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/AssemblyInfo.cs (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psd1 (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psm1 (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/Modules/PSDiagnostics/PSDiagnostics.psd1 (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/Modules/PSDiagnostics/PSDiagnostics.psm1 (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/PSL_profile.ps1 (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/README.md (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/host.cs (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/main.cs (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/project.json (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/rawui.cs (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/readline.cs (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/ui.cs (100%) rename src/{Microsoft.PowerShell.Linux.Host => Microsoft.PowerShell.Host}/update-content.sh (100%) diff --git a/src/Microsoft.PowerShell.Linux.Host/.gitignore b/src/Microsoft.PowerShell.Host/.gitignore similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/.gitignore rename to src/Microsoft.PowerShell.Host/.gitignore diff --git a/src/Microsoft.PowerShell.Linux.Host/AssemblyInfo.cs b/src/Microsoft.PowerShell.Host/AssemblyInfo.cs similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/AssemblyInfo.cs rename to src/Microsoft.PowerShell.Host/AssemblyInfo.cs diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 rename to src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psd1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psd1 similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psd1 rename to src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psd1 diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psm1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psm1 similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psm1 rename to src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psm1 diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 rename to src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 rename to src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 rename to src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/PSDiagnostics/PSDiagnostics.psd1 b/src/Microsoft.PowerShell.Host/Modules/PSDiagnostics/PSDiagnostics.psd1 similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/Modules/PSDiagnostics/PSDiagnostics.psd1 rename to src/Microsoft.PowerShell.Host/Modules/PSDiagnostics/PSDiagnostics.psd1 diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/PSDiagnostics/PSDiagnostics.psm1 b/src/Microsoft.PowerShell.Host/Modules/PSDiagnostics/PSDiagnostics.psm1 similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/Modules/PSDiagnostics/PSDiagnostics.psm1 rename to src/Microsoft.PowerShell.Host/Modules/PSDiagnostics/PSDiagnostics.psm1 diff --git a/src/Microsoft.PowerShell.Linux.Host/PSL_profile.ps1 b/src/Microsoft.PowerShell.Host/PSL_profile.ps1 similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/PSL_profile.ps1 rename to src/Microsoft.PowerShell.Host/PSL_profile.ps1 diff --git a/src/Microsoft.PowerShell.Linux.Host/README.md b/src/Microsoft.PowerShell.Host/README.md similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/README.md rename to src/Microsoft.PowerShell.Host/README.md diff --git a/src/Microsoft.PowerShell.Linux.Host/host.cs b/src/Microsoft.PowerShell.Host/host.cs similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/host.cs rename to src/Microsoft.PowerShell.Host/host.cs diff --git a/src/Microsoft.PowerShell.Linux.Host/main.cs b/src/Microsoft.PowerShell.Host/main.cs similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/main.cs rename to src/Microsoft.PowerShell.Host/main.cs diff --git a/src/Microsoft.PowerShell.Linux.Host/project.json b/src/Microsoft.PowerShell.Host/project.json similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/project.json rename to src/Microsoft.PowerShell.Host/project.json diff --git a/src/Microsoft.PowerShell.Linux.Host/rawui.cs b/src/Microsoft.PowerShell.Host/rawui.cs similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/rawui.cs rename to src/Microsoft.PowerShell.Host/rawui.cs diff --git a/src/Microsoft.PowerShell.Linux.Host/readline.cs b/src/Microsoft.PowerShell.Host/readline.cs similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/readline.cs rename to src/Microsoft.PowerShell.Host/readline.cs diff --git a/src/Microsoft.PowerShell.Linux.Host/ui.cs b/src/Microsoft.PowerShell.Host/ui.cs similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/ui.cs rename to src/Microsoft.PowerShell.Host/ui.cs diff --git a/src/Microsoft.PowerShell.Linux.Host/update-content.sh b/src/Microsoft.PowerShell.Host/update-content.sh similarity index 100% rename from src/Microsoft.PowerShell.Linux.Host/update-content.sh rename to src/Microsoft.PowerShell.Host/update-content.sh From bd599ed62a5dd318ca3da38deefd4310b0794a0a Mon Sep 17 00:00:00 2001 From: PowerShell Team Date: Fri, 1 Apr 2016 19:00:51 -0700 Subject: [PATCH 320/342] Move Module files from psl-monad submodule to super-project This commit uses master branch 8abffd25ebc33cbc0b4ce224b46e699704b01728 --- .../Microsoft.PowerShell.Diagnostics.psd1 | 16 + .../Microsoft.PowerShell.Utility.psd1 | 33 + .../Microsoft.PowerShell.Diagnostics.psd1 | 13 + .../AppxProvider/AppxProvider.Resource.psd1 | Bin 0 -> 5082 bytes src/Modules/AppxProvider/AppxProvider.psd1 | Bin 0 -> 1222 bytes src/Modules/AppxProvider/AppxProvider.psm1 | 956 ++ .../ArchiveResources.psd1 | Bin 0 -> 5124 bytes .../Microsoft.PowerShell.Archive.psd1 | 12 + .../Microsoft.PowerShell.Archive.psm1 | Bin 0 -> 105036 bytes .../Microsoft.PowerShell.Host.psd1 | 14 + .../Microsoft.PowerShell.Management.psd1 | 99 + .../Microsoft.PowerShell.Security.psd1 | 14 + .../Microsoft.PowerShell.Utility.psm1 | 709 + .../Microsoft.WSMan.Management.psd1 | 15 + src/Modules/PSDiagnostics/PSDiagnostics.psd1 | Bin 0 -> 1214 bytes src/Modules/PSDiagnostics/PSDiagnostics.psm1 | Bin 0 -> 23122 bytes src/Modules/PSGet/PSGet.Format.ps1xml | 202 + src/Modules/PSGet/PSGet.Resource.psd1 | Bin 0 -> 69704 bytes src/Modules/PSGet/PSGet.psd1 | Bin 0 -> 3940 bytes src/Modules/PSGet/PSModule.psm1 | 13064 ++++++++++++++++ 20 files changed, 15147 insertions(+) create mode 100644 src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 create mode 100644 src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 create mode 100644 src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 create mode 100644 src/Modules/AppxProvider/AppxProvider.Resource.psd1 create mode 100644 src/Modules/AppxProvider/AppxProvider.psd1 create mode 100644 src/Modules/AppxProvider/AppxProvider.psm1 create mode 100644 src/Modules/Microsoft.PowerShell.Archive/ArchiveResources.psd1 create mode 100644 src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1 create mode 100644 src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1 create mode 100644 src/Modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 create mode 100644 src/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 create mode 100644 src/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 create mode 100644 src/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 create mode 100644 src/Modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1 create mode 100644 src/Modules/PSDiagnostics/PSDiagnostics.psd1 create mode 100644 src/Modules/PSDiagnostics/PSDiagnostics.psm1 create mode 100644 src/Modules/PSGet/PSGet.Format.ps1xml create mode 100644 src/Modules/PSGet/PSGet.Resource.psd1 create mode 100644 src/Modules/PSGet/PSGet.psd1 create mode 100644 src/Modules/PSGet/PSModule.psm1 diff --git a/src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 b/src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 new file mode 100644 index 000000000..d72eb9e28 --- /dev/null +++ b/src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 @@ -0,0 +1,16 @@ +@{ +GUID="CA046F10-CA64-4740-8FF9-2565DBA61A4F" +Author="Microsoft Corporation" +CompanyName="Microsoft Corporation" +Copyright="© Microsoft Corporation. All rights reserved." +ModuleVersion="3.0.0.0" +PowerShellVersion="3.0" +CLRVersion="4.0" +AliasesToExport = @() +FunctionsToExport = @() +CmdletsToExport="Get-WinEvent", "Get-Counter", "Import-Counter", "Export-Counter", "New-WinEvent" +NestedModules="Microsoft.PowerShell.Commands.Diagnostics.dll" +TypesToProcess="GetEvent.types.ps1xml" +FormatsToProcess="Event.format.ps1xml","Diagnostics.format.ps1xml" +HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390783' +} diff --git a/src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 new file mode 100644 index 000000000..618763603 --- /dev/null +++ b/src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 @@ -0,0 +1,33 @@ +@{ +GUID="1DA87E53-152B-403E-98DC-74D7B4D63D59" +Author="Microsoft Corporation" +CompanyName="Microsoft Corporation" +Copyright="© Microsoft Corporation. All rights reserved." +ModuleVersion="3.1.0.0" +PowerShellVersion="3.0" +CLRVersion="4.0" +CmdletsToExport= "Format-List", "Format-Custom", "Format-Table", "Format-Wide", + "Out-File", "Out-Printer", "Out-String", + "Out-GridView", "Get-FormatData", "Export-FormatData", "ConvertFrom-Json", "ConvertTo-Json", + "Invoke-RestMethod", "Invoke-WebRequest", "Register-ObjectEvent", "Register-EngineEvent", + "Wait-Event", "Get-Event", "Remove-Event", "Get-EventSubscriber", "Unregister-Event", + "New-Event", "Add-Member", "Add-Type", "Compare-Object", "ConvertTo-Html", "ConvertFrom-StringData", + "Export-Csv", "Import-Csv", "ConvertTo-Csv", "ConvertFrom-Csv", "Export-Alias", "Invoke-Expression", + "Get-Alias", "Get-Culture", "Get-Date", "Get-Host", "Get-Member", "Get-Random", "Get-UICulture", + "Get-Unique", "Export-PSSession", "Import-PSSession", "Import-Alias", "Import-LocalizedData", + "Select-String", "Measure-Object", "New-Alias", "New-TimeSpan", "Read-Host", "Set-Alias", "Set-Date", + "Start-Sleep", "Tee-Object", "Measure-Command", "Update-List", "Update-TypeData", "Update-FormatData", + "Remove-TypeData", "Get-TypeData", "Write-Host", "Write-Progress", "New-Object", "Select-Object", + "Group-Object", "Sort-Object", "Get-Variable", "New-Variable", "Set-Variable", "Remove-Variable", + "Clear-Variable", "Export-Clixml", "Import-Clixml", "ConvertTo-Xml", "Select-Xml", "Write-Debug", + "Write-Verbose", "Write-Warning", "Write-Error", "Write-Information", "Write-Output", "Set-PSBreakpoint", "Get-PSBreakpoint", + "Remove-PSBreakpoint", "Enable-PSBreakpoint", "Disable-PSBreakpoint", "Get-PSCallStack", + "Send-MailMessage", "Get-TraceSource", "Set-TraceSource", "Trace-Command", "Show-Command", "Unblock-File", + "Get-Runspace", "Debug-Runspace", "Enable-RunspaceDebug", "Disable-RunspaceDebug", "Get-RunspaceDebug", "Wait-Debugger", + "ConvertFrom-String", "Convert-String" +FunctionsToExport= "Get-FileHash", "New-TemporaryFile", "New-Guid", "Format-Hex", "Import-PowerShellDataFile", + "ConvertFrom-SddlString" +AliasesToExport= "CFS", "fhx" +NestedModules="Microsoft.PowerShell.Commands.Utility.dll","Microsoft.PowerShell.Utility.psm1" +HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390787' +} diff --git a/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 new file mode 100644 index 000000000..dec59a24f --- /dev/null +++ b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 @@ -0,0 +1,13 @@ +@{ +GUID="CA046F10-CA64-4740-8FF9-2565DBA61A4F" +Author="Microsoft Corporation" +CompanyName="Microsoft Corporation" +Copyright="© Microsoft Corporation. All rights reserved." +ModuleVersion="3.0.0.0" +PowerShellVersion="3.0" +CmdletsToExport="Get-WinEvent", "New-WinEvent" +NestedModules="Microsoft.PowerShell.Commands.Diagnostics.dll" +TypesToProcess="..\..\GetEvent.types.ps1xml" +FormatsToProcess="..\..\Event.format.ps1xml" +HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390783' +} \ No newline at end of file diff --git a/src/Modules/AppxProvider/AppxProvider.Resource.psd1 b/src/Modules/AppxProvider/AppxProvider.Resource.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..f9c68ab194864bd775cf6037292a3aac443c9365 GIT binary patch literal 5082 zcmdUzTW{M&5QX=-K>x!6eMk!=M$^7E5D+(QfBd5}sDSM{;ItL8FN60h z_r#s+iukM*p`QZkmqPZrd$ji&e^0gQwfjXfkmP%xK9V5ZNLKCM3Co2d4X&+ZFLX9@ zucRx*!4D$gWtErykM3LdkA5wxeXTDgua)hm`klK!_R@*rm5!~Bb%^53T`2QvNu0XF z%X+fwJ`2#ilk7J_7DUOMwen>qoGx{?4)?w60o_UxS&b#v`<=NCFSP2AtvAxnsz&R* z_HA^9JyBk*?8U;}0c61UgEWx!mHSP*-?_IT#tDm7HlVEu)=@itzou)`m9%g542!AB zm3HlPa1VT*h6qK(@S5{nzu#LBx!L$xnK0+Rf#;s=o@>9b%pw?X#ZMaLi17k95>AUhH=`dLBGJmTjpvSuf8;irfIRbP!W?AD6&e+2{M3iN7McG%=c^A;aLV8uMt2E(`<3rzs zYi?ynr777gV`c#L^MKMK@MbroA}6G-Ij5H1FG#I6W8s&k@ggp%E&T>Wz%* z&hs<9+r-R|9MQ$Z_Hr-nPO~Mb|DfYO&L3LS@9imr@`yz3{nhckD(Nk;6TP_PH8aD| zqGSQ@{<*iqY@-@2`mvu3t%jZL9WU1IQrEHXSdMnt`OsSc`VURc%-|*8PZV<|t@zKy z&+0b(pJ7~Ky_ffXIK?J{ytmqvpVs@(e~?${;Mb;-(p+!vsMrh_4s*l)C+hxl@<{)y G;Ke78gG2KG literal 0 HcmV?d00001 diff --git a/src/Modules/AppxProvider/AppxProvider.psd1 b/src/Modules/AppxProvider/AppxProvider.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..b9f746d7e634645f09759b74cbe8833e08f297f2 GIT binary patch literal 1222 zcmbu9YfBqZ5Qg8+h5m=&msHSLV~kXg8f`gnAZD`-;< zwTX}ASdP7Lj}+grMtP=9Vm{BmEb52O)zr7#XGb+{tIMj9BhtF>5&JrtI%gf}3-(x- zNL}ryimpcHI+0bhk+$ZT+T1@QCef*`IR~s_Y}<}2FlkVMDgI;PvMRLTa^)3B(RZ?&yKcZV#{Xi1dDJ6}%f>h0;>46m0^! z)GKw%9#f6L {1}" -f ($o, $options[$o]) ) + } + + if($options.ContainsKey('Source')) + { + $SourceNames = $($options['Source']) + Write-Verbose ($LocalizedData.SpecifiedSourceName -f ($SourceNames)) + foreach($sourceName in $SourceNames) + { + if($script:AppxPackageSources.Contains($sourceName)) + { + $Sources += $script:AppxPackageSources[$sourceName] + } + else + { + $sourceByLocation = Get-SourceName -Location $sourceName + if ($sourceByLocation -ne $null) + { + $Sources += $script:AppxPackageSources[$sourceByLocation] + } + else + { + $message = $LocalizedData.PackageSourceNotFound -f ($sourceName) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PackageSourceNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $sourceName + } + } + } + } + else + { + Write-Verbose $LocalizedData.NoSourceNameIsSpecified + $script:AppxPackageSources.Values | Microsoft.PowerShell.Core\ForEach-Object { $Sources += $_ } + } + + if($options.ContainsKey($script:Architecture)) + { + $Architecture = $options[$script:Architecture] + } + if($options.ContainsKey($script:ResourceId)) + { + $ResourceId = $options[$script:ResourceId] + } + } + + foreach($source in $Sources) + { + $location = $source.SourceLocation + if($request.IsCanceled) + { + return + } + if(-not(Test-Path $location)) + { + $message = $LocalizedData.PathNotFound -f ($Location) + Write-Verbose $message + continue + } + + $packages = Get-AppxPackagesFromPath -path $location + foreach($pkg in $packages) + { + if($request.IsCanceled) + { + return + } + + $pkgManifest = Get-PackageManfiestData -PackageFullPath $pkg.FullName + if(-not $pkgManifest) + { + continue + } + + # $pkgManifest.Name has to match any of the supplied names, using PowerShell wildcards + if(-not($namesParameterEmpty)) + { + if(-not(($names | Microsoft.PowerShell.Core\ForEach-Object { if ($pkgManifest.Name -like $_){return $true; break} } -End {return $false}))) + { + continue + } + } + + # Version + if($RequiredVersion) + { + if($RequiredVersion -ne $pkgManifest.Version) + { + continue + } + } + else + { + if(-not((-not $MinimumVersion -or ($MinimumVersion -le $pkgManifest.Version)) -and + (-not $MaximumVersion -or ($MaximumVersion -ge $pkgManifest.Version)))) + { + continue + } + } + + + if($Architecture) + { + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $Architecture, $script:wildcardOptions + if(-not($wildcardPattern.IsMatch($pkgManifest.Architecture))) + { + continue + } + } + + if($ResourceId) + { + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $ResourceId, $script:wildcardOptions + if(-not($wildcardPattern.IsMatch($pkgManifest.ResourceId))) + { + continue + } + } + + $sid = New-SoftwareIdentityFromPackage -Package $pkgManifest -Source $source.Name + $fastPackageReference = $sid.fastPackageReference + if($streamedResults -notcontains $fastPackageReference) + { + $streamedResults += $fastPackageReference + Write-Output -InputObject $sid + } + } + } +} + +function Get-InstalledPackage +{ + [CmdletBinding()] + param + ( + [Parameter()] + [string] + $Name, + + [Parameter()] + [string] + $RequiredVersion, + + [Parameter()] + [string] + $MinimumVersion, + + [Parameter()] + [string] + $MaximumVersion + ) + + Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Get-InstalledPackage')) + + $Architecture = $null + $ResourceId = $null + + $options = $request.Options + if($options) + { + if($options.ContainsKey($script:Architecture)) + { + $Architecture = $options[$script:Architecture] + } + if($options.ContainsKey($script:ResourceId)) + { + $ResourceId = $options[$script:ResourceId] + } + } + + $params = @{} + if($Name) + { + $params.Add("Name", $Name) + } + $packages = Appx\Get-AppxPackage @params + + foreach($package in $packages) + { + if($RequiredVersion) + { + if($RequiredVersion -ne $package.Version) + { + continue + } + } + else + { + if(-not((-not $MinimumVersion -or ($MinimumVersion -le $package.Version)) -and + (-not $MaximumVersion -or ($MaximumVersion -ge $package.Version)))) + { + continue + } + } + + if($Architecture) + { + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $Architecture, $script:wildcardOptions + if(-not($wildcardPattern.IsMatch($package.Architecture))) + { + continue + } + } + if($ResourceId) + { + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $ResourceId,$script:wildcardOptions + if(-not($wildcardPattern.IsMatch($package.ResourceId))) + { + continue + } + } + + $sid = New-SoftwareIdentityFromPackage -Package $package + write-Output $sid + } +} + +function Install-Package +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $fastPackageReference + ) + + Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Install-Package')) + Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference) + + Appx\Add-AppxPackage -Path $fastPackageReference +} + +function UnInstall-Package +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $fastPackageReference + ) + + Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Uninstall-Package')) + Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference) + + Appx\Remove-AppxPackage -Package $fastPackageReference +} + +function Add-PackageSource +{ + [CmdletBinding()] + param + ( + [string] + $Name, + + [string] + $Location, + + [bool] + $Trusted + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Add-PackageSource')) + + Set-PackageSourcesVariable -Force + + if(-not (Microsoft.PowerShell.Management\Test-Path $Location) -and + -not (Test-WebUri -uri $Location)) + { + $LocationUri = [Uri]$Location + if($LocationUri.Scheme -eq 'file') + { + $message = $LocalizedData.PathNotFound -f ($Location) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Location + } + else + { + $message = $LocalizedData.InvalidWebUri -f ($Location, "Location") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Location + } + } + + if(Test-WildcardPattern $Name) + { + $message = $LocalizedData.PackageSourceNameContainsWildCards -f ($Name) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PackageSourceNameContainsWildCards" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + } + + $LocationString = Get-ValidPackageLocation -LocationString $Location -ParameterName "Location" + + # Check if Location is already registered with another Name + $existingSourceName = Get-SourceName -Location $LocationString + + if($existingSourceName -and + ($Name -ne $existingSourceName)) + { + $message = $LocalizedData.PackageSourceAlreadyRegistered -f ($existingSourceName, $Location, $Name) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PackageSourceAlreadyRegistered" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + # Check if Name is already registered + if($script:AppxPackageSources.Contains($Name)) + { + $currentSourceObject = $script:AppxPackageSources[$Name] + $null = $script:AppxPackageSources.Remove($Name) + } + + # Add new package source + $packageSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $Name + SourceLocation = $LocationString + Trusted=$Trusted + Registered= $true + }) + + $script:AppxPackageSources.Add($Name, $packageSource) + $message = $LocalizedData.SourceRegistered -f ($Name, $LocationString) + Write-Verbose $message + + # Persist the package sources + Save-PackageSources + + # return the package source object. + Write-Output -InputObject (New-PackageSourceFromSource -Source $packageSource) + +} + +function Resolve-PackageSource +{ + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Resolve-PackageSource')) + + Set-PackageSourcesVariable + + $SourceName = $request.PackageSources + + if(-not $SourceName) + { + $SourceName = "*" + } + + foreach($src in $SourceName) + { + if($request.IsCanceled) + { + return + } + + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $src,$script:wildcardOptions + $sourceFound = $false + + $script:AppxPackageSources.GetEnumerator() | + Microsoft.PowerShell.Core\Where-Object {$wildcardPattern.IsMatch($_.Key)} | + Microsoft.PowerShell.Core\ForEach-Object { + $source = $script:AppxPackageSources[$_.Key] + $packageSource = New-PackageSourceFromSource -Source $source + Write-Output -InputObject $packageSource + $sourceFound = $true + } + + if(-not $sourceFound) + { + $sourceName = Get-SourceName -Location $src + if($sourceName) + { + $source = $script:AppxPackageSources[$sourceName] + $packageSource = New-PackageSourceFromSource -Source $source + Write-Output -InputObject $packageSource + } + elseif( -not (Test-WildcardPattern $src)) + { + $message = $LocalizedData.PackageSourceNotFound -f ($src) + Write-Error -Message $message -ErrorId "PackageSourceNotFound" -Category InvalidOperation -TargetObject $src + } + } + } +} + +function Remove-PackageSource +{ + param + ( + [string] + $Name + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Remove-PackageSource')) + + Set-PackageSourcesVariable -Force + + $SourcesToBeRemoved = @() + + foreach ($sourceName in $Name) + { + if($request.IsCanceled) + { + return + } + + # Check if $Name contains any wildcards + if(Test-WildcardPattern $sourceName) + { + $message = $LocalizedData.PackageSourceNameContainsWildCards -f ($sourceName) + Write-Error -Message $message -ErrorId "PackageSourceNameContainsWildCards" -Category InvalidOperation -TargetObject $sourceName + continue + } + + # Check if the specified package source name is in the registered package sources + if(-not $script:AppxPackageSources.Contains($sourceName)) + { + $message = $LocalizedData.PackageSourceNotFound -f ($sourceName) + Write-Error -Message $message -ErrorId "PackageSourceNotFound" -Category InvalidOperation -TargetObject $sourceName + continue + } + + $SourcesToBeRemoved += $sourceName + $message = $LocalizedData.PackageSourceUnregistered -f ($sourceName) + Write-Verbose $message + } + + # Remove the SourcesToBeRemoved + $SourcesToBeRemoved | Microsoft.PowerShell.Core\ForEach-Object { $null = $script:AppxPackageSources.Remove($_) } + + # Persist the package sources + Save-PackageSources +} +#endregion + +#region Common functions + +function Get-AppxPackagesFromPath +{ + param + ( + [Parameter(Mandatory=$true)] + $Path + ) + + $filterAppxPackages = "*"+$script:AppxPackageExtension + $packages = Get-ChildItem -path $Path -filter $filterAppxPackages + + return $packages + +} + +function Get-PackageManfiestData +{ + param + ( + [Parameter(Mandatory=$true)] + $PackageFullPath + ) + $guid = [System.Guid]::NewGuid().toString() + try + { + [System.IO.Compression.ZipFile]::ExtractToDirectory($PackageFullPath, "$env:TEMP\$guid") + } + catch + { + Write-Verbose( $LocalizedData.MetaDataExtractionFailed -f ($PackageFullPath) ) + return $null + } + + [xml] $packageManifest = Get-Content "$env:TEMP\$guid\$script:AppxManifestFile" -ErrorAction SilentlyContinue + if($packageManifest) + { + $Identity = $packageManifest.Package.Identity + $manifestData = new-object psObject -Property @{Name=$Identity.Name; Architecture=$Identity.ProcessorArchitecture; Publisher=$Identity.Publisher; Version=$Identity.Version; ResourceId=$Identity.resourceId; PackageFullName=$PackageFullPath} + Remove-Item -Path "$env:TEMP\$guid" -Recurse -Force -ErrorAction SilentlyContinue + return $manifestData + } + else + { + Write-Verbose ($LocalizedData.MetaDataExtractionFailed -f ($PackageFullPath) ) + } + return $null +} + +function New-FastPackageReference +{ + param + ( + [Parameter(Mandatory=$true)] + [string] + $PackageFullName + ) + return "$PackageFullName" +} + +function New-SoftwareIdentityFromPackage +{ + param + ( + [Parameter(Mandatory=$true)] + $Package, + + [string] + $Source + + ) + + $fastPackageReference = New-FastPackageReference -PackageFullName $Package.PackageFullName + + if(-not($Source)) + { + $Source = $Package.Publisher + } + $details = @{ + Publisher = $Package.Publisher + Architecture = $Package.Architecture + ResourceId = $Package.ResourceId + PackageFullName = $Package.PackageFullName + } + + $params = @{ + FastPackageReference = $fastPackageReference; + Name = $Package.Name; + Version = $Package.Version; + versionScheme = "MultiPartNumeric"; + Source = $source; + Details = $details; + } + + $sid = New-SoftwareIdentity @params + return $sid +} + +function Test-WebUri +{ + [CmdletBinding()] + [OutputType([bool])] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $uri + ) + + return ($uri.AbsoluteURI -ne $null) -and ($uri.Scheme -match '[http|https]') +} + +function Test-WildcardPattern +{ + [CmdletBinding()] + [OutputType([bool])] + param( + [Parameter(Mandatory=$true)] + [ValidateNotNull()] + $Name + ) + + return [System.Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Name) +} + +function DeSerialize-PSObject +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + $Path + ) + $filecontent = Microsoft.PowerShell.Management\Get-Content -Path $Path + [System.Management.Automation.PSSerializer]::Deserialize($filecontent) +} + +function Get-SourceName +{ + [CmdletBinding()] + [OutputType("string")] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Location + ) + + Set-PackageSourcesVariable + + foreach($source in $script:AppxPackageSources.Values) + { + if($source.SourceLocation -eq $Location) + { + return $source.Name + } + } +} + +function WebRequestApisAvailable +{ + $webRequestApiAvailable = $false + try + { + [System.Net.WebRequest] + $webRequestApiAvailable = $true + } + catch + { + } + return $webRequestApiAvailable +} + +function Ping-Endpoint +{ + param + ( + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Endpoint + ) + + $results = @{} + + if(WebRequestApisAvailable) + { + $iss = [System.Management.Automation.Runspaces.InitialSessionState]::Create() + $iss.types.clear() + $iss.formats.clear() + $iss.LanguageMode = "FullLanguage" + + $WebRequestcmd = @' + try + {{ + $request = [System.Net.WebRequest]::Create("{0}") + $request.Method = 'GET' + $request.Timeout = 30000 + $response = [System.Net.HttpWebResponse]$request.GetResponse() + $response + $response.Close() + }} + catch [System.Net.WebException] + {{ + "Error:System.Net.WebException" + }} +'@ -f $EndPoint + + $ps = [powershell]::Create($iss).AddScript($WebRequestcmd) + $response = $ps.Invoke() + $ps.dispose() + + if ($response -ne "Error:System.Net.WebException") + { + $results.Add($Script:ResponseUri,$response.ResponseUri.ToString()) + $results.Add($Script:StatusCode,$response.StatusCode.value__) + } + } + else + { + $response = $null + try + { + $httpClient = New-Object 'System.Net.Http.HttpClient' + $response = $httpclient.GetAsync($endpoint) + } + catch + { + } + + if ($response -ne $null -and $response.result -ne $null) + { + $results.Add($Script:ResponseUri,$response.Result.RequestMessage.RequestUri.AbsoluteUri.ToString()) + $results.Add($Script:StatusCode,$response.result.StatusCode.value__) + } + } + return $results +} + +function Get-ValidPackageLocation +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $LocationString, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $ParameterName + ) + + # Get the actual Uri from the Location + if(-not (Microsoft.PowerShell.Management\Test-Path $LocationString)) + { + $results = Ping-Endpoint -Endpoint $LocationString + + if ($results.ContainsKey("Exception")) + { + $Exception = $results["Exception"] + if($Exception) + { + $message = $LocalizedData.InvalidWebUri -f ($LocationString, $ParameterName) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -ExceptionObject $Exception ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + } + + if ($results.ContainsKey("ResponseUri")) + { + $LocationString = $results["ResponseUri"] + } + } + + return $LocationString +} + +function Set-PackageSourcesVariable +{ + param([switch]$Force) + + if(-not $script:AppxPackageSources -or $Force) + { + if(Microsoft.PowerShell.Management\Test-Path $script:AppxPackageSourcesFilePath) + { + $script:AppxPackageSources = DeSerialize-PSObject -Path $script:AppxPackageSourcesFilePath + } + else + { + $script:AppxPackageSources = [ordered]@{} + } + } +} + +function Save-PackageSources +{ + if($script:AppxPackageSources) + { + if(-not (Microsoft.PowerShell.Management\Test-Path $script:AppxLocalPath)) + { + $null = Microsoft.PowerShell.Management\New-Item -Path $script:AppxLocalPath ` + -ItemType Directory -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + } + Microsoft.PowerShell.Utility\Out-File -FilePath $script:AppxPackageSourcesFilePath -Force -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:AppxPackageSources)) + } +} + +function New-PackageSourceFromSource +{ + param + ( + [Parameter(Mandatory)] + $Source + ) + + # create a new package source + $src = New-PackageSource -Name $Source.Name ` + -Location $Source.SourceLocation ` + -Trusted $Source.Trusted ` + -Registered $Source.Registered ` + + Write-Verbose ( $LocalizedData.PackageSourceDetails -f ($src.Name, $src.Location, $src.IsTrusted, $src.IsRegistered) ) + + # return the package source object. + Write-Output -InputObject $src +} +#endregion + +# Utility to throw an errorrecord +function ThrowError +{ + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $ExceptionName, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $ExceptionMessage, + + [System.Object] + $ExceptionObject, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $ErrorId, + + [parameter(Mandatory = $true)] + [ValidateNotNull()] + [System.Management.Automation.ErrorCategory] + $ErrorCategory + ) + + $exception = New-Object $ExceptionName $ExceptionMessage; + $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $ErrorId, $ErrorCategory, $ExceptionObject + $CallerPSCmdlet.ThrowTerminatingError($errorRecord) +} +#endregion + +Export-ModuleMember -Function Find-Package, ` + Install-Package, ` + Uninstall-Package, ` + Get-InstalledPackage, ` + Remove-PackageSource, ` + Resolve-PackageSource, ` + Add-PackageSource, ` + Get-DynamicOptions, ` + Initialize-Provider, ` + Get-PackageProviderName \ No newline at end of file diff --git a/src/Modules/Microsoft.PowerShell.Archive/ArchiveResources.psd1 b/src/Modules/Microsoft.PowerShell.Archive/ArchiveResources.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..914f951df0fc7ca023e898d5f507f03564e11d25 GIT binary patch literal 5124 zcmd6r%WfM-5Jh`!ApbCc7urNboU8>zkz|;F6BCKzMRqhvi2}rjhm;jX@UJJir;DxX z;q*|Xokc+KF+JV&ymhOF|NQ+jRN-w{gi#oV+i(;93X?F_+G(h@Hr2`}t^BI@O1tjj zD!+SSsn2nE6}|~C;`>bZ=W%x(*5S2wF2XDvhu?HnOU^u8hjVFJ>s^H(!%;l-GVmH` z*W2(eoW-?4+%*lqNCJ}3JD08t$w6uzPQs;Zn@G-bv$vAG$M9YFtnW&9Zgi3zwXViG zgUywsAd&ljYR4-6MqU-K{5}?bl4K%6G_Lf0t5cQEJj8Po`R3Yt(e4XL#U5;J#;>on z_fPW9qcv;EoJZ?#WYt_TAU4xyeZ%g|DpX$#oqkJv$amo zrQ58{b765W#c-v}E%ibp=ZWP|za3e5Y_Hc^c#dFB!7r^i1IkbjTjTVezfR8lJDZlxy~Yq44A(BjN9&&VHMk*uWuy@M9riF zj&K=ePuh{QT>820xJ{G=qE*Qo`#z4m0Fqdx>T11by24K?+PpN|;0-F7y;h&Z5$mza zR;j5;xQ{!^2(>D2SB5c3UJ;jjBLR*vJH`>y9)CEt3cqjsP1ritisyQl=U=7Xqvt;r2kpn z>_YXhl>8=tm9Y)m(mfN~QrC9Yw9wsI0jn#$%+u?q>!0LFt*%UF*A2ex(wFyZuSM%F z$qJ%Dw27+g>M7P{)kW5E|67ajgNS>_+t;R3om(mn?I|F27_0`vF8k+AREP3%vRCvH za+-5b>WEZ|bz5V>RCl{4kA&+ckG7{LvNBRN-fbAQr>T)?!RD%_XK>h?=&Lcc@3pQz z%%WAYxb4w?K1`)IF@5sByT9BEUw86|?r0s=5t*hII0Ve5YPShutTX+X&6z$I9W%v= z*4atqt~YXQR!!CAy(ppNRPu6sW5-~_7blvO{RCEfHJQY|H2E}F=7=Qiu+G(mJTO0! zhgVP78%AEk=OzcIe5CmfiQC=V&|z$|P-fs%i=82Q7W2gnO<#an(YtF#w|;6Yv5TSI zzh><`hAtkiG&R_>M&9GP(KeO8aJ|Vd;jNUzZ7iJ2-}(s=r5x^>`E$h3l@8C|K6Uv2 z&uZC=@?3RTmeVu=&#z;?$$OfVnfNX9-f6~>vn}_D1<1P1m#fC}?`z32y!%9-b5>pt z&JBjtR42J+ude5wVVnb*p>1Mv9}}`oiq|Bks2`qb4xf3Sn>b;eN^_1q?c7TPF;5ki zo&oloL`zkJ^*?N^Z~JVxU{d*#h+4kEA?!u>EVH#ggBoALeMHiph4b8lh;H`D(O@hK z?vidhYm+Duv>oYblV^dUaLeuzN0qB-pfhm3dw@p%eF1gcOH-e7Z*FCK0!cZrN!{jj z?{>SqM;}j#Wh$++k%d$LH4e8T3-? X*uv!ar8;v2y1vrCY)ASJjv3}(wXc>j literal 0 HcmV?d00001 diff --git a/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1 b/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1 new file mode 100644 index 000000000..859ea5512 --- /dev/null +++ b/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1 @@ -0,0 +1,12 @@ +@{ +GUID="eb74e8da-9ae2-482a-a648-e96550fb8733" +Author="Microsoft Corporation" +CompanyName="Microsoft Corporation" +Copyright="© Microsoft Corporation. All rights reserved." +ModuleVersion="1.0.0.0" +FunctionsToExport = @('Compress-Archive', 'Expand-Archive') +CmdletsToExport = @() +AliasesToExport = @() +NestedModules="Microsoft.PowerShell.Archive.psm1" +HelpInfoURI = 'http://go.microsoft.com/fwlink/?LinkId=393254' +} diff --git a/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1 b/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1 new file mode 100644 index 0000000000000000000000000000000000000000..b301646d6e2d70578f66a644f2a06ad5352fd9c3 GIT binary patch literal 105036 zcmeI5ZIczpnWoR@joAOtL-(%a_0W>WyC2pbdjh7D&tjes)I(zy0UUf7<+Q!~gfr{_V&0_U8Mz_i6n9B<}w8=0g1c(dOdj%gv4WJHPvK zjQnWxL;QXc_kR-qf4q4ZcixCkCo$Wj&Ak_M?QQ;b^Iq}vwE>FnHlN2+JpDLkd=$`K zjb|C@B<8-k`7TD^+dMhDcQ3~H+vdZ~-{ZO$zub=}x#J{09mg|wHmC8|qhUmT|4ZC) z8u#oC{faLx_ zjidPPcQ3}hGC=h-etR@vaX(;rv@!NeI0FBAh>v47xOY2nhmy~mSO9CH!SCa_C&3HR z0SuqUD31aLL7nqPe5ld%G&uPr{xLJpL)%*gg>qWo9qxNL(B?4i{M+WE;IGFOf8pPw z;0<`3XY^cpOP(3$qZt2sz=D-4^G3uC1DJPz$=h}3;6P$-ydx4Fv7YBQR&haf;coP3Tj8EW+ zH4v794SRxybFcIjIs!dV>05N{&gR*0N3P3BQcLZhYKkmPt|7KwZOkkY*dW1kJji(B z!|A}!FVFC{jA4xv&*vy`UOwA$n(_$(EOtK!o(((@wLM0{a!J}s+Fu#$3sxI#U`$)n zc`w2&PX@iUe3vz{J#eAKMmG#3UNuJO9OB0k#g&HHT2|3%=0|+ugelDKZL&P*>W}_ z0e(S-Pvf63zxU$v$AQ^Ncyl=Zv}@kn&nI1#7qV}FI#3@fr@0P;_9b*zGf%x+$iN3q zBoDb3woCE+lc38qiZIWB9vM$_e0E0VTY)tZ+Ra7JW63JxCwo$)SzcOJ)A~6dxmfN? zyE~1-;L`2TnD5Ul@L@!uL>Y?DO3d(GpANXnvZs3`f44Gf)gYc?)Q7`&F|R#?v2W|d zvyeApWW1?7aFS3*JNRm3*w&zoJdWepqk*dr-e5Kq2Rr<@f7=(@_l*G zGg(4Ednv}vYp{pV zptRlQljB8397h3?8d;^s!7*&HXemj5IPj6!9Gi|sX5P6RK>k=(WX`fD{7Rkr+ool| z_agdGE(09Kt}TV%1-|$QjbD?)IbM!s<4WLt@A-jR@5q}BLK2WX((z!^OBt|rfcuJ9Pm6r}lNeL-pE8Bqw&nVfY=$J) zdXqztv~4LjO16^NT#;A8)sn7Jl8*8e`b4g@K89Y3V6j4b5hp2&dKNQ4duyC?i@wOV zraeIai!c=aJHdn$#>)utA@9&Tk#Y{$c|zYp{R21Tn3PgwpGfdLe>{K^xS$@ zku8+e9nNOSF>Zw%b9V`U>4)lCb}gR8Y9>sWnd%Qx$Zw7wlWoqSoklL^i827i|H&K9 zQGxl$MoTR48h64rLOp55&5*6j@n0T0|1R!12`W4e*zat{vEFnH%OlX{<4oh=>9fp_ zEdVAW&~4|=B{a?ZUex@Ed;UKBpTCX<2vrxlI8&LV9@(y2?nRB!Ho%nL8_D(cpxtR; zM-`J;^7I7^2WRnTZVSsObT4FRFKV5RK2`Mu{(s)=zoGy32K@H}ubXGt!dUJujwpy7 zei$+#-F4;3en$0xD zmvy4H&plYp3mYnW%N4IxRZ8WR;n$f~;vltAH0#dUI^gGn?RpSvFDDV1;7O3z_b0lY zq>~8G@zmF00lo>%I~a5iyC!>-+obelvJYw9pikeI?J9N(tgt5!UO=;kAJ}oNdtghJ z<^9Lh^KI#IKJES~QD|GOe)Tlkm0n*Od>)zq`$L>^Bh#X`uc}*vx;F0KHq`9QG&=Zb z5^LEeEo(Vmt>kHK&gF5ItVNomP3v88I_H_J_k4!Go^Lf8)#JK^_c$JYJ9wlF0FC-$ z@U8cU`1V13{>S)_UYv1$qL@~{e-b_kZmF&^jkrytuZO$rmCLBy_Z&24`fZF(UGqVB zJ>}t3Na1IVr?nVFkOsb<6rD(&#iYO=33sxLOjM^IXzd zTI1J2E>l(e$BZ^#XQ_O1DAXg937e@zVrz3d`Lp3u{>{gcW&N+H%YHt(^KbEa{4amb zza50mcxBcWlKMWD`(KB=t^QQKHqQvu0a<6c5+hSFWF-7a>c~6{c)y4mk>~p+s!6{L zEXd;YRH`JVTF3hlInBovqK+~1l~o{~eRP(YQhmM?9Xw>2y;#&oE~|W=&)0*P#htL_ zDu8GLOzj#uG|JcR=P_4B9gODhtK(sasVq~)dp30XoJ3@SY-r_$Rrjke@Nr!b45_r2 zuwII9Q#Y;a^yc=3f%0wIydTnXqmY)*0tVoqTZUB`r0X!M-E?rWW+Dh#b3DvoygYn= zXQ)w9^^=rMA-xylc+{T_u+7u3rVnX_#I*F)(svwi6L}?y0&h)UES=*R3>`@ol{zPv zB(fh0w3aTovgg}awedX&s!w_EiuGD+VA=8W+uDGBO&5f+MP7rV?&=50l?IK38*tnb2t z6;xccd{>=1)`54{a`)EqC~Rb^N?7}IZ(uL7#(VE={v)K~i@{%9j7W*qwFgznU-F-_ z4*wQj2RnZ8MFfL%ZU@=L&`i2~wJL`vqnB~silVbMz1@!|Wx41H7_W(63J8zlj%lC7 z4`H)epK>LiE+MV<0u5`u*mQOjabLbK2fwUN&vFmNlem*-%l-*#&OwYhg>PM)IK{Bn zH?$~s6j*zQ0#VJBPI+G(J6R4l+C@<7gvAa$JEL9d5T;{>*rf&o^MgZ;HZLH-koQy8^j7_Gx!rK5{@B90r~dBX3y=_U8+YrJ{d;x$Vf-8$*5J7q_L{Mm^#K*s|Saz_PWD38orWixsCdkR*%R?Xl*uH-0z6K5myUQ>T9#S?>2y!_W6w_R9Y2 zpF>Y6U(+{JvaYG~S!S)qfK;G!WH-bUH$wvXlt*XuE!Nidmn~c#<=u>m0{uAjIkFG& z?qE-9I9eZXRjVR7#1~^6?eWAjl(lL{0A&W5o;b)lY=F}huDp(0m+E<4KCcc>wO0J8 zY3qC(P>0?Uw7o92bxx3;Mm~vbv~AhjRk4znBNi?tHurVp0n~ZfWlbcEwwqc!Cn-kq zk;PJyxv#dz1j|gsNqx_;GnFK2!G9Wl!yn?g(Yl(Z0lDT>b<(<5&ep8#v_xQ7xU8jLzn5TvB zn$z>1>Q>#F9EEI+A%?o>#}ZxVu`=AdwtqEz=l4_3&n^?bxp6NPyY~ejbW(YKQH@0 zj5QaevTA7JxRYdVcS&DHTi?O5W}Z5J=HYynd44S6MU5YxUzE&uvuo%4jlp_RLG#+` zQtm&di8{d3F8Ojt{%&kZeU5Uq$ARkUeCkv@;P6h zzbyxrsL~c(jn$niT{d7p?vl@LMeoG*YqFfAm);jUt^1`_f#a|v+L@2?Qtjx}of8|v}u%ViWbveB#!&c@|LSvUV}+dASsst#`5Q4Vl#Au(ma+YFks}Ev>;4+ajSi z!oztlu6D+e53@=}+(>tXB@=n7pO`@IPGydh4t%%wq1JO{U?H;sf~hv~T@IC39eo0U zas!?HBq^WU#p>U{glM?j%c|N0BkH6vFxH-A>x!?yT-NT(ece1+$5zpNU1GnC*?3ZM zc3uUnard1^Bo8~E&8qXkmSZ;_@w8Ek9&_7Oo*J*)nmpFx>A7pRYOM~7Z77HoPh-3q z1eug@dnuhQ0I^}dbjNDBiz5gy`TptikKq7R;&xaWD;-Q-Vhhuj$+ z*5y+@Np{xW1R5{`GvFJ5?ZGgb?nCNaxyCn_6`_am9F=9Q`?u_Vjju;B?&Wy$hcj;v z<-D#n?1bC}ct<@m|Qy&8Uj}HlC&H zZ&MCS&`W=LkV`?cX=igyzFfOY`5p3w9Od$bT^UogtW%wCO5Qk1HXq~}$9H`?Xs4`x%X;$tmAH?5 z4~w9Tf?Ohbm!5r)<@#Me#>j7pn`4eXxf8ADqDSjvSx51=zLpv~$E|(~ZS6n5L`~20 zbfzh5mS;;?6!gk+PgLX6>D1AI^whOZqs?J&dhN#;=dq#AMFlGr8z6o(z)JN7%L1JE z6nq>0$!piPdG1YOS4=O=+9lPiV?nun| zB1oluL?0H4<%rJCYb(66k!y=;V(qmJ%e$|@k#l;H~RuWv3xRpQ#~hdeu0t(0YJ4!II1Q|Zh}pjAT#@BhzS^u^CR-g2Lc=9%#Qg}5y z6w-m$8m|2wnAI5x)Dd87}5H|!u$v@Cmyy&ZQ^OTON=6A0&Miu{x|^4;l! zMDFva5B?(hZa96zI-SQ$vTf%*g)kq{vry4NFR+IA*y+iHwWp@%5ph~!{Z6d1&Wcnt zdL#6veSTzZ3{^Y(Pc+g)e`4xZH{G5zdl^L6ww#4#`b56iMMr{t><)IlT(eOrJv(- zN8g<+W(nmwJ^^7lo_kfCTh^7=>72Ln6dI_Q`Ui4Lpx(;-o2Aob@_WTO<)LM#s8^_1 zZ{S???fPQNG3)(jnw`4eqoKM$Xa8v=dSyDxw>GXa z{pEV3bLz47?Be_oa<_a%a~{h?`DYR3)Nr!4pND42%GPEmGcC_Y_TI|x%IMio_&Rsm z2iY*OIs8{$hx+TyGfBwzQsjU4a1{T~=xNuPTLhWbbXM%weDJv!17s zXPvI^_sGk-HUFg%^JX*Hl^ZH?8Y_P~%cq z8r85>*=Bz-88qMeL<=;5E)D8r{Dp18Lb>)$F9*EKJsf#7_vyW($%{}2S6!dZki<8} zXWn~5r8RYj^wkW(gcHD6Q`RVZ!w#%8Z*GI>&hT4e1PiA$X$Z=ZoD?N6_mTw)D?4!uJ&+4*I@bU=+7a|7L z>QCN#=D4aQpZ>nj|M>1X{l-JHYB6^bUv3A>HH4$!w{n4HOY^#0$#Uh5cTPxOe>xV@ z@-n{GV@TgM7fbq{K6yPDt&XI9xJc>eq4m$AhMvA%qwPqapG;AtJbGGhr5A`3sq*~k zmuDGG`7QUA8JX`ZzvaHGVGXbcC*fOq`_oN1Uu}uX^&?}%EUez*%UOTK>hqoIt9)C3 z4ok(k^et)V;O(dY_jnBR>z&O--pd}N z@j0ne?fdE3+#Z>FJ@QD`=xbS|rM`8Y!}9N8scOI1y-w{;RZq&kV?4&&vlBg!z)Js8 zb~GqHUW(_i_tV|(y>rZ0M&>&-$QQPs8Q$0UZ>ihe?(>`$@{X^=&hs3qaW8?QROtJ< z?mEw_@JQ(Ty)|{on~yE?ed=?vGe1g_FyuGop2rbAr5$+oUS#yxpLLZyKaJf=HQk!E zUD5+X>zJ_*<~P4ySLUY9uT9q!g%bm+H_gAX?!1jeZu?walFhgAbyt`h($%gFk~b?=w+o+ahn`ARSAxW{q#w9_Q5;^NsQPeAXLWzmNHchoZI z8v4V?)*ExLC%zZYdjFmvJr3=~_IeK)YZ{VWzV!-qFaEa*Pm}hTv0FjA-?XC|yF1;7 zIJVO8{AkF%Br}N~>v5htn@Xdn9cZTOI!WcM6Z+HH;|_lC6e(hTg|%_kx!L8zDhn2q zUOVmV%TIn_44slInrUC4WJ!@GYYT8OUvG!1SRIXLYSnn_755sKr(Ejgdk-&r#!~d) zlRB>irc^F8DScY`B(lbUu*QpxI# zbb9EO;2e)SPdmZC{AQlDqqg7AQ={VHhI2Wwl(tXnaIRZT%Lnz(p5DTG98V6s9(&K7 z){MO>sD2sr7#!E&nRKEb-#%Ti^sLhfKee>NzMguH$`kdjRJ_xxUvck$BbI41zP7Tr z@;=?wBO7^bzl?Q04Q)!N4ozjaRXdvAxnx1;^@GQE!@?cJwUuG%r0LW{k7l8l<;s-5 zmA>2^`2Mh4S2SWt3EN@$iN2`MRj)Z7%<~e+@v%CcWp124t=kW;e)BA3H@x>Cr+S~|?vtG{ylow=ujX*hz?=kod|%f=<)@Hv zJX^}Z9KVj?P5HzJ@x(N5DKncga_g(L8zx_Y4UGmiB4*9tT#lS3<&HWDV+?a&XRGJ) zbm4>0tBk@#|7|)4VM+G`{xTJ%3mI*YaC^a;FCp_%`hE?_b~D z)ro>-1m;{mx9H``fvQ|NhV^Lx$^SeF`A0X?*#n$RD{ZC1rIQFakwt6XoZW`r(A%Xx zc1{B1+zV=ADVz69Z|2DZzZq=g^nAyDe#HAa{7mkl zN`ICAGL3I7=UM}(uK?@^6;p?-`(v@VoFPT6jEW9*9nPSGW5{*7mQ^QeL+ZQbnx6}u zxJ@*sYEN0=DbEq~iJI&c$g!l}01P@Klxl-cXW={gRE;w=dmu;>Qc|vzMce=O`bYhK zKbOZ#b;&Ac_jA6^kM6t1xLyyOWrwgf$1iaAnos$A-W@*o&bt;p&)2tI`afgj>u!7I z*@a|zC~2^cMoE^&luy6B464*=g@w=w|G7Sxg7XqYwB?@r?K&i7Wp#=MnXdLfU41cX z>LIGj&%FFA8XTWoN6*-_0-5(COyBx+HL~<_oN;xsMG5s5{Cn7&=@`q(7OM$k)1B-`bpr~@(X^mP9Fr*oqLwR z8eK}eHKpHNgu-~~iD|5P6d0wh4_ChOxXh5f{8%%`y_B8&7h~(yF>FEVI{VcS)#Uf@ z$M5eVG3&k81g4g(T!WHz$6|XWq#YCHr&mt>$`@hzuf!;5Pg*NpH~#kBJN6&1qj&DN zv13nWoviz-WR1sIPr1G(=SootJHGL|_XdyrJn}zIJz?Fl>}k9g@yx@xj|@W9{L(%e zk6d3ZsY_N5dE!lfCujMHth20wtU$7Rj6bz~$?gf8weRg<)Y4}>3A${Xdn@lIyGrkE zE6*ZpWznp3bLu(k|I-XUr|q0oCGxz#`EyY8&cMk81$7$dKJT*KoSr53ExF@(4816+ z>0Y6_Ht7Aly!l3_rgM&7KC9<(cD%$n)#%Z|^k&~>7=Ij_JJmtki23YjUT@klva*x8 zr|Yyg54N}AJ(w#0cpL4x={HxQsB4#>JQ#B2d5cw#%BT8R)2^ETNgieDO;~@Xx+g#6 zcbxw=tSMEb2Sat!8qItqcIWpTUQ=q#pW`T*&cDGP%)^iVan2jQa;}T1P6yebIr=Du zpz=VSpLrfsWBK~{iO#IM<&YA;Qduo4swqy9@23Y&nBncH#rD-r$GZ)es91mZdTC=y z$*{b0G6JiJ#9jRVLe(eKpY<583zthwayc}lrS|#T3(@a2eP6cT$bhY^jkL5|>UE(> z8?zc#C4G`zGNs1R@seET+Rc1v#AQo&DeOWzg}%&H7^{@Y^H{nR-BO1k_NNx+2%#rF zCd%gD()ohx##*9oYcx*jWEIU&2{J5J{@%mS;-2HcGna#!1*gi<`%V$6CLb0fmhT;N zCCId$#{ZVI@;PPt?Wb}aWT)4xIn}t{V>@d#qnl@T^!)2Lsp}9g#5?zLEKMgz>v^6^ zbzko}PZg{ZA3t5{kiYe{&}blIPf|vod@*Cz%TlY#uY5iGb2_|d{O(I3Oj41bndHf!5u+plU90& z?Wtd@KH_!aM=@{eAL4GEmZv_6v9)21vRuuztmPD+O2xQ$OOp6u%yw~roS3MTtTETd zBisu(u`8tv*JXE{f!+u@-wTSXTJ%+1@5krwh7qw=AH}#IZa#<#2dm-VM+XAk2Xv6; zSk6IMlX9KqL5xlm!TyaUI7+K&SzEGYmOuPe31eEln8Tx_sAsKH*1syULCzepUk)7e z82mU{+1`?H)UFVe4FCYlC_$QBzms# zu*sf5Gk7pR_8NTB*!h}#TXJhNm-c;k)>GY#xusiYyX;|(!jH1%kZZ-V4YLK>-iFx< zmKs;rG(5~YNtCx>j_ zVaKr}j@f=5QE$niWbL-Inl)SZE_U6O#q};QEcB0SeJv-xuJdOpzO*dX1Mi$f9 z=Z#%!Fv&Aof8P0JWzcm>?Jk>{W)E26ygQ?RE?`aLEmxmgaTep0QM;`^=O^S8S+_G{ zJ|AgSdh;HQZ(@G_Em@s)V=YC5tAOE~0+4P-nKU%Ub)RALy9V^3~aarCJtH?am&c!(}E{Msh8A z9@~Lk*?{GYum#ar|LLnBMy5&*_o!S6w@dN;^@vU%$2a|>wc?=G2xCjKMpFC7+}?uZ z(v1X=X^1|_6V>}8i0sim^}#A*C*o(nAGrtBo!jx5oleNfxR>@ueCIwt_UX}c$#c)5 zPA2P?!{*GghnuBsEVaZIvL@|EF+bUZ@cn#%<>KaxpvWKNZ@PV{!+CwoXSJ{z^L)UN ztc$ZS>pjA0be%$-caxe%^IDkGV-Al`&g^1>5UW0iF&+F#KMtceLzdMeFmrA8{TP?Z zX4+GG9Nb3FQg5{DaPpq$qAK`hf6DP73tCq~rqpGW#+6Lwl&>{@?N&P?9U30Z%L z|MueVzXXn~7cf41i!aCj|Iozii-0rDkCkBUjcTRNu3|k2sZ96OaA#J@Keb5V?32#a z54ktMQ{v0a{TR161DwqI$H4}w2CDT#Vn^_ya`Y_V<8N{!?on+6E`g6u;Svph7ScVY zqp6t317$pFNwo&&cM8X`v|%%tpQ;WpdR6%sjp{*N!#(do@SKhV=BHj(o<3fOKo+2; zF=JS3v@dIghQliXwI_Z|4E8oZ4;o(xO{n)^mDrS@YB<$#>7iwt>R2aap+>ux%ik7t zQch?768m8L@QYYD**WwN>#JSx`MF>|GxEQp9R^upP$(s_n=6IVMvNk?J&$A_{N{sweU3UE| zGF*#~4kK4Oj(^iVMV?n!PW@^fic-fsdrjB;+dSO+L8F_YJ$S=;E~K|M!V9ed$XkuQ zdcCe}c$kr%2llGniGTP?jh3GiuZk;wDDb1q+I^Q)O{)H;|_kk+YKq;yx%I3YD*CK+`sU)s&!TTxA!G~3b=Me?eG|m*|6epb&WZO5+x5rvhgKTaF z>2^L(xz6BtVcfZ62z{N`8sD{htm3MkkwKm^fKhhv0Niizyk z?Aa@GS2S~%IX(2q<9)|2r_GAXxT1t6?5e7yv2F*BdDqyu*PvB(8CRAx8Xl_F-P{_b zj^BFuZjC>#HwntuuX3Gh&>EeQy(+sFlPCBrc&n_Rn7bZJ+5`GtRi5(mH%i#hZ=wmE zUd^~`d#$ewBcRuuh-v+{F61?(y&>}*_gvfGm5|uWr5?l5my~t^Igl*aI~#vdbPcU^ zp30-b3MM<|nG_SJdKq|9b0t%uub=qI^`&|Z4Qn*j)SNpnYYrmy>3gP`IiG!c4pg1y z`$73j!FR=JifL1%&3TG>jEAf#>LYSPUQ&G5iYZgP`YfKMo}&?Ohd)7jTOD<+bG=oY zrAy{vKz)_gvaLoZk1);#Uo$U2td(7E7F~ z!Dy~?;x%4&={=J84>V}*&GBPOT&s?Y7y8R!9sFKCJRk8z z-Osf6`EB5KH~vxEX4Ubp@t64d-{UmDZwrf;aLu36-JGKMe6T#)*Oss69K>(aSp-pT zQ9b@r^~$=Ke5mr^R6`ygT3y^dhZQO4^s6JB(*|5`FY4Co}?LQBC%CJRaWJ_Mr*6PEv z_$EPnH!KcWWx@mqb)FHLL8PaB`12B$Q%MjR$21qU7$P#@pnpJX=g1^~_ff`hQV&Fj z^EYWp6MN})JMbd!QEn)|BmPO|%ioPnlCEBeMYkTPmZCf&_Oyax-Q%=r(e5B()oFG$ z*3x-{1c$yFNadjOxsim+E?al)1Ln)JvH9i~c(rMg(FaDB;SjtLO zYg-;0*~U|xFU~PHd|j4M&gE2GgN0j)C_V1HOiZhqe$H30tW_yR({Uz0UTgR)IN(#X zM6udfbVI2>45^%x%>AIdyitACKCQ>&mE=FPwk^rY*Riz%-168&@k@~CJ*SHJfS)+U zYg_g&hfxF8{#>m@zc=_xt+Z=>-ySf%C!_U#N6tMb2gE}x!6w{+i3ll04DJ@x?|59K zNxh$jnS7MLiG84>C^hXOn2#W2J?Kzb@&NK^$1xZ0)@0`Q&-%5TKc^hi5(nSbXUy|f zsm~e#%lzA+tvh|=`R@L4{lvQQ{Zz|tsRrQ6@$&kT>lAc(KI+Jn&C6*oakAQ4-6}_3 ze(qApuh#+e?Dc>Nji2YYDdOwAt@K^Ka$ZdPO$5GceBF*``=N!L!ls-gbsJHoFy_gQ zI6^1u_-fD-#l+Z5B6VVIzTtd8B2Dn%%KK>fmJEVEVA+Ud6^KRgK-`O0owGq>y!{zW zoP`pjV>gu}=T^#dVmUZlkQoi3v1_gQc&64BPdh!8UpZv`y$9Ri>DVdl;Yl%4eU>~w z-)6>?0W*>~#M{AYZ*ov|lY359zvrPv*X<e&46@OnQ^&g%>qpWS^DIGQ#~bILo`H(Gav$>lw#!SF!|Yo(rK{xm>*56UDC$ z@`OzRZbd@GtmrP0m(CQgXLohfKup#tY7}in%S2lYRiqU zbC#maM(rnaPrc5=ZKtEGI#H>}=T-b)uM>Y9{67|O~wV|CaA)#7Q=?JmUXN4jOgNa`iKnxi(J2Z ztw^%vOID<%=ZCRt(V0r?to$*D{COLEpM`cQTE|+9duBgA>m*=@uI!`j(A3f%zPN{x z@;(D>%!kowilxcFcbCIjJdN*mUcyhO?x~#9hne)w;jv7qbso=9`Pzc+ldx>;y`}cB z-3)&ZKJ@+DUWdlivA&O^M50ff-15(#w za`!$dm_|4D8t3&&Z_|38WNJ=k=IQ|3dE~SVHKA%z*iToVD8trP_ zDJ^38sT~8=C2Y<=*QzjeDXx$07@*ZTb0y-n|PpV`K1 zKeQR`p%v3yki^->%+_WxQVZ$SuZL!-!w0R5K>0%4)a!wB}vYF{&~pgvW&s zo?@r^6!OlB*BU>C4y5t^d9(k9{?i&A+#SC?vy3%tF>>3-2|_oADh72lRnu5OWcPns zubA%Y)d^N*|#_ zjS2v>Rd=uUquG0B z@}5SkTY1s{Af6awlh-KZ&rRbg=G%G1v`V*4^{J%V?}HLgUhIaQLU=V~)%_6e`!&)diU>QZxINgnFo+8RA>r`u>Cd=fUT(Evv#9q@V^it60IIOwP%vFB-Q#}I& z4@Crt1S#T%n{dz_?WH|WF=jg7W4xb|P7^H6UKZ(+?<%sHR`d=`?-8jG?I_dhH@m-iCt z+3N#zt$ykrywuY`j5gBT^%Z_s&Y~#Ak&{a8KsQ&Ebrryw#gn0ZC;%%{bW0ODCf_k zZ;$FLR?KGw*6vGjx}Wg1Z&e2xzUAFt&Iad&}}! zyr=q1wFh552>-|X8Sy{l>FLB)D)#j=WBt6UJH#_oOT5&G^2%HS?}MVY7rLeimV|l*4LSch zcy*qNVjsN5uq~^GG?&?O>}gHiGA#K>dkCqGw&Zobe=47Sd`7*aOKAr^zsV-lpmc24+EJSK{qh8B2x&hhPZ7OoZF3WlpXnNXT5iOUsEo4w02^q+% z<(xT{`;?0@uOOP2v65dUeG+vn3vbqbOjgykPK4zqI@dZ8I&^d3^V5+P=h;Wzlb7j;#1*l#S6l_4KjZpeLLQL8)QKe0{u zTTjv)eKfTG)}_xHOdW$95=iT-9p;Iz^WM;R`Ra_yH5Q_{QpT2~7;BU27pnGXM>vrK zRMN_Os)_tE=76$grDSjOA93#&!4>rF^SG`#jmP+isxMb>!N|5QVJ>XaewLF?ei`z0 zeDhOe56En?>QfF-S;e*?X;^#Y+wgxDpQtyz%9AdZB&tu&O#xq*GLzj=sn>2BGGC`L zqqUBxT2-j;gCFj_U#p2d*3qz(t6Tnde4W2*{@2=y*?9aunJ0pokM2Bf-*~>em%b^F z-rf7premsSDPOzH>rm@#@)}7{{6j=blq>7;sv@B=71W6aEcAHEe|#Rc3E$dlb=PX= zevGWR!|^}1(e$W$|HnnVQ}QNd;3>QH$c&p-)bslF+*xQ;<}?BkO?eI(@ePsF8jk0Y zhw-fOeft>18n#X!{nYj`$y#|z-h1jbUv1oC+{K%JhziQfiDA}K$ZN<*K>(plcBI{PnzOB`tw@uH&W{@j5XGuGJiLU6K(;lxK^dQ1<7ipc5E2l#04 zJ9FKG-f5od5E)en+7D0cl;n9V_hWgK^r;3hmdJJ52*i0ESLaty z=gM`{4|Gk2&GwpIrmqm?*bD&ohhq20=jrm~br@aw$uc3#==rmmZHvsw$co83=e zAFPy41-lq_885|I#{H*R^iz1cif}RdfXP|Zv67z?L~c*d`mKmTWSKd!61d7WR9D8z zZ+j!rH9BaD`D*?dE>78@7RZSKL@wKL)1#k{s~%-LJB5be)y_km^)}To`zrdrs+hhe zo6|`Cw?P$7+<6^%yC2f#Xg+y>-N*1#%8cW~cI2)YNY>@Nk-O!>c>fe5_?!lgMc@8N zKF9i}8qu2uyNK*P)_gVEca5*xJ=Ig&9?#^@=ktZwi?q_=^H?tqkduIKp#`cUT(a3@X7d3PQtUVY@f&MvQy&lQhz zx;)(=y|s^Z+P9shulMBRDXBUVgQnAQ{SHgZAlgRGn|2qUo^|i*7v!ClwVN@TpXu+_ zTw}?cZRnX)D-s2_kwrY8_RAz6c4tz7xf|Y088(#}eBIdZ&DHbNPX(2pZ(XqkPI+2t z+`NB@&!RlNQd&FIzK|YFSXIc^{M0|_(;@NjsS1TB=M;AP_|m_n^~UXdJ(wL0emHeb zsm6xI0nW=IS=XaOoel;*84{|{a6_NNwplN)2xR?Bebrra+H3F(YXzF&fo|DpD^@?mmG4~tUdLZf8 z7O1m}-l9AP@f??e>a97}MuxUa>nyor_uLzgYjoRFW(^ZptRr9z*K99Wnqu6=$VO;OU zeXKtFeJOtqNbq*7Fr_ivkEuw4I<3~e?D29>s@Zr`+0*!!MlP-LydM&ViZ6i<`kaP# zF5!r0PB?;}yrsM&(JJ5Q$_l)^BjeLOz|)C_OTKd5`FHKTUY5T#9Az|da8BZ`1y<8H zoX=&=<4y_X$ciBD4Rj-h(7rKjC9xBnK_1s|YYncg)91x?|we?c}v@B zv@7+y{M7bPb?ZN8Rcre?>vpw1c9NRfNWGR)_|@nz2YVUEJ1$!GolBT3k9&T+uq@7A z9aUrNUe(!vdE{8rw!U)#6W`v3)BKk0)UHm4ISyY!ZyBcu(+@kgY}%WHjg!ZdmqKQ4 zhA)+8yF2)5o%*N~)AYTv(A3$-DIoZrByX;kjQOq;0p}zG|BAO7!(VDl%Baz3piY^( z`p-TH4`)B@cN$HpV65NFlWbb&*epw#vi8zSDbJ?oyUgj|uV(n;9ggxt4})*AHSQj7 zo#H|!P@X2pH}+mjjG=ylA{Z$VG z11dLEU+k^r+xtf>Ve}|1pD%x#d%ycAWWcq%CJb!z|I3GLb~89}WIng$6ZAF6nMc=QW|R#e-{{hC^1C&MSuAQwznt;|M>u zMf|QeDw6S=sI_07mD7jukNx}QTg#lOLbv*NRcyGlQwe$INU7mVYWUDSyTJc1- z%5G(%0W9X+S!tHm@yTYEKqNqsZ&`1$pReIjRub&xKN|HVw)|Xe#G}CCa^w_0oOR@) zr&Ou%Bo{XSCw{$9^+oDlp00>89u@1q#0Vd5eifsPeP+4?JB^>^o*Ha9w(}$XJXX=_ zKBrC#dnD7kj4etCbw0>4gkVGEs}6@}oQKDE)n{w*N^jt(KlAkr{lBSl)-cH1`P2A{ zO{FH8Yu5Ol*9%vzw9d)2;jd#}ep`O3QKOE1ol7mwDxRz9MoxFZl7B-s@6*9r+Et&E zQPOyCLj{LOVEt*|yNZSI0-7EFPsBO*Ciu6ry0IMxb{!!oI)DT4<0PW5VM=?oG7N4MdRELOz4QMz1u#wN7I1B!cwa8X3ht+W9_Hf8{`+S^gJvF+C<8PPm&wHe@7R5MJl literal 0 HcmV?d00001 diff --git a/src/Modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 b/src/Modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 new file mode 100644 index 000000000..9b3ecfc5f --- /dev/null +++ b/src/Modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 @@ -0,0 +1,14 @@ +@{ +GUID="56D66100-99A0-4FFC-A12D-EEE9A6718AEF" +Author="Microsoft Corporation" +CompanyName="Microsoft Corporation" +Copyright="© Microsoft Corporation. All rights reserved." +ModuleVersion="3.0.0.0" +PowerShellVersion="3.0" +CLRVersion="4.0" +AliasesToExport = @() +FunctionsToExport = @() +CmdletsToExport="Start-Transcript", "Stop-Transcript" +NestedModules="Microsoft.PowerShell.ConsoleHost.dll" +HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390784' +} diff --git a/src/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 b/src/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 new file mode 100644 index 000000000..425e64b78 --- /dev/null +++ b/src/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 @@ -0,0 +1,99 @@ +@{ +GUID="EEFCB906-B326-4E99-9F54-8B4BB6EF3C6D" +Author="Microsoft Corporation" +CompanyName="Microsoft Corporation" +Copyright="© Microsoft Corporation. All rights reserved." +ModuleVersion="3.1.0.0" +PowerShellVersion="3.0" +CLRVersion="4.0" +NestedModules="Microsoft.PowerShell.Commands.Management.dll" +HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390785' +AliasesToExport = @("gcb", "scb") +FunctionsToExport = @() +CmdletsToExport=@("Add-Content", + "Clear-Content", + "Clear-ItemProperty", + "Join-Path", + "Convert-Path", + "Copy-ItemProperty", + "Get-EventLog", + "Clear-EventLog", + "Write-EventLog", + "Limit-EventLog", + "Show-EventLog", + "New-EventLog", + "Remove-EventLog", + "Get-ChildItem", + "Get-Content", + "Get-ItemProperty", + "Get-ItemPropertyValue", + "Get-WmiObject", + "Invoke-WmiMethod", + "Move-ItemProperty", + "Get-Location", + "Set-Location", + "Push-Location", + "Pop-Location", + "New-PSDrive", + "Remove-PSDrive", + "Get-PSDrive", + "Get-Item", + "New-Item", + "Set-Item", + "Remove-Item", + "Move-Item", + "Rename-Item", + "Copy-Item", + "Clear-Item", + "Invoke-Item", + "Get-PSProvider", + "New-ItemProperty", + "Split-Path", + "Test-Path", + "Get-Process", + "Stop-Process", + "Wait-Process", + "Debug-Process", + "Start-Process", + "Remove-ItemProperty", + "Remove-WmiObject", + "Rename-ItemProperty", + "Register-WmiEvent", + "Resolve-Path", + "Get-Service", + "Stop-Service", + "Start-Service", + "Suspend-Service", + "Resume-Service", + "Restart-Service", + "Set-Service", + "New-Service", + "Set-Content", + "Set-ItemProperty", + "Set-WmiInstance", + "Get-Transaction", + "Start-Transaction", + "Complete-Transaction", + "Undo-Transaction", + "Use-Transaction", + "New-WebServiceProxy", + "Get-HotFix", + "Test-Connection", + "Enable-ComputerRestore", + "Disable-ComputerRestore", + "Checkpoint-Computer", + "Get-ComputerRestorePoint", + "Restart-Computer", + "Stop-Computer", + "Restore-Computer", + "Add-Computer", + "Remove-Computer", + "Test-ComputerSecureChannel", + "Reset-ComputerMachinePassword", + "Rename-Computer", + "Get-ControlPanelItem", + "Show-ControlPanelItem", + "Clear-Recyclebin", + "Get-Clipboard", + "Set-Clipboard") +} diff --git a/src/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 b/src/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 new file mode 100644 index 000000000..a5a678d7b --- /dev/null +++ b/src/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 @@ -0,0 +1,14 @@ +@{ +GUID="A94C8C7E-9810-47C0-B8AF-65089C13A35A" +Author="Microsoft Corporation" +CompanyName="Microsoft Corporation" +Copyright="© Microsoft Corporation. All rights reserved." +ModuleVersion="3.0.0.0" +PowerShellVersion="3.0" +CLRVersion="4.0" +AliasesToExport = @() +FunctionsToExport = @() +CmdletsToExport="Get-Acl", "Set-Acl", "Get-PfxCertificate", "Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "Get-AuthenticodeSignature", "Set-AuthenticodeSignature", "ConvertFrom-SecureString", "ConvertTo-SecureString", "Get-CmsMessage", "Unprotect-CmsMessage", "Protect-CmsMessage" , "New-FileCatalog" , "Test-FileCatalog" +NestedModules="Microsoft.PowerShell.Security.dll" +HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390786' +} diff --git a/src/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 b/src/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 new file mode 100644 index 000000000..85eaf1533 --- /dev/null +++ b/src/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 @@ -0,0 +1,709 @@ +function Get-FileHash +{ + [CmdletBinding(DefaultParameterSetName = "Path", HelpURI = "http://go.microsoft.com/fwlink/?LinkId=517145")] + param( + [Parameter(Mandatory, ParameterSetName="Path", Position = 0)] + [System.String[]] + $Path, + + [Parameter(Mandatory, ParameterSetName="LiteralPath", ValueFromPipelineByPropertyName = $true)] + [Alias("PSPath")] + [System.String[]] + $LiteralPath, + + [Parameter(Mandatory, ParameterSetName="Stream")] + [System.IO.Stream] + $InputStream, + + [ValidateSet("SHA1", "SHA256", "SHA384", "SHA512", "MACTripleDES", "MD5", "RIPEMD160")] + [System.String] + $Algorithm="SHA256" + ) + + begin + { + # Construct the strongly-typed crypto object + + # First see if it has a FIPS algorithm + $hasherType = "System.Security.Cryptography.${Algorithm}CryptoServiceProvider" -as [Type] + if ($hasherType) + { + $hasher = $hasherType::New() + } + else + { + # Check if the type is supported in the current system + $algorithmType = "System.Security.Cryptography.${Algorithm}" -as [Type] + if ($algorithmType) + { + if ($Algorithm -eq "MACTripleDES") + { + $hasher = $algorithmType::New() + } + else + { + $hasher = $algorithmType::Create() + } + } + else + { + $errorId = "AlgorithmTypeNotSupported" + $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidArgument + $errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::AlgorithmTypeNotSupported -f $Algorithm + $exception = [System.InvalidOperationException]::New($errorMessage) + $errorRecord = [System.Management.Automation.ErrorRecord]::New($exception, $errorId, $errorCategory, $null) + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + } + + function GetStreamHash + { + param( + [System.IO.Stream] + $InputStream, + + [System.String] + $RelatedPath, + + [System.Security.Cryptography.HashAlgorithm] + $Hasher) + + # Compute file-hash using the crypto object + [Byte[]] $computedHash = $Hasher.ComputeHash($InputStream) + [string] $hash = [BitConverter]::ToString($computedHash) -replace '-','' + + if ($RelatedPath -eq $null) + { + $retVal = [PSCustomObject] @{ + Algorithm = $Algorithm.ToUpperInvariant() + Hash = $hash + } + } + else + { + $retVal = [PSCustomObject] @{ + Algorithm = $Algorithm.ToUpperInvariant() + Hash = $hash + Path = $RelatedPath + } + } + $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") + $retVal + } + } + + process + { + if($PSCmdlet.ParameterSetName -eq "Stream") + { + GetStreamHash -InputStream $InputStream -RelatedPath $null -Hasher $hasher + } + else + { + $pathsToProcess = @() + if($PSCmdlet.ParameterSetName -eq "LiteralPath") + { + $pathsToProcess += Resolve-Path -LiteralPath $LiteralPath | Foreach-Object ProviderPath + } + if($PSCmdlet.ParameterSetName -eq "Path") + { + $pathsToProcess += Resolve-Path $Path | Foreach-Object ProviderPath + } + + foreach($filePath in $pathsToProcess) + { + if(Test-Path -LiteralPath $filePath -PathType Container) + { + continue + } + + try + { + # Read the file specified in $FilePath as a Byte array + [system.io.stream]$stream = [system.io.file]::OpenRead($filePath) + GetStreamHash -InputStream $stream -RelatedPath $filePath -Hasher $hasher + } + catch [Exception] + { + $errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::FileReadError -f $FilePath, $_ + Write-Error -Message $errorMessage -Category ReadError -ErrorId "FileReadError" -TargetObject $FilePath + return + } + finally + { + if($stream) + { + $stream.Dispose() + } + } + } + } + } +} + +<# This cmdlet is used to create a new temporary file in $env:temp #> +function New-TemporaryFile +{ + [CmdletBinding( + HelpURI='http://go.microsoft.com/fwlink/?LinkId=526726', + SupportsShouldProcess=$true)] + [OutputType([System.IO.FileInfo])] + Param() + + Begin + { + try + { + if($PSCmdlet.ShouldProcess($env:TEMP)) + { + $tempFilePath = [System.IO.Path]::GetTempFileName() + } + } + catch + { + $errorRecord = [System.Management.Automation.ErrorRecord]::new($_.Exception,"NewTemporaryFileWriteError", "WriteError", $env:TEMP) + Write-Error -ErrorRecord $errorRecord + return + } + + if($tempFilePath) + { + Get-Item $tempFilePath + } + } +} + +<# This cmdlet is used to generate a new guid #> +function New-Guid +{ + [CmdletBinding(HelpURI='http://go.microsoft.com/fwlink/?LinkId=526920')] + [OutputType([System.Guid])] + Param() + + Begin + { + [Guid]::NewGuid() + } +} + +<############################################################################################ +# Format-Hex cmdlet helps in displaying the Hexadecimal equivalent of the input data. +############################################################################################> +function Format-Hex +{ + [CmdletBinding( + DefaultParameterSetName="Path", + HelpUri="http://go.microsoft.com/fwlink/?LinkId=526919")] + [Alias("fhx")] + [OutputType("Microsoft.PowerShell.Commands.ByteCollection")] + param + ( + [Parameter (Mandatory=$true, Position=0, ParameterSetName="Path")] + [ValidateNotNullOrEmpty()] + [string[]] $Path, + + [Parameter (Mandatory=$true, ParameterSetName="LiteralPath")] + [ValidateNotNullOrEmpty()] + [Alias("PSPath")] + [string[]] $LiteralPath, + + [Parameter(Mandatory=$true, ParameterSetName="ByInputObject", ValueFromPipeline=$true)] + [Object] $InputObject, + + [Parameter (ParameterSetName="ByInputObject")] + [ValidateSet("Ascii", "UTF32", "UTF7", "UTF8", "BigEndianUnicode", "Unicode")] + [string] $Encoding = "Ascii", + + [Parameter(ParameterSetName="ByInputObject")] + [switch]$Raw + ) + + begin + { + $bufferSize = 16 + $inputStreamArray = [System.Collections.ArrayList]::New() + <############################################################################################ + # The ConvertToHexadecimalHelper is a helper method used to fetch unicode bytes from the + # input data and display the hexadecimial representaion of the of the input data in bytes. + ############################################################################################> + function ConvertToHexadecimalHelper + { + param + ( + [Byte[]] $inputBytes, + [string] $path, + [Uint32] $offset + ) + + # This section is used to display the hexadecimal + # representaion of the of the input data in bytes. + if($inputBytes -ne $null) + { + $byteCollectionObject = [Microsoft.PowerShell.Commands.ByteCollection]::new($offset, $inputBytes, $path) + Write-Output -InputObject $byteCollectionObject + } + } + + <############################################################################################ + # The ProcessFileContent is a helper method used to fetch file contents in blocks and + # process it to support displaying hexadecimal formating of the fetched content. + ############################################################################################> + function ProcessFileContent + { + param + ( + [string] $filePath, + [boolean] $isLiteralPath + ) + + if($isLiteralPath) + { + $resolvedPaths = Resolve-Path -LiteralPath $filePath + } + else + { + $resolvedPaths = Resolve-Path -Path $filePath + } + + # If Path resolution has failed then a corresponding non-terminating error is + # written to the pipeline. We continue processing any remaining files. + if($resolvedPaths -eq $null) + { + return + } + + if($resolvedPaths.Count -gt 1) + { + # write a non-terminating error message indicating that path specified is resolving to multiple file system paths. + $errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::FormatHexResolvePathError -f $filePath + Write-Error -Message $errorMessage -Category ([System.Management.Automation.ErrorCategory]::InvalidData) -ErrorId "FormatHexResolvePathError" + } + + $targetFilePath = $resolvedPaths.ProviderPath + + + if($targetFilePath -ne $null) + { + $buffer = [byte[]]::new($bufferSize) + + try + { + try + { + $currentFileStream = [System.IO.File]::Open($targetFilePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read) + } + catch + { + # Failed to access the file. Write a non terminating error to the pipeline + # and move on with the remaining files. + $exception = $_.Exception + if($null -ne $_.Exception -and + $null -ne $_.Exception.InnerException) + { + $exception = $_.Exception.InnerException + } + + $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception,"FormatHexFileAccessError", ([System.Management.Automation.ErrorCategory]::ReadError), $targetFilePath) + $PSCmdlet.WriteError($errorRecord) + } + + if($null -ne $currentFileStream) + { + $srcStream = [System.IO.BinaryReader]::new($currentFileStream) + $displayHeader = $true + $offset = 0 + $blockCounter = 0 + while($numberOfBytesRead = $srcStream.Read($buffer, 0, $bufferSize)) + { + # send only the bytes that have been read + # if we send the whole buffer, we'll have extraneous bytes + # at the end of an incomplete group of 16 bytes + if ( $numberOfBytesRead -eq $bufferSize ) + { + # under some circumstances if we don't copy the buffer + # and the results are stored to a variable, the results are not + # correct and one object replicated in all the output objects + ConvertToHexadecimalHelper ($buffer.Clone()) $targetFilePath $offset + } + else + { + # handle the case of the partial (and probably last) buffer + $bytesReadBuffer = [byte[]]::New($numberOfBytesRead) + [Array]::Copy($buffer,0, $bytesReadBuffer,0,$numberOfBytesRead) + ConvertToHexadecimalHelper $bytesReadBuffer $targetFilePath $offset + } + $displayHeader = $false + $blockCounter++; + + # Updating the offset value. + $offset = $blockCounter*0x10 + } + } + } + finally + { + If($null -ne $currentFileStream) + { + $currentFileStream.Dispose() + } + If($null -ne $srcStream) + { + $srcStream.Dispose() + } + } + } + } + } + + process + { + switch($PSCmdlet.ParameterSetName) + { + "Path" + { + ProcessFileContent $Path $false + } + "LiteralPath" + { + ProcessFileContent $LiteralPath $true + } + "ByInputObject" + { + # If it's an actual byte array, then we directly use it for hexadecimal formatting. + if($InputObject -is [Byte[]]) + { + ConvertToHexadecimalHelper $InputObject $null + return + } + # if it's a single byte, we'll assume streaming + elseif($InputObject -is [byte]) + { + $null = $inputStreamArray.Add($InputObject) + } + # If the input data is of string type then directly get bytes out of it. + elseif($InputObject -is [string]) + { + # The ValidateSet arribute on the Encoding paramter makes sure that only + # valid values (supported on all paltforms where Format-Hex is avaliable) + # are allowed through user input. + $inputBytes = [Text.Encoding]::$Encoding.GetBytes($InputObject) + ConvertToHexadecimalHelper $inputBytes $null + return + } + elseif($InputObject -is [System.IO.FileSystemInfo]) + { + # If file path is provided as an input, use the file contents to show the hexadecimal format. + $filePath = ([System.IO.FileSystemInfo]$InputObject).FullName + ProcessFileContent $filePath $false + return + } + elseif($InputObject -is [int64]) + { + $inputBytes = [BitConverter]::GetBytes($InputObject) + $null = $inputStreamArray.AddRange($inputBytes) + } + elseif($InputObject -is [int64[]]) + { + foreach($i64 in $InputObject) + { + $inputBytes = [BitConverter]::GetBytes($i64) + $null = $inputStreamArray.AddRange($inputBytes) + } + } + elseif($InputObject -is [int]) + { + # If we get what appears as ints, it may not be what the user really wants. + # for example, if the user types a small set of numbers just to get their + # character representations, as follows: + # + # 170..180 | format-hex + # Path: + # 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F + #00000000 AA AB AC AD AE AF B0 B1 B2 B3 B4 ª«¬­®¯°±²³´ + # + # any integer padding is likely to be more confusing than this + # fairly compact representation. + # + # However, some might like to see the results with the raw data, + # -Raw exists to provide that behavior: + # PS# 170..180 | format-hex -Raw + # + # Path: + # + # 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F + # + # 00000000 AA 00 00 00 AB 00 00 00 AC 00 00 00 AD 00 00 00 ª...«...¬...­... + # 00000010 AE 00 00 00 AF 00 00 00 B0 00 00 00 B1 00 00 00 ®...¯...°...±... + # 00000020 B2 00 00 00 B3 00 00 00 B4 00 00 00 ²...³...´... + # + # this provides a representation of the piped numbers which includes all + # of the bytes which are in an int32 + if ( $Raw ) + { + $inputBytes = [BitConverter]::GetBytes($InputObject) + $null = $inputStreamArray.AddRange($inputBytes) + } + else + { + # first determine whether we can represent this as a byte + $possibleByte = $InputObject -as [byte] + # first determine whether we can represent this as a int16 + $possibleInt16 = $InputObject -as [int16] + if ( $possibleByte -ne $null ) + { + $null = $inputStreamArray.Add($possibleByte) + } + elseif ( $possibleint16 -ne $null ) + { + $inputBytes = [BitConverter]::GetBytes($possibleInt16) + $null = $inputStreamArray.AddRange($inputBytes) + } + else + { + # now int + $inputBytes = [BitConverter]::GetBytes($InputObject) + $null = $inputStreamArray.AddRange($inputBytes) + } + } + } + else + { + # Otherwise, write a non-terminating error message indicating that input object type is not supported. + $errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::FormatHexTypeNotSupported -f $InputObject.GetType() + Write-Error -Message $errorMessage -Category ([System.Management.Automation.ErrorCategory]::ParserError) -ErrorId "FormatHexFailureTypeNotSupported" + } + # Handle streaming case here + # during this process we may not have enough characters to create a ByteCollection + # if we do, create as many ByteCollections as necessary, each being 16 bytes in length + if ( $inputStreamArray.Count -ge $bufferSize ) + { + $rowCount = [math]::Floor($inputStreamArray.Count/$bufferSize) + $arrayLength = $bufferSize * $rowCount + for($i = 0; $i -lt $rowCount; $i++) + { + $rowOffset = $i * $bufferSize + ConvertToHexadecimalHelper -inputBytes $inputStreamArray.GetRange($rowOffset, $bufferSize) -path ' ' -offset $offset + $offset += $bufferSize + } + # We use RemoveRange because of the pathological case of having + # streamed combination of bytes, int16, int32, int64 which are greater + # than 16 bytes. Consider the case: + # $i = [int16]::MaxValue + 3 + # $i64=[int64]::MaxValue -5 + # .{ $i;$i;$i;$i64 } | format-hex + # which create an arraylist 20 bytes + # we need to remove only the bytes from the array which we emitted + $inputStreamArray.RemoveRange(0,$arrayLength) + } + } + } + } + end + { + # now manage any left over bytes in the $inputStreamArray + if ( $PSCmdlet.ParameterSetName -eq "ByInputObject" ) + { + ConvertToHexadecimalHelper $inputStreamArray $null -path ' ' -offset $offset + } + } + +} + +## Imports a PowerShell Data File - a PowerShell hashtable defined in +## a file (such as a Module manifest, session configuration file) +function Import-PowerShellDataFile +{ + [CmdletBinding(DefaultParameterSetName = "ByPath", HelpUri = "http://go.microsoft.com/fwlink/?LinkID=623621")] + [OutputType("System.Collections.Hashtable")] + param( + [Parameter(ParameterSetName = "ByPath", Position = 0)] + [String[]] $Path, + + [Parameter(ParameterSetName = "ByLiteralPath", ValueFromPipelineByPropertyName = $true)] + [Alias("PSPath")] + [String[]] $LiteralPath + ) + + begin + { + function ThrowInvalidDataFile + { + param($resolvedPath, $extraError) + + $errorId = "CouldNotParseAsPowerShellDataFile$extraError" + $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidData + $errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::CouldNotParseAsPowerShellDataFile -f $resolvedPath + $exception = [System.InvalidOperationException]::New($errorMessage) + $errorRecord = [System.Management.Automation.ErrorRecord]::New($exception, $errorId, $errorCategory, $null) + $PSCmdlet.WriteError($errorRecord) + } + } + + process + { + foreach($resolvedPath in (Resolve-Path @PSBoundParameters)) + { + $parseErrors = $null + $ast = [System.Management.Automation.Language.Parser]::ParseFile(($resolvedPath.ProviderPath), [ref] $null, [ref] $parseErrors) + if ($parseErrors.Length -gt 0) + { + ThrowInvalidDataFile $resolvedPath + } + else + { + $data = $ast.Find( { $args[0] -is [System.Management.Automation.Language.HashtableAst] }, $false ) + if($data) + { + $data.SafeGetValue() + } + else + { + ThrowInvalidDataFile $resolvedPath "NoHashtableRoot" + } + } + } + } +} + +## Converts a SDDL string into an object-based representation of a security +## descriptor +function ConvertFrom-SddlString +{ + [CmdletBinding(HelpUri = "http://go.microsoft.com/fwlink/?LinkId=623636")] + param( + ## The string representing the security descriptor in SDDL syntax + [Parameter(Mandatory, Position = 0)] + [String] $Sddl, + + ## The type of rights that this SDDL string represents, if any. + [Parameter()] + [ValidateSet( + "FileSystemRights", "RegistryRights", "ActiveDirectoryRights", + "MutexRights", "SemaphoreRights", "CryptoKeyRights", + "EventWaitHandleRights")] + $Type + ) + + ## Translates a SID into a NT Account + function ConvertTo-NtAccount + { + param($Sid) + + if($Sid) + { + $securityIdentifier = [System.Security.Principal.SecurityIdentifier] $Sid + + try + { + $ntAccount = $securityIdentifier.Translate([System.Security.Principal.NTAccount]).ToString() + } + catch{} + + $ntAccount + } + } + + ## Gets the access rights that apply to an access mask, preferring right types + ## of 'Type' if specified. + function Get-AccessRights + { + param($AccessMask, $Type) + + ## All the types of access rights understood by .NET + $rightTypes = [Ordered] @{ + "FileSystemRights" = [System.Security.AccessControl.FileSystemRights] + "RegistryRights" = [System.Security.AccessControl.RegistryRights] + "ActiveDirectoryRights" = [System.DirectoryServices.ActiveDirectoryRights] + "MutexRights" = [System.Security.AccessControl.MutexRights] + "SemaphoreRights" = [System.Security.AccessControl.SemaphoreRights] + "CryptoKeyRights" = [System.Security.AccessControl.CryptoKeyRights] + "EventWaitHandleRights" = [System.Security.AccessControl.EventWaitHandleRights] + } + $typesToExamine = $rightTypes.Values + + ## If they know the access mask represents a certain type, prefer its names + ## (i.e.: CreateLink for the registry over CreateDirectories for the filesystem) + if($Type) + { + $typesToExamine = @($rightTypes[$Type]) + $typesToExamine + } + + + ## Stores the access types we've found that apply + $foundAccess = @() + + ## Store the access types we've already seen, so that we don't report access + ## flags that are essentially duplicate. Many of the access values in the different + ## enumerations have the same value but with different names. + $foundValues = @{} + + ## Go through the entries in the different right types, and see if they apply to the + ## provided access mask. If they do, then add that to the result. + foreach($rightType in $typesToExamine) + { + foreach($accessFlag in [Enum]::GetNames($rightType)) + { + $longKeyValue = [long] $rightType::$accessFlag + if(-not $foundValues.ContainsKey($longKeyValue)) + { + $foundValues[$longKeyValue] = $true + if(($AccessMask -band $longKeyValue) -eq ($longKeyValue)) + { + $foundAccess += $accessFlag + } + } + } + } + + $foundAccess | Sort-Object + } + + ## Converts an ACE into a string representation + function ConvertTo-AceString + { + param( + [Parameter(ValueFromPipeline)] + $Ace, + $Type + ) + + process + { + foreach($aceEntry in $Ace) + { + $AceString = (ConvertTo-NtAccount $aceEntry.SecurityIdentifier) + ": " + $aceEntry.AceQualifier + if($aceEntry.AceFlags -ne "None") + { + $AceString += " " + $aceEntry.AceFlags + } + + if($aceEntry.AccessMask) + { + $foundAccess = Get-AccessRights $aceEntry.AccessMask $Type + + if($foundAccess) + { + $AceString += " ({0})" -f ($foundAccess -join ", ") + } + } + + $AceString + } + } + } + + $rawSecurityDescriptor = [Security.AccessControl.CommonSecurityDescriptor]::new($false,$false,$Sddl) + + $owner = ConvertTo-NtAccount $rawSecurityDescriptor.Owner + $group = ConvertTo-NtAccount $rawSecurityDescriptor.Group + $discretionaryAcl = ConvertTo-AceString $rawSecurityDescriptor.DiscretionaryAcl $Type + $systemAcl = ConvertTo-AceString $rawSecurityDescriptor.SystemAcl $Type + + [PSCustomObject] @{ + Owner = $owner + Group = $group + DiscretionaryAcl = @($discretionaryAcl) + SystemAcl = @($systemAcl) + RawDescriptor = $rawSecurityDescriptor + } +} diff --git a/src/Modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1 b/src/Modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1 new file mode 100644 index 000000000..972d36886 --- /dev/null +++ b/src/Modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1 @@ -0,0 +1,15 @@ +@{ +GUID="766204A6-330E-4263-A7AB-46C87AFC366C" +Author="Microsoft Corporation" +CompanyName="Microsoft Corporation" +Copyright="© Microsoft Corporation. All rights reserved." +ModuleVersion="3.0.0.0" +PowerShellVersion="3.0" +CLRVersion="4.0" +AliasesToExport = @() +FunctionsToExport = @() +CmdletsToExport="Disable-WSManCredSSP", "Enable-WSManCredSSP", "Get-WSManCredSSP", "Set-WSManQuickConfig", "Test-WSMan", "Invoke-WSManAction", "Connect-WSMan", "Disconnect-WSMan", "Get-WSManInstance", "Set-WSManInstance", "Remove-WSManInstance", "New-WSManInstance", "New-WSManSessionOption" +NestedModules="Microsoft.WSMan.Management.dll" +FormatsToProcess="WSMan.format.ps1xml" +HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390788' +} diff --git a/src/Modules/PSDiagnostics/PSDiagnostics.psd1 b/src/Modules/PSDiagnostics/PSDiagnostics.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..3d73330c0a96c15203b362028fe12f57c9f6c791 GIT binary patch literal 1214 zcmbu9*-pY>5QWdRiSIzX(nN?TiZ>(>Tw)@Ih|6__f=$>$>lWh!`I724BZ@7qF-_Z_ znK?6O=1h5hs_I^gT2O9!?dwzr+EGPIYHLeHb$G6;tZn7B#wpMSr;_{37AVA0_R}W* z5{MF!0k$ru5}B7$HEOz2qDzf5@j4Af)SB=+=I-LlsqWsfKLacgr(q_K#SAp2(olCg z;yr+iG5=4-F}Wtx>%lPbY>)8yeZ~UOHTAi2AM(WhE2P5^>ow1g3YmTy^wVKBeY|HL z7f<`Po{Ge;z2E7HHbLGvq6O>FtIuaxcXS$A*P)I-srDLM&?Ys@u74W$k?RT7o33A* z+A){$ZK}l{MX1t4AJf)UZ1XOlS&UZ2O#e1Di?6utoeG@gYl1Hbm95)-qQ(e0+1p8)h}Ys>AgYJ(D!%%KH_Ye|Ad|) zvyr=G_@2pp#4OwExAHZQG7Kgm3*2ReDp^$Jk7vh<7}lO6%8g30)aFKR25e P))D%rJ@#+);2ZD)XDGiD literal 0 HcmV?d00001 diff --git a/src/Modules/PSDiagnostics/PSDiagnostics.psm1 b/src/Modules/PSDiagnostics/PSDiagnostics.psm1 new file mode 100644 index 0000000000000000000000000000000000000000..d36168f27d69af230b08b017761397df82fd8b03 GIT binary patch literal 23122 zcmeHPX>S|J5$&%IkpIAyh(LyyvUS_uI9S_~6C;*wSjOgq)>w!XB`a$kktoZX&HnWy z?{%@%$J8{35_LET2x^AYN8Qy`)jj&pzyIi_-S6G+TnnGSxjlE_w%wsSb0_%y*5CEr zvDAT=OKCx@T=#0ujBW&J4K)V`Hb%|ZqK*wN3AW4IK=n?<{?DF z+QRn)BL}!1x*hyI1Kcflgby)bYY*2w{2urb1I)dJd&RzwnYLWl!n$6*)0iA$9WI={t@*&+04_a}eHzU>6l$LY$TCx=0K2?QClgPAFZ79h69f+;g8 zXZo0Tc8Es_@)0OF1Wl8Jt26FFrzn5oF#rb!MGjEDC;03E8_H6s7n+1KHWf#Hlr{D( zbpQQOPwKeO(K)`<#eHByiLV16>Mretx;=26%+@-lt=YH=HFfZm<|Z)3-roT~8`2@D z60Yg2_uZSJJ<{@o%UkGUkEh17^%vi_H=K(cx$mB4ZT1Y5eHV7Sn~YsOe`=39L;GjI zJoRutjcIlH=(6RV0J9@dNl&tWu5o;7<3>uV{rOb-(}U~)^8;v%a<~N@q^~^2-%g~B z?ECAv|Dy+gdydIW@_aLDp^v3S%|Pyy&^G?kKORF)PvD(s`={vfZ88IAuYTwgX>E$> z6ZgQ~bsvnL@mTe!e71@4gh)@gi;;0#8+6Au`5KtgroKI&KkjYQSjBM8W0;OC;qb=m z(UJfA0(jD|lFwX!QXVzMV17&t-hw~$uIdXff(50L(!AlZo5DNlL%=`XIn$G}0KGM4y!{);Pp_;up`;q4@c*>*3y{&EEz zTo7wwHmLA{Ui82{gY0+kk#&eV-bC&>mYaSq3&s}KwH(I0TXM@2g%d;A051OoJugAs zUjbYEJLyt8O?4&smEb+bqwf_YvK`X#VukBJ>brDK5j`pq0+%< zi*ZxW+b>52Z=xh5WdG#7&pwIT8D=lce+EGf4_OkKS)-vArz%j;k zEvyHW$O-N(Onx(;T0H~KC4WbF2Y^T}9e|_E2(Feo#_erH9bC(8A3QnANBP<7r~b%m zQXA_{c?Fmp4`NSx{q)jqQg1#v$}C?VD16{;iBS+SU}Tj0v=)u1u+B{Dx{LQ=%eXOCh#gp2+sI_ETq%2n(HeLP`Ae=U@rNCy(LyC6 ziYZbY^g0?EBSLB%HUA=z?8u8X)Ds^+DJF8YaJ?RWS&$XC$#BVnka8z@2lg%bfi*;( zTH|F6ZDUx&2o*Zcka8}DKMi?G)%6&agt%o2qaL_LIsky_ZlHQyJ6Git#SyjoZnE9&jhE%b=+biaPkU1iF?y7ka>z zTW%|b7+TfOud0v$bz>B%6!pF ze*wK%86h_oLHCO10lBf@@0QS?x

|(MnEszY=b|MBcTI8VT3K&xz)c7t7u%wsBqY zwm^%V!$-Wu9H=BOw!oil&x;;tC$hz5!G*um2d+Lpi#t}{EhKJsJePreSm ztiejSDsc~2>Ii3`aGnHy&jAGO5u71auw#zyQGf+xW zs`gr^CnUR)LYtOWt9Bwa6Smi9^IeRmrG#0^S#Jy8lT~u|S4*thBdOy+HL?m3c_|X* zDTotrNX{EHjYX*kc^+GbSyk2{uPI@c#>m{i4sr5xK;Iuqv=6&1#mym`W-U9mU5yC1 zcgJX2_mD`*Dj>YZcL05)H#kNQ?(T6Xh!GaK#@#|jtSNMzRr1nw{b^(Mu}&CpPvsCN z1Bfg4<38Y2#bftpz#3q7o}@T}HcM=+JMuGGei~CIyPp!P=s4YVl-+`Szj71MP61(i z2>Uglo}E9-VTDZjVtl#_T~D(c_)g*6%8!v`PyFxn6va=_lN?*_vJa3QPhpN&BJ}McYp$bxlGxQ_65|!$ zU;KmzGr|^p7^$wy2dkRjJojscSvUuB75LCQ=UJHQRm?@Tjc?#>XuI?i^y^~T^ewTr zr8;&uvuRsT_TA4u7GaHFS2<=S<+)SI=&o0cd0NegTa+f7o>Xha?`aoJO3lw4@!W!(JK@Qt7aqTT_zs>H8AYjg4*4tk8ab`db5~` zXJUzAI0-w8SjRdEJ3HhOPpL8L=c;^?oh(skZL@D${nx%$v?Y-`eOT;uT0?IbKNFcX zKR2PC%f@gPSs8ca4-w5XTKXBkSSzQeXQi#>z5%aATT(vEI{Gk5n|Y#~AWS`<(wl0N zKGiFuJw}9QfHi}NlTi%4O4t1z_dGktQ*+@&?W{lR@)`Ka*`(?@Mn5u@M1(F zpP0X;XWTmrb!&3x3BGmwiR1Te#J2B2C2e2N$koSa^k*q&%aE#)7zf(cPy@P&29zkX zbY>ig%t*fswMtJAl_^{|MvMcIRh=KeRn~_^Cj{PR_VfefIWx>Vm8GLVm@p*2kh!`zd90bfq?9`xBk3>{qlGA(D1W13K^_^e@Yh)B?V&OR*AF zhO09-gRi}PK}=Wa~cci>=mr(nO=n@>E-CB3JF(OupK? znHRZE8@Xwo+Y+&#mgG{F!{qI&3~xMnU)8EHTDGj4)1It|@G|yh%TKvdlB4#SB!6$0 zJzX!)Q%QuJN%^c-dQa)gyXwh5?pW|`Nygx;=^w%yKf~Wc#9%X(w};y3$qbKG0Exy@ zd4@PL^rOD9h9S`~^DK_ePcWwQDE5+Zonj2%HVoB;cuhz-Vd-GAxq0qJPLEY*FL6+I zLvBayX1p2=t2%Y3D9LS&USocwF?ifEZUv-`$RMuZNaojUCCxo+{??z3yJ}V2XN82$ zH&=KDnpySt(DymKp)-%~Lwq0MJ6D@^#Fh}or`%C^JFq5dGAlVBeb&RQRN(7d(K$}` zOw8?Ko+|{srdY{aEToH>R?6*7JPBBQK$f)uyXTJ1XLM6ocWB%9z&mEB ztOl^MvJV{UGS<|Bl@^Q6Hn>==^pt!U^*H#VO~~_u$-%alkX79oXZHEp+3Tx0=$y4Ry8K4^FQus_*{&OI>e(p*2&chLpcJD!3&(6k+lp7FJ7YmZ|#tB!=- zcyi39G9M#Ur;!3jE9|&Jka;1Px{e;Mh}We%T$!Y*DZ7%YH7Pw7-*f4wv|Uzb0{oKJTt=34dQ;Mz z%fM6J;rx29cXAEdRLvE*9~Ym=8rN4+YcK2fbk(~JdRz8+!Q+gtxi)pVwyUp8GnYwt z7u5;T5vAmR&8sxy^5uL=RW_5bUzJa6vvLx?gB48opuR^WP6_h=GRZzzx@Y^HZ)Fc% z+qvq?>AcpZ_vtxr9y>9^;QnwAs|){M4d19?{$=f^alBf4I*&f(`|4pno@dfM+?JWU z>NtBgZQb=zKnz`5^jaRTz0%r+a`-#XbM2E~MV`%`9(igRLo;iU|FID0PvKeAq}=Nc zYd-w%T^uXtZqqkZ6t6PlhP2VKY7QL3~(_Se?;)_E@a}f+}>F06| zl1ecUh@&N)+KKL1TjR=nxEeXD_qsa%rSzxpEH2d9$vdw{l!4}{*65qyVKsxk2sc&F zCuJ{HtZu?)s#pkbEZNmb-r7~M#@~eOwMr778@mnCxA3|N`CE82)d0p&JeSgRm-;5; zZ=K<~4f40}x<2`<-tV`Cd(`-ve=^B)ds(Pxl-O^))Jx+=3;E%vNwL>Xs`Q`qm~n#C_q<{tSyDpo(^|1-Rf7>Dn(ad)`xzhqM9Hedz$ zdv|=k7UdH5JACYw*OkKiblf|Ve6%`ST79zSsrE?mVS9kZeHi=Qy}G%ZjvZY`C4|w{ HXUgiom*a%< literal 0 HcmV?d00001 diff --git a/src/Modules/PSGet/PSGet.Format.ps1xml b/src/Modules/PSGet/PSGet.Format.ps1xml new file mode 100644 index 000000000..54ff00a1f --- /dev/null +++ b/src/Modules/PSGet/PSGet.Format.ps1xml @@ -0,0 +1,202 @@ + + + + + PSRepositoryItemInfo + + Microsoft.PowerShell.Commands.PSRepositoryItemInfo + + + + + 10 + + + 35 + + + 10 + + + 20 + + + + + + + + Version + + + Name + + + Type + + + Repository + + + Description + + + + + + + + PSRepository + + Microsoft.PowerShell.Commands.PSRepository + + + + + 25 + + + 25 + + + 20 + + + + + + + + Name + + + PackageManagementProvider + + + InstallationPolicy + + + SourceLocation + + + + + + + + PSScriptInfo + + Microsoft.PowerShell.Commands.PSScriptInfo + + + + + 10 + + + 25 + + + 20 + + + + + + + + Version + + + Name + + + Author + + + Description + + + + + + + + PSGetDscResourceInfo + + Microsoft.PowerShell.Commands.PSGetCommandInfo + Microsoft.PowerShell.Commands.PSGetDscResourceInfo + + + + + 35 + + + 10 + + + 35 + + + + + + + + Name + + + Version + + + ModuleName + + + Repository + + + + + + + + PSGetRoleCapabilityInfo + + Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo + + + + + 35 + + + 10 + + + 35 + + + + + + + + Name + + + Version + + + ModuleName + + + Repository + + + + + + + + diff --git a/src/Modules/PSGet/PSGet.Resource.psd1 b/src/Modules/PSGet/PSGet.Resource.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..5177bec6b84b495f13b5c0b5aa366aba6e0eaa08 GIT binary patch literal 69704 zcmeI5-E$OKa`yY$5x(+`-@6X4BbbdaV|&+ovo?Osz`!azd>Cn%@YMz*1dA6mvLqH` zhyQik`Kw1sW}Z4#UELA`%n}43byuB_{Cx7`RQ>P&{A~59{rS_?pV*r9?|OA>^~369 z^>%f-da-)G`rYb$wO)O(I$ZtS{=a9R9ojcPtj_H3v*A0gKeapf_lbS-!hSkleQ8(U zT)nhE>on5Y@Y|8yePo~h!Tx<}SJwHzvHK5gq?b0*e-2lyR}WYFtGo8|xn2Fp{%7{r zHo~F({H4u(X5;*A8Rt{v0d#*mj%jeBOJK-rhZ$sdenukEL!)f?k7oZB;w-W#ZUX1_nTpKh!k z+rOuFpSZfV`Tol&{onTg+D3S0|Gr8i>HEJKzTdot{Xv#q82`>MxrVbe(xx?hYx6xF z_Iq>*D*Sf!Tch+h#*4?RuT3WRjd~AO_wCc)E}+d{8QosLTgMCI%yawX+$g!e;C+wc zJ&NYt>`u>RyP2Z$)$Qh?QRVwV^Uq8sFC(Lp!D$(l4EHEn*RVTH|7%s(Fs9!08txBT zndiP^8i=l<#m`Jm=5+R!Y3$J;;UQVSvrn>SU{e_d?cO(9AKB>G>OAM#X40%ZI!#I5 zHY<%W-sej18!cYh4%sJu76n=eiDb z?!>Nx&v;XfcRFyM)vj$6{$*5FhWB7}?7DUEubS_%7pKEDPgegic@6hNQRx)ElKqJTuk2^hyieb{_D93Dc-osb z=F<(UZ@I8PlE4F7KchJ}Zmf2tHAoGlHBHNqts|q9&-i1~7i$$dh;*Y-F9$j2CwL-^ zqSZ;h#&X48#nZQTJ-BiiFX!naO_Gg$Y8s-IVPja${xIY7L4&iOb6XX5W`35wp1d$! zfAKA1n3v*bzrljz4z?jDg6)5^k^|RU-b&2=kqeZsK^R}p8Z*- z*QZ&8E&4Rsv+?_p0JsBBhQ&t@z!CT;*?W)zUJIQYTlPEl&FSD*kIkArH9Lq@`JFe? zXY3q*1l474Bi5AMGB0sswLj1Vgv_|H{wlGd%S0+dV8o(Cm0)b_f{!Ds;JSV?NF7oT zk|-O;zlX!lUk}u9E+M1H3vYj z)y7U~LB*qEtA1vd4LiIX&A68jKl#Y+pT?1!FuA^;^LMh7T4CJ}dN9Tsd`fJAk6D6| zWFc$Br&y}RPJxy_W=sT^vD4rm#lbf%kEMu-*b#cZwcH{fgI z#gN?uQydJQ@Tsj1UxlCQXYYP_kuP<>k7tZs^zZq*;T~jP9(LXA{d&ocah;D2r4;dt zd)FFamo(I$dBA-yXaC6WsGDS~@j48SL zo5o*oU)+Pg6SA>CQd1app>14mcO0eL&SxclVFd`M~ z%)!8*uS{#aUR`}kts;Cstff**2u^!^ZSjCte?duH&j@bwkr?-i8ONTOuTtjg)M$Y9 zpbB?tG|}jJeSJ&O?sQyz%R1;)w4lIPhaBa892CgwTS9@GMsvvy8Akd_;4oD>`c6PA z=XM3MA2i5RexFj{GCj3M`I5Rys-==KzuT*)J-q9(6|&!_S=I){YRFMU4@e)ig@X%Z zL*|-#AsPVX^8J-!U?q^ZuVj;Ea9xe(DmQ#Qs6b{8?P3*y?dtWtXmEYuTd1jm6QQIc zFQ;i8Ls*U)2Rh)H!a6JKp`NPDZZDQq7WFUf3T)A@hd!E2H;9U$&Z0ayE$xTup>qgctQ?*bPpB%l%JCf{{%5R5g>Qk#%5SRVyp!rT` z<<@>G)q;?N~yUKF@rt18sEz8+{AQ7LXc-&$2A!}aQt4;YTDz2 zTj2`EYHhPTE|^<0ZO(4WjtHG^w&S~d>Sep1)?fFrj;eOseIB2D$W`qAwpr&l#tYCA zIbu;hON4hD-?i__v4EJU1N85#b@yt;=JP2Y`#-bs$yNqJ1ntvFj$C*hLL<*%i~jmD z4Y%D{wqqZ1XXt459KEbB*W_+uVKmttkVZy({7ipCMbVKD?&}RRWNLo+6@d>GV`TZw z>mnOY?D0Bb$Z>==MTb6CULw_f3dVY;=(udXb8@*pLNC%f7_RgBNuC$3;@^}}VKl#rNS&HWpXREi z&y==@cYC}djs|LIJhR<+5hWlh{|WmOw@ zSy@y`@OQ-4bK zn6u);{Rw$TQl?ks_J!H&c;KgPG$_xpZ&-*7`&09P{V|rUiY{@Dv+ZiKoNh;}d}rn0 z)zK=?v5Z#vj{d54rxhnQ$mjolut?9-0kO{Ge`FzYp%=H;93-5Om5uF-yxC8fp(Q-kD{9Ma8+8Bg@p| zVQyj;x{J}#@Up6neR}koqRnQRB3d{%^bLN@{VC*vptG<`$kJw?AD%pLxg$Edw&TR0 zYH@8%k87(Jl@CQWa*ZK6WZXU?HMN#OzMIO#EBhwuk-Z#l51Szyfvd9&d5wXdvU&n> z8%iPD+Eu?l&-b-G^qc)y~@(A#Ana6$GQnuE|b%?FTN+YH%;EZH`#h_+JHu!6&!ZoI7}V9 zMmdgDL(9lU#GW#(qZ_xi8blYu!pd6^`w%(k?4$Y_nc-}xnvkWhy^r%U)a!@za~F)N zz6RIL{?&?(vK8~nC3jaY>)L9w`uZ?WabFP>Zz)n`1THM4uJ1VS#ZR`@eYh@Hv@t%9 z=OcQ|8vMfU>KuuvT*udUitsA6u<(6~RjYX~*=P4W5pm{k^B%&#j5P{*or|TWZTmsT zrcbY+m)#!IV5)P46F15Lx<$hNA`{3#D~~#>O6;#}04P^=*)Q!{KVidpm^V#75Pb%m z`iVQQo8Q9H<5U0P-Op|t{?R@aSHY?}oxXHUVH?&&NNceQq--S0o!eDuFon^$G&a-39@%_+KARqsq(OA|Qv*j7hGu&j$>ECsCv zz=|kG5|M_V*>d0Hy)y8kuc2AywL-_t`DFfAw)Xz1%vzVIBh2w3SfP{i-L0eLgf~5KluOA4S%OJ2Evh>QF6&J}Fg8#vD;B8>^Y#CA$flO?#=OwEo&8 z2t*Zge`&w-*~dxO>2>0LY9v@O9WgVz$|v;$Cm{2!HHyx%hZbiZtbSwHz;9#^89W}) zDAJ{VH7uc@lJE{T&ZqaS)KU(8HRvMPN;3Eh<5usKt8}Ne-0Z7IGqajW0uKkuh-og&r%DW{VH;;PTOO%i$|+}8U9s;e^4KFEu{~!&70N#-%2-Hd%a9I{#dR0XAM$4;p#OgG(Wu3c9zJ`6Ne?@gc^Nf`Xpz} zJ|w!zHYfI~I7^W`_3ql0CY&FgVLX5I-0Z`zSAT7Pj?HJ$Kh1MM+3WM>Ga+Q6fvdAq zoYw;%^>?!jukB*56ag%=QdfaIWupz&wfwkAr4KyGcN9BNUj2J*FEJO z^{}b3fA3?>o9)WC<(FesK<{#ZWx(fy`bS`58; zzA^XEzxt;qQ#l)YfABGP>|gor`D|uAw-=R){*D=&?De@t3cnjVVtfw1p(5bl^{XGs zt_L#jWn;+Cp=Zp%`5$s3%I%SP39SFhW{j%2*8<6fLq|oS;mnc!OqV?QRdwZnk+SsMFs{bkaEg7SHOKZ>&)M@VDF36K z?RZi7*|pOtuYn!ZdR%{vE!wE^5i;Q&Idk>5Iv+He?%13923^h-B%#r%RXL?SdseTj zBdskv?Wa_|a^lEEk#)^qt4{`t2tUYBqp4UsPED)A=bFhlQ8$41XQqd`mo7G}HCYT_ zXVq3om8!^8(R;QE{}&w~-`V`%TaOc3KHr_9YqEBSbWuaD&jt=GcWqcRb^#x+^~d~c zd+snRSYNCGdt0eDmHo#mK}R~R)o<%GsUx=8TJ8WNOws3&eNPS}pIfQVmEel!MlUiT z=p>RAwBz^oe(9;|GI2^^3;*ozR`f1 z3;ly_)je|;j$tFls}RQ(aVY}dZbi}qVgYrCsCJ}^Lrb;L2;xRj$MHmeR_c3xg-g!2 zCK>I>)WY|N8gh@T@f?l5wms@d1Jt52+M5ko8Y74UvjK3vzmu@7;q{Mg4)lXNuw_&k zdM7iuZfe|KM^Z=+G{dJwAJABL{ds4qo6J$trEW^wK_30xN3E%@#&NCtT50`qE`glu zbJEAMQ8mAZruu8n96L<&cqRo@$DOTCFJJvwhWKQPhLx*Gn&X{n8^#jRUlAHpEBxd2 zApKFv6V9PyMNga9L^otjow@6aiuRmzX>@!gdy_xr|8X^QJa1H`4~!@DgT-_A`8oQP zGymVdvn@z&_IKkM7}M#^zS^_*SSr?iZLmUFCg%41XX~)i_~c{<1lpPza3w z;7vPo$@r@U3~QeLH)eBRnw7j~|8q9Q-xcdNjyE;L{b0^^glgwxx3CNKoPg7mXW@cRTdVE) zzdidlIt$yY;$3GwA67dkb;?Kk@ti;FZ%;PlsMA-mBua~p(Q$OEx`6jq(%GV@LvK=Z zT6oOB3cL?&GrfP^t?IP3?whvL7sEN9@6D$@AMqDD_uu5CTrJosGhRtDvv};RR7S8h3w7q6CbZlIjf*=sM_JKW zXD_F;d9Ep~b8K7rInK)Vsl0CzUfMTN~P)>`k< z)wJI8rmcbJJKr_An5Sra=a}orvhw7cso!!sk2Y6>M;dw*MN-DJj~!i~sFj^`Jcrj4 z9OsVtf-cY7Ddk&V+Etz>_x%1CbB}X)V+8B@{+>6LZS<_q_OyRsmF|BVq?YGy*3m*b zPezvahjd>=jV{fb*U_`)*@i5^#dwU!o$=d=QT*H_I`;I~c>K~n<+NM9zIs4u{FvLZ zxBmD&{IOIY88JLj_!E$!o~_2;K;Ty76w zJLT=sWqg0sVBBtAh63X~j%k7xe2i#niM8LnKe}&;8O6tn>9H9Z(dSxg=C{`+m+-o! zZJ*icn8W;32M12OKvU|I%1(X=)9@?2*-mV$7Y6j`L`A~ZM&xFb8B}N8)f&{2@M+e8|`Nk*&y2)2Y z=Lh*)kG|B=<9?-5FYr=NqAHqyX_R40Zx1B4RbzhTMhPKEbhfjh;Fi&w0cTI%ZfKD$n%iyOt_( zji~$gb`239y-&nfWVZ0$K9aIvepQc#ajiecq=$kXIb{3DOz5HPBd6zN9~C!AI(6dV zv3(QIf|=)9wyl{ORnxYgHEWv32G0E|=c1s_g}X)A^gJ2GveVQcP8MClE@GY4UrrZ5 z`<#gy9Z!#pXN#Pf+v^%3X--9T`D!E#OY6DP_s#j7<==!kh~(&crz-kc4qOheP7X4C zm&gI$gjL8Agjc#TbnJO2E=UO3!v^`9PcH7PT*Tty^F1r1^8(}Upy(IxTjG03`muys zU$uwCH}u+68<{mBuT43vjKX_*k!5+ic{Anfy#0B2!ZLMo>{8w>{w6=a{LpGaH-^sj zOjmN|`6{$&YUk0Pel|SU*=NOG9w(00``Z}~?P_6tur59c`4XS;0?g0zE$Lv5IP>>5 z16F-)pX+}i&(@M5C(Afg`_?$qsJahvw4RKcGw(}idocJoo$zSKVprr*RMC1m?75}P zJndzl-6z$3%O`=ovn?mr#pyDgQ{q{0URiOiavf~_SLGl+KzIU9QUAarp4v~EO*kLQ z!@Xs@l236@JKoJQ9$ubn=;q$ABTyH7hn9gsurKe6m&^whd5R*rlQ9+4NwA5h*%tM? zBC<95EcfAiTDc$F-j7r6FT>A#?`@O5Z2jdUemZvSs`)t{Z?hfid+k84n{C)8j=fJC zHr{cq`~G+~42MTg-LrLj=g8RVIU)tysO}(d9D64xe%of$vySO?J+z;_ zr=>>YmDAcyJfFEAr+8--6sO;3^J+QA&(;3^z!tZ+ln>nf%tlvNQ_j1Hlk#_)W!J4h zJRfRWI$UmhmT=E@5OrPce$1b@g(6c=0&(7tcaCOOu0#eoXO7w|OV(1Sn$I#G?<)40 zZT)WhoVM6eL)&JbRZyxi63uA z(_D-l)oYgTh<9m_6FDAgJTHcd6mcqDBGYedZ#i(IIhpL4gfXu|Vk-}_&5T`T8`);< zV&z~AJS!3%CRR8jvexA+XZX-}(8y*W*eET~NpkC{7up zurunPr8-Q`18h~f^o5~rI03)l+BAQEZrP@uzmGepS1yy~d5zvhuB#?~mg~?T^k|;5 zRVIYPb4FhgL;I`+@_Fr(5r`d$v#>Y1UQZm6<;oqu-woD}?Ejl#b-h^b!^-tiKdSlz z>z4-d#2Y5x>|W+_tNzH zkk3H_LE@Z&eQW>v@8e#9+P{D$-Z!1&R8@OzMq<4+XkTcmaz>R#u|r?$&tJb8rubSm%R>mgIcjz)Vn~adL~1ixo=B0OCeVO!Mpw3v)MdDMV*?b z9q|N8(K>${)v3C_jAP!Pj4rpaSm!n(@cuyAeAX}ApZS`11y|XZ=PEr;XmbQ`sr6oY z9HhP{PwsW{wam%qiYW3-^K)po$`hem(-M|v)BZez+QZD-N>cV7V@b;2h9sStjQ9I# zmP%3`A#B04wR``Pl-G0_Ny_7FlB9g?HjF%b@+3r}m*nH0PRL{ZP+Fht;INh%Q*3k55HM zI#}oHpMQa?s$IOb`(N8{ahI%tJYH}A*tvX8MimKoU-usP5p=A#U4y2Hw{`By@%2<3 zwC!_$h|pzUeOJ-B;h%sg<<*pFsq_v+pKTU<3rZt(svGp*1G8Kf_LCL5oLpqRsH^=f z7s&e6$;C9Km&=9n<$9)S=pFcHlN2Z?z%yfhFgcD|*py!nsr@VmyU9UI@vF5E(~_`_ zZD`lndW~tB{VWw%Efv$W-eez$QvGR*%DCJaJ|WvEbmCDyGDsdVx{G^$I%iVYB^fnv zx^ic8Pt()rT+Q`(>zBj-<8xHwdFM`~k5A|7$sdoc=l=G9v=|SZ?3k>VS7QfS6FE2` zieK3JJeNxhM&#Zq3{Rv`qt2%-tkPP;hs_1(N=w@U2k2YE9c)t zKTe1ESpHe>zTSR*dC}F21dwM0jj#{(X(;BR)57bOV6yt$an5m(BT=M?T#;|#>Gk?l zoaNhVMmfFfs(pIyiOt%c_j_JwA5YKiX9eat&I;+;1&?8~IE#<0FQw8H*Zbps=KPP# zd6%7h7Aotl;{4X8Eakr9lbWg0Gswt8jJvyf+y{GMKk_rO{T$NNyTp64Db3H;V$URd zsY|EAg^51 zY#^U{7IM2ih=VbUccZtxXuT6NQ`V-HxoRU&}E8bqgJ?<^Y8bDJ=_w7tq!-+mE4+gE^={cN0(G$dxo;{P3Lz9%( zW~s5({C>}_rRKo7Z+1tg9{v@{Mz`3J=QoaRG|siuEIlK&e8=a7_ig(Mg?^Z2z52qu z<%x~>)Z%g~@nD_md!=8?N0dz0>%ni{w}aFQUwH>%)Bv1YoD9c%LJ@cfC2HnGXZYJX zv7?c^hl)j7dV@`Z(tY&d6sVla-GEvlYwBgVklesbvTf|`a`G`XDzbpo{IN>QG+lD$ z?JDJGdd6MlX==p2e0^ga$NrH$B{M>H{&KR_8}X+lSDS23p91eog8H-VDm}f?`jWGE z5kp*s%+#@dTGFz;&uXdhz9greXIGi2l#_CMHPQJ+xGG|u##7Uy#PPGM#G&+81}UV1FR z+N!7ud7jvOPcGJihb32pEeI5^Ge?`o*If~f)KyR8^D#QV8pOMq#t}#Lqk(BGoH+%( z$8#zE025Dl*G1%1rQ=rV2)t^^sQrdlD;0I@k4+-x>3Vh2Q0KXfB-}QAJ$!ezlPs-r z09P#&Q}bM{blf(?e#@-OsaYBNRAWC^Cn>pWft+?PU(@#aF*|mV-ZIW$MDMQZU%#@L z_iqNfxLfQ!MctN*S0{l}Gj5i}oK?7&GAwOQfl4%)j9d1u1N#-jy4G;WLsLSXH| z&*NdFHe3GX(5t8nSTASPdeJGV6@B;3Uc?)4@VXCd4LtKrHK?AZYuD5@$XZ7xed)~p zw0C96&j;F7Do^Jr=kX8rhBYm-P+Se)#WT;9#@R0amhoh*;5ium z)OTvESAV{q;!A74{@;4JWK79Je!5JyKdS$d{~@moI#ngvWdjcJ8B&XEfT-AiK0Wuq z_C_Z$xR-14_&i}P+Z}NkefF!}M&26BWZV3cigc?A7>r`=GTVNs({YXL#~VVf+hLcRj>1yHIItSMVF6i|iGh4Rbrx{PUFRTl|9y z*~nCFZ9Q+dz)$UJ<9q%rR-glUFJIXh zWKZ$aekzoD>bB$O&Jo8>$2KPX8B22bt1Lg!5zX%9Bd}SU{M0V1%?Lr(!B_1WQsUjP zkX6!srG1&nD4~^=TSgOl7qD07#tAIX*##fz*vV1nod5MzQtzN z?d>V|*w*TAKsXq1G2Uu>X~`ak?j6UA%0gsmk_0%8atwp7!UMW(kq(8tLzgG!>2wvm z%(;t@ud#Ph570Ban+hiKo7d{|A;GeDCw67)AN38h%smOBhfdTNkmX>{_URsN6WZCo z&=p5Fc(8q=!AqkPo!(ixE?0x^VI1U7{Q%OP-u@hm1X`5*D!#&ZM8#0Gs=a{+qNrPx z-t2R8{&I-c+!y}c@LOMZ_f1axlt)F1Idex<`>tK5XO^>ebO9-@eP(q8coCy#8P7FU zkXbzIw^odMn!?iyIU@^&h*SOjP^#Xxqs3F)j|{VrIpB`4bG18W92JL5JHA9i7>oJ! zd_!@#gR!ZlC;?WRN90uczXsM(j)6p4}Z5Iqw@RUEk=@N>IdO(9=5&mPv^$E!TR_ zh)^hvEcV zk9%F6=sdMT7Y^Z}LpgtFFvE!Mqw zU5^ueWylgXjp~-?K7}@>dTG8jnetw4xctaQAYaPc7mkWlj-z7w1$(|&SOesk@t36C zM-FPrzIcapj=J5RdtXyU7GrKXrIhP%nlSIYpV%A;5bF^2dqx1?ExkPJRjta$XFZ!& zBgCTkL)`4eO+Dn2V~tET_YKZ-VT?ROwq_p7A_0LduyJ48C!l8}Te_|M;gs(e{qW_I zrfaKzSpCd+=2-fg{q~Rcd!H)xNy>Eg?W$%;yzep2$u&~fkQUuc)2MpAJ_VNW=aH>7qq?aX zm0R-sxAKK8GR?9pyNK@uMZqt+T9Lp!8{V~|#@#ZL$aS9vao(re80@R-H$US+^9cSF zFwaBYH2pzRlvPybp;F_jWlS?&UY0aY%>%g1PjTDj(XY#t3G~{Rul@2Cg#D!ZeUw66 zogyuOcjFZBFJKFQapqCVjyVs0$S?`@nn!_V?;R4Bv8wRDbp!V+46mw#`w98ch4kZ<7fY+oH4 zy7pxL<-ANFTOtA0-CLL2fS3z<9t^v#b&VRc`|LV{_1t)m)h4n8r6CFY1n(jT;Wz=Q zaFnO4Ypj)ZD&FwyD_0Xea2D%thq%HcVB!=ZFV=i(xD(`vHFG}YXleNlBnS8luqZpx zC#)qX1^Q%7fpHXvt0J!z91r)(9}&YVO6p^w`$jiqTy%o{pKT|4w$LN{DI?)KgO7{r zy+-@AsV?l>eW$kK7beY|oQpg13?4(ltvpNUam|xCK8G5$>M6fm@l)n)&b@7?>y9|k zM=AyIxUQ;~y_227D#&t6wp(r>!_SPv&6&3-%ZpID^je3mP>b}n;MR7MYL9k4G4 zJ#GK`UHv5Md#uze)Kj$2D7dxTxi-^ZQT2_)0XJXNPB>S09QS@hO||cR%pTs) z$Iol{7n44yM6O%e9cg=H79;w1Sp*rwZ||MJmf`ELlyE3AJJ<&zMfAbD0;(=zHSvn# zGCt0;2H~II+6am#v2$2$yf&T{9ipD_)+B)^t0^Nd%}_<%yNp>$omtNt?%OrDS)BaP z6Io(4@_Bwm9n-D4EUIU=C5y2yo_nC)^YF-Z9QoJm7qF(@XOt03_N~f%)&9nMpVlsF z!Dp8U<-dCphegl&%g%1wT7u^7Q{LMA+jwW2_#JxX2*atp{d)V)jk{@5iCilFS5LHK zw*%XqG(dJ%~1C3nf1^3!@WM~e^K=IZK-KRx3kyAhaAQjXR$XV@ZSD|h?1 z`vYUPm<aAKKs3!T&2K4sy9|pYco#=oKiX z?Z{Caj@6s%)WC-^<8||5*gfWCzvEfivFoPWr)PEt(owO2ytK#8?X}aRUxuDYqDPYl zCWS|%4sMse2ewas=6bHgWAb~&C}9Pa>%og24KhrNTmh&)1%Sxe^X9B2A#IU{b7o=fbwl3LdrIRUp)nYv+Z dMB$%VjsIr@ExxhyRkw!zhij{U8vZ9%`#&ASnIZrH literal 0 HcmV?d00001 diff --git a/src/Modules/PSGet/PSGet.psd1 b/src/Modules/PSGet/PSGet.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..9fa416ac9861be505c0c091165e7c53e57178224 GIT binary patch literal 3940 zcmcJS+fEZv6o%KeiSIyqQ#DeoMHCGY0)kD1G?sE-+EOO=WEl>|@Ibz#`u%%%+UY<~ z(~`-Y_x|@f{A=yC{{7vx-}c;|*>~%5gm%oeZr9ebhOOBSXVywq9{ZlNo?Thn^8C}> z_?$E5_4yls(-|V13d*~3_B~tWo_Yu~WduyPX?0>_xj=jAeCG@y; z-^;AqaC0B`Q^EPj&pLEAX`^)r>M3s}XS*5*R~(V_V#g8RLgvQjc$Vbt4y&~Wk{sfd z4nBzN>~X&^#(N;L$*#R%Mv<{sjIBC}*T;C4wbzb&YsfM0kwv}$%sT9eb2c4T8M$QV zRbW-nzwRu(8oUyAKF4YS_PcyU!nG8(^FCfrctt#0-j)@-BF{XPw|yjw%ksYboyGzq z_8cH-jhv}S=wj*9DwS$ITNE zZl45sG8a}OdE`g!eaZsby;Spr-216xwG5IhJq>jcPAtwL>C!|G zDT9FsnB6J;gj#<6=n39og5Qb=RqQjWpsX zS_Y1X<8B-Xr5L6S^YuBG3(RV?D1+_7|D+4e!xZ5 z*a3B=s_q8ek?vLUyE=uaSDTdsGIL1iYxx`2sogQJOrIoO}< o5p(!jec%QWdF$f7gYP%&vneX{T*QVubfw#zZ|Py94%f@@AMc3rW&i*H literal 0 HcmV?d00001 diff --git a/src/Modules/PSGet/PSModule.psm1 b/src/Modules/PSGet/PSModule.psm1 new file mode 100644 index 000000000..6ddcc4db7 --- /dev/null +++ b/src/Modules/PSGet/PSModule.psm1 @@ -0,0 +1,13064 @@ + +######################################################################################### +# +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# PowerShellGet Module +# +######################################################################################### + +Microsoft.PowerShell.Core\Set-StrictMode -Version Latest + +#region script variables + +# Check if this is nano server. [System.Runtime.Loader.AssemblyLoadContext] is only available on NanoServer +$script:isNanoServer = $null -ne ('System.Runtime.Loader.AssemblyLoadContext' -as [Type]) + +try +{ + $script:MyDocumentsFolderPath = [Environment]::GetFolderPath("MyDocuments") +} +catch +{ + $script:MyDocumentsFolderPath = $null +} + +$script:ProgramFilesPSPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell" + +$script:MyDocumentsPSPath = if($script:MyDocumentsFolderPath) + { + Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsFolderPath -ChildPath "WindowsPowerShell" + } + else + { + Microsoft.PowerShell.Management\Join-Path -Path $env:USERPROFILE -ChildPath "Documents\WindowsPowerShell" + } + +$script:ProgramFilesModulesPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesPSPath -ChildPath "Modules" +$script:MyDocumentsModulesPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsPSPath -ChildPath "Modules" + +$script:ProgramFilesScriptsPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesPSPath -ChildPath "Scripts" + +$script:MyDocumentsScriptsPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsPSPath -ChildPath "Scripts" + +$script:TempPath = ([System.IO.DirectoryInfo]$env:TEMP).FullName +$script:PSGetItemInfoFileName = "PSGetModuleInfo.xml" +$script:PSGetProgramDataPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramData -ChildPath 'Microsoft\Windows\PowerShell\PowerShellGet\' +$script:PSGetAppLocalPath = Microsoft.PowerShell.Management\Join-Path -Path $env:LOCALAPPDATA -ChildPath 'Microsoft\Windows\PowerShell\PowerShellGet\' +$script:PSGetModuleSourcesFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath "PSRepositories.xml" +$script:PSGetModuleSources = $null +$script:PSGetInstalledModules = $null +$script:PSGetSettingsFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath "PowerShellGetSettings.xml" +$script:PSGetSettings = $null + +$script:MyDocumentsInstalledScriptInfosPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsScriptsPath -ChildPath 'InstalledScriptInfos' +$script:ProgramFilesInstalledScriptInfosPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesScriptsPath -ChildPath 'InstalledScriptInfos' + +$script:InstalledScriptInfoFileName = 'InstalledScriptInfo.xml' +$script:PSGetInstalledScripts = $null + +# Public PSGallery module source name and location +$Script:PSGalleryModuleSource="PSGallery" +$Script:PSGallerySourceUri = 'https://go.microsoft.com/fwlink/?LinkID=397631&clcid=0x409' +$Script:PSGalleryPublishUri = 'https://go.microsoft.com/fwlink/?LinkID=397527&clcid=0x409' +$Script:PSGalleryScriptSourceUri = 'https://go.microsoft.com/fwlink/?LinkID=622995&clcid=0x409' + +# PSGallery V3 Source +$Script:PSGalleryV3SourceUri = 'https://go.microsoft.com/fwlink/?LinkId=528403&clcid=0x409' + +$Script:PSGalleryV2ApiAvailable = $true +$Script:PSGalleryV3ApiAvailable = $false +$Script:PSGalleryApiChecked = $false + +$Script:ResponseUri = "ResponseUri" +$Script:StatusCode = "StatusCode" +$Script:Exception = "Exception" + +$script:PSModuleProviderName = 'PowerShellGet' +$script:PackageManagementProviderParam = "PackageManagementProvider" +$script:PublishLocation = "PublishLocation" +$script:ScriptSourceLocation = 'ScriptSourceLocation' +$script:ScriptPublishLocation = 'ScriptPublishLocation' + +$script:NuGetProviderName = "NuGet" +$script:NuGetProviderVersion = [Version]'2.8.5.201' + +$script:SupportsPSModulesFeatureName="supports-powershell-modules" +$script:FastPackRefHastable = @{} +$script:NuGetBinaryProgramDataPath="$env:ProgramFiles\PackageManagement\ProviderAssemblies" +$script:NuGetBinaryLocalAppDataPath="$env:LOCALAPPDATA\PackageManagement\ProviderAssemblies" +# go fwlink for 'https://nuget.org/nuget.exe' +$script:NuGetClientSourceURL = 'http://go.microsoft.com/fwlink/?LinkID=690216&clcid=0x409' +$script:NuGetExeName = 'NuGet.exe' +$script:NuGetExePath = $null +$script:NuGetProvider = $null +# PowerShellGetFormatVersion will be incremented when we change the .nupkg format structure. +# PowerShellGetFormatVersion is in the form of Major.Minor. +# Minor is incremented for the backward compatible format change. +# Major is incremented for the breaking change. +$script:CurrentPSGetFormatVersion = "1.0" +$script:PSGetFormatVersion = "PowerShellGetFormatVersion" +$script:SupportedPSGetFormatVersionMajors = @("1") +$script:ModuleReferences = 'Module References' +$script:AllVersions = "AllVersions" +$script:Filter = "Filter" +$script:IncludeValidSet = @('DscResource','Cmdlet','Function','Workflow','RoleCapability') +$script:DscResource = "PSDscResource" +$script:Command = "PSCommand" +$script:Cmdlet = "PSCmdlet" +$script:Function = "PSFunction" +$script:Workflow = "PSWorkflow" +$script:RoleCapability = 'PSRoleCapability' +$script:Includes = "PSIncludes" +$script:Tag = "Tag" +$script:NotSpecified= '_NotSpecified_' +$script:PSGetModuleName = 'PowerShellGet' +$script:FindByCanonicalId = 'FindByCanonicalId' +$script:InstalledLocation = 'InstalledLocation' +$script:PSArtifactType = 'Type' +$script:PSArtifactTypeModule = 'Module' +$script:PSArtifactTypeScript = 'Script' +$script:All = 'All' + +$script:Name = 'Name' +$script:Version = 'Version' +$script:Guid = 'Guid' +$script:Path = 'Path' +$script:ScriptBase = 'ScriptBase' +$script:Description = 'Description' +$script:Author = 'Author' +$script:CompanyName = 'CompanyName' +$script:Copyright = 'Copyright' +$script:Tags = 'Tags' +$script:LicenseUri = 'LicenseUri' +$script:ProjectUri = 'ProjectUri' +$script:IconUri = 'IconUri' +$script:RequiredModules = 'RequiredModules' +$script:ExternalModuleDependencies = 'ExternalModuleDependencies' +$script:ReleaseNotes = 'ReleaseNotes' +$script:RequiredScripts = 'RequiredScripts' +$script:ExternalScriptDependencies = 'ExternalScriptDependencies' +$script:DefinedCommands = 'DefinedCommands' +$script:DefinedFunctions = 'DefinedFunctions' +$script:DefinedWorkflows = 'DefinedWorkflows' +$script:TextInfo = (Get-Culture).TextInfo + +$script:PSScriptInfoProperties = @($script:Name + $script:Version, + $script:Guid, + $script:Path, + $script:ScriptBase, + $script:Description, + $script:Author, + $script:CompanyName, + $script:Copyright, + $script:Tags, + $script:ReleaseNotes, + $script:RequiredModules, + $script:ExternalModuleDependencies, + $script:RequiredScripts, + $script:ExternalScriptDependencies, + $script:LicenseUri, + $script:ProjectUri, + $script:IconUri, + $script:DefinedCommands, + $script:DefinedFunctions, + $script:DefinedWorkflows + ) + +$script:SystemEnvironmentKey = 'HKLM:\System\CurrentControlSet\Control\Session Manager\Environment' +$script:UserEnvironmentKey = 'HKCU:\Environment' +$script:SystemEnvironmentVariableMaximumLength = 1024 +$script:UserEnvironmentVariableMaximumLength = 255 +$script:EnvironmentVariableTarget = @{ Process = 0; User = 1; Machine = 2 } + +# Wildcard pattern matching configuration. +$script:wildcardOptions = [System.Management.Automation.WildcardOptions]::CultureInvariant -bor ` + [System.Management.Automation.WildcardOptions]::IgnoreCase + +$script:DynamicOptionTypeMap = @{ + 0 = [string]; # String + 1 = [string[]]; # StringArray + 2 = [int]; # Int + 3 = [switch]; # Switch + 4 = [string]; # Folder + 5 = [string]; # File + 6 = [string]; # Path + 7 = [Uri]; # Uri + 8 = [SecureString]; #SecureString + } +#endregion script variables + +#region Module message resolvers +$script:PackageManagementMessageResolverScriptBlock = { + param($i, $Message) + return (PackageManagementMessageResolver -MsgId $i, -Message $Message) + } + +$script:PackageManagementSaveModuleMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = $LocalizedData.InstallModulewhatIfMessage + $QuerySaveUntrustedPackage = $LocalizedData.QuerySaveUntrustedPackage + + switch ($i) + { + 'ActionInstallPackage' { return "Save-Module" } + 'QueryInstallUntrustedPackage' {return $QuerySaveUntrustedPackage} + 'TargetPackage' { return $PackageTarget } + Default { + $Message = $Message -creplace "Install", "Download" + $Message = $Message -creplace "install", "download" + return (PackageManagementMessageResolver -MsgId $i, -Message $Message) + } + } + } + +$script:PackageManagementInstallModuleMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = $LocalizedData.InstallModulewhatIfMessage + + switch ($i) + { + 'ActionInstallPackage' { return "Install-Module" } + 'TargetPackage' { return $PackageTarget } + Default { + return (PackageManagementMessageResolver -MsgId $i, -Message $Message) + } + } + } + +$script:PackageManagementUnInstallModuleMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = $LocalizedData.InstallModulewhatIfMessage + switch ($i) + { + 'ActionUninstallPackage' { return "Uninstall-Module" } + 'TargetPackageVersion' { return $PackageTarget } + Default { + return (PackageManagementMessageResolver -MsgId $i, -Message $Message) + } + } + } + +$script:PackageManagementUpdateModuleMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = ($LocalizedData.UpdateModulewhatIfMessage -replace "__OLDVERSION__",$($psgetItemInfo.Version)) + switch ($i) + { + 'ActionInstallPackage' { return "Update-Module" } + 'TargetPackage' { return $PackageTarget } + Default { + return (PackageManagementMessageResolver -MsgId $i, -Message $Message) + } + } + } + +function PackageManagementMessageResolver($MsgID, $Message) { + $NoMatchFound = $LocalizedData.NoMatchFound + $SourceNotFound = $LocalizedData.SourceNotFound + $ModuleIsNotTrusted = $LocalizedData.ModuleIsNotTrusted + $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted + $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedPackage + + switch ($MsgID) + { + 'NoMatchFound' { return $NoMatchFound } + 'SourceNotFound' { return $SourceNotFound } + 'CaptionPackageNotTrusted' { return $ModuleIsNotTrusted } + 'CaptionSourceNotTrusted' { return $RepositoryIsNotTrusted } + 'QueryInstallUntrustedPackage' {return $QueryInstallUntrustedPackage} + Default { + if($Message) + { + $tempMessage = $Message -creplace "PackageSource", "PSRepository" + $tempMessage = $Message -creplace "packagesource", "psrepository" + $tempMessage = $Message -creplace "Package", "Module" + $tempMessage = $tempMessage -creplace "package", "module" + $tempMessage = $tempMessage -creplace "Sources", "Repositories" + $tempMessage = $tempMessage -creplace "sources", "repositories" + $tempMessage = $tempMessage -creplace "Source", "Repository" + $tempMessage = $tempMessage -creplace "source", "repository" + + return $tempMessage + } + } + } +} + +#endregion Module message resolvers + +#region Script message resolvers +$script:PackageManagementMessageResolverScriptBlockForScriptCmdlets = { + param($i, $Message) + return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) + } + +$script:PackageManagementSaveScriptMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage + $QuerySaveUntrustedPackage = $LocalizedData.QuerySaveUntrustedScriptPackage + + switch ($i) + { + 'ActionInstallPackage' { return "Save-Script" } + 'QueryInstallUntrustedPackage' {return $QuerySaveUntrustedPackage} + 'TargetPackage' { return $PackageTarget } + Default { + $Message = $Message -creplace "Install", "Download" + $Message = $Message -creplace "install", "download" + return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) + } + } + } + +$script:PackageManagementInstallScriptMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage + + switch ($i) + { + 'ActionInstallPackage' { return "Install-Script" } + 'TargetPackage' { return $PackageTarget } + Default { + return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) + } + } + } + +$script:PackageManagementUnInstallScriptMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage + switch ($i) + { + 'ActionUninstallPackage' { return "Uninstall-Script" } + 'TargetPackageVersion' { return $PackageTarget } + Default { + return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) + } + } + } + +$script:PackageManagementUpdateScriptMessageResolverScriptBlock = { + param($i, $Message) + $PackageTarget = ($LocalizedData.UpdateScriptwhatIfMessage -replace "__OLDVERSION__",$($psgetItemInfo.Version)) + switch ($i) + { + 'ActionInstallPackage' { return "Update-Script" } + 'TargetPackage' { return $PackageTarget } + Default { + return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) + } + } + } + +function PackageManagementMessageResolverForScripts($MsgID, $Message) { + $NoMatchFound = $LocalizedData.NoMatchFoundForScriptName + $SourceNotFound = $LocalizedData.SourceNotFound + $ScriptIsNotTrusted = $LocalizedData.ScriptIsNotTrusted + $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted + $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedScriptPackage + + switch ($MsgID) + { + 'NoMatchFound' { return $NoMatchFound } + 'SourceNotFound' { return $SourceNotFound } + 'CaptionPackageNotTrusted' { return $ScriptIsNotTrusted } + 'CaptionSourceNotTrusted' { return $RepositoryIsNotTrusted } + 'QueryInstallUntrustedPackage' {return $QueryInstallUntrustedPackage} + Default { + if($Message) + { + $tempMessage = $Message -creplace "PackageSource", "PSRepository" + $tempMessage = $Message -creplace "packagesource", "psrepository" + $tempMessage = $Message -creplace "Package", "Script" + $tempMessage = $tempMessage -creplace "package", "script" + $tempMessage = $tempMessage -creplace "Sources", "Repositories" + $tempMessage = $tempMessage -creplace "sources", "repositories" + $tempMessage = $tempMessage -creplace "Source", "Repository" + $tempMessage = $tempMessage -creplace "source", "repository" + + return $tempMessage + } + } + } +} + +#endregion Script message resolvers + +Microsoft.PowerShell.Utility\Import-LocalizedData LocalizedData -filename PSGet.Resource.psd1 + +#region Add .Net type for Telemetry APIs + +# This code is required to add a .Net type and call the Telemetry APIs +# This is required since PowerShell does not support generation of .Net Anonymous types +# +$requiredAssembly = ( + "system.management.automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" + ) + +$source = @" +using System; +using System.Management.Automation; + +namespace Microsoft.PowerShell.Get +{ + public static class Telemetry + { + public static void TraceMessageArtifactsNotFound(string[] artifactsNotFound, string operationName) + { + Microsoft.PowerShell.Telemetry.Internal.TelemetryAPI.TraceMessage(operationName, new { ArtifactsNotFound = artifactsNotFound }); + } + + public static void TraceMessageNonPSGalleryRegistration(string sourceLocationType, string sourceLocationHash, string installationPolicy, string packageManagementProvider, string publishLocationHash, string scriptSourceLocationHash, string scriptPublishLocationHash, string operationName) + { + Microsoft.PowerShell.Telemetry.Internal.TelemetryAPI.TraceMessage(operationName, new { SourceLocationType = sourceLocationType, SourceLocationHash = sourceLocationHash, InstallationPolicy = installationPolicy, PackageManagementProvider = packageManagementProvider, PublishLocationHash = publishLocationHash, ScriptSourceLocationHash = scriptSourceLocationHash, ScriptPublishLocationHash = scriptPublishLocationHash }); + } + + } +} +"@ + +# Telemetry is turned off by default. +$script:TelemetryEnabled = $false + +try +{ + Add-Type -ReferencedAssemblies $requiredAssembly -TypeDefinition $source -Language CSharp -ErrorAction SilentlyContinue + + # If the telemetry namespace/methods are not found flow goes to the catch block where telemetry is disabled + $telemetryMethods = ([Microsoft.PowerShell.Get.Telemetry] | Get-Member -Static).Name + + if ($telemetryMethods.Contains("TraceMessageArtifactsNotFound") -and $telemetryMethods.Contains("TraceMessageNonPSGalleryRegistration")) + { + # Turn ON Telemetry if the infrastructure is present on the machine + $script:TelemetryEnabled = $true + } +} +catch +{ + # Disable Telemetry if there are any issues finding/loading the Telemetry infrastructure + $script:TelemetryEnabled = $false +} + + +#endregion + +#region *-Module cmdlets +function Publish-Module +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(SupportsShouldProcess=$true, + PositionalBinding=$false, + HelpUri='http://go.microsoft.com/fwlink/?LinkID=398575', + DefaultParameterSetName="ModuleNameParameterSet")] + Param + ( + [Parameter(Mandatory=$true, + ParameterSetName="ModuleNameParameterSet", + ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Name, + + [Parameter(Mandatory=$true, + ParameterSetName="ModulePathParameterSet", + ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [Parameter(ParameterSetName="ModuleNameParameterSet")] + [ValidateNotNullOrEmpty()] + [Version] + $RequiredVersion, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $NuGetApiKey, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Repository = $Script:PSGalleryModuleSource, + + [Parameter()] + [ValidateSet("1.0")] + [Version] + $FormatVersion, + + [Parameter()] + [string[]] + $ReleaseNotes, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Tags, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $LicenseUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $IconUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ProjectUri + ) + + Begin + { + if($script:isNanoServer) { + $message = $LocalizedData.PublishPSArtifactUnsupportedOnNano -f "Module" + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "PublishModuleIsNotSupportedOnNanoServer" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $PSCmdlet ` + -ErrorCategory InvalidOperation + } + + Get-PSGalleryApiAvailability -Repository $Repository + + if($LicenseUri -and -not (Test-WebUri -uri $LicenseUri)) + { + $message = $LocalizedData.InvalidWebUri -f ($LicenseUri, "LicenseUri") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $LicenseUri + } + + if($IconUri -and -not (Test-WebUri -uri $IconUri)) + { + $message = $LocalizedData.InvalidWebUri -f ($IconUri, "IconUri") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $IconUri + } + + if($ProjectUri -and -not (Test-WebUri -uri $ProjectUri)) + { + $message = $LocalizedData.InvalidWebUri -f ($ProjectUri, "ProjectUri") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $ProjectUri + } + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe + } + + Process + { + if($Repository -eq $Script:PSGalleryModuleSource) + { + $moduleSource = Get-PSRepository -Name $Repository -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + if(-not $moduleSource) + { + $message = $LocalizedData.PSGalleryNotFound -f ($Repository) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'PSGalleryNotFound' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Repository + return + } + } + else + { + $ev = $null + $moduleSource = Get-PSRepository -Name $Repository -ErrorVariable ev + if($ev) { return } + } + + $DestinationLocation = $moduleSource.PublishLocation + + if(-not $DestinationLocation -or + (-not (Microsoft.PowerShell.Management\Test-Path $DestinationLocation) -and + -not (Test-WebUri -uri $DestinationLocation))) + + { + $message = $LocalizedData.PSGalleryPublishLocationIsMissing -f ($Repository, $Repository) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PSGalleryPublishLocationIsMissing" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Repository + } + + $message = $LocalizedData.PublishLocation -f ($DestinationLocation) + Write-Verbose -Message $message + + if(-not $NuGetApiKey.Trim()) + { + if(Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation) + { + $NuGetApiKey = "$(Get-Random)" + } + else + { + $message = $LocalizedData.NuGetApiKeyIsRequiredForNuGetBasedGalleryService -f ($Repository, $DestinationLocation) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "NuGetApiKeyIsRequiredForNuGetBasedGalleryService" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + } + + $providerName = Get-ProviderName -PSCustomObject $moduleSource + if($providerName -ne $script:NuGetProviderName) + { + $message = $LocalizedData.PublishModuleSupportsOnlyNuGetBasedPublishLocations -f ($moduleSource.PublishLocation, $Repository, $Repository) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PublishModuleSupportsOnlyNuGetBasedPublishLocations" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Repository + } + + $moduleName = $null + + if($Name) + { + $module = Microsoft.PowerShell.Core\Get-Module -ListAvailable -Name $Name -Verbose:$false | + Microsoft.PowerShell.Core\Where-Object {-not $RequiredVersion -or ($RequiredVersion -eq $_.Version)} + + if(-not $module) + { + if($RequiredVersion) + { + $message = $LocalizedData.ModuleWithRequiredVersionNotAvailableLocally -f ($Name, $RequiredVersion) + } + else + { + $message = $LocalizedData.ModuleNotAvailableLocally -f ($Name) + } + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "ModuleNotAvailableLocallyToPublish" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + + } + elseif($module.GetType().ToString() -ne "System.Management.Automation.PSModuleInfo") + { + $message = $LocalizedData.AmbiguousModuleName -f ($Name) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "AmbiguousModuleNameToPublish" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + } + + $moduleName = $module.Name + $Path = $module.ModuleBase + } + else + { + $resolvedPath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $resolvedPath -or + -not (Microsoft.PowerShell.Management\Test-Path -Path $resolvedPath -PathType Container)) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage ($LocalizedData.PathIsNotADirectory -f ($Path)) ` + -ErrorId "PathIsNotADirectory" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Path + return + } + + $moduleName = Microsoft.PowerShell.Management\Split-Path -Path $resolvedPath -Leaf + $modulePathWithVersion = $false + + # if the Leaf of the $resolvedPath is a version, use its parent folder name as the module name + $ModuleVersion = New-Object System.Version + if([System.Version]::TryParse($moduleName, ([ref]$ModuleVersion))) + { + $moduleName = Microsoft.PowerShell.Management\Split-Path -Path (Microsoft.PowerShell.Management\Split-Path $resolvedPath -Parent) -Leaf + $modulePathWithVersion = $true + } + + $manifestPath = Join-Path -Path $resolvedPath -ChildPath "$moduleName.psd1" + $module = $null + + if(Microsoft.PowerShell.Management\Test-Path -Path $manifestPath -PathType Leaf) + { + $ev = $null + $module = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $manifestPath ` + -ErrorVariable ev ` + -Verbose:$VerbosePreference + if($ev) + { + # Above Test-ModuleManifest cmdlet should write an errors to the Errors stream and Console. + return + } + } + elseif(-not $modulePathWithVersion -and ($PSVersionTable.PSVersion -ge [Version]'5.0')) + { + $module = Microsoft.PowerShell.Core\Get-Module -Name $resolvedPath -ListAvailable -ErrorAction SilentlyContinue -Verbose:$false + } + + if(-not $module) + { + $message = $LocalizedData.InvalidModulePathToPublish -f ($Path) + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'InvalidModulePathToPublish' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Path + } + elseif($module.GetType().ToString() -ne "System.Management.Automation.PSModuleInfo") + { + $message = $LocalizedData.AmbiguousModulePath -f ($Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'AmbiguousModulePathToPublish' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Path + } + + if($module -and (-not $module.Path.EndsWith('.psd1', [System.StringComparison]::OrdinalIgnoreCase))) + { + $message = $LocalizedData.InvalidModuleToPublish -f ($module.Name) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidModuleToPublish" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $module.Name + } + + $moduleName = $module.Name + $Path = $module.ModuleBase + } + + $message = $LocalizedData.PublishModuleLocation -f ($moduleName, $Path) + Write-Verbose -Message $message + + #If users are providing tags using -Tags while running PS 5.0, will show warning messages + if($Tags) + { + $message = $LocalizedData.TagsShouldBeIncludedInManifestFile -f ($moduleName, $Path) + Write-Warning $message + } + + if($ReleaseNotes) + { + $message = $LocalizedData.ReleaseNotesShouldBeIncludedInManifestFile -f ($moduleName, $Path) + Write-Warning $message + } + + if($LicenseUri) + { + $message = $LocalizedData.LicenseUriShouldBeIncludedInManifestFile -f ($moduleName, $Path) + Write-Warning $message + } + + if($IconUri) + { + $message = $LocalizedData.IconUriShouldBeIncludedInManifestFile -f ($moduleName, $Path) + Write-Warning $message + } + + if($ProjectUri) + { + $message = $LocalizedData.ProjectUriShouldBeIncludedInManifestFile -f ($moduleName, $Path) + Write-Warning $message + } + + + # Copy the source module to temp location to publish + $tempModulePath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath ` + -ChildPath "$(Microsoft.PowerShell.Utility\Get-Random)\$moduleName" + + if(-not $FormatVersion) + { + $tempModulePathForFormatVersion = $tempModulePath + } + elseif ($FormatVersion -eq "1.0") + { + $tempModulePathForFormatVersion = Microsoft.PowerShell.Management\Join-Path $tempModulePath "Content\Deployment\$script:ModuleReferences\$moduleName" + } + + $null = Microsoft.PowerShell.Management\New-Item -Path $tempModulePathForFormatVersion -ItemType Directory -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + Microsoft.PowerShell.Management\Copy-Item -Path "$Path\*" -Destination $tempModulePathForFormatVersion -Force -Recurse -Confirm:$false -WhatIf:$false + + try + { + $manifestPath = Microsoft.PowerShell.Management\Join-Path $tempModulePathForFormatVersion "$moduleName.psd1" + + if(-not (Microsoft.PowerShell.Management\Test-Path $manifestPath)) + { + $message = $LocalizedData.InvalidModuleToPublish -f ($moduleName) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidModuleToPublish" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $moduleName + } + + $ev = $null + $moduleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $manifestPath ` + -ErrorVariable ev ` + -Verbose:$VerbosePreference + if($ev) + { + # Above Test-ModuleManifest cmdlet should write an errors to the Errors stream and Console. + return + } + + if(-not $moduleInfo -or + -not $moduleInfo.Author -or + -not $moduleInfo.Description) + { + $message = $LocalizedData.MissingRequiredManifestKeys -f ($moduleName) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "MissingRequiredModuleManifestKeys" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $moduleName + } + + # Check if the specified module name is already used for a script on the specified repository + # Use Find-Script to check if that name is already used as scriptname + $scriptPSGetItemInfo = Find-Script -Name $moduleName ` + -Repository $Repository ` + -Tag 'PSScript' ` + -Verbose:$VerbosePreference ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Debug:$DebugPreference | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $moduleName} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + if($scriptPSGetItemInfo) + { + $message = $LocalizedData.SpecifiedNameIsAlearyUsed -f ($moduleName, $Repository, 'Find-Script') + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SpecifiedNameIsAlearyUsed" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $moduleName + } + + $currentPSGetItemInfo = Find-Module -Name $moduleInfo.Name ` + -Repository $Repository ` + -Verbose:$VerbosePreference ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Debug:$DebugPreference | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $moduleInfo.Name} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + + if($currentPSGetItemInfo -and $currentPSGetItemInfo.Version -ge $moduleInfo.Version) + { + $message = $LocalizedData.ModuleVersionShouldBeGreaterThanGalleryVersion -f ($moduleInfo.Name, $moduleInfo.Version, $currentPSGetItemInfo.Version, $currentPSGetItemInfo.RepositorySourceLocation) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "ModuleVersionShouldBeGreaterThanGalleryVersion" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + + $shouldProcessMessage = $LocalizedData.PublishModulewhatIfMessage -f ($moduleInfo.Version, $moduleInfo.Name) + if($PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Module")) + { + Publish-PSArtifactUtility -PSModuleInfo $moduleInfo ` + -ManifestPath $manifestPath ` + -NugetApiKey $NuGetApiKey ` + -Destination $DestinationLocation ` + -Repository $Repository ` + -NugetPackageRoot $tempModulePath ` + -FormatVersion $FormatVersion ` + -ReleaseNotes $($ReleaseNotes -join "`r`n") ` + -Tags $Tags ` + -LicenseUri $LicenseUri ` + -IconUri $IconUri ` + -ProjectUri $ProjectUri ` + -Verbose:$VerbosePreference ` + -WarningAction $WarningPreference ` + -ErrorAction $ErrorActionPreference ` + -Debug:$DebugPreference + } + } + finally + { + Microsoft.PowerShell.Management\Remove-Item $tempModulePath -Force -Recurse -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + } +} + +function Find-Module +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=398574')] + [outputtype("PSCustomObject[]")] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Position=0)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter()] + [switch] + $AllVersions, + + [Parameter()] + [switch] + $IncludeDependencies, + + [Parameter()] + [ValidateNotNull()] + [string] + $Filter, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Tag, + + [Parameter()] + [ValidateNotNull()] + [ValidateSet('DscResource','Cmdlet','Function','RoleCapability')] + [string[]] + $Includes, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $DscResource, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $RoleCapability, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Command, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Repository + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet + } + + Process + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion ` + -AllVersions:$AllVersions + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + + if($PSBoundParameters.ContainsKey("Repository")) + { + $PSBoundParameters["Source"] = $Repository + $null = $PSBoundParameters.Remove("Repository") + + $ev = $null + $null = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false + if($ev) { return } + } + + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + + $modulesFoundInPSGallery = @() + + # No Telemetry must be performed if PSGallery is not in the supplied list of Repositories + $isRepositoryNullOrPSGallerySpecified = $false + if ($Repository -and ($Repository -Contains $Script:PSGalleryModuleSource)) + { + $isRepositoryNullOrPSGallerySpecified = $true + } + elseif(-not $Repository) + { + $psgalleryRepo = Get-PSRepository -Name $Script:PSGalleryModuleSource ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if($psgalleryRepo) + { + $isRepositoryNullOrPSGallerySpecified = $true + } + } + + PackageManagement\Find-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object { + + $psgetItemInfo = New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule + + $psgetItemInfo + + if ($psgetItemInfo -and + $isRepositoryNullOrPSGallerySpecified -and + $script:TelemetryEnabled -and + ($psgetItemInfo.Repository -eq $Script:PSGalleryModuleSource)) + { + $modulesFoundInPSGallery += $psgetItemInfo.Name + } + } + + # Perform Telemetry if Repository is not supplied or Repository contains PSGallery + # We are only interested in finding modules not in PSGallery + if ($isRepositoryNullOrPSGallerySpecified) + { + Log-ArtifactNotFoundInPSGallery -SearchedName $Name -FoundName $modulesFoundInPSGallery -operationName 'PSGET_FIND_MODULE' + } + } +} + +function Save-Module +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameAndPathParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkId=531351', + SupportsShouldProcess=$true)] + Param + ( + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputOjectAndPathParameterSet')] + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputOjectAndLiteralPathParameterSet')] + [ValidateNotNull()] + [PSCustomObject[]] + $InputObject, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository, + + [Parameter(Mandatory=$true, ParameterSetName='NameAndPathParameterSet')] + [Parameter(Mandatory=$true, ParameterSetName='InputOjectAndPathParameterSet')] + [string] + $Path, + + [Parameter(Mandatory=$true, ParameterSetName='NameAndLiteralPathParameterSet')] + [Parameter(Mandatory=$true, ParameterSetName='InputOjectAndLiteralPathParameterSet')] + [string] + $LiteralPath, + + [Parameter()] + [switch] + $Force + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Repository + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet + + # Module names already tried in the current pipeline for InputObject parameterset + $moduleNamesInPipeline = @() + } + + Process + { + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementSaveModuleMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + + # When -Force is specified, Path will be created if not available. + if(-not $Force) + { + if($Path) + { + $destinationPath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-path $destinationPath)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + } + + $PSBoundParameters['Path'] = $destinationPath + } + else + { + $destinationPath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $destinationPath)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $LiteralPath ` + -ErrorCategory InvalidArgument + } + + $PSBoundParameters['LiteralPath'] = $destinationPath + } + } + + if($Name) + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -TestWildcardsInName ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + if($PSBoundParameters.ContainsKey("Repository")) + { + $PSBoundParameters["Source"] = $Repository + $null = $PSBoundParameters.Remove("Repository") + + $ev = $null + $null = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false + if($ev) { return } + } + + $null = PackageManagement\Save-Package @PSBoundParameters + } + elseif($InputObject) + { + $null = $PSBoundParameters.Remove("InputObject") + + foreach($inputValue in $InputObject) + { + if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -and + ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and + ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo")) + + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` + -ErrorId "InvalidInputObjectValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $inputValue + } + + if( ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or + ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or + ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -or + ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -or + ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -or + ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo")) + { + $psgetModuleInfo = $inputValue.PSGetModuleInfo + } + else + { + $psgetModuleInfo = $inputValue + } + + # Skip the module name if it is already tried in the current pipeline + if($moduleNamesInPipeline -contains $psgetModuleInfo.Name) + { + continue + } + + $moduleNamesInPipeline += $psgetModuleInfo.Name + + if ($psgetModuleInfo.PowerShellGetFormatVersion -and + ($script:SupportedPSGetFormatVersionMajors -notcontains $psgetModuleInfo.PowerShellGetFormatVersion.Major)) + { + $message = $LocalizedData.NotSupportedPowerShellGetFormatVersion -f ($psgetModuleInfo.Name, $psgetModuleInfo.PowerShellGetFormatVersion, $psgetModuleInfo.Name) + Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation + continue + } + + $PSBoundParameters["Name"] = $psgetModuleInfo.Name + $PSBoundParameters["RequiredVersion"] = $psgetModuleInfo.Version + $PSBoundParameters['Source'] = $psgetModuleInfo.Repository + $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psgetModuleInfo) + + $null = PackageManagement\Save-Package @PSBoundParameters + } + } + } +} + +function Install-Module +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkID=398573', + SupportsShouldProcess=$true)] + Param + ( + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputObject')] + [ValidateNotNull()] + [PSCustomObject[]] + $InputObject, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository, + + [Parameter()] + [ValidateSet("CurrentUser","AllUsers")] + [string] + $Scope = "AllUsers", + + [Parameter()] + [switch] + $Force + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Repository + + if(-not (Test-RunningAsElevated) -and ($Scope -ne "CurrentUser")) + { + # Throw an error when Install-Module is used as a non-admin user and '-Scope CurrentUser' is not specified + $message = $LocalizedData.InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:programFilesModulesPath, $script:MyDocumentsModulesPath) + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet + + # Module names already tried in the current pipeline for InputObject parameterset + $moduleNamesInPipeline = @() + $YesToAll = $false + $NoToAll = $false + $SourceSGrantedTrust = @() + $SourcesDeniedTrust = @() + } + + Process + { + $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted + $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedPackage + $PackageTarget = $LocalizedData.InstallModulewhatIfMessage + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementInstallModuleMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + $PSBoundParameters['Scope'] = $Scope + + if($PSCmdlet.ParameterSetName -eq "NameParameterSet") + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -TestWildcardsInName ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + if($PSBoundParameters.ContainsKey("Repository")) + { + $PSBoundParameters["Source"] = $Repository + $null = $PSBoundParameters.Remove("Repository") + + $ev = $null + $null = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false + if($ev) { return } + } + + $null = PackageManagement\Install-Package @PSBoundParameters + } + elseif($PSCmdlet.ParameterSetName -eq "InputObject") + { + $null = $PSBoundParameters.Remove("InputObject") + + foreach($inputValue in $InputObject) + { + if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -and + ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and + ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo")) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` + -ErrorId "InvalidInputObjectValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $inputValue + } + + if( ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or + ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or + ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -or + ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -or + ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -or + ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo")) + { + $psgetModuleInfo = $inputValue.PSGetModuleInfo + } + else + { + $psgetModuleInfo = $inputValue + } + + # Skip the module name if it is already tried in the current pipeline + if($moduleNamesInPipeline -contains $psgetModuleInfo.Name) + { + continue + } + + $moduleNamesInPipeline += $psgetModuleInfo.Name + + if ($psgetModuleInfo.PowerShellGetFormatVersion -and + ($script:SupportedPSGetFormatVersionMajors -notcontains $psgetModuleInfo.PowerShellGetFormatVersion.Major)) + { + $message = $LocalizedData.NotSupportedPowerShellGetFormatVersion -f ($psgetModuleInfo.Name, $psgetModuleInfo.PowerShellGetFormatVersion, $psgetModuleInfo.Name) + Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation + continue + } + + $PSBoundParameters["Name"] = $psgetModuleInfo.Name + $PSBoundParameters["RequiredVersion"] = $psgetModuleInfo.Version + $PSBoundParameters['Source'] = $psgetModuleInfo.Repository + $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psgetModuleInfo) + + #Check if module is already installed + $InstalledModuleInfo = Test-ModuleInstalled -Name $psgetModuleInfo.Name -RequiredVersion $psgetModuleInfo.Version + if(-not $Force -and $InstalledModuleInfo -ne $null) + { + $message = $LocalizedData.ModuleAlreadyInstalledVerbose -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase) + Write-Verbose -Message $message + } + else + { + $source = $psgetModuleInfo.Repository + $installationPolicy = (Get-PSRepository -Name $source).InstallationPolicy + $ShouldProcessMessage = $PackageTarget -f ($psgetModuleInfo.Name, $psgetModuleInfo.Version) + + if($psCmdlet.ShouldProcess($ShouldProcessMessage)) + { + if($installationPolicy.Equals("Untrusted", [StringComparison]::OrdinalIgnoreCase)) + { + if(-not($YesToAll -or $NoToAll -or $SourceSGrantedTrust.Contains($source) -or $sourcesDeniedTrust.Contains($source) -or $Force)) + { + $message = $QueryInstallUntrustedPackage -f ($psgetModuleInfo.Name, $psgetModuleInfo.RepositorySourceLocation) + if($PSVersionTable.PSVersion -ge [Version]"5.0") + { + $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted",$true, [ref]$YesToAll, [ref]$NoToAll) + } + else + { + $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted", [ref]$YesToAll, [ref]$NoToAll) + } + + if($sourceTrusted) + { + $SourceSGrantedTrust+=$source + } + else + { + $SourcesDeniedTrust+=$source + } + } + } + + if($installationPolicy.Equals("trusted", [StringComparison]::OrdinalIgnoreCase) -or $SourceSGrantedTrust.Contains($source) -or $YesToAll -or $Force) + { + $PSBoundParameters["Force"] = $true + $null = PackageManagement\Install-Package @PSBoundParameters + } + } + } + } + } + } +} + +function Update-Module +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(SupportsShouldProcess=$true, + HelpUri='http://go.microsoft.com/fwlink/?LinkID=398576')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Position=0)] + [ValidateNotNullOrEmpty()] + [String[]] + $Name, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter()] + [Switch] + $Force + ) + + Begin + { + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet + + # Module names already tried in the current pipeline + $moduleNamesInPipeline = @() + } + + Process + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $GetPackageParameters = @{} + $GetPackageParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + $GetPackageParameters["Provider"] = $script:PSModuleProviderName + $GetPackageParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + $GetPackageParameters['ErrorAction'] = 'SilentlyContinue' + $GetPackageParameters['WarningAction'] = 'SilentlyContinue' + + $PSGetItemInfos = @() + + if($Name) + { + foreach($moduleName in $Name) + { + $GetPackageParameters['Name'] = $moduleName + $installedPackages = PackageManagement\Get-Package @GetPackageParameters + + if(-not $installedPackages -and -not (Test-WildcardPattern -Name $moduleName)) + { + $availableModules = Get-Module -ListAvailable $moduleName -Verbose:$false | Microsoft.PowerShell.Utility\Select-Object -Unique + + if(-not $availableModules) + { + $message = $LocalizedData.ModuleNotInstalledOnThisMachine -f ($moduleName) + Write-Error -Message $message -ErrorId 'ModuleNotInstalledOnThisMachine' -Category InvalidOperation -TargetObject $moduleName + } + else + { + $message = $LocalizedData.ModuleNotInstalledUsingPowerShellGet -f ($moduleName) + Write-Error -Message $message -ErrorId 'ModuleNotInstalledUsingInstallModuleCmdlet' -Category InvalidOperation -TargetObject $moduleName + } + + continue + } + + $installedPackages | + Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule} | + Microsoft.PowerShell.Core\ForEach-Object { + if(-not (Test-RunningAsElevated) -and $_.InstalledLocation.StartsWith($script:programFilesModulesPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + if(-not (Test-WildcardPattern -Name $moduleName)) + { + $message = $LocalizedData.AdminPrivilegesRequiredForUpdate -f ($_.Name, $_.InstalledLocation) + Write-Error -Message $message -ErrorId "AdminPrivilegesAreRequiredForUpdate" -Category InvalidOperation -TargetObject $moduleName + } + continue + } + + $PSGetItemInfos += $_ + } + } + } + else + { + + $PSGetItemInfos = PackageManagement\Get-Package @GetPackageParameters | + Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule} | + Microsoft.PowerShell.Core\Where-Object { + (Test-RunningAsElevated) -or + $_.InstalledLocation.StartsWith($script:MyDocumentsModulesPath, [System.StringComparison]::OrdinalIgnoreCase) + } + } + + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementUpdateModuleMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + + foreach($psgetItemInfo in $PSGetItemInfos) + { + # Skip the module name if it is already tried in the current pipeline + if($moduleNamesInPipeline -contains $psgetItemInfo.Name) + { + continue + } + + $moduleNamesInPipeline += $psgetItemInfo.Name + + $message = $LocalizedData.CheckingForModuleUpdate -f ($psgetItemInfo.Name) + Write-Verbose -Message $message + + $providerName = Get-ProviderName -PSCustomObject $psgetItemInfo + if(-not $providerName) + { + $providerName = $script:NuGetProviderName + } + + $PSBoundParameters["Name"] = $psgetItemInfo.Name + $PSBoundParameters['Source'] = $psgetItemInfo.Repository + + Get-PSGalleryApiAvailability -Repository (Get-SourceName -Location $psgetItemInfo.RepositorySourceLocation) + + $PSBoundParameters["PackageManagementProvider"] = $providerName + $PSBoundParameters["InstallUpdate"] = $true + + if($psgetItemInfo.InstalledLocation.ToString().StartsWith($script:MyDocumentsModulesPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + $PSBoundParameters["Scope"] = "CurrentUser" + } + else + { + $PSBoundParameters['Scope'] = 'AllUsers' + } + + $sid = PackageManagement\Install-Package @PSBoundParameters + } + } +} + +function Uninstall-Module +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameParameterSet', + SupportsShouldProcess=$true, + HelpUri='http://go.microsoft.com/fwlink/?LinkId=526864')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Mandatory=$true, + Position=0, + ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [String[]] + $Name, + + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputObject')] + [ValidateNotNull()] + [PSCustomObject[]] + $InputObject, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ParameterSetName='NameParameterSet')] + [switch] + $AllVersions, + + [Parameter()] + [Switch] + $Force + ) + + Process + { + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementUnInstallModuleMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + + if($PSCmdlet.ParameterSetName -eq "InputObject") + { + $null = $PSBoundParameters.Remove("InputObject") + + foreach($inputValue in $InputObject) + { + if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo")) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` + -ErrorId "InvalidInputObjectValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $inputValue + } + + $PSBoundParameters["Name"] = $inputValue.Name + $PSBoundParameters["RequiredVersion"] = $inputValue.Version + + $null = PackageManagement\Uninstall-Package @PSBoundParameters + } + } + else + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -TestWildcardsInName ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion ` + -AllVersions:$AllVersions + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $null = PackageManagement\Uninstall-Package @PSBoundParameters + } + } +} + +function Get-InstalledModule +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkId=526863')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Position=0)] + [ValidateNotNullOrEmpty()] + [String[]] + $Name, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter()] + [switch] + $AllVersions + ) + + Process + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion ` + -AllVersions:$AllVersions + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule + + PackageManagement\Get-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule} + } +} + +#endregion *-Module cmdlets + +#region Find-DscResouce cmdlet + +function Find-DscResource +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri = 'http://go.microsoft.com/fwlink/?LinkId=517196')] + [outputtype('PSCustomObject[]')] + Param + ( + [Parameter(Position = 0)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $ModuleName, + + [Parameter()] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter()] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter()] + [switch] + $AllVersions, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Tag, + + [Parameter()] + [ValidateNotNull()] + [string] + $Filter, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository + ) + + + Process + { + $PSBoundParameters['Includes'] = 'DscResource' + + if($PSBoundParameters.ContainsKey('Name')) + { + $PSBoundParameters['DscResource'] = $Name + $null = $PSBoundParameters.Remove('Name') + } + + if($PSBoundParameters.ContainsKey('ModuleName')) + { + $PSBoundParameters['Name'] = $ModuleName + $null = $PSBoundParameters.Remove('ModuleName') + } + + PowerShellGet\Find-Module @PSBoundParameters | + Microsoft.PowerShell.Core\ForEach-Object { + $psgetModuleInfo = $_ + $psgetModuleInfo.Includes.DscResource | Microsoft.PowerShell.Core\ForEach-Object { + if($Name -and ($Name -notcontains $_)) + { + return + } + + $psgetDscResourceInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $_ + Version = $psgetModuleInfo.Version + ModuleName = $psgetModuleInfo.Name + Repository = $psgetModuleInfo.Repository + PSGetModuleInfo = $psgetModuleInfo + }) + + $psgetDscResourceInfo.PSTypeNames.Insert(0, 'Microsoft.PowerShell.Commands.PSGetDscResourceInfo') + $psgetDscResourceInfo + } + } + } +} + +#endregion Find-DscResouce cmdlet + +#region Find-Command cmdlet + +function Find-Command +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri = 'http://go.microsoft.com/fwlink/?LinkId=733636')] + [outputtype('PSCustomObject[]')] + Param + ( + [Parameter(Position = 0)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $ModuleName, + + [Parameter()] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter()] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter()] + [switch] + $AllVersions, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Tag, + + [Parameter()] + [ValidateNotNull()] + [string] + $Filter, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository + ) + + + Process + { + if($PSBoundParameters.ContainsKey('Name')) + { + $PSBoundParameters['Command'] = $Name + $null = $PSBoundParameters.Remove('Name') + } + else + { + $PSBoundParameters['Includes'] = @('Cmdlet','Function') + } + + if($PSBoundParameters.ContainsKey('ModuleName')) + { + $PSBoundParameters['Name'] = $ModuleName + $null = $PSBoundParameters.Remove('ModuleName') + } + + PowerShellGet\Find-Module @PSBoundParameters | + Microsoft.PowerShell.Core\ForEach-Object { + $psgetModuleInfo = $_ + $psgetModuleInfo.Includes.Command | Microsoft.PowerShell.Core\ForEach-Object { + if(($_ -eq "*") -or ($Name -and ($Name -notcontains $_))) + { + return + } + + $psgetCommandInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $_ + Version = $psgetModuleInfo.Version + ModuleName = $psgetModuleInfo.Name + Repository = $psgetModuleInfo.Repository + PSGetModuleInfo = $psgetModuleInfo + }) + + $psgetCommandInfo.PSTypeNames.Insert(0, 'Microsoft.PowerShell.Commands.PSGetCommandInfo') + $psgetCommandInfo + } + } + } +} + +#endregion Find-Command cmdlet + +#region Find-RoleCapability cmdlet + +function Find-RoleCapability +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri = 'http://go.microsoft.com/fwlink/?LinkId=718029')] + [outputtype('PSCustomObject[]')] + Param + ( + [Parameter(Position = 0)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $ModuleName, + + [Parameter()] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter()] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter()] + [switch] + $AllVersions, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Tag, + + [Parameter()] + [ValidateNotNull()] + [string] + $Filter, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository + ) + + + Process + { + $PSBoundParameters['Includes'] = 'RoleCapability' + + if($PSBoundParameters.ContainsKey('Name')) + { + $PSBoundParameters['RoleCapability'] = $Name + $null = $PSBoundParameters.Remove('Name') + } + + if($PSBoundParameters.ContainsKey('ModuleName')) + { + $PSBoundParameters['Name'] = $ModuleName + $null = $PSBoundParameters.Remove('ModuleName') + } + + PowerShellGet\Find-Module @PSBoundParameters | + Microsoft.PowerShell.Core\ForEach-Object { + $psgetModuleInfo = $_ + $psgetModuleInfo.Includes.RoleCapability | Microsoft.PowerShell.Core\ForEach-Object { + if($Name -and ($Name -notcontains $_)) + { + return + } + + $psgetRoleCapabilityInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $_ + Version = $psgetModuleInfo.Version + ModuleName = $psgetModuleInfo.Name + Repository = $psgetModuleInfo.Repository + PSGetModuleInfo = $psgetModuleInfo + }) + + $psgetRoleCapabilityInfo.PSTypeNames.Insert(0, 'Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo') + $psgetRoleCapabilityInfo + } + } + } +} + +#endregion Find-RoleCapability cmdlet + +#region *-Script cmdlets +function Publish-Script +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(SupportsShouldProcess=$true, + PositionalBinding=$false, + DefaultParameterSetName='PathParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619788')] + Param + ( + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='PathParameterSet')] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='LiteralPathParameterSet')] + [ValidateNotNullOrEmpty()] + [string] + $LiteralPath, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $NuGetApiKey, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Repository = $Script:PSGalleryModuleSource + ) + + Begin + { + if($script:isNanoServer) { + $message = $LocalizedData.PublishPSArtifactUnsupportedOnNano -f "Script" + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "PublishScriptIsNotSupportedOnNanoServer" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $PSCmdlet ` + -ErrorCategory InvalidOperation + } + + Get-PSGalleryApiAvailability -Repository $Repository + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe + } + + Process + { + $scriptFilePath = $null + if($Path) + { + $scriptFilePath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $scriptFilePath -or + -not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + } + } + else + { + $scriptFilePath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $scriptFilePath -or + -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $scriptFilePath -PathType Leaf)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $LiteralPath ` + -ErrorCategory InvalidArgument + } + } + + if(-not $scriptFilePath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) + { + $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "InvalidScriptFilePath" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $scriptFilePath ` + -ErrorCategory InvalidArgument + return + } + + if($Repository -eq $Script:PSGalleryModuleSource) + { + $repo = Get-PSRepository -Name $Repository -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + if(-not $repo) + { + $message = $LocalizedData.PSGalleryNotFound -f ($Repository) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'PSGalleryNotFound' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Repository + return + } + } + else + { + $ev = $null + $repo = Get-PSRepository -Name $Repository -ErrorVariable ev + if($ev) { return } + } + + $DestinationLocation = $null + + if(Get-Member -InputObject $repo -Name $script:ScriptPublishLocation) + { + $DestinationLocation = $repo.ScriptPublishLocation + } + + if(-not $DestinationLocation -or + (-not (Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation) -and + -not (Test-WebUri -uri $DestinationLocation))) + + { + $message = $LocalizedData.PSRepositoryScriptPublishLocationIsMissing -f ($Repository, $Repository) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PSRepositoryScriptPublishLocationIsMissing" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Repository + } + + $message = $LocalizedData.PublishLocation -f ($DestinationLocation) + Write-Verbose -Message $message + + if(-not $NuGetApiKey.Trim()) + { + if(Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation) + { + $NuGetApiKey = "$(Get-Random)" + } + else + { + $message = $LocalizedData.NuGetApiKeyIsRequiredForNuGetBasedGalleryService -f ($Repository, $DestinationLocation) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "NuGetApiKeyIsRequiredForNuGetBasedGalleryService" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + } + + $providerName = Get-ProviderName -PSCustomObject $repo + if($providerName -ne $script:NuGetProviderName) + { + $message = $LocalizedData.PublishScriptSupportsOnlyNuGetBasedPublishLocations -f ($DestinationLocation, $Repository, $Repository) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PublishScriptSupportsOnlyNuGetBasedPublishLocations" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Repository + } + + if($Path) + { + $PSScriptInfo = Test-ScriptFileInfo -Path $scriptFilePath + } + else + { + $PSScriptInfo = Test-ScriptFileInfo -LiteralPath $scriptFilePath + } + + if(-not $PSScriptInfo) + { + # Test-ScriptFileInfo throws the actual error + return + } + + $scriptName = $PSScriptInfo.Name + + # Copy the source script file to temp location to publish + $tempScriptPath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath ` + -ChildPath "$(Microsoft.PowerShell.Utility\Get-Random)\$scriptName" + + $null = Microsoft.PowerShell.Management\New-Item -Path $tempScriptPath -ItemType Directory -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + if($Path) + { + Microsoft.PowerShell.Management\Copy-Item -Path $scriptFilePath -Destination $tempScriptPath -Force -Recurse -Confirm:$false -WhatIf:$false + } + else + { + Microsoft.PowerShell.Management\Copy-Item -LiteralPath $scriptFilePath -Destination $tempScriptPath -Force -Recurse -Confirm:$false -WhatIf:$false + } + + try + { + # Check if the specified script name is already used for a module on the specified repository + # Use Find-Module to check if that name is already used as module name + $modulePSGetItemInfo = Find-Module -Name $scriptName ` + -Repository $Repository ` + -Tag 'PSModule' ` + -Verbose:$VerbosePreference ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Debug:$DebugPreference | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $scriptName} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + if($modulePSGetItemInfo) + { + $message = $LocalizedData.SpecifiedNameIsAlearyUsed -f ($scriptName, $Repository, 'Find-Module') + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SpecifiedNameIsAlearyUsed" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $scriptName + } + + $currentPSGetItemInfo = $null + $currentPSGetItemInfo = Find-Script -Name $scriptName ` + -Repository $Repository ` + -Verbose:$VerbosePreference ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Debug:$DebugPreference | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $scriptName} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + + if($currentPSGetItemInfo -and $currentPSGetItemInfo.Version -ge $PSScriptInfo.Version) + { + $message = $LocalizedData.ScriptVersionShouldBeGreaterThanGalleryVersion -f ($scriptName, + $PSScriptInfo.Version, + $currentPSGetItemInfo.Version, + $currentPSGetItemInfo.RepositorySourceLocation) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "ScriptVersionShouldBeGreaterThanGalleryVersion" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + + $shouldProcessMessage = $LocalizedData.PublishScriptwhatIfMessage -f ($PSScriptInfo.Version, $scriptName) + if($PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Script")) + { + Publish-PSArtifactUtility -PSScriptInfo $PSScriptInfo ` + -NugetApiKey $NuGetApiKey ` + -Destination $DestinationLocation ` + -Repository $Repository ` + -NugetPackageRoot $tempScriptPath ` + -Verbose:$VerbosePreference ` + -WarningAction $WarningPreference ` + -ErrorAction $ErrorActionPreference ` + -Debug:$DebugPreference + } + } + finally + { + Microsoft.PowerShell.Management\Remove-Item $tempScriptPath -Force -Recurse -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + } +} + +function Find-Script +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkId=619785')] + [outputtype("PSCustomObject[]")] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Position=0)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter()] + [switch] + $AllVersions, + + [Parameter()] + [switch] + $IncludeDependencies, + + [Parameter()] + [ValidateNotNull()] + [string] + $Filter, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Tag, + + [Parameter()] + [ValidateNotNull()] + [ValidateSet('Function','Workflow')] + [string[]] + $Includes, + + [Parameter()] + [ValidateNotNull()] + [string[]] + $Command, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Repository + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet + } + + Process + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion ` + -AllVersions:$AllVersions + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $PSBoundParameters['Provider'] = $script:PSModuleProviderName + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript + + if($PSBoundParameters.ContainsKey("Repository")) + { + $PSBoundParameters["Source"] = $Repository + $null = $PSBoundParameters.Remove("Repository") + + $ev = $null + $repositories = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false + if($ev) { return } + + $RepositoriesWithoutScriptSourceLocation = $false + foreach($repo in $repositories) + { + if(-not $repo.ScriptSourceLocation) + { + $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($repo.Name) + Write-Error -Message $message ` + -ErrorId 'ScriptSourceLocationIsMissing' ` + -Category InvalidArgument ` + -TargetObject $repo.Name ` + -Exception 'System.ArgumentException' + + $RepositoriesWithoutScriptSourceLocation = $true + } + } + + if($RepositoriesWithoutScriptSourceLocation) + { + return + } + } + + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlockForScriptCmdlets + + $scriptsFoundInPSGallery = @() + + # No Telemetry must be performed if PSGallery is not in the supplied list of Repositories + $isRepositoryNullOrPSGallerySpecified = $false + if ($Repository -and ($Repository -Contains $Script:PSGalleryModuleSource)) + { + $isRepositoryNullOrPSGallerySpecified = $true + } + elseif(-not $Repository) + { + $psgalleryRepo = Get-PSRepository -Name $Script:PSGalleryModuleSource ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + # And check for IsDeafult? + if($psgalleryRepo) + { + $isRepositoryNullOrPSGallerySpecified = $true + } + } + + PackageManagement\Find-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object { + $psgetItemInfo = New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeScript + + $psgetItemInfo + + if ($psgetItemInfo -and + $isRepositoryNullOrPSGallerySpecified -and + $script:TelemetryEnabled -and + ($psgetItemInfo.Repository -eq $Script:PSGalleryModuleSource)) + { + $scriptsFoundInPSGallery += $psgetItemInfo.Name + } + } + + # Perform Telemetry if Repository is not supplied or Repository contains PSGallery + # We are only interested in finding artifacts not in PSGallery + if ($isRepositoryNullOrPSGallerySpecified) + { + Log-ArtifactNotFoundInPSGallery -SearchedName $Name -FoundName $scriptsFoundInPSGallery -operationName PSGET_FIND_SCRIPT + } + } +} + +function Save-Script +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameAndPathParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619786', + SupportsShouldProcess=$true)] + Param + ( + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputOjectAndPathParameterSet')] + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputOjectAndLiteralPathParameterSet')] + [ValidateNotNull()] + [PSCustomObject[]] + $InputObject, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository, + + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndPathParameterSet')] + + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='InputOjectAndPathParameterSet')] + [string] + $Path, + + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameAndLiteralPathParameterSet')] + + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='InputOjectAndLiteralPathParameterSet')] + [string] + $LiteralPath, + + [Parameter()] + [switch] + $Force + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Repository + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet + + # Script names already tried in the current pipeline for InputObject parameterset + $scriptNamesInPipeline = @() + } + + Process + { + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementSaveScriptMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript + + # When -Force is specified, Path will be created if not available. + if(-not $Force) + { + if($Path) + { + $destinationPath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-path $destinationPath)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + } + + $PSBoundParameters['Path'] = $destinationPath + } + else + { + $destinationPath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $destinationPath)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $LiteralPath ` + -ErrorCategory InvalidArgument + } + + $PSBoundParameters['LiteralPath'] = $destinationPath + } + } + + if($Name) + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -TestWildcardsInName ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + if($PSBoundParameters.ContainsKey("Repository")) + { + $PSBoundParameters["Source"] = $Repository + $null = $PSBoundParameters.Remove("Repository") + + $ev = $null + $repositories = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false + if($ev) { return } + + $RepositoriesWithoutScriptSourceLocation = $false + foreach($repo in $repositories) + { + if(-not $repo.ScriptSourceLocation) + { + $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($repo.Name) + Write-Error -Message $message ` + -ErrorId 'ScriptSourceLocationIsMissing' ` + -Category InvalidArgument ` + -TargetObject $repo.Name ` + -Exception 'System.ArgumentException' + + $RepositoriesWithoutScriptSourceLocation = $true + } + } + + if($RepositoriesWithoutScriptSourceLocation) + { + return + } + } + + $null = PackageManagement\Save-Package @PSBoundParameters + } + elseif($InputObject) + { + $null = $PSBoundParameters.Remove("InputObject") + + foreach($inputValue in $InputObject) + { + if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo")) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` + -ErrorId "InvalidInputObjectValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $inputValue + } + + $psRepositoryItemInfo = $inputValue + + # Skip the script name if it is already tried in the current pipeline + if($scriptNamesInPipeline -contains $psRepositoryItemInfo.Name) + { + continue + } + + $scriptNamesInPipeline += $psRepositoryItemInfo.Name + + if ($psRepositoryItemInfo.PowerShellGetFormatVersion -and + ($script:SupportedPSGetFormatVersionMajors -notcontains $psRepositoryItemInfo.PowerShellGetFormatVersion.Major)) + { + $message = $LocalizedData.NotSupportedPowerShellGetFormatVersionScripts -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.PowerShellGetFormatVersion, $psRepositoryItemInfo.Name) + Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation + continue + } + + $PSBoundParameters["Name"] = $psRepositoryItemInfo.Name + $PSBoundParameters["RequiredVersion"] = $psRepositoryItemInfo.Version + $PSBoundParameters['Source'] = $psRepositoryItemInfo.Repository + $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psRepositoryItemInfo) + + $null = PackageManagement\Save-Package @PSBoundParameters + } + } + } +} + +function Install-Script +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619784', + SupportsShouldProcess=$true)] + Param + ( + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Name, + + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputObject')] + [ValidateNotNull()] + [PSCustomObject[]] + $InputObject, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [string[]] + $Repository, + + [Parameter()] + [ValidateSet("CurrentUser","AllUsers")] + [string] + $Scope = 'AllUsers', + + [Parameter()] + [Switch] + $NoPathUpdate, + + [Parameter()] + [switch] + $Force + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Repository + + if(-not (Test-RunningAsElevated) -and ($Scope -ne "CurrentUser")) + { + # Throw an error when Install-Script is used as a non-admin user and '-Scope CurrentUser' is not specified + $AdminPreviligeErrorMessage = $LocalizedData.InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath) + $AdminPreviligeErrorId = 'InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser' + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $AdminPreviligeErrorMessage ` + -ErrorId $AdminPreviligeErrorId ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + # Check and add the scope path to PATH environment variable + if($Scope -eq 'AllUsers') + { + $scopePath = $script:ProgramFilesScriptsPath + } + else + { + $scopePath = $script:MyDocumentsScriptsPath + } + + ValidateAndSet-PATHVariableIfUserAccepts -Scope $Scope ` + -ScopePath $scopePath ` + -NoPathUpdate:$NoPathUpdate ` + -Force:$Force + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet + + # Script names already tried in the current pipeline for InputObject parameterset + $scriptNamesInPipeline = @() + + $YesToAll = $false + $NoToAll = $false + $SourceSGrantedTrust = @() + $SourcesDeniedTrust = @() + } + + Process + { + $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted + $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedScriptPackage + $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementInstallScriptMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript + $PSBoundParameters['Scope'] = $Scope + + if($PSCmdlet.ParameterSetName -eq "NameParameterSet") + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -TestWildcardsInName ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + if($PSBoundParameters.ContainsKey("Repository")) + { + $PSBoundParameters["Source"] = $Repository + $null = $PSBoundParameters.Remove("Repository") + + $ev = $null + $repositories = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false + if($ev) { return } + + $RepositoriesWithoutScriptSourceLocation = $false + foreach($repo in $repositories) + { + if(-not $repo.ScriptSourceLocation) + { + $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($repo.Name) + Write-Error -Message $message ` + -ErrorId 'ScriptSourceLocationIsMissing' ` + -Category InvalidArgument ` + -TargetObject $repo.Name ` + -Exception 'System.ArgumentException' + + $RepositoriesWithoutScriptSourceLocation = $true + } + } + + if($RepositoriesWithoutScriptSourceLocation) + { + return + } + } + + if(-not $Force) + { + foreach($scriptName in $Name) + { + # Throw an error if there is a command with the same name and -force is not specified. + $cmd = Microsoft.PowerShell.Core\Get-Command -Name $scriptName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if($cmd) + { + # Check if this script was already installed, may be with -Force + $InstalledScriptInfo = Test-ScriptInstalled -Name $scriptName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if(-not $InstalledScriptInfo) + { + $message = $LocalizedData.CommandAlreadyAvailable -f ($scriptName) + Write-Error -Message $message -ErrorId CommandAlreadyAvailableWitScriptName -Category InvalidOperation + + # return if only single name is specified + if($scriptName -eq $Name) + { + return + } + } + } + } + } + + $null = PackageManagement\Install-Package @PSBoundParameters + } + elseif($PSCmdlet.ParameterSetName -eq "InputObject") + { + $null = $PSBoundParameters.Remove("InputObject") + + foreach($inputValue in $InputObject) + { + + if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo")) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` + -ErrorId "InvalidInputObjectValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $inputValue + } + + $psRepositoryItemInfo = $inputValue + + # Skip the script name if it is already tried in the current pipeline + if($scriptNamesInPipeline -contains $psRepositoryItemInfo.Name) + { + continue + } + + $scriptNamesInPipeline += $psRepositoryItemInfo.Name + + if ($psRepositoryItemInfo.PowerShellGetFormatVersion -and + ($script:SupportedPSGetFormatVersionMajors -notcontains $psRepositoryItemInfo.PowerShellGetFormatVersion.Major)) + { + $message = $LocalizedData.NotSupportedPowerShellGetFormatVersionScripts -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.PowerShellGetFormatVersion, $psRepositoryItemInfo.Name) + Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation + continue + } + + $PSBoundParameters["Name"] = $psRepositoryItemInfo.Name + $PSBoundParameters["RequiredVersion"] = $psRepositoryItemInfo.Version + $PSBoundParameters['Source'] = $psRepositoryItemInfo.Repository + $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psRepositoryItemInfo) + + $InstalledScriptInfo = Test-ScriptInstalled -Name $psRepositoryItemInfo.Name + if(-not $Force -and $InstalledScriptInfo) + { + $message = $LocalizedData.ScriptAlreadyInstalledVerbose -f ($InstalledScriptInfo.Version, $InstalledScriptInfo.Name, $InstalledScriptInfo.ScriptBase) + Write-Verbose -Message $message + } + else + { + # Throw an error if there is a command with the same name and -force is not specified. + if(-not $Force) + { + $cmd = Microsoft.PowerShell.Core\Get-Command -Name $psRepositoryItemInfo.Name ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if($cmd) + { + $message = $LocalizedData.CommandAlreadyAvailable -f ($psRepositoryItemInfo.Name) + Write-Error -Message $message -ErrorId CommandAlreadyAvailableWitScriptName -Category InvalidOperation + + continue + } + } + + $source = $psRepositoryItemInfo.Repository + $installationPolicy = (Get-PSRepository -Name $source).InstallationPolicy + $ShouldProcessMessage = $PackageTarget -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.Version) + + if($psCmdlet.ShouldProcess($ShouldProcessMessage)) + { + if($installationPolicy.Equals("Untrusted", [StringComparison]::OrdinalIgnoreCase)) + { + if(-not($YesToAll -or $NoToAll -or $SourceSGrantedTrust.Contains($source) -or $sourcesDeniedTrust.Contains($source) -or $Force)) + { + $message = $QueryInstallUntrustedPackage -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.RepositorySourceLocation) + + if($PSVersionTable.PSVersion -ge [Version]"5.0") + { + $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted",$true, [ref]$YesToAll, [ref]$NoToAll) + } + else + { + $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted", [ref]$YesToAll, [ref]$NoToAll) + } + + if($sourceTrusted) + { + $SourcesGrantedTrust+=$source + } + else + { + $SourcesDeniedTrust+=$source + } + } + } + } + if($installationPolicy.Equals("trusted", [StringComparison]::OrdinalIgnoreCase) -or $SourcesGrantedTrust.Contains($source) -or $YesToAll -or $Force) + { + $PSBoundParameters["Force"] = $true + $null = PackageManagement\Install-Package @PSBoundParameters + } + } + } + } + } +} + +function Update-Script +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(SupportsShouldProcess=$true, + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619787')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Position=0)] + [ValidateNotNullOrEmpty()] + [String[]] + $Name, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter()] + [Switch] + $Force + ) + + Begin + { + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet + + # Script names already tried in the current pipeline + $scriptNamesInPipeline = @() + } + + Process + { + $scriptFilePathsToUpdate = @() + + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + if($Name) + { + foreach($scriptName in $Name) + { + $availableScriptPaths = Get-AvailableScriptFilePath -Name $scriptName -Verbose:$false + + if(-not $availableScriptPaths -and -not (Test-WildcardPattern -Name $scriptName)) + { + $message = $LocalizedData.ScriptNotInstalledOnThisMachine -f ($scriptName, $script:MyDocumentsScriptsPath, $script:ProgramFilesScriptsPath) + Write-Error -Message $message -ErrorId "ScriptNotInstalledOnThisMachine" -Category InvalidOperation -TargetObject $scriptName + continue + } + + foreach($scriptFilePath in $availableScriptPaths) + { + $installedScriptFilePath = Get-InstalledScriptFilePath -Name ([System.IO.Path]::GetFileNameWithoutExtension($scriptFilePath)) | + Microsoft.PowerShell.Core\Where-Object {$_ -eq $scriptFilePath } + + # Check if this script got installed with PowerShellGet and user has required permissions + if ($installedScriptFilePath) + { + if(-not (Test-RunningAsElevated) -and $installedScriptFilePath.StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + if(-not (Test-WildcardPattern -Name $scriptName)) + { + $message = $LocalizedData.AdminPrivilegesRequiredForScriptUpdate -f ($scriptName, $installedScriptFilePath) + Write-Error -Message $message -ErrorId "AdminPrivilegesAreRequiredForUpdate" -Category InvalidOperation -TargetObject $scriptName + } + continue + } + + $scriptFilePathsToUpdate += $installedScriptFilePath + } + else + { + if(-not (Test-WildcardPattern -Name $scriptName)) + { + $message = $LocalizedData.ScriptNotInstalledUsingPowerShellGet -f ($scriptName) + Write-Error -Message $message -ErrorId "ScriptNotInstalledUsingPowerShellGet" -Category InvalidOperation -TargetObject $scriptName + } + continue + } + } + } + } + else + { + $isRunningAsElevated = Test-RunningAsElevated + $installedScriptFilePaths = Get-InstalledScriptFilePath + + if($isRunningAsElevated) + { + $scriptFilePathsToUpdate = $installedScriptFilePaths + } + else + { + # Update the scripts installed under + $scriptFilePathsToUpdate = $installedScriptFilePaths | Microsoft.PowerShell.Core\Where-Object { + $_.StartsWith($script:MyDocumentsScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)} + } + } + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript + $PSBoundParameters["MessageResolver"] = $script:PackageManagementUpdateScriptMessageResolverScriptBlock + $PSBoundParameters["InstallUpdate"] = $true + + foreach($scriptFilePath in $scriptFilePathsToUpdate) + { + $scriptName = [System.IO.Path]::GetFileNameWithoutExtension($scriptFilePath) + + $installedScriptInfoFilePath = $null + $installedScriptInfoFileName = "$($scriptName)_$script:InstalledScriptInfoFileName" + + if($scriptFilePath.ToString().StartsWith($script:MyDocumentsScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + $PSBoundParameters["Scope"] = "CurrentUser" + $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsInstalledScriptInfosPath ` + -ChildPath $installedScriptInfoFileName + } + elseif($scriptFilePath.ToString().StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + $PSBoundParameters["Scope"] = "AllUsers" + $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesInstalledScriptInfosPath ` + -ChildPath $installedScriptInfoFileName + + } + + $psgetItemInfo = $null + if($installedScriptInfoFilePath -and (Microsoft.PowerShell.Management\Test-Path -Path $installedScriptInfoFilePath -PathType Leaf)) + { + $psgetItemInfo = DeSerialize-PSObject -Path $installedScriptInfoFilePath + } + + # Skip the script name if it is already tried in the current pipeline + if(-not $psgetItemInfo -or ($scriptNamesInPipeline -contains $psgetItemInfo.Name)) + { + continue + } + + + $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $psgetItemInfo.InstalledLocation ` + -ChildPath "$($psgetItemInfo.Name).ps1" + + # Remove the InstalledScriptInfo.xml file if the actual script file was manually uninstalled by the user + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item -Path $installedScriptInfoFilePath -Force -ErrorAction SilentlyContinue + + continue + } + + $scriptNamesInPipeline += $psgetItemInfo.Name + + $message = $LocalizedData.CheckingForScriptUpdate -f ($psgetItemInfo.Name) + Write-Verbose -Message $message + + $providerName = Get-ProviderName -PSCustomObject $psgetItemInfo + if(-not $providerName) + { + $providerName = $script:NuGetProviderName + } + + $PSBoundParameters["PackageManagementProvider"] = $providerName + $PSBoundParameters["Name"] = $psgetItemInfo.Name + $PSBoundParameters['Source'] = $psgetItemInfo.Repository + + Get-PSGalleryApiAvailability -Repository (Get-SourceName -Location $psgetItemInfo.RepositorySourceLocation) + + $sid = PackageManagement\Install-Package @PSBoundParameters + } + } +} + +function Uninstall-Script +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(DefaultParameterSetName='NameParameterSet', + SupportsShouldProcess=$true, + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619789')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Mandatory=$true, + Position=0, + ParameterSetName='NameParameterSet')] + [ValidateNotNullOrEmpty()] + [String[]] + $Name, + + [Parameter(Mandatory=$true, + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + Position=0, + ParameterSetName='InputObject')] + [ValidateNotNull()] + [PSCustomObject[]] + $InputObject, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true, + ParameterSetName='NameParameterSet')] + [ValidateNotNull()] + [Version] + $MaximumVersion, + + [Parameter()] + [Switch] + $Force + ) + + Process + { + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementUnInstallScriptMessageResolverScriptBlock + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript + + if($PSCmdlet.ParameterSetName -eq "InputObject") + { + $null = $PSBoundParameters.Remove("InputObject") + + foreach($inputValue in $InputObject) + { + if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and + ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo")) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` + -ErrorId "InvalidInputObjectValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $inputValue + } + + $PSBoundParameters["Name"] = $inputValue.Name + $PSBoundParameters["RequiredVersion"] = $inputValue.Version + + $null = PackageManagement\Uninstall-Package @PSBoundParameters + } + } + else + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -TestWildcardsInName ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $null = PackageManagement\Uninstall-Package @PSBoundParameters + } + } +} + +function Get-InstalledScript +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkId=619790')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Position=0)] + [ValidateNotNullOrEmpty()] + [String[]] + $Name, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MinimumVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $RequiredVersion, + + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNull()] + [Version] + $MaximumVersion + ) + + Process + { + $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` + -Name $Name ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion ` + -RequiredVersion $RequiredVersion + + if(-not $ValidationResult) + { + # Validate-VersionParameters throws the error. + # returning to avoid further execution when different values are specified for -ErrorAction parameter + return + } + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlockForScriptCmdlets + $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript + + PackageManagement\Get-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeScript} + } +} + +#endregion *-Script cmdlets + +#region *-PSRepository cmdlets + +function Register-PSRepository +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(PositionalBinding=$false, + HelpUri='http://go.microsoft.com/fwlink/?LinkID=517129')] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Name, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $SourceLocation, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $PublishLocation, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ScriptSourceLocation, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ScriptPublishLocation, + + [Parameter()] + [ValidateSet('Trusted','Untrusted')] + [string] + $InstallationPolicy = 'Untrusted', + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $PackageManagementProvider + ) + + DynamicParam + { + if (Get-Variable -Name SourceLocation -ErrorAction SilentlyContinue) + { + Set-Variable -Name selctedProviderName -value $null -Scope 1 + + if(Get-Variable -Name PackageManagementProvider -ErrorAction SilentlyContinue) + { + $selctedProviderName = $PackageManagementProvider + $null = Get-DynamicParameters -Location $SourceLocation -PackageManagementProvider ([REF]$selctedProviderName) + } + else + { + $dynamicParameters = Get-DynamicParameters -Location $SourceLocation -PackageManagementProvider ([REF]$selctedProviderName) + Set-Variable -Name PackageManagementProvider -Value $selctedProviderName -Scope 1 + $null = $dynamicParameters + } + } + } + + Begin + { + Get-PSGalleryApiAvailability -Repository $Name + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet + + if($PackageManagementProvider) + { + $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Name -ne $script:PSModuleProviderName -and $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) } + + if (-not $providers -or $providers.Name -notcontains $PackageManagementProvider) + { + $possibleProviderNames = $script:NuGetProviderName + + if($providers) + { + $possibleProviderNames = ($providers.Name -join ',') + } + + $message = $LocalizedData.InvalidPackageManagementProviderValue -f ($PackageManagementProvider, $possibleProviderNames, $script:NuGetProviderName) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidPackageManagementProviderValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $PackageManagementProvider + return + } + } + } + + Process + { + # Ping and resolve the specified location + $SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) ` + -LocationParameterName 'SourceLocation' ` + -CallerPSCmdlet $PSCmdlet + if(-not $SourceLocation) + { + # Above Resolve-Location function throws an error when it is not able to resolve a location + return + } + + if($InstallationPolicy -eq "Trusted") + { + $PSBoundParameters.Add("Trusted", $true) + } + + $providerName = $null + + if($PackageManagementProvider) + { + $providerName = $PackageManagementProvider + } + elseif($selctedProviderName) + { + $providerName = $selctedProviderName + } + else + { + $providerName = Get-PackageManagementProviderName -Location $SourceLocation + } + + if($providerName) + { + $PSBoundParameters[$script:PackageManagementProviderParam] = $providerName + } + + if($PublishLocation) + { + $PSBoundParameters[$script:PublishLocation] = Get-LocationString -LocationUri $PublishLocation + } + + if($ScriptPublishLocation) + { + $PSBoundParameters[$script:ScriptPublishLocation] = Get-LocationString -LocationUri $ScriptPublishLocation + } + + if($ScriptSourceLocation) + { + $PSBoundParameters[$script:ScriptSourceLocation] = Get-LocationString -LocationUri $ScriptSourceLocation + } + + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + + $PSBoundParameters["Location"] = Get-LocationString -LocationUri $SourceLocation + $null = $PSBoundParameters.Remove("SourceLocation") + $null = $PSBoundParameters.Remove("InstallationPolicy") + + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + + $null = PackageManagement\Register-PackageSource @PSBoundParameters + } +} + +function Set-PSRepository +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(PositionalBinding=$false, + HelpUri='http://go.microsoft.com/fwlink/?LinkID=517128')] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Name, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $SourceLocation, + + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $PublishLocation, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ScriptSourceLocation, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ScriptPublishLocation, + + [Parameter()] + [ValidateSet('Trusted','Untrusted')] + [string] + $InstallationPolicy, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $PackageManagementProvider + ) + + DynamicParam + { + if (Get-Variable -Name Name -ErrorAction SilentlyContinue) + { + $moduleSource = Get-PSRepository -Name $Name -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + + if($moduleSource) + { + $providerName = (Get-ProviderName -PSCustomObject $moduleSource) + + $loc = $moduleSource.SourceLocation + + if(Get-Variable -Name SourceLocation -ErrorAction SilentlyContinue) + { + $loc = $SourceLocation + } + + if(Get-Variable -Name PackageManagementProvider -ErrorAction SilentlyContinue) + { + $providerName = $PackageManagementProvider + } + + $null = Get-DynamicParameters -Location $loc -PackageManagementProvider ([REF]$providerName) + } + } + } + + Begin + { + Get-PSGalleryApiAvailability -Repository $Name + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet + + if($PackageManagementProvider) + { + $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Name -ne $script:PSModuleProviderName -and $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) } + + if (-not $providers -or $providers.Name -notcontains $PackageManagementProvider) + { + $possibleProviderNames = $script:NuGetProviderName + + if($providers) + { + $possibleProviderNames = ($providers.Name -join ',') + } + + $message = $LocalizedData.InvalidPackageManagementProviderValue -f ($PackageManagementProvider, $possibleProviderNames, $script:NuGetProviderName) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidPackageManagementProviderValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $PackageManagementProvider + return + } + } + } + + Process + { + # Ping and resolve the specified location + if($SourceLocation) + { + # Ping and resolve the specified location + $SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) ` + -LocationParameterName 'SourceLocation' ` + -CallerPSCmdlet $PSCmdlet + if(-not $SourceLocation) + { + # Above Resolve-Location function throws an error when it is not able to resolve a location + return + } + } + + $ModuleSource = Get-PSRepository -Name $Name -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + + if(-not $ModuleSource) + { + $message = $LocalizedData.RepositoryNotFound -f ($Name) + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "RepositoryNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $Name + } + + if (-not $PackageManagementProvider) + { + $PackageManagementProvider = (Get-ProviderName -PSCustomObject $ModuleSource) + } + + $Trusted = $ModuleSource.Trusted + if($InstallationPolicy) + { + if($InstallationPolicy -eq "Trusted") + { + $Trusted = $true + } + else + { + $Trusted = $false + } + + $null = $PSBoundParameters.Remove("InstallationPolicy") + } + + if($PublishLocation) + { + $PSBoundParameters[$script:PublishLocation] = Get-LocationString -LocationUri $PublishLocation + } + + if($ScriptPublishLocation) + { + $PSBoundParameters[$script:ScriptPublishLocation] = Get-LocationString -LocationUri $ScriptPublishLocation + } + + if($ScriptSourceLocation) + { + $PSBoundParameters[$script:ScriptSourceLocation] = Get-LocationString -LocationUri $ScriptSourceLocation + } + + if($SourceLocation) + { + $PSBoundParameters["NewLocation"] = Get-LocationString -LocationUri $SourceLocation + + $null = $PSBoundParameters.Remove("SourceLocation") + } + + $PSBoundParameters[$script:PackageManagementProviderParam] = $PackageManagementProvider + $PSBoundParameters.Add("Trusted", $Trusted) + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + + $null = PackageManagement\Set-PackageSource @PSBoundParameters + } +} + +function Unregister-PSRepository +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=517130')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true, + Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Name + } + + Process + { + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + + $null = $PSBoundParameters.Remove("Name") + + foreach ($moduleSourceName in $Name) + { + # Check if $moduleSourceName contains any wildcards + if(Test-WildcardPattern $moduleSourceName) + { + $message = $LocalizedData.RepositoryNameContainsWildCards -f ($moduleSourceName) + Write-Error -Message $message -ErrorId "RepositoryNameContainsWildCards" -Category InvalidOperation + continue + } + + $PSBoundParameters["Source"] = $moduleSourceName + + $null = PackageManagement\Unregister-PackageSource @PSBoundParameters + } + } +} + +function Get-PSRepository +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=517127')] + Param + ( + [Parameter(ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string[]] + $Name + ) + + Begin + { + Get-PSGalleryApiAvailability -Repository $Name + } + + Process + { + $PSBoundParameters["Provider"] = $script:PSModuleProviderName + $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock + + if($Name) + { + foreach($sourceName in $Name) + { + $PSBoundParameters["Name"] = $sourceName + + $packageSources = PackageManagement\Get-PackageSource @PSBoundParameters + + $packageSources | Microsoft.PowerShell.Core\ForEach-Object { New-ModuleSourceFromPackageSource -PackageSource $_ } + } + } + else + { + $packageSources = PackageManagement\Get-PackageSource @PSBoundParameters + + $packageSources | Microsoft.PowerShell.Core\ForEach-Object { New-ModuleSourceFromPackageSource -PackageSource $_ } + } + } +} + +#endregion *-PSRepository cmdlets + +#region *-ScriptFileInfo cmdlets + +# Below is the sample PSScriptInfo in a script file. +<#PSScriptInfo + +.VERSION 1.0 + +.GUID 544238e3-1751-4065-9227-be105ff11636 + +.AUTHOR manikb + +.COMPANYNAME Microsoft Corporation + +.COPYRIGHT (c) 2015 Microsoft Corporation. All rights reserved. + +.TAGS Tag1 Tag2 Tag3 + +.LICENSEURI https://contoso.com/License + +.PROJECTURI https://contoso.com/ + +.ICONURI https://contoso.com/Icon + +.EXTERNALMODULEDEPENDENCIES ExternalModule1 + +.REQUIREDSCRIPTS Start-WFContosoServer,Stop-ContosoServerScript + +.EXTERNALSCRIPTDEPENDENCIES Stop-ContosoServerScript + +.RELEASENOTES +contoso script now supports following features +Feature 1 +Feature 2 +Feature 3 +Feature 4 +Feature 5 + +#> + +<# #Requires -Module statements #> + +<# + +.DESCRIPTION + Description goes here. + +#> + + +# +function Test-ScriptFileInfo +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(PositionalBinding=$false, + DefaultParameterSetName='PathParameterSet', + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619791')] + Param + ( + [Parameter(Mandatory=$true, + Position=0, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='PathParameterSet')] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + ParameterSetName='LiteralPathParameterSet')] + [ValidateNotNullOrEmpty()] + [string] + $LiteralPath + ) + + Process + { + $scriptFilePath = $null + if($Path) + { + $scriptFilePath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $scriptFilePath -or -not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + return + } + } + else + { + $scriptFilePath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $scriptFilePath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $scriptFilePath -PathType Leaf)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $LiteralPath ` + -ErrorCategory InvalidArgument + return + } + } + + if(-not $scriptFilePath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) + { + $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "InvalidScriptFilePath" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $scriptFilePath ` + -ErrorCategory InvalidArgument + return + } + + $PSScriptInfo = New-PSScriptInfoObject -Path $scriptFilePath + + [System.Management.Automation.Language.Token[]]$tokens = $null; + [System.Management.Automation.Language.ParseError[]]$errors = $null; + $ast = [System.Management.Automation.Language.Parser]::ParseFile($scriptFilePath, ([ref]$tokens), ([ref]$errors)) + + + $notSupportedOnNanoErrorIds = @('WorkflowNotSupportedInPowerShellCore', + 'ConfigurationNotSupportedInPowerShellCore') + $errosAfterSkippingOneCoreErrors = $errors | Microsoft.PowerShell.Core\Where-Object { $notSupportedOnNanoErrorIds -notcontains $_.ErrorId} + + if($errosAfterSkippingOneCoreErrors) + { + $errorMessage = ($LocalizedData.ScriptParseError -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "ScriptParseError" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $errosAfterSkippingOneCoreErrors ` + -ErrorCategory InvalidArgument + return + } + + if($ast) + { + # Get the block/group comment begining with <#PSScriptInfo + $CommentTokens = $tokens | Microsoft.PowerShell.Core\Where-Object {$_.Kind -eq 'Comment'} + + $psscriptInfoComments = $CommentTokens | + Microsoft.PowerShell.Core\Where-Object { $_.Extent.Text -match "<#PSScriptInfo" } | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $psscriptInfoComments) + { + $errorMessage = ($LocalizedData.MissingPSScriptInfo -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "MissingPSScriptInfo" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $scriptFilePath ` + -ErrorCategory InvalidArgument + return + } + + # $psscriptInfoComments.Text will have the multiline PSScriptInfo comment, + # split them into multiple lines to parse for the PSScriptInfo metadata properties. + $commentLines = $psscriptInfoComments.Text -split "`r`n" + + $KeyName = $null + $Value = "" + + # PSScriptInfo comment will be in following format: + <#PSScriptInfo + + .VERSION 1.0 + + .GUID 544238e3-1751-4065-9227-be105ff11636 + + .AUTHOR manikb + + .COMPANYNAME Microsoft Corporation + + .COPYRIGHT (c) 2015 Microsoft Corporation. All rights reserved. + + .TAGS Tag1 Tag2 Tag3 + + .LICENSEURI https://contoso.com/License + + .PROJECTURI https://contoso.com/ + + .ICONURI https://contoso.com/Icon + + .EXTERNALMODULEDEPENDENCIES ExternalModule1 + + .REQUIREDSCRIPTS Start-WFContosoServer,Stop-ContosoServerScript + + .EXTERNALSCRIPTDEPENDENCIES Stop-ContosoServerScript + + .RELEASENOTES + contoso script now supports following features + Feature 1 + Feature 2 + Feature 3 + Feature 4 + Feature 5 + + #> + # If comment line count is not more than two, it doesn't have the any metadata property + # First line is <#PSScriptInfo + # Last line #> + # + if($commentLines.Count -gt 2) + { + for($i = 1; $i -lt ($commentLines.count - 1); $i++) + { + $line = $commentLines[$i] + + if(-not $line) + { + continue + } + + # A line is starting with . conveys a new metadata property + # __NEWLINE__ is used for replacing the value lines while adding the value to $PSScriptInfo object + # + if($line.trim().StartsWith('.')) + { + $parts = $line.trim() -split '[.\s+]',3 | Microsoft.PowerShell.Core\Where-Object {$_} + + if($KeyName -and $Value) + { + if($keyName -eq $script:ReleaseNotes) + { + $Value = $Value.Trim() -split '__NEWLINE__' + } + elseif($keyName -eq $script:DESCRIPTION) + { + $Value = $Value -split '__NEWLINE__' + $Value = ($Value -join "`r`n").Trim() + } + else + { + $Value = $Value -split '__NEWLINE__' | Microsoft.PowerShell.Core\Where-Object { $_ } + + if($Value -and $Value.GetType().ToString() -eq "System.String") + { + $Value = $Value.Trim() + } + } + + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $KeyName ` + -PropertyValue $Value ` + -CallerPSCmdlet $PSCmdlet + } + + $KeyName = $null + $Value = "" + + if($parts.GetType().ToString() -eq "System.String") + { + $KeyName = $parts + } + else + { + $KeyName = $parts[0]; + $Value = $parts[1] + } + } + else + { + if($Value) + { + # __NEWLINE__ is used for replacing the value lines while adding the value to $PSScriptInfo object + $Value += '__NEWLINE__' + } + + $Value += $line + } + } + + if($KeyName -and $Value) + { + if($keyName -eq $script:ReleaseNotes) + { + $Value = $Value.Trim() -split '__NEWLINE__' + } + elseif($keyName -eq $script:DESCRIPTION) + { + $Value = $Value -split '__NEWLINE__' + $Value = ($Value -join "`r`n").Trim() + } + else + { + $Value = $Value -split '__NEWLINE__' | Microsoft.PowerShell.Core\Where-Object { $_ } + + if($Value -and $Value.GetType().ToString() -eq "System.String") + { + $Value = $Value.Trim() + } + } + + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $KeyName ` + -PropertyValue $Value ` + -CallerPSCmdlet $PSCmdlet + + $KeyName = $null + $Value = "" + } + } + + $helpContent = $ast.GetHelpContent() + if($helpContent -and $helpContent.Description) + { + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $script:DESCRIPTION ` + -PropertyValue $helpContent.Description.Trim() ` + -CallerPSCmdlet $PSCmdlet + + } + + # Handle RequiredModules + if((Microsoft.PowerShell.Utility\Get-Member -InputObject $ast -Name 'ScriptRequirements') -and + $ast.ScriptRequirements -and + (Microsoft.PowerShell.Utility\Get-Member -InputObject $ast.ScriptRequirements -Name 'RequiredModules') -and + $ast.ScriptRequirements.RequiredModules) + { + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $script:RequiredModules ` + -PropertyValue $ast.ScriptRequirements.RequiredModules ` + -CallerPSCmdlet $PSCmdlet + } + + # Get all defined functions and populate DefinedCommands, DefinedFunctions and DefinedWorkflows + $allCommands = $ast.FindAll({param($i) return ($i.GetType().Name -eq 'FunctionDefinitionAst')}, $true) + + if($allCommands) + { + $allCommandNames = $allCommands | ForEach-Object {$_.Name} | Select-Object -Unique + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $script:DefinedCommands ` + -PropertyValue $allCommandNames ` + -CallerPSCmdlet $PSCmdlet + + $allFunctionNames = $allCommands | Where-Object {-not $_.IsWorkflow} | ForEach-Object {$_.Name} | Select-Object -Unique + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $script:DefinedFunctions ` + -PropertyValue $allFunctionNames ` + -CallerPSCmdlet $PSCmdlet + + + $allWorkflowNames = $allCommands | Where-Object {$_.IsWorkflow} | ForEach-Object {$_.Name} | Select-Object -Unique + ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` + -PropertyName $script:DefinedWorkflows ` + -PropertyValue $allWorkflowNames ` + -CallerPSCmdlet $PSCmdlet + } + } + + # Ensure that the script file has the required metadata properties. + if(-not $PSScriptInfo.Version -or -not $PSScriptInfo.Guid -or -not $PSScriptInfo.Author -or -not $PSScriptInfo.Description) + { + $errorMessage = ($LocalizedData.MissingRequiredPSScriptInfoProperties -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "MissingRequiredPSScriptInfoProperties" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + return + } + + $PSScriptInfo = Get-OrderedPSScriptInfoObject -PSScriptInfo $PSScriptInfo + + return $PSScriptInfo + } +} + +function New-ScriptFileInfo +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(PositionalBinding=$false, + SupportsShouldProcess=$true, + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619792')] + Param + ( + [Parameter(Mandatory=$false, + Position=0, + ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $Version, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Author, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Description, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Guid] + $Guid, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String] + $CompanyName, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Copyright, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Object[]] + $RequiredModules, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $ExternalModuleDependencies, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $RequiredScripts, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $ExternalScriptDependencies, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Tags, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ProjectUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $LicenseUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $IconUri, + + [Parameter()] + [string[]] + $ReleaseNotes, + + [Parameter()] + [switch] + $PassThru, + + [Parameter()] + [switch] + $Force + ) + + Process + { + if($Path) + { + if(-not $Path.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) + { + $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $Path) + ThrowError -ExceptionName 'System.ArgumentException' ` + -ExceptionMessage $errorMessage ` + -ErrorId 'InvalidScriptFilePath' ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + return + } + + if(-not $Force -and (Microsoft.PowerShell.Management\Test-Path -Path $Path)) + { + $errorMessage = ($LocalizedData.ScriptFileExist -f $Path) + ThrowError -ExceptionName 'System.ArgumentException' ` + -ExceptionMessage $errorMessage ` + -ErrorId 'ScriptFileExist' ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + return + } + } + elseif(-not $PassThru) + { + ThrowError -ExceptionName 'System.ArgumentException' ` + -ExceptionMessage $LocalizedData.MissingTheRequiredPathOrPassThruParameter ` + -ErrorId 'MissingTheRequiredPathOrPassThruParameter' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + if(-not $Version) + { + $Version = [Version]'1.0' + } + + if(-not $Author) + { + $Author = (Get-EnvironmentVariable -Name 'USERNAME' -Target $script:EnvironmentVariableTarget.Process -ErrorAction SilentlyContinue) + } + + if(-not $Guid) + { + $Guid = [System.Guid]::NewGuid() + } + + $params = @{ + Version = $Version + Author = $Author + Guid = $Guid + CompanyName = $CompanyName + Copyright = $Copyright + ExternalModuleDependencies = $ExternalModuleDependencies + RequiredScripts = $RequiredScripts + ExternalScriptDependencies = $ExternalScriptDependencies + Tags = $Tags + ProjectUri = $ProjectUri + LicenseUri = $LicenseUri + IconUri = $IconUri + ReleaseNotes = $ReleaseNotes + } + + if(-not (Validate-ScriptFileInfoParameters -parameters $params)) + { + return + } + + if("$Description" -match '<#' -or "$Description" -match '#>') + { + $message = $LocalizedData.InvalidParameterValue -f ($Description, 'Description') + Write-Error -Message $message -ErrorId 'InvalidParameterValue' -Category InvalidArgument + + return + } + + $PSScriptInfoString = Get-PSScriptInfoString @params + + $requiresStrings = Get-RequiresString -RequiredModules $RequiredModules + + $ScriptCommentHelpInfoString = Get-ScriptCommentHelpInfoString -Description $Description + + $ScriptMetadataString = $PSScriptInfoString + $ScriptMetadataString += "`r`n" + + if("$requiresStrings".Trim()) + { + $ScriptMetadataString += "`r`n" + $ScriptMetadataString += $requiresStrings -join "`r`n" + $ScriptMetadataString += "`r`n" + } + + $ScriptMetadataString += "`r`n" + $ScriptMetadataString += $ScriptCommentHelpInfoString + $ScriptMetadataString += "Param()`r`n`r`n" + + $tempScriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $env:TEMP -ChildPath "$(Get-Random).ps1" + + try + { + Microsoft.PowerShell.Management\Set-Content -Value $ScriptMetadataString -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false + + $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath + + if(-not $scriptInfo) + { + # Above Test-ScriptFileInfo cmdlet writes the errors + return + } + + if($Path -and ($Force -or $PSCmdlet.ShouldProcess($Path, ($LocalizedData.NewScriptFileInfowhatIfMessage -f $Path) ))) + { + Microsoft.PowerShell.Management\Copy-Item -Path $tempScriptFilePath -Destination $Path -Force -WhatIf:$false -Confirm:$false + } + + if($PassThru) + { + Write-Output -InputObject $ScriptMetadataString + } + } + finally + { + Microsoft.PowerShell.Management\Remove-Item -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + } + } +} + +function Update-ScriptFileInfo +{ + <# + .ExternalHelp PSGet.psm1-help.xml + #> + [CmdletBinding(PositionalBinding=$false, + DefaultParameterSetName='PathParameterSet', + SupportsShouldProcess=$true, + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619793')] + Param + ( + [Parameter(Mandatory=$true, + Position=0, + ParameterSetName='PathParameterSet', + ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [Parameter(Mandatory=$true, + Position=0, + ParameterSetName='LiteralPathParameterSet', + ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string] + $LiteralPath, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $Version, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Author, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Guid] + $Guid, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Description, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String] + $CompanyName, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Copyright, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Object[]] + $RequiredModules, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $ExternalModuleDependencies, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $RequiredScripts, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $ExternalScriptDependencies, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Tags, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ProjectUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $LicenseUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $IconUri, + + [Parameter()] + [string[]] + $ReleaseNotes, + + [Parameter()] + [switch] + $PassThru, + + [Parameter()] + [switch] + $Force + ) + + Process + { + $scriptFilePath = $null + if($Path) + { + $scriptFilePath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $scriptFilePath -or + -not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $Path ` + -ErrorCategory InvalidArgument + } + } + else + { + $scriptFilePath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $scriptFilePath -or + -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $scriptFilePath -PathType Leaf)) + { + $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $LiteralPath ` + -ErrorCategory InvalidArgument + } + } + + if(-not $scriptFilePath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) + { + $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "InvalidScriptFilePath" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $scriptFilePath ` + -ErrorCategory InvalidArgument + return + } + + $psscriptInfo = $null + try + { + $psscriptInfo = Test-ScriptFileInfo -LiteralPath $scriptFilePath + } + catch + { + if(-not $Force) + { + throw $_ + return + } + } + + if(-not $psscriptInfo) + { + if(-not $Description) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.DescriptionParameterIsMissingForAddingTheScriptFileInfo ` + -ErrorId 'DescriptionParameterIsMissingForAddingTheScriptFileInfo' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + if(-not $Version) + { + $Version = [Version]'1.0' + } + + if(-not $Author) + { + $Author = (Get-EnvironmentVariable -Name 'USERNAME' -Target $script:EnvironmentVariableTarget.Process -ErrorAction SilentlyContinue) + } + + if(-not $Guid) + { + $Guid = [System.Guid]::NewGuid() + } + } + else + { + # Use existing values if any of the parameters are not specified during Update-ScriptFileInfo + if(-not $Version -and $psscriptInfo.Version) + { + $Version = $psscriptInfo.Version + } + + if(-not $Guid -and $psscriptInfo.Guid) + { + $Guid = $psscriptInfo.Guid + } + + if(-not $Author -and $psscriptInfo.Author) + { + $Author = $psscriptInfo.Author + } + + if(-not $CompanyName -and $psscriptInfo.CompanyName) + { + $CompanyName = $psscriptInfo.CompanyName + } + + if(-not $Copyright -and $psscriptInfo.Copyright) + { + $Copyright = $psscriptInfo.Copyright + } + + if(-not $RequiredModules -and $psscriptInfo.RequiredModules) + { + $RequiredModules = $psscriptInfo.RequiredModules + } + + if(-not $ExternalModuleDependencies -and $psscriptInfo.ExternalModuleDependencies) + { + $ExternalModuleDependencies = $psscriptInfo.ExternalModuleDependencies + } + + if(-not $RequiredScripts -and $psscriptInfo.RequiredScripts) + { + $RequiredScripts = $psscriptInfo.RequiredScripts + } + + if(-not $ExternalScriptDependencies -and $psscriptInfo.ExternalScriptDependencies) + { + $ExternalScriptDependencies = $psscriptInfo.ExternalScriptDependencies + } + + if(-not $Tags -and $psscriptInfo.Tags) + { + $Tags = $psscriptInfo.Tags + } + + if(-not $ProjectUri -and $psscriptInfo.ProjectUri) + { + $ProjectUri = $psscriptInfo.ProjectUri + } + + if(-not $LicenseUri -and $psscriptInfo.LicenseUri) + { + $LicenseUri = $psscriptInfo.LicenseUri + } + + if(-not $IconUri -and $psscriptInfo.IconUri) + { + $IconUri = $psscriptInfo.IconUri + } + + if(-not $ReleaseNotes -and $psscriptInfo.ReleaseNotes) + { + $ReleaseNotes = $psscriptInfo.ReleaseNotes + } + } + + $params = @{ + Version = $Version + Author = $Author + Guid = $Guid + CompanyName = $CompanyName + Copyright = $Copyright + ExternalModuleDependencies = $ExternalModuleDependencies + RequiredScripts = $RequiredScripts + ExternalScriptDependencies = $ExternalScriptDependencies + Tags = $Tags + ProjectUri = $ProjectUri + LicenseUri = $LicenseUri + IconUri = $IconUri + ReleaseNotes = $ReleaseNotes + } + + if(-not (Validate-ScriptFileInfoParameters -parameters $params)) + { + return + } + + if("$Description" -match '<#' -or "$Description" -match '#>') + { + $message = $LocalizedData.InvalidParameterValue -f ($Description, 'Description') + Write-Error -Message $message -ErrorId 'InvalidParameterValue' -Category InvalidArgument + + return + } + + $PSScriptInfoString = Get-PSScriptInfoString @params + + $requiresStrings = "" + $requiresStrings = Get-RequiresString -RequiredModules $RequiredModules + + $DescriptionValue = if($Description) {$Description} else {$psscriptInfo.Description} + $ScriptCommentHelpInfoString = Get-ScriptCommentHelpInfoString -Description $DescriptionValue + + $ScriptMetadataString = $PSScriptInfoString + $ScriptMetadataString += "`r`n" + + if("$requiresStrings".Trim()) + { + $ScriptMetadataString += "`r`n" + $ScriptMetadataString += $requiresStrings -join "`r`n" + $ScriptMetadataString += "`r`n" + } + + $ScriptMetadataString += "`r`n" + $ScriptMetadataString += $ScriptCommentHelpInfoString + $ScriptMetadataString += "`r`nParam()`r`n`r`n" + if(-not $ScriptMetadataString) + { + return + } + + $tempScriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $env:TEMP -ChildPath "$(Get-Random).ps1" + + try + { + # First create a new script file with new script metadata to ensure that updated values are valid. + Microsoft.PowerShell.Management\Set-Content -Value $ScriptMetadataString -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false + + $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath + + if(-not $scriptInfo) + { + # Above Test-ScriptFileInfo cmdlet writes the error + return + } + + $scriptFileContents = Microsoft.PowerShell.Management\Get-Content -LiteralPath $scriptFilePath + + # If -Force is specified and script file doesnt have a valid PSScriptInfo + # Prepend the PSScriptInfo and Check if the Test-ScriptFileInfo returns a valid script info without any errors + if($Force -and -not $psscriptInfo) + { + # Add the script file contents to the temp file with script metadata + Microsoft.PowerShell.Management\Set-Content -LiteralPath $tempScriptFilePath ` + -Value $ScriptMetadataString,$scriptFileContents ` + -Force ` + -WhatIf:$false ` + -Confirm:$false + + $tempScriptInfo = $null + try + { + $tempScriptInfo = Test-ScriptFileInfo -LiteralPath $tempScriptFilePath + } + catch + { + $errorMessage = ($LocalizedData.UnableToAddPSScriptInfo -f $scriptFilePath) + ThrowError -ExceptionName 'System.InvalidOperationException' ` + -ExceptionMessage $errorMessage ` + -ErrorId 'UnableToAddPSScriptInfo' ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $scriptFilePath ` + -ErrorCategory InvalidOperation + return + } + } + else + { + [System.Management.Automation.Language.Token[]]$tokens = $null; + [System.Management.Automation.Language.ParseError[]]$errors = $null; + $ast = [System.Management.Automation.Language.Parser]::ParseFile($scriptFilePath, ([ref]$tokens), ([ref]$errors)) + + # Update PSScriptInfo and #Requires + $CommentTokens = $tokens | Microsoft.PowerShell.Core\Where-Object {$_.Kind -eq 'Comment'} + + $psscriptInfoComments = $CommentTokens | + Microsoft.PowerShell.Core\Where-Object { $_.Extent.Text -match "<#PSScriptInfo" } | + Microsoft.PowerShell.Utility\Select-Object -First 1 + + if(-not $psscriptInfoComments) + { + $errorMessage = ($LocalizedData.MissingPSScriptInfo -f $scriptFilePath) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "MissingPSScriptInfo" ` + -CallerPSCmdlet $PSCmdlet ` + -ExceptionObject $scriptFilePath ` + -ErrorCategory InvalidArgument + return + } + + # Ensure that metadata is replaced at the correct location and should not corrupt the existing script file. + + # Remove the lines between below lines and add the new PSScriptInfo and new #Requires statements + # ($psscriptInfoComments.Extent.StartLineNumber - 1) + # ($psscriptInfoComments.Extent.EndLineNumber - 1) + $tempContents = @() + $IsNewPScriptInfoAdded = $false + + for($i = 0; $i -lt $scriptFileContents.Count; $i++) + { + $line = $scriptFileContents[$i] + if(($i -ge ($psscriptInfoComments.Extent.StartLineNumber - 1)) -and + ($i -le ($psscriptInfoComments.Extent.EndLineNumber - 1))) + { + if(-not $IsNewPScriptInfoAdded) + { + $PSScriptInfoString = $PSScriptInfoString.TrimStart() + $requiresStrings = $requiresStrings.TrimEnd() + + $tempContents += "$PSScriptInfoString `r`n`r`n$($requiresStrings -join "`r`n")" + $IsNewPScriptInfoAdded = $true + } + } + elseif($line -notmatch "\s*#Requires\s+-Module") + { + # Add the existing lines if they are not part of PSScriptInfo comment or not containing #Requires -Module statements. + $tempContents += $line + } + } + + Microsoft.PowerShell.Management\Set-Content -Value $tempContents -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false + + $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath + + if(-not $scriptInfo) + { + # Above Test-ScriptFileInfo cmdlet writes the error + return + } + + # Now update the Description value if a new is specified. + if($Description) + { + $tempContents = @() + $IsDescriptionAdded = $false + + $IsDescriptionBeginFound = $false + $scriptFileContents = Microsoft.PowerShell.Management\Get-Content -Path $tempScriptFilePath + + for($i = 0; $i -lt $scriptFileContents.Count; $i++) + { + $line = $scriptFileContents[$i] + + if(-not $IsDescriptionAdded) + { + if(-not $IsDescriptionBeginFound) + { + if($line.Trim().StartsWith(".DESCRIPTION", [System.StringComparison]::OrdinalIgnoreCase)) + { + $IsDescriptionBeginFound = $true + } + else + { + $tempContents += $line + } + } + else + { + # Description begin has found + # Skip the old description lines until description end is found + + if($line.Trim().StartsWith("#>", [System.StringComparison]::OrdinalIgnoreCase) -or + $line.Trim().StartsWith(".", [System.StringComparison]::OrdinalIgnoreCase)) + { + $tempContents += ".DESCRIPTION `r`n$($Description -join "`r`n")`r`n" + $IsDescriptionAdded = $true + $tempContents += $line + } + } + } + else + { + $tempContents += $line + } + } + + Microsoft.PowerShell.Management\Set-Content -Value $tempContents -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false + + $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath + + if(-not $scriptInfo) + { + # Above Test-ScriptFileInfo cmdlet writes the error + return + } + } + } + + if($Force -or $PSCmdlet.ShouldProcess($scriptFilePath, ($LocalizedData.UpdateScriptFileInfowhatIfMessage -f $Path) )) + { + Microsoft.PowerShell.Management\Copy-Item -Path $tempScriptFilePath -Destination $scriptFilePath -Force -WhatIf:$false -Confirm:$false + + if($PassThru) + { + $ScriptMetadataString + } + } + } + finally + { + Microsoft.PowerShell.Management\Remove-Item -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + } + } +} + +function Get-RequiresString +{ + [CmdletBinding()] + Param + ( + [Parameter()] + [Object[]] + $RequiredModules + ) + + Process + { + if($RequiredModules) + { + $RequiredModuleStrings = @() + + foreach($requiredModuleObject in $RequiredModules) + { + if($requiredModuleObject.GetType().ToString() -eq 'System.Collections.Hashtable') + { + if(($requiredModuleObject.Keys.Count -eq 1) -and + (Microsoft.PowerShell.Utility\Get-Member -InputObject $requiredModuleObject -Name 'ModuleName')) + { + $RequiredModuleStrings += $requiredModuleObject['ModuleName'].ToString() + } + else + { + $moduleSpec = New-Object Microsoft.PowerShell.Commands.ModuleSpecification -ArgumentList $requiredModuleObject + if (-not (Microsoft.PowerShell.Utility\Get-Variable -Name moduleSpec -ErrorAction SilentlyContinue)) + { + return + } + + $keyvalueStrings = $requiredModuleObject.Keys | Microsoft.PowerShell.Core\ForEach-Object {"$_ = '$( $requiredModuleObject[$_])'"} + $RequiredModuleStrings += "@{$($keyvalueStrings -join '; ')}" + } + } + elseif(($PSVersionTable.PSVersion -eq [Version]'3.0') -and + ($requiredModuleObject.GetType().ToString() -eq 'Microsoft.PowerShell.Commands.ModuleSpecification')) + { + # ModuleSpecification.ToString() is not implemented on PowerShell 3.0. + + $optionalString = " " + + if($requiredModuleObject.Version) + { + $optionalString += "ModuleVersion = '$($requiredModuleObject.Version.ToString())'; " + } + + if($requiredModuleObject.Guid) + { + $optionalString += "Guid = '$($requiredModuleObject.Guid.ToString())'; " + } + + if($optionalString.Trim()) + { + $moduleSpecString = "@{ ModuleName = '$($requiredModuleObject.Name.ToString())';$optionalString}" + } + else + { + $moduleSpecString = $requiredModuleObject.Name.ToString() + } + + $RequiredModuleStrings += $moduleSpecString + } + else + { + $RequiredModuleStrings += $requiredModuleObject.ToString() + } + } + + $hashRequiresStrings = $RequiredModuleStrings | + Microsoft.PowerShell.Core\ForEach-Object { "#Requires -Module $_" } + + return $hashRequiresStrings + } + else + { + return "" + } + } +} + +function Get-PSScriptInfoString +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Version] + $Version, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Guid] + $Guid, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Author, + + [Parameter()] + [String] + $CompanyName, + + [Parameter()] + [string] + $Copyright, + + [Parameter()] + [String[]] + $ExternalModuleDependencies, + + [Parameter()] + [string[]] + $RequiredScripts, + + [Parameter()] + [String[]] + $ExternalScriptDependencies, + + [Parameter()] + [string[]] + $Tags, + + [Parameter()] + [Uri] + $ProjectUri, + + [Parameter()] + [Uri] + $LicenseUri, + + [Parameter()] + [Uri] + $IconUri, + + [Parameter()] + [string[]] + $ReleaseNotes + ) + + Process + { + $PSScriptInfoString = @" + +<#PSScriptInfo + +.VERSION $Version + +.GUID $Guid + +.AUTHOR $Author + +.COMPANYNAME $CompanyName + +.COPYRIGHT $Copyright + +.TAGS $Tags + +.LICENSEURI $LicenseUri + +.PROJECTURI $ProjectUri + +.ICONURI $IconUri + +.EXTERNALMODULEDEPENDENCIES $($ExternalModuleDependencies -join ',') + +.REQUIREDSCRIPTS $($RequiredScripts -join ',') + +.EXTERNALSCRIPTDEPENDENCIES $($ExternalScriptDependencies -join ',') + +.RELEASENOTES +$($ReleaseNotes -join "`r`n") + +#> +"@ + return $PSScriptInfoString + } +} + +function Validate-ScriptFileInfoParameters +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [PSCustomObject] + $Parameters + ) + + $hasErrors = $false + + $Parameters.Keys | ForEach-Object { + + $parameterName = $_ + + $parameterValue = $($Parameters[$parameterName]) + + if("$parameterValue" -match '<#' -or "$parameterValue" -match '#>') + { + $message = $LocalizedData.InvalidParameterValue -f ($parameterValue, $parameterName) + Write-Error -Message $message -ErrorId 'InvalidParameterValue' -Category InvalidArgument + + $hasErrors = $true + } + } + + return (-not $hasErrors) +} + +function Get-ScriptCommentHelpInfoString +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Description, + + [Parameter()] + [string] + $Synopsis, + + [Parameter()] + [string[]] + $Example, + + [Parameter()] + [string[]] + $Inputs, + + [Parameter()] + [string[]] + $Outputs, + + [Parameter()] + [string[]] + $Notes, + + [Parameter()] + [string[]] + $Link, + + [Parameter()] + [string] + $Component, + + [Parameter()] + [string] + $Role, + + [Parameter()] + [string] + $Functionality + ) + + Process + { + $ScriptCommentHelpInfoString = "<# `r`n`r`n.DESCRIPTION `r`n $Description `r`n`r`n" + + if("$Synopsis".Trim()) + { + $ScriptCommentHelpInfoString += ".SYNOPSIS `r`n$Synopsis `r`n`r`n" + } + + if("$Example".Trim()) + { + $Example | ForEach-Object { + if($_) + { + $ScriptCommentHelpInfoString += ".EXAMPLE `r`n$_ `r`n`r`n" + } + } + } + + if("$Inputs".Trim()) + { + $Inputs | ForEach-Object { + if($_) + { + $ScriptCommentHelpInfoString += ".INPUTS `r`n$_ `r`n`r`n" + } + } + } + + if("$Outputs".Trim()) + { + $Outputs | ForEach-Object { + if($_) + { + $ScriptCommentHelpInfoString += ".OUTPUTS `r`n$_ `r`n`r`n" + } + } + } + + if("$Notes".Trim()) + { + $ScriptCommentHelpInfoString += ".NOTES `r`n$($Notes -join "`r`n") `r`n`r`n" + } + + if("$Link".Trim()) + { + $Link | ForEach-Object { + if($_) + { + $ScriptCommentHelpInfoString += ".LINK `r`n$_ `r`n`r`n" + } + } + } + + if("$Component".Trim()) + { + $ScriptCommentHelpInfoString += ".COMPONENT `r`n$($Component -join "`r`n") `r`n`r`n" + } + + if("$Role".Trim()) + { + $ScriptCommentHelpInfoString += ".ROLE `r`n$($Role -join "`r`n") `r`n`r`n" + } + + if("$Functionality".Trim()) + { + $ScriptCommentHelpInfoString += ".FUNCTIONALITY `r`n$($Functionality -join "`r`n") `r`n`r`n" + } + + $ScriptCommentHelpInfoString += "#> `r`n" + + return $ScriptCommentHelpInfoString + } +} + +#endregion *-ScriptFileInfo cmdlets + +#region Utility functions +function ToUpper +{ + param([string]$str) + return $script:TextInfo.ToUpper($str) +} + +function Resolve-PathHelper +{ + param + ( + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $path, + + [Parameter()] + [switch] + $isLiteralPath, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $callerPSCmdlet + ) + + $resolvedPaths =@() + + foreach($currentPath in $path) + { + try + { + if($isLiteralPath) + { + $currentResolvedPaths = Microsoft.PowerShell.Management\Resolve-Path -LiteralPath $currentPath -ErrorAction Stop + } + else + { + $currentResolvedPaths = Microsoft.PowerShell.Management\Resolve-Path -Path $currentPath -ErrorAction Stop + } + } + catch + { + $errorMessage = ($LocalizedData.PathNotFound -f $currentPath) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $errorMessage ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $callerPSCmdlet ` + -ErrorCategory InvalidOperation + } + + foreach($currentResolvedPath in $currentResolvedPaths) + { + $resolvedPaths += $currentResolvedPath.ProviderPath + } + } + + $resolvedPaths +} + +function Check-PSGalleryApiAvailability +{ + param + ( + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $PSGalleryV2ApiUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $PSGalleryV3ApiUri + ) + + # check internet availability first + $connected = $false + if(Get-Command Microsoft.PowerShell.Management\Test-Connection -ErrorAction SilentlyContinue) + { + $connected = Microsoft.PowerShell.Management\Test-Connection -ComputerName "www.microsoft.com" -Count 1 -Quiet + } + else + { + $connected = NetTCPIP\Test-NetConnection -ComputerName "www.microsoft.com" -InformationLevel Quiet + } + if ( -not $connected) + { + return + } + + $statusCode_v2 = $null + $resolvedUri_v2 = $null + $statusCode_v3 = $null + $resolvedUri_v3 = $null + + # ping V2 + $res_v2 = Ping-Endpoint -Endpoint $PSGalleryV2ApiUri + if ($res_v2.ContainsKey($Script:ResponseUri)) + { + $resolvedUri_v2 = $res_v2[$Script:ResponseUri] + } + if ($res_v2.ContainsKey($Script:StatusCode)) + { + $statusCode_v2 = $res_v2[$Script:StatusCode] + } + + + # ping V3 + $res_v3 = Ping-Endpoint -Endpoint $PSGalleryV3ApiUri + if ($res_v3.ContainsKey($Script:ResponseUri)) + { + $resolvedUri_v3 = $res_v3[$Script:ResponseUri] + } + if ($res_v3.ContainsKey($Script:StatusCode)) + { + $statusCode_v3 = $res_v3[$Script:StatusCode] + } + + + $Script:PSGalleryV2ApiAvailable = (($statusCode_v2 -eq 200) -and ($resolvedUri_v2)) + $Script:PSGalleryV3ApiAvailable = (($statusCode_v3 -eq 200) -and ($resolvedUri_v3)) + $Script:PSGalleryApiChecked = $true +} + +function Get-PSGalleryApiAvailability +{ + param + ( + [Parameter()] + [string[]] + $Repository + ) + + # skip if repository is null or not PSGallery + if ( -not $Repository) + { + return + } + + if ($Repository -notcontains $Script:PSGalleryModuleSource ) + { + return + } + + # run check only once + if( -not $Script:PSGalleryApiChecked) + { + $null = Check-PSGalleryApiAvailability -PSGalleryV2ApiUri $Script:PSGallerySourceUri -PSGalleryV3ApiUri $Script:PSGalleryV3SourceUri + } + + if ( -not $Script:PSGalleryV2ApiAvailable ) + { + if ($Script:PSGalleryV3ApiAvailable) + { + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $LocalizedData.PSGalleryApiV2Discontinued ` + -ErrorId "PSGalleryApiV2Discontinued" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + else + { + # both APIs are down, throw error + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $LocalizedData.PowerShellGalleryUnavailable ` + -ErrorId "PowerShellGalleryUnavailable" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + + } + else + { + if ($Script:PSGalleryV3ApiAvailable) + { + Write-Warning -Message $LocalizedData.PSGalleryApiV2Deprecated + return + } + } + + # if V2 is available and V3 is not available, do nothing +} + +function HttpClientApisAvailable +{ + $HttpClientApisAvailable = $false + try + { + [System.Net.Http.HttpClient] + $HttpClientApisAvailable = $true + } + catch + { + } + return $HttpClientApisAvailable +} + +function Ping-Endpoint +{ + param + ( + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Endpoint, + + [Parameter()] + [switch] + $AllowAutoRedirect = $true + ) + + $results = @{} + + if(HttpClientApisAvailable) + { + $response = $null + try + { + $handler = New-Object System.Net.Http.HttpClientHandler + $handler.UseDefaultCredentials = $true + $httpClient = New-Object System.Net.Http.HttpClient -ArgumentList $handler + $response = $httpclient.GetAsync($endpoint) + } + catch + { + } + + if ($response -ne $null -and $response.result -ne $null) + { + $results.Add($Script:ResponseUri,$response.Result.RequestMessage.RequestUri.AbsoluteUri.ToString()) + $results.Add($Script:StatusCode,$response.result.StatusCode.value__) + } + } + else + { + $iss = [System.Management.Automation.Runspaces.InitialSessionState]::Create() + $iss.types.clear() + $iss.formats.clear() + $iss.LanguageMode = "FullLanguage" + + $WebRequestcmd = @' + try + {{ + $request = [System.Net.WebRequest]::Create("{0}") + $request.Method = 'GET' + $request.Timeout = 30000 + $request.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials + $request.AllowAutoRedirect = ${1} + $response = [System.Net.HttpWebResponse]$request.GetResponse() + if($response.StatusCode.value__ -eq 302) + {{ + $response.Headers["Location"].ToString() + }} + else + {{ + $response + }} + $response.Close() + }} + catch [System.Net.WebException] + {{ + "Error:System.Net.WebException" + }} +'@ -f $EndPoint, $AllowAutoRedirect + + $ps = [powershell]::Create($iss).AddScript($WebRequestcmd) + $response = $ps.Invoke() + $ps.dispose() + if ($response -ne "Error:System.Net.WebException") + { + if($AllowAutoRedirect) + { + $results.Add($Script:ResponseUri,$response.ResponseUri.ToString()) + $results.Add($Script:StatusCode,$response.StatusCode.value__) + } + else + { + $results.Add($Script:ResponseUri,[String]$response) + } + } + } + return $results +} + +function Validate-VersionParameters +{ + Param( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet, + + [Parameter()] + [String[]] + $Name, + + [Parameter()] + [Version] + $MinimumVersion, + + [Parameter()] + [Version] + $RequiredVersion, + + [Parameter()] + [Version] + $MaximumVersion, + + [Parameter()] + [Switch] + $AllVersions, + + [Parameter()] + [Switch] + $TestWildcardsInName + ) + + if($TestWildcardsInName -and $Name -and (Test-WildcardPattern -Name "$Name")) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage ($LocalizedData.NameShouldNotContainWildcardCharacters -f "$($Name -join ',')") ` + -ErrorId 'NameShouldNotContainWildcardCharacters' ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + } + elseif($AllVersions -and ($RequiredVersion -or $MinimumVersion -or $MaximumVersion)) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.AllVersionsCannotBeUsedWithOtherVersionParameters ` + -ErrorId 'AllVersionsCannotBeUsedWithOtherVersionParameters' ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument + } + elseif($RequiredVersion -and ($MinimumVersion -or $MaximumVersion)) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.VersionRangeAndRequiredVersionCannotBeSpecifiedTogether ` + -ErrorId "VersionRangeAndRequiredVersionCannotBeSpecifiedTogether" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument + } + elseif($MinimumVersion -and $MaximumVersion -and ($MinimumVersion -gt $MaximumVersion)) + { + $Message = $LocalizedData.MinimumVersionIsGreaterThanMaximumVersion -f ($MinimumVersion, $MaximumVersion) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $Message ` + -ErrorId "MinimumVersionIsGreaterThanMaximumVersion" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument + } + elseif($AllVersions -or $RequiredVersion -or $MinimumVersion -or $MaximumVersion) + { + if(-not $Name -or $Name.Count -ne 1 -or (Test-WildcardPattern -Name $Name[0])) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.VersionParametersAreAllowedOnlyWithSingleName ` + -ErrorId "VersionParametersAreAllowedOnlyWithSingleName" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument + } + } + + return $true +} + +function ValidateAndSet-PATHVariableIfUserAccepts +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [string] + $Scope, + + [Parameter(Mandatory=$true)] + [string] + $ScopePath, + + [Parameter()] + [Switch] + $NoPathUpdate, + + [Parameter()] + [Switch] + $Force, + + [Parameter()] + $Request + ) + + Set-PSGetSettingsVariable + + # Check and add the scope path to PATH environment variable if USER accepts the prompt. + if($Scope -eq 'AllUsers') + { + $envVariableTarget = $script:EnvironmentVariableTarget.Machine + $scriptPATHPromptQuery=$LocalizedData.ScriptPATHPromptQuery -f $ScopePath + $scopeSpecificKey = 'AllUsersScope_AllowPATHChangeForScripts' + } + else + { + $envVariableTarget = $script:EnvironmentVariableTarget.User + $scriptPATHPromptQuery=$LocalizedData.ScriptPATHPromptQuery -f $ScopePath + $scopeSpecificKey = 'CurrentUserScope_AllowPATHChangeForScripts' + } + + $AlreadyPromptedForScope = $script:PSGetSettings.Contains($scopeSpecificKey) + Write-Debug "Already prompted for the current scope:$AlreadyPromptedForScope" + + if(-not $AlreadyPromptedForScope) + { + # Read the file contents once again to ensure that it was not set in another PowerShell Session + Set-PSGetSettingsVariable -Force + + $AlreadyPromptedForScope = $script:PSGetSettings.Contains($scopeSpecificKey) + Write-Debug "After reading contents of PowerShellGetSettings.xml file, the Already prompted for the current scope:$AlreadyPromptedForScope" + + if($AlreadyPromptedForScope) + { + return + } + + $userResponse = $false + + if(-not $NoPathUpdate) + { + $scopePathEndingWithBackSlash = "$scopePath\" + + # Check and add the $scopePath to $env:Path value + if( (($env:PATH -split ';') -notcontains $scopePath) -and + (($env:PATH -split ';') -notcontains $scopePathEndingWithBackSlash)) + { + if($Force) + { + $userResponse = $true + } + else + { + $scriptPATHPromptCaption = $LocalizedData.ScriptPATHPromptCaption + + if($Request) + { + $userResponse = $Request.ShouldContinue($scriptPATHPromptQuery, $scriptPATHPromptCaption) + } + else + { + $userResponse = $PSCmdlet.ShouldContinue($scriptPATHPromptQuery, $scriptPATHPromptCaption) + } + } + + if($userResponse) + { + $currentPATHValue = Get-EnvironmentVariable -Name 'PATH' -Target $envVariableTarget + + if((($currentPATHValue -split ';') -notcontains $scopePath) -and + (($currentPATHValue -split ';') -notcontains $scopePathEndingWithBackSlash)) + { + # To ensure that the installed script is immediately usable, + # we need to add the scope path to the PATH enviroment variable. + Set-EnvironmentVariable -Name 'PATH' ` + -Value "$currentPATHValue;$scopePath" ` + -Target $envVariableTarget + + Write-Verbose ($LocalizedData.AddedScopePathToPATHVariable -f ($scopePath,$Scope)) + } + + # Process specific PATH + # Check and add the $scopePath to $env:Path value of current process + # so that installed scripts can be used in the current process. + $target = $script:EnvironmentVariableTarget.Process + $currentPATHValue = Get-EnvironmentVariable -Name 'PATH' -Target $target + + if((($currentPATHValue -split ';') -notcontains $scopePath) -and + (($currentPATHValue -split ';') -notcontains $scopePathEndingWithBackSlash)) + { + # To ensure that the installed script is immediately usable, + # we need to add the scope path to the PATH enviroment variable. + Set-EnvironmentVariable -Name 'PATH' ` + -Value "$currentPATHValue;$scopePath" ` + -Target $target + + Write-Verbose ($LocalizedData.AddedScopePathToProcessSpecificPATHVariable -f ($scopePath,$Scope)) + } + } + } + } + + # Add user's response to the PowerShellGet.settings file + $script:PSGetSettings[$scopeSpecificKey] = $userResponse + + Save-PSGetSettings + } +} + +function Save-PSGetSettings +{ + if($script:PSGetSettings) + { + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $script:PSGetAppLocalPath)) + { + $null = Microsoft.PowerShell.Management\New-Item -Path $script:PSGetAppLocalPath ` + -ItemType Directory ` + -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false ` + -WhatIf:$false + } + + Microsoft.PowerShell.Utility\Out-File -FilePath $script:PSGetSettingsFilePath -Force ` + -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:PSGetSettings)) + + Write-Debug "In Save-PSGetSettings, persisted the $script:PSGetSettingsFilePath file" + } +} + +function Set-PSGetSettingsVariable +{ + [CmdletBinding()] + param([switch]$Force) + + if(-not $script:PSGetSettings -or $Force) + { + if(Microsoft.PowerShell.Management\Test-Path -Path $script:PSGetSettingsFilePath) + { + $script:PSGetSettings = DeSerialize-PSObject -Path $script:PSGetSettingsFilePath + } + else + { + $script:PSGetSettings = [ordered]@{} + } + } +} + +function Set-ModuleSourcesVariable +{ + [CmdletBinding()] + param([switch]$Force) + + if(-not $script:PSGetModuleSources -or $Force) + { + $isPersistRequired = $false + if(Microsoft.PowerShell.Management\Test-Path $script:PSGetModuleSourcesFilePath) + { + $script:PSGetModuleSources = DeSerialize-PSObject -Path $script:PSGetModuleSourcesFilePath + } + else + { + $script:PSGetModuleSources = [ordered]@{} + + if(-not $script:PSGetModuleSources.Contains($Script:PSGalleryModuleSource)) + { + $isPersistRequired = $true + $psgalleryLocation = Resolve-Location -Location $Script:PSGallerySourceUri ` + -LocationParameterName 'SourceLocation' ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + + $scriptSourceLocation = Resolve-Location -Location $Script:PSGalleryScriptSourceUri ` + -LocationParameterName 'ScriptSourceLocation' ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if($psgalleryLocation) + { + $result = Ping-Endpoint -Endpoint $Script:PSGalleryPublishUri -AllowAutoRedirect:$false + if ($result.ContainsKey($Script:ResponseUri) -and $result[$Script:ResponseUri]) + { + $script:PSGalleryPublishUri = $result[$Script:ResponseUri] + } + $moduleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $Script:PSGalleryModuleSource + SourceLocation = $psgalleryLocation + PublishLocation = $Script:PSGalleryPublishUri + ScriptSourceLocation = $scriptSourceLocation + ScriptPublishLocation = $Script:PSGalleryPublishUri + Trusted=$false + Registered=$true + InstallationPolicy = 'Untrusted' + PackageManagementProvider=$script:NuGetProviderName + ProviderOptions = @{} + }) + + $moduleSource.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository") + $script:PSGetModuleSources.Add($Script:PSGalleryModuleSource, $moduleSource) + } + } + } + + # Already registed repositories may not have the ScriptSourceLocation property, try to populate it from the existing SourceLocation + # Also populate the PublishLocation and ScriptPublishLocation from the SourceLocation if PublishLocation is empty/null. + # + $script:PSGetModuleSources.Keys | Microsoft.PowerShell.Core\ForEach-Object { + $moduleSource = $script:PSGetModuleSources[$_] + + if(-not (Get-Member -InputObject $moduleSource -Name $script:ScriptSourceLocation)) + { + $scriptSourceLocation = Get-ScriptSourceLocation -Location $moduleSource.SourceLocation + + Microsoft.PowerShell.Utility\Add-Member -InputObject $script:PSGetModuleSources[$_] ` + -MemberType NoteProperty ` + -Name $script:ScriptSourceLocation ` + -Value $scriptSourceLocation + + if(Get-Member -InputObject $moduleSource -Name $script:PublishLocation) + { + if(-not $moduleSource.PublishLocation) + { + $script:PSGetModuleSources[$_].PublishLocation = Get-PublishLocation -Location $moduleSource.SourceLocation + } + + Microsoft.PowerShell.Utility\Add-Member -InputObject $script:PSGetModuleSources[$_] ` + -MemberType NoteProperty ` + -Name $script:ScriptPublishLocation ` + -Value $moduleSource.PublishLocation + } + + $isPersistRequired = $true + } + } + + if($isPersistRequired) + { + Save-ModuleSources + } + } +} + +function Get-PackageManagementProviderName +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Location + ) + + $PackageManagementProviderName = $null + $loc = Get-LocationString -LocationUri $Location + + $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) } + + foreach($provider in $providers) + { + # Skip the PowerShellGet provider + if($provider.ProviderName -eq $script:PSModuleProviderName) + { + continue + } + + $packageSource = Get-PackageSource -Location $loc -Provider $provider.ProviderName -ErrorAction SilentlyContinue + + if($packageSource) + { + $PackageManagementProviderName = $provider.ProviderName + break + } + } + + return $PackageManagementProviderName +} + +function Get-ProviderName +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [PSCustomObject] + $PSCustomObject + ) + + $providerName = $script:NuGetProviderName + + if((Get-Member -InputObject $PSCustomObject -Name PackageManagementProvider)) + { + $providerName = $PSCustomObject.PackageManagementProvider + } + + return $providerName +} + +function Get-DynamicParameters +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $Location, + + [Parameter(Mandatory=$true)] + [REF] + $PackageManagementProvider + ) + + $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary + $dynamicOptions = $null + + $loc = Get-LocationString -LocationUri $Location + + if(-not $loc) + { + return $paramDictionary + } + + # Ping and resolve the specified location + $loc = Resolve-Location -Location $loc ` + -LocationParameterName 'Location' ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if(-not $loc) + { + return $paramDictionary + } + + $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) } + + if ($PackageManagementProvider.Value) + { + # Skip the PowerShellGet provider + if($PackageManagementProvider.Value -ne $script:PSModuleProviderName) + { + $SelectedProvider = $providers | Where-Object {$_.ProviderName -eq $PackageManagementProvider.Value} + + if($SelectedProvider) + { + $res = Get-PackageSource -Location $loc -Provider $PackageManagementProvider.Value -ErrorAction SilentlyContinue + + if($res) + { + $dynamicOptions = $SelectedProvider.DynamicOptions + } + } + } + } + else + { + $PackageManagementProvider.Value = Get-PackageManagementProviderName -Location $Location + if($PackageManagementProvider.Value) + { + $provider = $providers | Where-Object {$_.ProviderName -eq $PackageManagementProvider.Value} + $dynamicOptions = $provider.DynamicOptions + } + } + + foreach ($option in $dynamicOptions) + { + # Skip the Destination parameter + if( $option.IsRequired -and + ($option.Name -eq "Destination") ) + { + continue + } + + $paramAttribute = New-Object System.Management.Automation.ParameterAttribute + $paramAttribute.Mandatory = $option.IsRequired + + $message = $LocalizedData.DynamicParameterHelpMessage -f ($option.Name, $PackageManagementProvider.Value, $loc, $option.Name) + $paramAttribute.HelpMessage = $message + + $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] + $attributeCollection.Add($paramAttribute) + + $ageParam = New-Object System.Management.Automation.RuntimeDefinedParameter($option.Name, + $script:DynamicOptionTypeMap[$option.Type.value__], + $attributeCollection) + $paramDictionary.Add($option.Name, $ageParam) + } + + return $paramDictionary +} + +function New-PSGetItemInfo +{ + param + ( + [Parameter(Mandatory=$true)] + $SoftwareIdentity, + + [Parameter()] + $PackageManagementProviderName, + + [Parameter()] + [string] + $SourceLocation, + + [Parameter(Mandatory=$true)] + [string] + $Type, + + [Parameter()] + [string] + $InstalledLocation, + + [Parameter()] + [System.DateTime] + $InstalledDate, + + [Parameter()] + [System.DateTime] + $UpdatedDate + ) + + foreach($swid in $SoftwareIdentity) + { + + if($SourceLocation) + { + $sourceName = (Get-SourceName -Location $SourceLocation) + } + else + { + # First get the source name from the Metadata + # if not exists, get the source name from $swid.Source + # otherwise default to $swid.Source + $sourceName = (Get-First $swid.Metadata["SourceName"]) + + if(-not $sourceName) + { + $sourceName = (Get-SourceName -Location $swid.Source) + } + + if(-not $sourceName) + { + $sourceName = $swid.Source + } + + $SourceLocation = Get-SourceLocation -SourceName $sourceName + } + + $published = (Get-First $swid.Metadata["published"]) + $PublishedDate = New-Object System.DateTime + + $InstalledDateString = (Get-First $swid.Metadata['installeddate']) + if(-not $InstalledDate -and $InstalledDateString) + { + $InstalledDate = New-Object System.DateTime + if(-not ([System.DateTime]::TryParse($InstalledDateString, ([ref]$InstalledDate)))) + { + $InstalledDate = $null + } + } + + $UpdatedDateString = (Get-First $swid.Metadata['updateddate']) + if(-not $UpdatedDate -and $UpdatedDateString) + { + $UpdatedDate = New-Object System.DateTime + if(-not ([System.DateTime]::TryParse($UpdatedDateString, ([ref]$UpdatedDate)))) + { + $UpdatedDate = $null + } + } + + $tags = (Get-First $swid.Metadata["tags"]) -split " " + $userTags = @() + + $exportedDscResources = @() + $exportedRoleCapabilities = @() + $exportedCmdlets = @() + $exportedFunctions = @() + $exportedWorkflows = @() + $exportedCommands = @() + + $exportedRoleCapabilities += (Get-First $swid.Metadata['RoleCapabilities']) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + $exportedDscResources += (Get-First $swid.Metadata["DscResources"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + $exportedCmdlets += (Get-First $swid.Metadata["Cmdlets"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + $exportedFunctions += (Get-First $swid.Metadata["Functions"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + $exportedWorkflows += (Get-First $swid.Metadata["Workflows"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + $exportedCommands += $exportedCmdlets + $exportedFunctions + $exportedWorkflows + $PSGetFormatVersion = $null + + ForEach($tag in $tags) + { + if(-not $tag.Trim()) + { + continue + } + + $parts = $tag -split "_",2 + if($parts.Count -ne 2) + { + $userTags += $tag + continue + } + + Switch($parts[0]) + { + $script:Command { $exportedCommands += $parts[1]; break } + $script:DscResource { $exportedDscResources += $parts[1]; break } + $script:Cmdlet { $exportedCmdlets += $parts[1]; break } + $script:Function { $exportedFunctions += $parts[1]; break } + $script:Workflow { $exportedWorkflows += $parts[1]; break } + $script:RoleCapability { $exportedRoleCapabilities += $parts[1]; break } + $script:PSGetFormatVersion { $PSGetFormatVersion = $parts[1]; break } + $script:Includes { break } + Default { $userTags += $tag; break } + } + } + + $ArtifactDependencies = @() + Foreach ($dependencyString in $swid.Dependencies) + { + [Uri]$packageId = $null + if([Uri]::TryCreate($dependencyString, [System.UriKind]::Absolute, ([ref]$packageId))) + { + $segments = $packageId.Segments + $Version = $null + $DependencyName = $null + if ($segments) + { + $DependencyName = [Uri]::UnescapeDataString($segments[0].Trim('/', '\')) + $Version = if($segments.Count -gt 1){[Uri]::UnescapeDataString($segments[1])} + } + + $dep = [ordered]@{ + Name=$DependencyName + } + + if($Version) + { + # Required/exact version is represented in NuGet as "[2.0]" + if ($Version -match "\[+[0-9.]+\]") + { + $dep["RequiredVersion"] = $Version.Trim('[', ']') + } + elseif ($Version -match "\[+[0-9., ]+\]") + { + # Minimum and Maximum version range is represented in NuGet as "[1.0, 2.0]" + $versionRange = $Version.Trim('[', ']') -split ',' | Microsoft.PowerShell.Core\Where-Object {$_} + if($versionRange -and $versionRange.count -eq 2) + { + $dep["MinimumVersion"] = $versionRange[0].Trim() + $dep["MaximumVersion"] = $versionRange[1].Trim() + } + } + elseif ($Version -match "\(+[0-9., ]+\]") + { + # Maximum version is represented in NuGet as "(, 2.0]" + $maximumVersion = $Version.Trim('(', ']') -split ',' | Microsoft.PowerShell.Core\Where-Object {$_} + + if($maximumVersion) + { + $dep["MaximumVersion"] = $maximumVersion.Trim() + } + } + else + { + $dep['MinimumVersion'] = $Version + } + } + + $dep["CanonicalId"]=$dependencyString + + $ArtifactDependencies += $dep + } + } + + $additionalMetadata = New-Object -TypeName System.Collections.Hashtable + foreach ( $key in $swid.Metadata.Keys.LocalName) + { + if (!$additionalMetadata.ContainsKey($key)) + { + $additionalMetadata.Add($key, (Get-First $swid.Metadata[$key]) ) + } + } + + if($additionalMetadata.ContainsKey('ItemType')) + { + $Type = $additionalMetadata['ItemType'] + } + elseif($userTags -contains 'PSModule') + { + $Type = $script:PSArtifactTypeModule + } + elseif($userTags -contains 'PSScript') + { + $Type = $script:PSArtifactTypeScript + } + + $PSGetItemInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $swid.Name + Version = [Version]$swid.Version + Type = $Type + Description = (Get-First $swid.Metadata["description"]) + Author = (Get-EntityName -SoftwareIdentity $swid -Role "author") + CompanyName = (Get-EntityName -SoftwareIdentity $swid -Role "owner") + Copyright = (Get-First $swid.Metadata["copyright"]) + PublishedDate = if([System.DateTime]::TryParse($published, ([ref]$PublishedDate))){$PublishedDate}; + InstalledDate = $InstalledDate; + UpdatedDate = $UpdatedDate; + LicenseUri = (Get-UrlFromSwid -SoftwareIdentity $swid -UrlName "license") + ProjectUri = (Get-UrlFromSwid -SoftwareIdentity $swid -UrlName "project") + IconUri = (Get-UrlFromSwid -SoftwareIdentity $swid -UrlName "icon") + Tags = $userTags + + Includes = @{ + DscResource = $exportedDscResources + Command = $exportedCommands + Cmdlet = $exportedCmdlets + Function = $exportedFunctions + Workflow = $exportedWorkflows + RoleCapability = $exportedRoleCapabilities + } + + PowerShellGetFormatVersion=[Version]$PSGetFormatVersion + + ReleaseNotes = (Get-First $swid.Metadata["releaseNotes"]) + + Dependencies = $ArtifactDependencies + + RepositorySourceLocation = $SourceLocation + Repository = $sourceName + PackageManagementProvider = if($PackageManagementProviderName) { $PackageManagementProviderName } else { (Get-First $swid.Metadata["PackageManagementProvider"]) } + + AdditionalMetadata = $additionalMetadata + }) + + if(-not $InstalledLocation) + { + $InstalledLocation = (Get-First $swid.Metadata[$script:InstalledLocation]) + } + + if($InstalledLocation) + { + Microsoft.PowerShell.Utility\Add-Member -InputObject $PSGetItemInfo -MemberType NoteProperty -Name $script:InstalledLocation -Value $InstalledLocation + } + + $PSGetItemInfo.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") + $PSGetItemInfo + } +} + +function Get-SourceName +{ + [CmdletBinding()] + [OutputType("string")] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Location + ) + + Set-ModuleSourcesVariable + + foreach($psModuleSource in $script:PSGetModuleSources.Values) + { + if(($psModuleSource.Name -eq $Location) -or + ($psModuleSource.SourceLocation -eq $Location) -or + ((Get-Member -InputObject $psModuleSource -Name $script:ScriptSourceLocation) -and + ($psModuleSource.ScriptSourceLocation -eq $Location))) + { + return $psModuleSource.Name + } + } +} + +function Get-SourceLocation +{ + [CmdletBinding()] + [OutputType("string")] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $SourceName + ) + + Set-ModuleSourcesVariable + + if($script:PSGetModuleSources.Contains($SourceName)) + { + return $script:PSGetModuleSources[$SourceName].SourceLocation + } + else + { + return $SourceName + } +} + +function Get-UrlFromSwid +{ + param + ( + [Parameter(Mandatory=$true)] + $SoftwareIdentity, + + [Parameter(Mandatory=$true)] + $UrlName + ) + + foreach($link in $SoftwareIdentity.Links) + { + if( $link.Relationship -eq $UrlName) + { + return $link.HRef + } + } + + return $null +} + +function Get-EntityName +{ + param + ( + [Parameter(Mandatory=$true)] + $SoftwareIdentity, + + [Parameter(Mandatory=$true)] + $Role + ) + + foreach( $entity in $SoftwareIdentity.Entities ) + { + if( $entity.Role -eq $Role) + { + $entity.Name + } + } +} + +function Install-NuGetClientBinaries +{ + [CmdletBinding()] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet, + + [parameter()] + [switch] + $BootstrapNuGetExe, + + [parameter()] + [switch] + $Force + ) + + if($script:NuGetProvider -and + (-not $BootstrapNuGetExe -or + ($script:NuGetExePath -and (Microsoft.PowerShell.Management\Test-Path -Path $script:NuGetExePath)))) + { + return + } + + $bootstrapNuGetProvider = (-not $script:NuGetProvider) + + if($bootstrapNuGetProvider) + { + # Bootstrap the NuGet provider only if it is not available. + # By default PackageManagement loads the latest version of the NuGet provider. + $nugetProvider = PackageManagement\Get-PackageProvider -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | + Microsoft.PowerShell.Core\Where-Object { + $_.Name -eq $script:NuGetProviderName -and + $_.Version -ge $script:NuGetProviderVersion + } + if($nugetProvider) + { + $script:NuGetProvider = $nugetProvider + + $bootstrapNuGetProvider = $false + } + else + { + # User might have installed it in an another console or in the same process, check available NuGet providers and import the required provider. + $availableNugetProviders = PackageManagement\Get-PackageProvider -Name $script:NuGetProviderName ` + -ListAvailable ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue | + Microsoft.PowerShell.Core\Where-Object { + $_.Name -eq $script:NuGetProviderName -and + $_.Version -ge $script:NuGetProviderVersion + } + if($availableNugetProviders) + { + # Force import ensures that nuget provider with minimum version got loaded. + $null = PackageManagement\Import-PackageProvider -Name $script:NuGetProviderName ` + -MinimumVersion $script:NuGetProviderVersion ` + -Force + + $nugetProvider = PackageManagement\Get-PackageProvider -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | + Microsoft.PowerShell.Core\Where-Object { + $_.Name -eq $script:NuGetProviderName -and + $_.Version -ge $script:NuGetProviderVersion + } + if($nugetProvider) + { + $script:NuGetProvider = $nugetProvider + + $bootstrapNuGetProvider = $false + } + } + } + } + + if($BootstrapNuGetExe -and + (-not $script:NuGetExePath -or + -not (Microsoft.PowerShell.Management\Test-Path -Path $script:NuGetExePath))) + { + $programDataExePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetProgramDataPath -ChildPath $script:NuGetExeName + $applocalDataExePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath $script:NuGetExeName + + # Check if NuGet.exe is available under one of the predefined PowerShellGet locations under ProgramData or LocalAppData + if(Microsoft.PowerShell.Management\Test-Path -Path $programDataExePath) + { + $script:NuGetExePath = $programDataExePath + $BootstrapNuGetExe = $false + } + elseif(Microsoft.PowerShell.Management\Test-Path -Path $applocalDataExePath) + { + $script:NuGetExePath = $applocalDataExePath + $BootstrapNuGetExe = $false + } + else + { + # Using Get-Command cmdlet, get the location of NuGet.exe if it is available under $env:PATH. + # NuGet.exe does not work if it is under $env:WINDIR, so skip it from the Get-Command results. + $nugetCmd = Microsoft.PowerShell.Core\Get-Command -Name $script:NuGetExeName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue | + Microsoft.PowerShell.Core\Where-Object { + $_.Path -and + ((Microsoft.PowerShell.Management\Split-Path -Path $_.Path -Leaf) -eq $script:NuGetExeName) -and + (-not $_.Path.StartsWith($env:windir, [System.StringComparison]::OrdinalIgnoreCase)) + } | Microsoft.PowerShell.Utility\Select-Object -First 1 + + if($nugetCmd -and $nugetCmd.Path) + { + $script:NuGetExePath = $nugetCmd.Path + $BootstrapNuGetExe = $false + } + } + } + else + { + # No need to bootstrap the NuGet.exe when $BootstrapNuGetExe is false or NuGet.exe path is already assigned. + $BootstrapNuGetExe = $false + } + + # On Nano server we don't need NuGet.exe + if(-not $bootstrapNuGetProvider -and ($script:isNanoServer -or -not $BootstrapNuGetExe)) + { + return + } + + # We should prompt only once for bootstrapping the NuGet provider and/or NuGet.exe + + # Should continue message for bootstrapping only NuGet provider + $shouldContinueQueryMessage = $LocalizedData.InstallNuGetProviderShouldContinueQuery -f @($script:NuGetProviderVersion,$script:NuGetBinaryProgramDataPath,$script:NuGetBinaryLocalAppDataPath) + $shouldContinueCaption = $LocalizedData.InstallNuGetProviderShouldContinueCaption + + # Should continue message for bootstrapping both NuGet provider and NuGet.exe + if($bootstrapNuGetProvider -and $BootstrapNuGetExe) + { + $shouldContinueQueryMessage = $LocalizedData.InstallNuGetBinariesShouldContinueQuery2 -f @($script:NuGetProviderVersion,$script:NuGetBinaryProgramDataPath,$script:NuGetBinaryLocalAppDataPath, $script:PSGetProgramDataPath, $script:PSGetAppLocalPath) + $shouldContinueCaption = $LocalizedData.InstallNuGetBinariesShouldContinueCaption2 + } + elseif($BootstrapNuGetExe) + { + # Should continue message for bootstrapping only NuGet.exe + $shouldContinueQueryMessage = $LocalizedData.InstallNuGetExeShouldContinueQuery -f ($script:PSGetProgramDataPath, $script:PSGetAppLocalPath) + $shouldContinueCaption = $LocalizedData.InstallNuGetExeShouldContinueCaption + } + + if($Force -or $psCmdlet.ShouldContinue($shouldContinueQueryMessage, $shouldContinueCaption)) + { + if($bootstrapNuGetProvider) + { + Write-Verbose -Message $LocalizedData.DownloadingNugetProvider + + $scope = 'CurrentUser' + if(Test-RunningAsElevated) + { + $scope = 'AllUsers' + } + + # Bootstrap the NuGet provider + $null = PackageManagement\Install-PackageProvider -Name $script:NuGetProviderName ` + -MinimumVersion $script:NuGetProviderVersion ` + -Scope $scope ` + -Force + + # Force import ensures that nuget provider with minimum version got loaded. + $null = PackageManagement\Import-PackageProvider -Name $script:NuGetProviderName ` + -MinimumVersion $script:NuGetProviderVersion ` + -Force + + $nugetProvider = PackageManagement\Get-PackageProvider -Name $script:NuGetProviderName + + if ($nugetProvider) + { + $script:NuGetProvider = $nugetProvider + } + } + + if($BootstrapNuGetExe -and -not $script:isNanoServer) + { + Write-Verbose -Message $LocalizedData.DownloadingNugetExe + + $nugetExeBasePath = $script:PSGetAppLocalPath + + # if the current process is running with elevated privileges, + # install NuGet.exe to $script:PSGetProgramDataPath + if(Test-RunningAsElevated) + { + $nugetExeBasePath = $script:PSGetProgramDataPath + } + + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $nugetExeBasePath)) + { + $null = Microsoft.PowerShell.Management\New-Item -Path $nugetExeBasePath ` + -ItemType Directory -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + } + + $nugetExeFilePath = Microsoft.PowerShell.Management\Join-Path -Path $nugetExeBasePath -ChildPath $script:NuGetExeName + + # Download the NuGet.exe from http://nuget.org/NuGet.exe + $null = Microsoft.PowerShell.Utility\Invoke-WebRequest -Uri $script:NuGetClientSourceURL ` + -OutFile $nugetExeFilePath + + if (Microsoft.PowerShell.Management\Test-Path -Path $nugetExeFilePath) + { + $script:NuGetExePath = $nugetExeFilePath + } + } + } + + $message = $null + $errorId = $null + $failedToBootstrapNuGetProvider = $false + $failedToBootstrapNuGetExe = $false + + if($bootstrapNuGetProvider -and -not $script:NuGetProvider) + { + $failedToBootstrapNuGetProvider = $true + + $message = $LocalizedData.CouldNotInstallNuGetProvider -f @($script:NuGetProviderVersion) + $errorId = 'CouldNotInstallNuGetProvider' + } + + if($BootstrapNuGetExe -and + (-not $script:NuGetExePath -or + -not (Microsoft.PowerShell.Management\Test-Path -Path $script:NuGetExePath))) + { + $failedToBootstrapNuGetExe = $true + + $message = $LocalizedData.CouldNotInstallNuGetExe -f @($script:NuGetProviderVersion) + $errorId = 'CouldNotInstallNuGetExe' + } + + # Change the error id and message if both NuGet provider and NuGet.exe are not installed. + if($failedToBootstrapNuGetProvider -and $failedToBootstrapNuGetExe) + { + $message = $LocalizedData.CouldNotInstallNuGetBinaries2 -f @($script:NuGetProviderVersion) + $errorId = 'CouldNotInstallNuGetBinaries' + } + + # Throw the error message if one of the above conditions are met + if($message -and $errorId) + { + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId $errorId ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidOperation + } +} + +# Check if current user is running with elevated privileges +function Test-RunningAsElevated +{ + [CmdletBinding()] + [OutputType([bool])] + Param() + + $wid=[System.Security.Principal.WindowsIdentity]::GetCurrent() + $prp=new-object System.Security.Principal.WindowsPrincipal($wid) + $adm=[System.Security.Principal.WindowsBuiltInRole]::Administrator + return $prp.IsInRole($adm) +} + +function Get-EscapedString +{ + [CmdletBinding()] + [OutputType([String])] + Param + ( + [Parameter()] + [string] + $ElementValue + ) + + return [System.Security.SecurityElement]::Escape($ElementValue) +} + +function ValidateAndGet-ScriptDependencies +{ + param( + [Parameter(Mandatory=$true)] + [string] + $Repository, + + [Parameter(Mandatory=$true)] + [PSCustomObject] + $DependentScriptInfo, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet + ) + + $DependenciesDetails = @() + + # Validate dependent modules + $RequiredModuleSpecification = $DependentScriptInfo.RequiredModules + if($RequiredModuleSpecification) + { + ForEach($moduleSpecification in $RequiredModuleSpecification) + { + $ModuleName = $moduleSpecification.Name + + $FindModuleArguments = @{ + Repository = $Repository + Verbose = $VerbosePreference + ErrorAction = 'SilentlyContinue' + WarningAction = 'SilentlyContinue' + Debug = $DebugPreference + } + + if($DependentScriptInfo.ExternalModuleDependencies -contains $ModuleName) + { + Write-Verbose -Message ($LocalizedData.SkippedModuleDependency -f $ModuleName) + + continue + } + + $FindModuleArguments['Name'] = $ModuleName + $ReqModuleInfo = @{} + $ReqModuleInfo['Name'] = $ModuleName + + if($moduleSpecification.Version) + { + $FindModuleArguments['MinimumVersion'] = $moduleSpecification.Version + $ReqModuleInfo['MinimumVersion'] = $moduleSpecification.Version + } + elseif((Get-Member -InputObject $moduleSpecification -Name RequiredVersion) -and $moduleSpecification.RequiredVersion) + { + $FindModuleArguments['RequiredVersion'] = $moduleSpecification.RequiredVersion + $ReqModuleInfo['RequiredVersion'] = $moduleSpecification.RequiredVersion + } + + if((Get-Member -InputObject $moduleSpecification -Name MaximumVersion) -and $moduleSpecification.MaximumVersion) + { + # * can be specified in the MaximumVersion of a ModuleSpecification to convey that maximum possible value of that version part. + # like 1.0.0.* --> 1.0.0.99999999 + # replace * with 99999999, PowerShell core takes care validating the * to be the last character in the version string. + $maximumVersion = $moduleSpecification.MaximumVersion -replace '\*','99999999' + $FindModuleArguments['MaximumVersion'] = $maximumVersion + $ReqModuleInfo['MaximumVersion'] = $maximumVersion + } + + $psgetItemInfo = Find-Module @FindModuleArguments | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $ModuleName} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + + if(-not $psgetItemInfo) + { + $message = $LocalizedData.UnableToResolveScriptDependency -f ('module', $ModuleName, $DependentScriptInfo.Name, $Repository, 'ExternalModuleDependencies') + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "UnableToResolveScriptDependency" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidOperation + } + + $DependenciesDetails += $ReqModuleInfo + } + } + + # Validate dependent scrips + $RequiredScripts = $DependentScriptInfo.RequiredScripts + if($RequiredScripts) + { + ForEach($requiredScript in $RequiredScripts) + { + $FindScriptArguments = @{ + Repository = $Repository + Verbose = $VerbosePreference + ErrorAction = 'SilentlyContinue' + WarningAction = 'SilentlyContinue' + Debug = $DebugPreference + } + + if($DependentScriptInfo.ExternalScriptDependencies -contains $requiredScript) + { + Write-Verbose -Message ($LocalizedData.SkippedScriptDependency -f $requiredScript) + + continue + } + + $FindScriptArguments['Name'] = $requiredScript + $ReqScriptInfo = @{} + $ReqScriptInfo['Name'] = $requiredScript + + $psgetItemInfo = Find-Script @FindScriptArguments | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $requiredScript} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + + if(-not $psgetItemInfo) + { + $message = $LocalizedData.UnableToResolveScriptDependency -f ('script', $requiredScript, $DependentScriptInfo.Name, $Repository, 'ExternalScriptDependencies') + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "UnableToResolveScriptDependency" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidOperation + } + + $DependenciesDetails += $ReqScriptInfo + } + } + + return $DependenciesDetails +} + +function ValidateAndGet-RequiredModuleDetails +{ + param( + [Parameter()] + $ModuleManifestRequiredModules, + + [Parameter()] + [PSModuleInfo[]] + $RequiredPSModuleInfos, + + [Parameter(Mandatory=$true)] + [string] + $Repository, + + [Parameter(Mandatory=$true)] + [PSModuleInfo] + $DependentModuleInfo, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet + ) + + $RequiredModuleDetails = @() + + if(-not $RequiredPSModuleInfos) + { + return $RequiredModuleDetails + } + + if($ModuleManifestRequiredModules) + { + ForEach($RequiredModule in $ModuleManifestRequiredModules) + { + $ModuleName = $null + $VersionString = $null + + $ReqModuleInfo = @{} + + $FindModuleArguments = @{ + Repository = $Repository + Verbose = $VerbosePreference + ErrorAction = 'SilentlyContinue' + WarningAction = 'SilentlyContinue' + Debug = $DebugPreference + } + + # ModuleSpecification case + if($RequiredModule.GetType().ToString() -eq 'System.Collections.Hashtable') + { + $ModuleName = $RequiredModule.ModuleName + + # Version format in NuSpec: + # "[2.0]" --> (== 2.0) Required Version + # "2.0" --> (>= 2.0) Minimum Version + if($RequiredModule.Keys -Contains "RequiredVersion") + { + $FindModuleArguments['RequiredVersion'] = $RequiredModule.RequiredVersion + $ReqModuleInfo['RequiredVersion'] = $RequiredModule.RequiredVersion + } + elseif($RequiredModule.Keys -Contains "ModuleVersion") + { + $FindModuleArguments['MinimumVersion'] = $RequiredModule.ModuleVersion + $ReqModuleInfo['MinimumVersion'] = $RequiredModule.ModuleVersion + } + + if($RequiredModule.Keys -Contains 'MaximumVersion' -and $RequiredModule.MaximumVersion) + { + # * can be specified in the MaximumVersion of a ModuleSpecification to convey that maximum possible value of that version part. + # like 1.0.0.* --> 1.0.0.99999999 + # replace * with 99999999, PowerShell core takes care validating the * to be the last character in the version string. + $maximumVersion = $RequiredModule.MaximumVersion -replace '\*','99999999' + + $FindModuleArguments['MaximumVersion'] = $maximumVersion + $ReqModuleInfo['MaximumVersion'] = $maximumVersion + } + } + else + { + # Just module name was specified + $ModuleName = $RequiredModule.ToString() + } + + if((Get-ExternalModuleDependencies -PSModuleInfo $DependentModuleInfo) -contains $ModuleName) + { + Write-Verbose -Message ($LocalizedData.SkippedModuleDependency -f $ModuleName) + + continue + } + + # Skip this module name if it's name is not in $RequiredPSModuleInfos. + # This is required when a ModuleName is part of the NestedModules list of the actual module. + # $ModuleName is packaged as part of the actual module When $RequiredPSModuleInfos doesn't contain it's name. + if($RequiredPSModuleInfos.Name -notcontains $ModuleName) + { + continue + } + + $ReqModuleInfo['Name'] = $ModuleName + + # Add the dependency only if the module is available on the gallery + # Otherwise Module installation will fail as all required modules need to be available on + # the same Repository + $FindModuleArguments['Name'] = $ModuleName + + $psgetItemInfo = Find-Module @FindModuleArguments | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $ModuleName} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + + if(-not $psgetItemInfo) + { + $message = $LocalizedData.UnableToResolveModuleDependency -f ($ModuleName, $DependentModuleInfo.Name, $Repository, $ModuleName, $Repository, $ModuleName, $ModuleName) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "UnableToResolveModuleDependency" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidOperation + } + + $RequiredModuleDetails += $ReqModuleInfo + } + } + else + { + # If Import-LocalizedData cmdlet was failed to read the .psd1 contents + # use provided $RequiredPSModuleInfos (PSModuleInfo.RequiredModules or PSModuleInfo.NestedModules of the actual dependent module) + + $FindModuleArguments = @{ + Repository = $Repository + Verbose = $VerbosePreference + ErrorAction = 'SilentlyContinue' + WarningAction = 'SilentlyContinue' + Debug = $DebugPreference + } + + ForEach($RequiredModuleInfo in $RequiredPSModuleInfos) + { + $ModuleName = $requiredModuleInfo.Name + + if((Get-ExternalModuleDependencies -PSModuleInfo $DependentModuleInfo) -contains $ModuleName) + { + Write-Verbose -Message ($LocalizedData.SkippedModuleDependency -f $ModuleName) + + continue + } + + $FindModuleArguments['Name'] = $ModuleName + $FindModuleArguments['MinimumVersion'] = $requiredModuleInfo.Version + + $psgetItemInfo = Find-Module @FindModuleArguments | + Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $ModuleName} | + Microsoft.PowerShell.Utility\Select-Object -Last 1 + + if(-not $psgetItemInfo) + { + $message = $LocalizedData.UnableToResolveModuleDependency -f ($ModuleName, $DependentModuleInfo.Name, $Repository, $ModuleName, $Repository, $ModuleName, $ModuleName) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "UnableToResolveModuleDependency" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + } + + $RequiredModuleDetails += @{ + Name=$_.Name + MinimumVersion=$_.Version + } + } + } + + return $RequiredModuleDetails +} + +function Get-ExternalModuleDependencies +{ + Param ( + [Parameter(Mandatory=$true)] + [PSModuleInfo] + $PSModuleInfo + ) + + if($PSModuleInfo.PrivateData -and + ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and + $PSModuleInfo.PrivateData["PSData"] -and + ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable") -and + $PSModuleInfo.PrivateData.PSData['ExternalModuleDependencies'] -and + ($PSModuleInfo.PrivateData.PSData['ExternalModuleDependencies'].GetType().ToString() -eq "System.Object[]") + ) + { + return $PSModuleInfo.PrivateData.PSData.ExternalModuleDependencies + } +} + +function Get-ModuleDependencies +{ + Param ( + [Parameter(Mandatory=$true)] + [PSModuleInfo] + $PSModuleInfo, + + [Parameter(Mandatory=$true)] + [string] + $Repository, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet + ) + + $DependentModuleDetails = @() + + if($PSModuleInfo.RequiredModules -or $PSModuleInfo.NestedModules) + { + # PSModuleInfo.RequiredModules doesn't provide the RequiredVersion info from the ModuleSpecification + # Reading the contents of module manifest file using Import-LocalizedData cmdlet + # to get the RequiredVersion details. + Import-LocalizedData -BindingVariable ModuleManifestHashTable ` + -FileName (Microsoft.PowerShell.Management\Split-Path $PSModuleInfo.Path -Leaf) ` + -BaseDirectory $PSModuleInfo.ModuleBase ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + + if($PSModuleInfo.RequiredModules) + { + $ModuleManifestRequiredModules = $null + + if($ModuleManifestHashTable) + { + $ModuleManifestRequiredModules = $ModuleManifestHashTable.RequiredModules + } + + + $DependentModuleDetails += ValidateAndGet-RequiredModuleDetails -ModuleManifestRequiredModules $ModuleManifestRequiredModules ` + -RequiredPSModuleInfos $PSModuleInfo.RequiredModules ` + -Repository $Repository ` + -DependentModuleInfo $PSModuleInfo ` + -CallerPSCmdlet $CallerPSCmdlet ` + -Verbose:$VerbosePreference ` + -Debug:$DebugPreference + } + + if($PSModuleInfo.NestedModules) + { + $ModuleManifestRequiredModules = $null + + if($ModuleManifestHashTable) + { + $ModuleManifestRequiredModules = $ModuleManifestHashTable.NestedModules + } + + # A nested module is be considered as a dependency + # 1) whose module base is not under the specified module base OR + # 2) whose module base is under the specified module base and it's path doesn't exists + # + $RequiredPSModuleInfos = $PSModuleInfo.NestedModules | Microsoft.PowerShell.Core\Where-Object { + -not $_.ModuleBase.StartsWith($PSModuleInfo.ModuleBase, [System.StringComparison]::OrdinalIgnoreCase) -or + -not $_.Path -or + -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $_.Path) + } + + $DependentModuleDetails += ValidateAndGet-RequiredModuleDetails -ModuleManifestRequiredModules $ModuleManifestRequiredModules ` + -RequiredPSModuleInfos $RequiredPSModuleInfos ` + -Repository $Repository ` + -DependentModuleInfo $PSModuleInfo ` + -CallerPSCmdlet $CallerPSCmdlet ` + -Verbose:$VerbosePreference ` + -Debug:$DebugPreference + } + } + + return $DependentModuleDetails +} + +function Publish-PSArtifactUtility +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true, ParameterSetName='PublishModule')] + [ValidateNotNullOrEmpty()] + [PSModuleInfo] + $PSModuleInfo, + + [Parameter(Mandatory=$true, ParameterSetName='PublishScript')] + [ValidateNotNullOrEmpty()] + [PSCustomObject] + $PSScriptInfo, + + [Parameter(Mandatory=$true, ParameterSetName='PublishModule')] + [ValidateNotNullOrEmpty()] + [string] + $ManifestPath, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Destination, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Repository, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $NugetApiKey, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $NugetPackageRoot, + + [Parameter(ParameterSetName='PublishModule')] + [Version] + $FormatVersion, + + [Parameter(ParameterSetName='PublishModule')] + [string] + $ReleaseNotes, + + [Parameter(ParameterSetName='PublishModule')] + [string[]] + $Tags, + + [Parameter(ParameterSetName='PublishModule')] + [Uri] + $LicenseUri, + + [Parameter(ParameterSetName='PublishModule')] + [Uri] + $IconUri, + + [Parameter(ParameterSetName='PublishModule')] + [Uri] + $ProjectUri + ) + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe + + $PSArtifactType = $script:PSArtifactTypeModule + $Name = $null + $Description = $null + $Version = $null + $Author = $null + $CompanyName = $null + $Copyright = $null + + if($PSModuleInfo) + { + $Name = $PSModuleInfo.Name + $Description = $PSModuleInfo.Description + $Version = $PSModuleInfo.Version + $Author = $PSModuleInfo.Author + $CompanyName = $PSModuleInfo.CompanyName + $Copyright = $PSModuleInfo.Copyright + + if($PSModuleInfo.PrivateData -and + ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and + $PSModuleInfo.PrivateData["PSData"] -and + ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable") + ) + { + if( -not $Tags -and $PSModuleInfo.PrivateData.PSData["Tags"]) + { + $Tags = $PSModuleInfo.PrivateData.PSData.Tags + } + + if( -not $ReleaseNotes -and $PSModuleInfo.PrivateData.PSData["ReleaseNotes"]) + { + $ReleaseNotes = $PSModuleInfo.PrivateData.PSData.ReleaseNotes + } + + if( -not $LicenseUri -and $PSModuleInfo.PrivateData.PSData["LicenseUri"]) + { + $LicenseUri = $PSModuleInfo.PrivateData.PSData.LicenseUri + } + + if( -not $IconUri -and $PSModuleInfo.PrivateData.PSData["IconUri"]) + { + $IconUri = $PSModuleInfo.PrivateData.PSData.IconUri + } + + if( -not $ProjectUri -and $PSModuleInfo.PrivateData.PSData["ProjectUri"]) + { + $ProjectUri = $PSModuleInfo.PrivateData.PSData.ProjectUri + } + } + } + else + { + $PSArtifactType = $script:PSArtifactTypeScript + + $Name = $PSScriptInfo.Name + $Description = $PSScriptInfo.Description + $Version = $PSScriptInfo.Version + $Author = $PSScriptInfo.Author + $CompanyName = $PSScriptInfo.CompanyName + $Copyright = $PSScriptInfo.Copyright + + if($PSScriptInfo.'Tags') + { + $Tags = $PSScriptInfo.Tags + } + + if($PSScriptInfo.'ReleaseNotes') + { + $ReleaseNotes = $PSScriptInfo.ReleaseNotes + } + + if($PSScriptInfo.'LicenseUri') + { + $LicenseUri = $PSScriptInfo.LicenseUri + } + + if($PSScriptInfo.'IconUri') + { + $IconUri = $PSScriptInfo.IconUri + } + + if($PSScriptInfo.'ProjectUri') + { + $ProjectUri = $PSScriptInfo.ProjectUri + } + } + + + # Add PSModule and PSGet format version tags + if(-not $Tags) + { + $Tags = @() + } + + if($FormatVersion) + { + $Tags += "$($script:PSGetFormatVersion)_$FormatVersion" + } + + $DependentModuleDetails = @() + + if($PSScriptInfo) + { + $Tags += "PSScript" + + if($PSScriptInfo.DefinedCommands) + { + if($PSScriptInfo.DefinedFunctions) + { + $Tags += "$($script:Includes)_Function" + $Tags += $PSScriptInfo.DefinedFunctions | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } + } + + if($PSScriptInfo.DefinedWorkflows) + { + $Tags += "$($script:Includes)_Workflow" + $Tags += $PSScriptInfo.DefinedWorkflows | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Workflow)_$_" } + } + + $Tags += $PSScriptInfo.DefinedCommands | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } + } + + # Populate the dependencies elements from RequiredModules and RequiredScripts + # + $DependentModuleDetails += ValidateAndGet-ScriptDependencies -Repository $Repository ` + -DependentScriptInfo $PSScriptInfo ` + -CallerPSCmdlet $PSCmdlet ` + -Verbose:$VerbosePreference ` + -Debug:$DebugPreference + } + else + { + $Tags += "PSModule" + + Import-LocalizedData -BindingVariable ModuleManifestHashTable ` + -FileName (Microsoft.PowerShell.Management\Split-Path $ManifestPath -Leaf) ` + -BaseDirectory (Microsoft.PowerShell.Management\Split-Path $ManifestPath -Parent) ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + + + if($PSModuleInfo.ExportedCommands.Count) + { + if($PSModuleInfo.ExportedCmdlets.Count) + { + $Tags += "$($script:Includes)_Cmdlet" + $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" } + + #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice + if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*")) + { + $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } + } + + if($PSModuleInfo.ExportedFunctions.Count) + { + $Tags += "$($script:Includes)_Function" + $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } + + if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*")) + { + $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } + } + + $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } + } + + $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo + if($dscResourceNames) + { + $Tags += "$($script:Includes)_DscResource" + + $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" } + + #If DscResourcesToExport is commented out or "*" is used, we will write-warning + if($ModuleManifestHashTable -and + ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and + $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or + -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport")) + { + $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } + } + + $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo + if($RoleCapabilityNames) + { + $Tags += "$($script:Includes)_RoleCapability" + + $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" } + } + + # Populate the module dependencies elements from RequiredModules and + # NestedModules properties of the current PSModuleInfo + $DependentModuleDetails = Get-ModuleDependencies -PSModuleInfo $PSModuleInfo ` + -Repository $Repository ` + -CallerPSCmdlet $PSCmdlet ` + -Verbose:$VerbosePreference ` + -Debug:$DebugPreference + } + + $dependencies = @() + ForEach($Dependency in $DependentModuleDetails) + { + $ModuleName = $Dependency.Name + $VersionString = $null + + # Version format in NuSpec: + # "[2.0]" --> (== 2.0) Required Version + # "2.0" --> (>= 2.0) Minimum Version + # + # When only MaximumVersion is specified in the ModuleSpecification + # (,1.0] = x <= 1.0 + # + # When both Minimum and Maximum versions are specified in the ModuleSpecification + # [1.0,2.0] = 1.0 <= x <= 2.0 + + if($Dependency.Keys -Contains "RequiredVersion") + { + $VersionString = "[$($Dependency.RequiredVersion)]" + } + elseif($Dependency.Keys -Contains 'MinimumVersion' -and $Dependency.Keys -Contains 'MaximumVersion') + { + $VersionString = "[$($Dependency.MinimumVersion),$($Dependency.MaximumVersion)]" + } + elseif($Dependency.Keys -Contains 'MaximumVersion') + { + $VersionString = "(,$($Dependency.MaximumVersion)]" + } + elseif($Dependency.Keys -Contains 'MinimumVersion') + { + $VersionString = "$($Dependency.MinimumVersion)" + } + + $dependencies += "" + } + + # Populate the nuspec elements + $nuspec = @" + + + + $(Get-EscapedString -ElementValue "$Name") + $($Version) + $(Get-EscapedString -ElementValue "$Author") + $(Get-EscapedString -ElementValue "$CompanyName") + $(Get-EscapedString -ElementValue "$Description") + $(Get-EscapedString -ElementValue "$ReleaseNotes") + $(Get-EscapedString -ElementValue "$Copyright") + $(if($Tags){ Get-EscapedString -ElementValue ($Tags -join ' ')}) + $(if($LicenseUri){ + "$(Get-EscapedString -ElementValue "$LicenseUri") + true" + }) + $(if($ProjectUri){ + "$(Get-EscapedString -ElementValue "$ProjectUri")" + }) + $(if($IconUri){ + "$(Get-EscapedString -ElementValue "$IconUri")" + }) + + $dependencies + + + +"@ + + $NupkgPath = "$NugetPackageRoot\$Name.$($Version.ToString()).nupkg" + $NuspecPath = "$NugetPackageRoot\$Name.nuspec" + $tempErrorFile = $null + $tempOutputFile = $null + + try + { + # Remove existing nuspec and nupkg files + Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + + Microsoft.PowerShell.Management\Set-Content -Value $nuspec -Path $NuspecPath + + # Create .nupkg file + $output = & $script:NuGetExePath pack $NuspecPath -OutputDirectory $NugetPackageRoot + if($LASTEXITCODE) + { + if($PSArtifactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.FailedToCreateCompressedModule -f ($output) + $errorId = "FailedToCreateCompressedModule" + } + else + { + $message = $LocalizedData.FailedToCreateCompressedScript -f ($output) + $errorId = "FailedToCreateCompressedScript" + } + + Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation + return + } + + # Publish the .nupkg to gallery + $tempErrorFile = Microsoft.PowerShell.Management\Join-Path -Path $nugetPackageRoot -ChildPath "TempPublishError.txt" + $tempOutputFile = Microsoft.PowerShell.Management\Join-Path -Path $nugetPackageRoot -ChildPath "TempPublishOutput.txt" + + Microsoft.PowerShell.Management\Start-Process -FilePath "$script:NuGetExePath" ` + -ArgumentList @('push', $NupkgPath, '-source', $Destination, '-NonInteractive', '-ApiKey', $NugetApiKey) ` + -RedirectStandardError $tempErrorFile ` + -RedirectStandardOutput $tempOutputFile ` + -NoNewWindow ` + -Wait + + $errorMsg = Microsoft.PowerShell.Management\Get-Content -Path $tempErrorFile -Raw + + if($errorMsg) + { + if($PSArtifactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.FailedToPublish -f ($Name,$errorMsg) + $errorId = "FailedToPublishTheModule" + } + else + { + $message = $LocalizedData.FailedToPublishScript -f ($Name,$errorMsg) + $errorId = "FailedToPublishTheScript" + } + + Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation + } + else + { + if($PSArtifactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.PublishedSuccessfully -f ($Name, $Destination, $Name) + } + else + { + $message = $LocalizedData.PublishedScriptSuccessfully -f ($Name, $Destination, $Name) + } + + Write-Verbose -Message $message + } + } + finally + { + if($NupkgPath -and (Test-Path -Path $NupkgPath -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + if($NuspecPath -and (Test-Path -Path $NuspecPath -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + if($tempErrorFile -and (Test-Path -Path $tempErrorFile -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $tempErrorFile -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + if($tempOutputFile -and (Test-Path -Path $tempOutputFile -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $tempOutputFile -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + } +} + +function ValidateAndAdd-PSScriptInfoEntry +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [PSCustomObject] + $PSScriptInfo, + + [Parameter(Mandatory=$true)] + [string] + $PropertyName, + + [Parameter()] + $PropertyValue, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet + ) + + $Value = $PropertyValue + $KeyName = $PropertyName + + # return if $KeyName value is not null in $PSScriptInfo + if(-not $value -or -not $KeyName -or (Get-Member -InputObject $PSScriptInfo -Name $KeyName) -and $PSScriptInfo."$KeyName") + { + return + } + + switch($PropertyName) + { + # Validate the property value and also use proper key name as users can specify the property name in any case. + $script:Version { + $KeyName = $script:Version + + [Version]$Version = $null + + if([System.Version]::TryParse($Value, ([ref]$Version))) + { + $Value = $Version + } + else + { + $message = $LocalizedData.InvalidVersion -f ($Value) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidVersion" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Value + return + } + break + } + + $script:Author { $KeyName = $script:Author } + + $script:Guid { + $KeyName = $script:Guid + + [Guid]$guid = [System.Guid]::Empty + if([System.Guid]::TryParse($Value, ([ref]$guid))) + { + $Value = $guid + } + else + { + $message = $LocalizedData.InvalidGuid -f ($Value) + ThrowError -ExceptionName 'System.ArgumentException' ` + -ExceptionMessage $message ` + -ErrorId 'InvalidGuid' ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Value + return + } + + break + } + + $script:Description { $KeyName = $script:Description } + + $script:CompanyName { $KeyName = $script:CompanyName } + + $script:Copyright { $KeyName = $script:Copyright } + + $script:Tags { + $KeyName = $script:Tags + $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_} + break + } + + $script:LicenseUri { + $KeyName = $script:LicenseUri + if(-not (Test-WebUri -Uri $Value)) + { + $message = $LocalizedData.InvalidWebUri -f ($LicenseUri, "LicenseUri") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Value + return + } + + $Value = [Uri]$Value + } + + $script:ProjectUri { + $KeyName = $script:ProjectUri + if(-not (Test-WebUri -Uri $Value)) + { + $message = $LocalizedData.InvalidWebUri -f ($ProjectUri, "ProjectUri") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Value + return + } + + $Value = [Uri]$Value + } + + $script:IconUri { + $KeyName = $script:IconUri + if(-not (Test-WebUri -Uri $Value)) + { + $message = $LocalizedData.InvalidWebUri -f ($IconUri, "IconUri") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Value + return + } + + $Value = [Uri]$Value + } + + $script:ExternalModuleDependencies { + $KeyName = $script:ExternalModuleDependencies + $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_} + } + + $script:ReleaseNotes { $KeyName = $script:ReleaseNotes } + + $script:RequiredModules { $KeyName = $script:RequiredModules } + + $script:RequiredScripts { + $KeyName = $script:RequiredScripts + $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_} + } + + $script:ExternalScriptDependencies { + $KeyName = $script:ExternalScriptDependencies + $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_} + } + + $script:DefinedCommands { $KeyName = $script:DefinedCommands } + + $script:DefinedFunctions { $KeyName = $script:DefinedFunctions } + + $script:DefinedWorkflows { $KeyName = $script:DefinedWorkflows } + } + + Microsoft.PowerShell.Utility\Add-Member -InputObject $PSScriptInfo ` + -MemberType NoteProperty ` + -Name $KeyName ` + -Value $Value ` + -Force +} + +function Get-ExportedDscResources +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [PSModuleInfo] + $PSModuleInfo + ) + + $dscResources = @() + + if(Get-Command -Name Get-DscResource -Module PSDesiredStateConfiguration -ErrorAction SilentlyContinue) + { + $OldPSModulePath = $env:PSModulePath + + try + { + $env:PSModulePath = Join-Path -Path $PSHOME -ChildPath "Modules" + $env:PSModulePath = "$env:PSModulePath;$(Split-Path -Path $PSModuleInfo.ModuleBase -Parent)" + + $dscResources = PSDesiredStateConfiguration\Get-DscResource -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | + Microsoft.PowerShell.Core\ForEach-Object { + if($_.Module -and ($_.Module.Name -eq $PSModuleInfo.Name)) + { + $_.Name + } + } + } + finally + { + $env:PSModulePath = $OldPSModulePath + } + } + else + { + $dscResourcesDir = Microsoft.PowerShell.Management\Join-Path -Path $PSModuleInfo.ModuleBase -ChildPath "DscResources" + if(Microsoft.PowerShell.Management\Test-Path $dscResourcesDir) + { + $dscResources = Microsoft.PowerShell.Management\Get-ChildItem -Path $dscResourcesDir -Directory -Name + } + } + + return $dscResources +} + +function Get-AvailableRoleCapabilityName +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [PSModuleInfo] + $PSModuleInfo + ) + + $RoleCapabilityNames = @() + + $RoleCapabilitiesDir = Microsoft.PowerShell.Management\Join-Path -Path $PSModuleInfo.ModuleBase -ChildPath 'RoleCapabilities' + if(Microsoft.PowerShell.Management\Test-Path -Path $RoleCapabilitiesDir -PathType Container) + { + $RoleCapabilityNames = Microsoft.PowerShell.Management\Get-ChildItem -Path $RoleCapabilitiesDir ` + -Name -Filter *.psrc | + ForEach-Object {[System.IO.Path]::GetFileNameWithoutExtension($_)} + } + + return $RoleCapabilityNames +} + +function Get-LocationString +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter()] + [Uri] + $LocationUri + ) + + $LocationString = $null + + if($LocationUri) + { + if($LocationUri.Scheme -eq 'file') + { + $LocationString = $LocationUri.OriginalString + } + elseif($LocationUri.AbsoluteUri) + { + $LocationString = $LocationUri.AbsoluteUri + } + else + { + $LocationString = $LocationUri.ToString() + } + } + + return $LocationString +} + +#endregion Utility functions + +#region PowerShellGet Provider APIs Implementation +function Get-PackageProviderName +{ + return $script:PSModuleProviderName +} + +function Get-Feature +{ + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Get-Feature')) + Write-Output -InputObject (New-Feature $script:SupportsPSModulesFeatureName ) +} + +function Initialize-Provider +{ + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Initialize-Provider')) +} + +function Get-DynamicOptions +{ + param + ( + [Microsoft.PackageManagement.MetaProvider.PowerShell.OptionCategory] + $category + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Get-DynamicOptions')) + + Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:PackageManagementProviderParam -ExpectedType String -IsRequired $false) + + Write-Output -InputObject (New-DynamicOption -Category $category ` + -Name $script:PSArtifactType ` + -ExpectedType String ` + -IsRequired $false ` + -PermittedValues @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript, $script:All)) + + switch($category) + { + Package { + Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:Filter -ExpectedType String -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:Tag -ExpectedType StringArray -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name Includes -ExpectedType StringArray -IsRequired $false -PermittedValues $script:IncludeValidSet) + Write-Output -InputObject (New-DynamicOption -Category $category -Name DscResource -ExpectedType StringArray -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name RoleCapability -ExpectedType StringArray -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name Command -ExpectedType StringArray -IsRequired $false) + } + + Source { + Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:PublishLocation -ExpectedType String -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:ScriptSourceLocation -ExpectedType String -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:ScriptPublishLocation -ExpectedType String -IsRequired $false) + } + + Install + { + Write-Output -InputObject (New-DynamicOption -Category $category -Name "Scope" -ExpectedType String -IsRequired $false -PermittedValues @("CurrentUser","AllUsers")) + Write-Output -InputObject (New-DynamicOption -Category $category -Name "InstallUpdate" -ExpectedType Switch -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name 'NoPathUpdate' -ExpectedType Switch -IsRequired $false) + } + } +} + +function Add-PackageSource +{ + [CmdletBinding()] + param + ( + [string] + $Name, + + [string] + $Location, + + [bool] + $Trusted + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Add-PackageSource')) + + Set-ModuleSourcesVariable -Force + + $IsNewModuleSource = $false + $Options = $request.Options + + foreach( $o in $Options.Keys ) + { + Write-Debug ( "OPTION: {0} => {1}" -f ($o, $Options[$o]) ) + } + + if($Options.ContainsKey('IsNewModuleSource')) + { + $IsNewModuleSource = $Options['IsNewModuleSource'] + + if($IsNewModuleSource.GetType().ToString() -eq 'System.String') + { + if($IsNewModuleSource -eq 'false') + { + $IsNewModuleSource = $false + } + elseif($IsNewModuleSource -eq 'true') + { + $IsNewModuleSource = $true + } + } + } + + $IsUpdatePackageSource = $false + if($Options.ContainsKey('IsUpdatePackageSource')) + { + $IsUpdatePackageSource = $Options['IsUpdatePackageSource'] + + if($IsUpdatePackageSource.GetType().ToString() -eq 'System.String') + { + if($IsUpdatePackageSource -eq 'false') + { + $IsUpdatePackageSource = $false + } + elseif($IsUpdatePackageSource -eq 'true') + { + $IsUpdatePackageSource = $true + } + } + } + + $PublishLocation = $null + if($Options.ContainsKey($script:PublishLocation)) + { + $PublishLocation = $Options[$script:PublishLocation] + + if(-not (Microsoft.PowerShell.Management\Test-Path $PublishLocation) -and + -not (Test-WebUri -uri $PublishLocation)) + { + $PublishLocationUri = [Uri]$PublishLocation + if($PublishLocationUri.Scheme -eq 'file') + { + $message = $LocalizedData.PathNotFound -f ($PublishLocation) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $PublishLocation + } + else + { + $message = $LocalizedData.InvalidWebUri -f ($PublishLocation, "PublishLocation") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $PublishLocation + } + } + } + + $ScriptSourceLocation = $null + if($Options.ContainsKey($script:ScriptSourceLocation)) + { + $ScriptSourceLocation = $Options[$script:ScriptSourceLocation] + + if(-not (Microsoft.PowerShell.Management\Test-Path $ScriptSourceLocation) -and + -not (Test-WebUri -uri $ScriptSourceLocation)) + { + $ScriptSourceLocationUri = [Uri]$ScriptSourceLocation + if($ScriptSourceLocationUri.Scheme -eq 'file') + { + $message = $LocalizedData.PathNotFound -f ($ScriptSourceLocation) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $ScriptSourceLocation + } + else + { + $message = $LocalizedData.InvalidWebUri -f ($ScriptSourceLocation, "ScriptSourceLocation") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $ScriptSourceLocation + } + } + } + + $ScriptPublishLocation = $null + if($Options.ContainsKey($script:ScriptPublishLocation)) + { + $ScriptPublishLocation = $Options[$script:ScriptPublishLocation] + + if(-not (Microsoft.PowerShell.Management\Test-Path $ScriptPublishLocation) -and + -not (Test-WebUri -uri $ScriptPublishLocation)) + { + $ScriptPublishLocationUri = [Uri]$ScriptPublishLocation + if($ScriptPublishLocationUri.Scheme -eq 'file') + { + $message = $LocalizedData.PathNotFound -f ($ScriptPublishLocation) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $ScriptPublishLocation + } + else + { + $message = $LocalizedData.InvalidWebUri -f ($ScriptPublishLocation, "ScriptPublishLocation") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $ScriptPublishLocation + } + } + } + + # Ping and resolve the specified location + $Location = Resolve-Location -Location $Location ` + -LocationParameterName 'Location' ` + -CallerPSCmdlet $PSCmdlet + if(-not $Location) + { + # Above Resolve-Location function throws an error when it is not able to resolve a location + return + } + + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $Location) -and + -not (Test-WebUri -uri $Location) ) + { + $LocationUri = [Uri]$Location + if($LocationUri.Scheme -eq 'file') + { + $message = $LocalizedData.PathNotFound -f ($Location) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Location + } + else + { + $message = $LocalizedData.InvalidWebUri -f ($Location, "Location") + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Location + } + } + + if(Test-WildcardPattern $Name) + { + $message = $LocalizedData.RepositoryNameContainsWildCards -f ($Name) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "RepositoryNameContainsWildCards" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + } + + $LocationString = Get-ValidModuleLocation -LocationString $Location -ParameterName "Location" + + # Check if Location is already registered with another Name + $existingSourceName = Get-SourceName -Location $LocationString + + if($existingSourceName -and + ($Name -ne $existingSourceName) -and + -not $IsNewModuleSource) + { + $message = $LocalizedData.RepositoryAlreadyRegistered -f ($existingSourceName, $Location, $Name) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "RepositoryAlreadyRegistered" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + $currentSourceObject = $null + + # Check if Name is already registered + if($script:PSGetModuleSources.Contains($Name)) + { + $currentSourceObject = $script:PSGetModuleSources[$Name] + } + + if(-not $PublishLocation -and $currentSourceObject -and $currentSourceObject.PublishLocation) + { + $PublishLocation = $currentSourceObject.PublishLocation + } + + if((-not $ScriptPublishLocation) -and + $currentSourceObject -and + (Get-Member -InputObject $currentSourceObject -Name $script:ScriptPublishLocation) -and + $currentSourceObject.ScriptPublishLocation) + { + $ScriptPublishLocation = $currentSourceObject.ScriptPublishLocation + } + + if((-not $ScriptSourceLocation) -and + $currentSourceObject -and + (Get-Member -InputObject $currentSourceObject -Name $script:ScriptSourceLocation) -and + $currentSourceObject.ScriptSourceLocation) + { + $ScriptSourceLocation = $currentSourceObject.ScriptSourceLocation + } + + $IsProviderSpecified = $false; + if ($Options.ContainsKey($script:PackageManagementProviderParam)) + { + $SpecifiedProviderName = $Options[$script:PackageManagementProviderParam] + + $IsProviderSpecified = $true + + Write-Verbose ($LocalizedData.SpecifiedProviderName -f $SpecifiedProviderName) + if ($SpecifiedProviderName -eq $script:PSModuleProviderName) + { + $message = $LocalizedData.InvalidPackageManagementProviderValue -f ($SpecifiedProviderName, $script:NuGetProviderName, $script:NuGetProviderName) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidPackageManagementProviderValue" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $SpecifiedProviderName + return + } + } + else + { + $SpecifiedProviderName = $script:NuGetProviderName + Write-Verbose ($LocalizedData.ProviderNameNotSpecified -f $SpecifiedProviderName) + } + + $packageSource = $null + + $selProviders = $request.SelectProvider($SpecifiedProviderName) + + if(-not $selProviders -and $IsProviderSpecified) + { + $message = $LocalizedData.SpecifiedProviderNotAvailable -f $SpecifiedProviderName + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SpecifiedProviderNotAvailable" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $SpecifiedProviderName + } + + # Try with user specified provider or NuGet provider + foreach($SelectedProvider in $selProviders) + { + if($request.IsCanceled) + { + return + } + + if($SelectedProvider -and $SelectedProvider.Features.ContainsKey($script:SupportsPSModulesFeatureName)) + { + $packageSource = $SelectedProvider.ResolvePackageSources( (New-Request -Sources @($LocationString)) ) + } + else + { + $message = $LocalizedData.SpecifiedProviderDoesnotSupportPSModules -f $SelectedProvider.ProviderName + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SpecifiedProviderDoesnotSupportPSModules" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $SelectedProvider.ProviderName + } + + if($packageSource) + { + break + } + } + + # Poll other package provider when NuGet provider doesn't resolves the specified location + if(-not $packageSource -and -not $IsProviderSpecified) + { + Write-Verbose ($LocalizedData.PollingPackageManagementProvidersForLocation -f $LocationString) + + $moduleProviders = $request.SelectProvidersWithFeature($script:SupportsPSModulesFeatureName) + + foreach($provider in $moduleProviders) + { + if($request.IsCanceled) + { + return + } + + # Skip already tried $SpecifiedProviderName and PowerShellGet provider + if($provider.ProviderName -eq $SpecifiedProviderName -or + $provider.ProviderName -eq $script:PSModuleProviderName) + { + continue + } + + Write-Verbose ($LocalizedData.PollingSingleProviderForLocation -f ($LocationString, $provider.ProviderName)) + $packageSource = $provider.ResolvePackageSources((New-Request -Option @{} -Sources @($LocationString))) + + if($packageSource) + { + Write-Verbose ($LocalizedData.FoundProviderForLocation -f ($provider.ProviderName, $Location)) + $SelectedProvider = $provider + break + } + } + } + + if(-not $packageSource) + { + $message = $LocalizedData.SpecifiedLocationCannotBeRegistered -f $Location + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SpecifiedLocationCannotBeRegistered" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $Location + } + + $ProviderOptions = @{} + + $SelectedProvider.DynamicOptions | Microsoft.PowerShell.Core\ForEach-Object { + if($options.ContainsKey($_.Name) ) + { + $ProviderOptions[$_.Name] = $options[$_.Name] + } + } + + # Keep the existing provider options if not specified in Set-PSRepository + if($currentSourceObject) + { + $currentSourceObject.ProviderOptions.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { + if (-not $ProviderOptions.ContainsKey($_.Key) ) + { + $ProviderOptions[$_.Key] = $_.Value + } + } + } + + if(-not $PublishLocation) + { + $PublishLocation = Get-PublishLocation -Location $LocationString + } + + # Use the PublishLocation for the scripts when ScriptPublishLocation is not specified by the user + if(-not $ScriptPublishLocation) + { + $ScriptPublishLocation = $PublishLocation + + # ScriptPublishLocation and PublishLocation should be equal in case of SMB Share or Local directory paths + if($Options.ContainsKey($script:ScriptPublishLocation) -and + (Microsoft.PowerShell.Management\Test-Path -Path $ScriptPublishLocation)) + { + if($ScriptPublishLocation -ne $PublishLocation) + { + $message = $LocalizedData.PublishLocationPathsForModulesAndScriptsShouldBeEqual -f ($LocationString, $ScriptSourceLocation) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "PublishLocationPathsForModulesAndScriptsShouldBeEqual" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $Location + } + } + } + + if(-not $ScriptSourceLocation) + { + $ScriptSourceLocation = Get-ScriptSourceLocation -Location $LocationString + } + elseif($Options.ContainsKey($script:ScriptSourceLocation)) + { + # ScriptSourceLocation and SourceLocation cannot be same for they are URLs + # Both should be equal in case of SMB Share or Local directory paths + if(Microsoft.PowerShell.Management\Test-Path -Path $ScriptSourceLocation) + { + if($ScriptSourceLocation -ne $LocationString) + { + $message = $LocalizedData.SourceLocationPathsForModulesAndScriptsShouldBeEqual -f ($LocationString, $ScriptSourceLocation) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SourceLocationPathsForModulesAndScriptsShouldBeEqual" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $Location + } + } + else + { + if($ScriptSourceLocation -eq $LocationString) + { + $message = $LocalizedData.SourceLocationUrisForModulesAndScriptsShouldBeDifferent -f ($LocationString, $ScriptSourceLocation) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "SourceLocationUrisForModulesAndScriptsShouldBeDifferent" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation ` + -ExceptionObject $Location + } + } + } + + # no error so we can safely remove the source + if($script:PSGetModuleSources.Contains($Name)) + { + $null = $script:PSGetModuleSources.Remove($Name) + } + + # Add new module source + $moduleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $Name + SourceLocation = $LocationString + PublishLocation = $PublishLocation + ScriptSourceLocation = $ScriptSourceLocation + ScriptPublishLocation = $ScriptPublishLocation + Trusted=$Trusted + Registered= (-not $IsNewModuleSource) + InstallationPolicy = if($Trusted) {'Trusted'} else {'Untrusted'} + PackageManagementProvider = $SelectedProvider.ProviderName + ProviderOptions = $ProviderOptions + }) + + #region telemetry - Capture non-PSGallery registrations as telemetry events + if ($script:TelemetryEnabled) + { + + Log-NonPSGalleryRegistration -sourceLocation $moduleSource.SourceLocation ` + -installationPolicy $moduleSource.InstallationPolicy ` + -packageManagementProvider $moduleSource.PackageManagementProvider ` + -publishLocation $moduleSource.PublishLocation ` + -scriptSourceLocation $moduleSource.ScriptSourceLocation ` + -scriptPublishLocation $moduleSource.ScriptPublishLocation ` + -operationName PSGET_NONPSGALLERY_REGISTRATION ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + + } + #endregion + + $moduleSource.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository") + + # Persist the repositories only when Register-PSRepository cmdlet is used + if(-not $IsNewModuleSource) + { + $script:PSGetModuleSources.Add($Name, $moduleSource) + + $message = $LocalizedData.RepositoryRegistered -f ($Name, $LocationString) + Write-Verbose $message + + # Persist the module sources + Save-ModuleSources + } + + # return the package source object. + Write-Output -InputObject (New-PackageSourceFromModuleSource -ModuleSource $moduleSource) +} + +function Resolve-PackageSource +{ + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Resolve-PackageSource')) + + Set-ModuleSourcesVariable + + $SourceName = $request.PackageSources + + if(-not $SourceName) + { + $SourceName = "*" + } + + foreach($moduleSourceName in $SourceName) + { + if($request.IsCanceled) + { + return + } + + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $moduleSourceName,$script:wildcardOptions + $moduleSourceFound = $false + + $script:PSGetModuleSources.GetEnumerator() | + Microsoft.PowerShell.Core\Where-Object {$wildcardPattern.IsMatch($_.Key)} | + Microsoft.PowerShell.Core\ForEach-Object { + + $moduleSource = $script:PSGetModuleSources[$_.Key] + + $packageSource = New-PackageSourceFromModuleSource -ModuleSource $moduleSource + + Write-Output -InputObject $packageSource + + $moduleSourceFound = $true + } + + if(-not $moduleSourceFound) + { + $sourceName = Get-SourceName -Location $moduleSourceName + + if($sourceName) + { + $moduleSource = $script:PSGetModuleSources[$sourceName] + + $packageSource = New-PackageSourceFromModuleSource -ModuleSource $moduleSource + + Write-Output -InputObject $packageSource + } + elseif( -not (Test-WildcardPattern $moduleSourceName)) + { + $message = $LocalizedData.RepositoryNotFound -f ($moduleSourceName) + + Write-Error -Message $message -ErrorId "RepositoryNotFound" -Category InvalidOperation -TargetObject $moduleSourceName + } + } + } +} + +function Remove-PackageSource +{ + param + ( + [string] + $Name + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Remove-PackageSource')) + + Set-ModuleSourcesVariable -Force + + $ModuleSourcesToBeRemoved = @() + + foreach ($moduleSourceName in $Name) + { + if($request.IsCanceled) + { + return + } + + # Check if $Name contains any wildcards + if(Test-WildcardPattern $moduleSourceName) + { + $message = $LocalizedData.RepositoryNameContainsWildCards -f ($moduleSourceName) + Write-Error -Message $message -ErrorId "RepositoryNameContainsWildCards" -Category InvalidOperation -TargetObject $moduleSourceName + continue + } + + # Check if the specified module source name is in the registered module sources + if(-not $script:PSGetModuleSources.Contains($moduleSourceName)) + { + $message = $LocalizedData.RepositoryNotFound -f ($moduleSourceName) + Write-Error -Message $message -ErrorId "RepositoryNotFound" -Category InvalidOperation -TargetObject $moduleSourceName + continue + } + + $ModuleSourcesToBeRemoved += $moduleSourceName + $message = $LocalizedData.RepositoryUnregistered -f ($moduleSourceName) + Write-Verbose $message + } + + # Remove the module source + $ModuleSourcesToBeRemoved | Microsoft.PowerShell.Core\ForEach-Object { $null = $script:PSGetModuleSources.Remove($_) } + + # Persist the module sources + Save-ModuleSources +} + +function Find-Package +{ + [CmdletBinding()] + param + ( + [string[]] + $names, + + [string] + $requiredVersion, + + [string] + $minimumVersion, + + [string] + $maximumVersion + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Find-Package')) + + Set-ModuleSourcesVariable + + if($RequiredVersion -and $MinimumVersion) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.VersionRangeAndRequiredVersionCannotBeSpecifiedTogether ` + -ErrorId "VersionRangeAndRequiredVersionCannotBeSpecifiedTogether" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + if($RequiredVersion -or $MinimumVersion) + { + if(-not $names -or $names.Count -ne 1 -or (Test-WildcardPattern -Name $names[0])) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.VersionParametersAreAllowedOnlyWithSingleName ` + -ErrorId "VersionParametersAreAllowedOnlyWithSingleName" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + } + + $options = $request.Options + + foreach( $o in $options.Keys ) + { + Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) ) + } + + # When using -Name, we don't send PSGet-specific properties to the server - we will filter it ourselves + $postFilter = New-Object -TypeName System.Collections.Hashtable + if($options.ContainsKey("Name")) + { + if($options.ContainsKey("Includes")) + { + $postFilter["Includes"] = $options["Includes"] + $null = $options.Remove("Includes") + } + + if($options.ContainsKey("DscResource")) + { + $postFilter["DscResource"] = $options["DscResource"] + $null = $options.Remove("DscResource") + } + + if($options.ContainsKey('RoleCapability')) + { + $postFilter['RoleCapability'] = $options['RoleCapability'] + $null = $options.Remove('RoleCapability') + } + + if($options.ContainsKey("Command")) + { + $postFilter["Command"] = $options["Command"] + $null = $options.Remove("Command") + } + } + + $LocationOGPHashtable = [ordered]@{} + if($options -and $options.ContainsKey('Source')) + { + $SourceNames = $($options['Source']) + + Write-Verbose ($LocalizedData.SpecifiedSourceName -f ($SourceNames)) + + foreach($sourceName in $SourceNames) + { + if($script:PSGetModuleSources.Contains($sourceName)) + { + $ModuleSource = $script:PSGetModuleSources[$sourceName] + $LocationOGPHashtable[$ModuleSource.SourceLocation] = (Get-ProviderName -PSCustomObject $ModuleSource) + } + else + { + $sourceByLocation = Get-SourceName -Location $sourceName + + if ($sourceByLocation) + { + $ModuleSource = $script:PSGetModuleSources[$sourceByLocation] + $LocationOGPHashtable[$ModuleSource.SourceLocation] = (Get-ProviderName -PSCustomObject $ModuleSource) + } + else + { + $message = $LocalizedData.RepositoryNotFound -f ($sourceName) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "RepositoryNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $sourceName + } + } + } + } + elseif($options -and + $options.ContainsKey($script:PackageManagementProviderParam) -and + $options.ContainsKey('Location')) + { + $Location = $options['Location'] + $PackageManagementProvider = $options['PackageManagementProvider'] + + Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($Location, $PackageManagementProvider)) + + $LocationOGPHashtable[$Location] = $PackageManagementProvider + } + else + { + Write-Verbose $LocalizedData.NoSourceNameIsSpecified + + $script:PSGetModuleSources.Values | Microsoft.PowerShell.Core\ForEach-Object { $LocationOGPHashtable[$_.SourceLocation] = (Get-ProviderName -PSCustomObject $_) } + } + + $artifactTypes = $script:PSArtifactTypeModule + if($options.ContainsKey($script:PSArtifactType)) + { + $artifactTypes = $options[$script:PSArtifactType] + } + + if($artifactTypes -eq $script:All) + { + $artifactTypes = @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript) + } + + $providerOptions = @{} + + if($options.ContainsKey($script:AllVersions)) + { + $providerOptions[$script:AllVersions] = $options[$script:AllVersions] + } + + if($options.ContainsKey($script:Filter)) + { + $Filter = $options[$script:Filter] + $providerOptions['Contains'] = $Filter + } + + if($options.ContainsKey($script:Tag)) + { + $userSpecifiedTags = $options[$script:Tag] | Microsoft.PowerShell.Utility\Select-Object -Unique + } + else + { + $userSpecifiedTags = @($script:NotSpecified) + } + + $specifiedDscResources = @() + if($options.ContainsKey('DscResource')) + { + $specifiedDscResources = $options['DscResource'] | + Microsoft.PowerShell.Utility\Select-Object -Unique | + Microsoft.PowerShell.Core\ForEach-Object {"$($script:DscResource)_$_"} + } + + $specifiedRoleCapabilities = @() + if($options.ContainsKey('RoleCapability')) + { + $specifiedRoleCapabilities = $options['RoleCapability'] | + Microsoft.PowerShell.Utility\Select-Object -Unique | + Microsoft.PowerShell.Core\ForEach-Object {"$($script:RoleCapability)_$_"} + } + + $specifiedCommands = @() + if($options.ContainsKey('Command')) + { + $specifiedCommands = $options['Command'] | + Microsoft.PowerShell.Utility\Select-Object -Unique | + Microsoft.PowerShell.Core\ForEach-Object {"$($script:Command)_$_"} + } + + $specifiedIncludes = @() + if($options.ContainsKey('Includes')) + { + $includes = $options['Includes'] | + Microsoft.PowerShell.Utility\Select-Object -Unique | + Microsoft.PowerShell.Core\ForEach-Object {"$($script:Includes)_$_"} + + # Add PSIncludes_DscResource to $specifiedIncludes iff -DscResource names are not specified + # Add PSIncludes_RoleCapability to $specifiedIncludes iff -RoleCapability names are not specified + # Add PSIncludes_Cmdlet or PSIncludes_Function to $specifiedIncludes iff -Command names are not specified + # otherwise $script:NotSpecified will be added to $specifiedIncludes + if($includes) + { + if(-not $specifiedDscResources -and ($includes -contains "$($script:Includes)_DscResource") ) + { + $specifiedIncludes += "$($script:Includes)_DscResource" + } + + if(-not $specifiedRoleCapabilities -and ($includes -contains "$($script:Includes)_RoleCapability") ) + { + $specifiedIncludes += "$($script:Includes)_RoleCapability" + } + + if(-not $specifiedCommands) + { + if($includes -contains "$($script:Includes)_Cmdlet") + { + $specifiedIncludes += "$($script:Includes)_Cmdlet" + } + + if($includes -contains "$($script:Includes)_Function") + { + $specifiedIncludes += "$($script:Includes)_Function" + } + + if($includes -contains "$($script:Includes)_Workflow") + { + $specifiedIncludes += "$($script:Includes)_Workflow" + } + } + } + } + + if(-not $specifiedDscResources) + { + $specifiedDscResources += $script:NotSpecified + } + + if(-not $specifiedRoleCapabilities) + { + $specifiedRoleCapabilities += $script:NotSpecified + } + + if(-not $specifiedCommands) + { + $specifiedCommands += $script:NotSpecified + } + + if(-not $specifiedIncludes) + { + $specifiedIncludes += $script:NotSpecified + } + + $providerSearchTags = @{} + + foreach($tag in $userSpecifiedTags) + { + foreach($include in $specifiedIncludes) + { + foreach($command in $specifiedCommands) + { + foreach($resource in $specifiedDscResources) + { + foreach($roleCapability in $specifiedRoleCapabilities) + { + $providerTags = @() + if($resource -ne $script:NotSpecified) + { + $providerTags += $resource + } + + if($roleCapability -ne $script:NotSpecified) + { + $providerTags += $roleCapability + } + + if($command -ne $script:NotSpecified) + { + $providerTags += $command + } + + if($include -ne $script:NotSpecified) + { + $providerTags += $include + } + + if($tag -ne $script:NotSpecified) + { + $providerTags += $tag + } + + if($providerTags) + { + $providerSearchTags["$tag $resource $roleCapability $command $include"] = $providerTags + } + } + } + } + } + } + + $InstallationPolicy = "Untrusted" + if($options.ContainsKey('InstallationPolicy')) + { + $InstallationPolicy = $options['InstallationPolicy'] + } + + $streamedResults = @() + + foreach($artifactType in $artifactTypes) + { + foreach($kvPair in $LocationOGPHashtable.GetEnumerator()) + { + if($request.IsCanceled) + { + return + } + + $Location = $kvPair.Key + if($artifactType -eq $script:PSArtifactTypeScript) + { + $sourceName = Get-SourceName -Location $Location + + if($SourceName) + { + $ModuleSource = $script:PSGetModuleSources[$SourceName] + + # Skip source if no ScriptSourceLocation is available. + if(-not $ModuleSource.ScriptSourceLocation) + { + if($options.ContainsKey('Source')) + { + $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($ModuleSource.Name) + Write-Error -Message $message ` + -ErrorId 'ScriptSourceLocationIsMissing' ` + -Category InvalidArgument ` + -TargetObject $ModuleSource.Name + } + + continue + } + + $Location = $ModuleSource.ScriptSourceLocation + } + } + + $ProviderName = $kvPair.Value + + Write-Verbose ($LocalizedData.GettingPackageManagementProviderObject -f ($ProviderName)) + + $provider = $request.SelectProvider($ProviderName) + + if(-not $provider) + { + Write-Error -Message ($LocalizedData.PackageManagementProviderIsNotAvailable -f $ProviderName) + + Continue + } + + Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($Location, $provider.ProviderName)) + + if($providerSearchTags.Values.Count) + { + $tagList = $providerSearchTags.Values + } + else + { + $tagList = @($script:NotSpecified) + } + + $namesParameterEmpty = ($names.Count -eq 1) -and ($names[0] -eq '') + + foreach($providerTag in $tagList) + { + if($request.IsCanceled) + { + return + } + + $FilterOnTag = @() + + if($providerTag -ne $script:NotSpecified) + { + $FilterOnTag = $providerTag + } + + if(Microsoft.PowerShell.Management\Test-Path -Path $Location) + { + if($artifactType -eq $script:PSArtifactTypeScript) + { + $FilterOnTag += 'PSScript' + } + elseif($artifactType -eq $script:PSArtifactTypeModule) + { + $FilterOnTag += 'PSModule' + } + } + + if($FilterOnTag) + { + $providerOptions["FilterOnTag"] = $FilterOnTag + } + elseif($providerOptions.ContainsKey('FilterOnTag')) + { + $null = $providerOptions.Remove('FilterOnTag') + } + + if($request.Options.ContainsKey($script:FindByCanonicalId)) + { + $providerOptions[$script:FindByCanonicalId] = $request.Options[$script:FindByCanonicalId] + } + + $providerOptions["Headers"] = 'PSGalleryClientVersion=1.1' + + $pkgs = $provider.FindPackages($names, + $requiredVersion, + $minimumVersion, + $maximumVersion, + (New-Request -Sources @($Location) -Options $providerOptions) ) + + foreach($pkg in $pkgs) + { + if($request.IsCanceled) + { + return + } + + # $pkg.Name has to match any of the supplied names, using PowerShell wildcards + if ($namesParameterEmpty -or ($names | % { if ($pkg.Name -like $_){return $true; break} } -End {return $false})) + { + $includePackage = $true + + # If -Name was provided, we need to post-filter + # Filtering has AND semantics between different parameters and OR within a parameter (each parameter is potentially an array) + if($options.ContainsKey("Name") -and $postFilter.Count -gt 0) + { + if ($pkg.Metadata["DscResources"].Count -gt 0) + { + $pkgDscResources = $pkg.Metadata["DscResources"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + } + else + { + $pkgDscResources = $pkg.Metadata["tags"] -Split " " ` + | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` + | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:DscResource, [System.StringComparison]::OrdinalIgnoreCase) } ` + | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:DscResource.Length + 1) } + } + + if ($pkg.Metadata['RoleCapabilities'].Count -gt 0) + { + $pkgRoleCapabilities = $pkg.Metadata['RoleCapabilities'] -Split ' ' | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + } + else + { + $pkgRoleCapabilities = $pkg.Metadata["tags"] -Split ' ' ` + | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` + | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:RoleCapability, [System.StringComparison]::OrdinalIgnoreCase) } ` + | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:RoleCapability.Length + 1) } + } + + if ($pkg.Metadata["Functions"].Count -gt 0) + { + $pkgFunctions = $pkg.Metadata["Functions"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + } + else + { + $pkgFunctions = $pkg.Metadata["tags"] -Split " " ` + | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` + | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:Function, [System.StringComparison]::OrdinalIgnoreCase) } ` + | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:Function.Length + 1) } + } + + if ($pkg.Metadata["Cmdlets"].Count -gt 0) + { + $pkgCmdlets = $pkg.Metadata["Cmdlets"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + } + else + { + $pkgCmdlets = $pkg.Metadata["tags"] -Split " " ` + | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` + | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:Cmdlet, [System.StringComparison]::OrdinalIgnoreCase) } ` + | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:Cmdlet.Length + 1) } + } + + if ($pkg.Metadata["Workflows"].Count -gt 0) + { + $pkgWorkflows = $pkg.Metadata["Workflows"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } + } + else + { + $pkgWorkflows = $pkg.Metadata["tags"] -Split " " ` + | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` + | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:Workflow, [System.StringComparison]::OrdinalIgnoreCase) } ` + | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:Workflow.Length + 1) } + } + + foreach ($key in $postFilter.Keys) + { + switch ($key) + { + "DscResource" { + $values = $postFilter[$key] + + $includePackage = $false + + foreach ($value in $values) + { + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $value,$script:wildcardOptions + + $pkgDscResources | Microsoft.PowerShell.Core\ForEach-Object { + if ($wildcardPattern.IsMatch($_)) + { + $includePackage = $true + break + } + } + } + + if (-not $includePackage) + { + break + } + } + + 'RoleCapability' { + $values = $postFilter[$key] + + $includePackage = $false + + foreach ($value in $values) + { + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $value,$script:wildcardOptions + + $pkgRoleCapabilities | Microsoft.PowerShell.Core\ForEach-Object { + if ($wildcardPattern.IsMatch($_)) + { + $includePackage = $true + break + } + } + } + + if (-not $includePackage) + { + break + } + } + + "Command" { + $values = $postFilter[$key] + + $includePackage = $false + + foreach ($value in $values) + { + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $value,$script:wildcardOptions + + $pkgFunctions | Microsoft.PowerShell.Core\ForEach-Object { + if ($wildcardPattern.IsMatch($_)) + { + $includePackage = $true + break + } + } + + $pkgCmdlets | Microsoft.PowerShell.Core\ForEach-Object { + if ($wildcardPattern.IsMatch($_)) + { + $includePackage = $true + break + } + } + + $pkgWorkflows | Microsoft.PowerShell.Core\ForEach-Object { + if ($wildcardPattern.IsMatch($_)) + { + $includePackage = $true + break + } + } + } + + if (-not $includePackage) + { + break + } + } + + "Includes" { + $values = $postFilter[$key] + + $includePackage = $false + + foreach ($value in $values) + { + switch ($value) + { + "Cmdlet" { if ($pkgCmdlets ) { $includePackage = $true } } + "Function" { if ($pkgFunctions ) { $includePackage = $true } } + "DscResource" { if ($pkgDscResources ) { $includePackage = $true } } + "RoleCapability" { if ($pkgRoleCapabilities ) { $includePackage = $true } } + "Workflow" { if ($pkgWorkflows ) { $includePackage = $true } } + } + } + + if (-not $includePackage) + { + break + } + } + } + } + } + + if ($includePackage) + { + $fastPackageReference = New-FastPackageReference -ProviderName $provider.ProviderName ` + -PackageName $pkg.Name ` + -Version $pkg.Version ` + -Source $Location ` + -ArtifactType $artifactType + + if($streamedResults -notcontains $fastPackageReference) + { + $streamedResults += $fastPackageReference + + $FromTrustedSource = $false + + $ModuleSourceName = Get-SourceName -Location $Location + + if($ModuleSourceName) + { + $FromTrustedSource = $script:PSGetModuleSources[$ModuleSourceName].Trusted + } + elseif($InstallationPolicy -eq "Trusted") + { + $FromTrustedSource = $true + } + + $sid = New-SoftwareIdentityFromPackage -Package $pkg ` + -PackageManagementProviderName $provider.ProviderName ` + -SourceLocation $Location ` + -IsFromTrustedSource:$FromTrustedSource ` + -Type $artifactType ` + -request $request + + $script:FastPackRefHastable[$fastPackageReference] = $pkg + + Write-Output -InputObject $sid + } + } + } + } + } + } + } +} + +function Download-Package +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $FastPackageReference, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Location + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Download-Package')) + + Install-PackageUtility -FastPackageReference $FastPackageReference -Request $Request -Location $Location +} + +function Install-Package +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $FastPackageReference + ) + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Install-Package')) + + Install-PackageUtility -FastPackageReference $FastPackageReference -Request $Request +} + +function Install-PackageUtility +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $FastPackageReference, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Location, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + $request + ) + + Set-ModuleSourcesVariable + + Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Install-PackageUtility')) + + Write-Debug ($LocalizedData.FastPackageReference -f $fastPackageReference) + + $Force = $false + $MinimumVersion = $null + $RequiredVersion = $null + $IsSavePackage = $false + $Scope = $null + $NoPathUpdate = $false + + # take the fastPackageReference and get the package object again. + $parts = $fastPackageReference -Split '[|]' + + if( $parts.Length -eq 5 ) + { + $providerName = $parts[0] + $packageName = $parts[1] + $version = $parts[2] + $sourceLocation= $parts[3] + $artfactType = $parts[4] + + # The default destination location for Modules and Scripts is ProgramFiles path + $scriptDestination = $script:ProgramFilesScriptsPath + $moduleDestination = $script:programFilesModulesPath + $Scope = 'AllUsers' + + if($artfactType -eq $script:PSArtifactTypeScript) + { + $AdminPreviligeErrorMessage = $LocalizedData.InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath) + $AdminPreviligeErrorId = 'InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser' + } + else + { + $AdminPreviligeErrorMessage = $LocalizedData.InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:programFilesModulesPath, $script:MyDocumentsModulesPath) + $AdminPreviligeErrorId = 'InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser' + } + + $installUpdate = $false + + $options = $request.Options + + if($options) + { + foreach( $o in $options.Keys ) + { + Write-Debug ("OPTION: {0} => {1}" -f ($o, $request.Options[$o]) ) + } + + if($options.ContainsKey('Scope')) + { + $Scope = $options['Scope'] + Write-Verbose ($LocalizedData.SpecifiedInstallationScope -f $Scope) + + if($Scope -eq "CurrentUser") + { + $scriptDestination = $script:MyDocumentsScriptsPath + $moduleDestination = $script:MyDocumentsModulesPath + } + elseif($Scope -eq "AllUsers") + { + $scriptDestination = $script:ProgramFilesScriptsPath + $moduleDestination = $script:programFilesModulesPath + + if(-not (Test-RunningAsElevated)) + { + # Throw an error when Install-Module/Script is used as a non-admin user and '-Scope CurrentUser' is not specified + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $AdminPreviligeErrorMessage ` + -ErrorId $AdminPreviligeErrorId ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + } + } + elseif($Location) + { + $IsSavePackage = $true + $Scope = $null + + $moduleDestination = $Location + $scriptDestination = $Location + } + # if no scope and no destination path and not elevated, then raise an error + elseif(-not (Test-RunningAsElevated)) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $AdminPreviligeErrorMessage ` + -ErrorId $AdminPreviligeErrorId ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + if($options.ContainsKey('Force')) + { + $Force = $options['Force'] + + if($Force.GetType().ToString() -eq 'System.String') + { + if($Force -eq 'false') + { + $Force = $false + } + elseif($Force -eq 'true') + { + $Force = $true + } + } + } + + if($options.ContainsKey('NoPathUpdate')) + { + $NoPathUpdate = $options['NoPathUpdate'] + + if($NoPathUpdate.GetType().ToString() -eq 'System.String') + { + if($NoPathUpdate -eq 'false') + { + $NoPathUpdate = $false + } + elseif($NoPathUpdate -eq 'true') + { + $NoPathUpdate = $true + } + } + } + + if($options.ContainsKey('MinimumVersion')) + { + $MinimumVersion = $options['MinimumVersion'] + } + + if($options.ContainsKey('RequiredVersion')) + { + $RequiredVersion = $options['RequiredVersion'] + } + + if($options.ContainsKey('InstallUpdate')) + { + $installUpdate = $options['InstallUpdate'] + + if($installUpdate.GetType().ToString() -eq 'System.String') + { + if($installUpdate -eq 'false') + { + $installUpdate = $false + } + elseif($installUpdate -eq 'true') + { + $installUpdate = $true + } + } + } + + if($Scope -and ($artfactType -eq $script:PSArtifactTypeScript) -and (-not $installUpdate)) + { + ValidateAndSet-PATHVariableIfUserAccepts -Scope $Scope ` + -ScopePath $scriptDestination ` + -Request $request ` + -NoPathUpdate:$NoPathUpdate ` + -Force:$Force + } + + if($artfactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.ModuleDestination -f @($moduleDestination) + } + else + { + $message = $LocalizedData.ScriptDestination -f @($scriptDestination, $moduleDestination) + } + Write-Verbose $message + } + + Write-Debug "ArtfactType is $artfactType" + + if($artfactType -eq $script:PSArtifactTypeModule) + { + # Test if module is already installed + $InstalledModuleInfo = if(-not $IsSavePackage){ Test-ModuleInstalled -Name $packageName -RequiredVersion $RequiredVersion } + + if(-not $Force -and $InstalledModuleInfo) + { + if($RequiredVersion -and (Test-ModuleSxSVersionSupport)) + { + # Check if the module with the required version is already installed otherwise proceed to install/update. + if($InstalledModuleInfo) + { + $message = $LocalizedData.ModuleWithRequiredVersionAlreadyInstalled -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase, $InstalledModuleInfo.Version) + Write-Error -Message $message -ErrorId "ModuleWithRequiredVersionAlreadyInstalled" -Category InvalidOperation + + return + } + } + else + { + if(-not $installUpdate) + { + if( (-not $MinimumVersion -and ($version -ne $InstalledModuleInfo.Version)) -or + ($MinimumVersion -and ($MinimumVersion -gt $InstalledModuleInfo.Version))) + { + if($PSVersionTable.PSVersion -ge [Version]"5.0") + { + $message = $LocalizedData.ModuleAlreadyInstalledSxS -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase, $version, $InstalledModuleInfo.Version, $version) + } + else + { + $message = $LocalizedData.ModuleAlreadyInstalled -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase, $InstalledModuleInfo.Version, $version) + } + Write-Error -Message $message -ErrorId "ModuleAlreadyInstalled" -Category InvalidOperation + } + else + { + $message = $LocalizedData.ModuleAlreadyInstalledVerbose -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase) + Write-Verbose $message + } + + return + } + else + { + if($InstalledModuleInfo.Version -lt $version) + { + $message = $LocalizedData.FoundModuleUpdate -f ($InstalledModuleInfo.Name, $version) + Write-Verbose $message + } + else + { + $message = $LocalizedData.NoUpdateAvailable -f ($InstalledModuleInfo.Name) + Write-Verbose $message + return + } + } + } + } + } + + if($artfactType -eq $script:PSArtifactTypeScript) + { + # Test if script is already installed + $InstalledScriptInfo = if(-not $IsSavePackage){ Test-ScriptInstalled -Name $packageName } + + Write-Debug "InstalledScriptInfo is $InstalledScriptInfo" + + if(-not $Force -and $InstalledScriptInfo) + { + if(-not $installUpdate) + { + if( (-not $MinimumVersion -and ($version -ne $InstalledScriptInfo.Version)) -or + ($MinimumVersion -and ($MinimumVersion -gt $InstalledScriptInfo.Version))) + { + $message = $LocalizedData.ScriptAlreadyInstalled -f ($InstalledScriptInfo.Version, $InstalledScriptInfo.Name, $InstalledScriptInfo.ScriptBase, $InstalledScriptInfo.Version, $version) + Write-Error -Message $message -ErrorId "ScriptAlreadyInstalled" -Category InvalidOperation + } + else + { + $message = $LocalizedData.ScriptAlreadyInstalledVerbose -f ($InstalledScriptInfo.Version, $InstalledScriptInfo.Name, $InstalledScriptInfo.ScriptBase) + Write-Verbose $message + } + + return + } + else + { + if($InstalledScriptInfo.Version -lt $version) + { + $message = $LocalizedData.FoundScriptUpdate -f ($InstalledScriptInfo.Name, $version) + Write-Verbose $message + } + else + { + $message = $LocalizedData.NoScriptUpdateAvailable -f ($InstalledScriptInfo.Name) + Write-Verbose $message + return + } + } + } + + # Throw an error if there is a command with the same name and -force is not specified. + if(-not $installUpdate -and + -not $IsSavePackage -and + -not $Force) + { + $cmd = Microsoft.PowerShell.Core\Get-Command -Name $packageName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if($cmd) + { + $message = $LocalizedData.CommandAlreadyAvailable -f ($packageName) + Write-Error -Message $message -ErrorId CommandAlreadyAvailableWitScriptName -Category InvalidOperation + return + } + } + } + + # create a temp folder and download the module + $tempDestination = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath -ChildPath "$(Microsoft.PowerShell.Utility\Get-Random)" + $null = Microsoft.PowerShell.Management\New-Item -Path $tempDestination -ItemType Directory -Force -Confirm:$false -WhatIf:$false + + try + { + $provider = $request.SelectProvider($providerName) + if(-not $provider) + { + Write-Error -Message ($LocalizedData.PackageManagementProviderIsNotAvailable -f $providerName) + + return + } + + if($request.IsCanceled) + { + return + } + + Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($provider.ProviderName, $providerName)) + + $newRequest = New-Request -Options @{Destination=$tempDestination; + ExcludeVersion=$true} ` + -Sources @($SourceLocation) + + if($artfactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.DownloadingModuleFromGallery -f ($packageName, $version, $sourceLocation) + } + else + { + $message = $LocalizedData.DownloadingScriptFromGallery -f ($packageName, $version, $sourceLocation) + } + Write-Verbose $message + + $installedPkgs = $provider.InstallPackage($script:FastPackRefHastable[$fastPackageReference], $newRequest) + + foreach($pkg in $installedPkgs) + { + if($request.IsCanceled) + { + return + } + + $destinationModulePath = Microsoft.PowerShell.Management\Join-Path -Path $moduleDestination -ChildPath $pkg.Name + + # Side-by-Side module version is avialable on PowerShell 5.0 or later versions only + # By default, PowerShell module versions will be installed/updated Side-by-Side. + if(Test-ModuleSxSVersionSupport) + { + $destinationModulePath = Microsoft.PowerShell.Management\Join-Path -Path $destinationModulePath -ChildPath $pkg.Version + } + + $destinationscriptPath = $scriptDestination + + # Get actual artifact type from the package + $packageType = $script:PSArtifactTypeModule + $installLocation = $destinationModulePath + $tempPackagePath = Microsoft.PowerShell.Management\Join-Path -Path $tempDestination -ChildPath $pkg.Name + if(Microsoft.PowerShell.Management\Test-Path -Path $tempPackagePath) + { + $packageFiles = Microsoft.PowerShell.Management\Get-ChildItem -Path $tempPackagePath -Recurse -Exclude "*.nupkg","*.nuspec" + + if($packageFiles -and $packageFiles.GetType().ToString() -eq 'System.IO.FileInfo' -and $packageFiles.Name -eq "$($pkg.Name).ps1") + { + $packageType = $script:PSArtifactTypeScript + $installLocation = $destinationscriptPath + } + } + + $AdditionalParams = @{} + + if(-not $IsSavePackage) + { + # During the install operation: + # InstalledDate should be the current Get-Date value + # UpdatedDate should be null + # + # During the update operation: + # InstalledDate should be from the previous version's InstalledDate otherwise current Get-Date value + # UpdatedDate should be the current Get-Date value + # + $InstalledDate = Microsoft.PowerShell.Utility\Get-Date + + if($installUpdate) + { + $AdditionalParams['UpdatedDate'] = Microsoft.PowerShell.Utility\Get-Date + + $InstalledItemDetails = $null + if($packageType -eq $script:PSArtifactTypeModule) + { + $InstalledItemDetails = Get-InstalledModuleDetails -Name $pkg.Name | Select-Object -Last 1 + } + elseif($packageType -eq $script:PSArtifactTypeScript) + { + $InstalledItemDetails = Get-InstalledScriptDetails -Name $pkg.Name | Select-Object -Last 1 + } + + if($InstalledItemDetails -and + $InstalledItemDetails.PSGetItemInfo -and + (Get-Member -InputObject $InstalledItemDetails.PSGetItemInfo -Name 'InstalledDate') -and + $InstalledItemDetails.PSGetItemInfo.InstalledDate) + { + $InstalledDate = $InstalledItemDetails.PSGetItemInfo.InstalledDate + } + } + + $AdditionalParams['InstalledDate'] = $InstalledDate + } + + $sid = New-SoftwareIdentityFromPackage -Package $pkg ` + -SourceLocation $sourceLocation ` + -PackageManagementProviderName $provider.ProviderName ` + -Request $request ` + -Type $packageType ` + -InstalledLocation $installLocation ` + @AdditionalParams + + # construct the PSGetItemInfo from SoftwareIdentity and persist it + $psgItemInfo = New-PSGetItemInfo -SoftwareIdentity $pkg ` + -PackageManagementProviderName $provider.ProviderName ` + -SourceLocation $sourceLocation ` + -Type $packageType ` + -InstalledLocation $installLocation ` + @AdditionalParams + + if($packageType -eq $script:PSArtifactTypeModule) + { + if ($psgItemInfo.PowerShellGetFormatVersion -and + ($script:SupportedPSGetFormatVersionMajors -notcontains $psgItemInfo.PowerShellGetFormatVersion.Major)) + { + $message = $LocalizedData.NotSupportedPowerShellGetFormatVersion -f ($psgItemInfo.Name, $psgItemInfo.PowerShellGetFormatVersion, $psgItemInfo.Name) + Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation + continue + } + + if(-not $psgItemInfo.PowerShellGetFormatVersion) + { + $sourceModulePath = Microsoft.PowerShell.Management\Join-Path $tempDestination $pkg.Name + } + else + { + $sourceModulePath = Microsoft.PowerShell.Management\Join-Path $tempDestination "$($pkg.Name)\Content\*\$script:ModuleReferences\$($pkg.Name)" + } + + $CurrentModuleInfo = $null + + # Validate the module + if(-not $IsSavePackage) + { + $CurrentModuleInfo = Test-ValidManifestModule -ModuleBasePath $sourceModulePath + + if(-not $CurrentModuleInfo) + { + $message = $LocalizedData.InvalidPSModule -f ($pkg.Name) + Write-Error -Message $message -ErrorId "InvalidManifestModule" -Category InvalidOperation + continue + } + } + + # Test if module is already installed + $InstalledModuleInfo2 = if(-not $IsSavePackage){ Test-ModuleInstalled -Name $pkg.Name -RequiredVersion $pkg.Version } + + if($pkg.Name -ne $packageName) + { + if(-not $Force -and $InstalledModuleInfo2) + { + if(Test-ModuleSxSVersionSupport) + { + if($pkg.version -eq $InstalledModuleInfo2.Version) + { + if(-not $installUpdate) + { + $message = $LocalizedData.ModuleWithRequiredVersionAlreadyInstalled -f ($InstalledModuleInfo2.Version, $InstalledModuleInfo2.Name, $InstalledModuleInfo2.ModuleBase, $InstalledModuleInfo2.Version) + } + else + { + $message = $LocalizedData.NoUpdateAvailable -f ($pkg.Name) + } + + Write-Verbose $message + Continue + } + } + else + { + if(-not $installUpdate) + { + $message = $LocalizedData.ModuleAlreadyInstalledVerbose -f ($InstalledModuleInfo2.Version, $InstalledModuleInfo2.Name, $InstalledModuleInfo2.ModuleBase) + Write-Verbose $message + Continue + } + else + { + if($pkg.version -gt $InstalledModuleInfo2.Version) + { + $message = $LocalizedData.FoundModuleUpdate -f ($pkg.Name, $pkg.Version) + Write-Verbose $message + } + else + { + $message = $LocalizedData.NoUpdateAvailable -f ($pkg.Name) + Write-Verbose $message + Continue + } + } + } + } + + if($IsSavePackage) + { + $DependencyInstallMessage = $LocalizedData.SavingDependencyModule -f ($pkg.Name, $pkg.Version, $packageName) + } + else + { + $DependencyInstallMessage = $LocalizedData.InstallingDependencyModule -f ($pkg.Name, $pkg.Version, $packageName) + } + + Write-Verbose $DependencyInstallMessage + } + + # check if module is in use + if($InstalledModuleInfo2) + { + $moduleInUse = Test-ModuleInUse -ModuleBasePath $InstalledModuleInfo2.ModuleBase ` + -ModuleName $InstalledModuleInfo2.Name ` + -ModuleVersion $InstalledModuleInfo2.Version ` + -Verbose:$VerbosePreference ` + -WarningAction $WarningPreference ` + -ErrorAction $ErrorActionPreference ` + -Debug:$DebugPreference + + if($moduleInUse) + { + $message = $LocalizedData.ModuleIsInUse -f ($psgItemInfo.Name) + Write-Verbose $message + continue + } + } + + Copy-Module -SourcePath $sourceModulePath -DestinationPath $destinationModulePath -PSGetItemInfo $psgItemInfo + + if(-not $IsSavePackage) + { + # Write warning messages if externally managed module dependencies are not installed. + $ExternalModuleDependencies = Get-ExternalModuleDependencies -PSModuleInfo $CurrentModuleInfo + foreach($ExternalDependency in $ExternalModuleDependencies) + { + $depModuleInfo = Test-ModuleInstalled -Name $ExternalDependency + + if(-not $depModuleInfo) + { + Write-Warning -Message ($LocalizedData.MissingExternallyManagedModuleDependency -f $ExternalDependency,$pkg.Name,$ExternalDependency) + } + else + { + Write-Verbose -Message ($LocalizedData.ExternallyManagedModuleDependencyIsInstalled -f $ExternalDependency) + } + } + } + + # Remove the old module base folder if it is different from the required destination module path when -Force is specified + if($Force -and + $InstalledModuleInfo2 -and + -not $destinationModulePath.StartsWith($InstalledModuleInfo2.ModuleBase, [System.StringComparison]::OrdinalIgnoreCase)) + { + Microsoft.PowerShell.Management\Remove-Item -Path $InstalledModuleInfo2.ModuleBase ` + -Force -Recurse ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + } + + if($IsSavePackage) + { + $message = $LocalizedData.ModuleSavedSuccessfully -f ($psgItemInfo.Name) + } + else + { + $message = $LocalizedData.ModuleInstalledSuccessfully -f ($psgItemInfo.Name) + } + Write-Verbose $message + } + + + if($packageType -eq $script:PSArtifactTypeScript) + { + if ($psgItemInfo.PowerShellGetFormatVersion -and + ($script:SupportedPSGetFormatVersionMajors -notcontains $psgItemInfo.PowerShellGetFormatVersion.Major)) + { + $message = $LocalizedData.NotSupportedPowerShellGetFormatVersionScripts -f ($psgItemInfo.Name, $psgItemInfo.PowerShellGetFormatVersion, $psgItemInfo.Name) + Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation + continue + } + + $sourceScriptPath = Microsoft.PowerShell.Management\Join-Path -Path $tempPackagePath -ChildPath "$($pkg.Name).ps1" + + $currentScriptInfo = $null + if(-not $IsSavePackage) + { + # Validate the script + $currentScriptInfo = Test-ScriptFileInfo -Path $sourceScriptPath -ErrorAction SilentlyContinue + + if(-not $currentScriptInfo) + { + $message = $LocalizedData.InvalidPowerShellScriptFile -f ($pkg.Name) + Write-Error -Message $message -ErrorId "InvalidPowerShellScriptFile" -Category InvalidOperation -TargetObject $pkg.Name + continue + } + } + + # Test if script is already installed + $InstalledScriptInfo2 = if(-not $IsSavePackage){ Test-ScriptInstalled -Name $pkg.Name } + + if($pkg.Name -ne $packageName) + { + if(-not $Force -and $InstalledScriptInfo2) + { + if(-not $installUpdate) + { + $message = $LocalizedData.ScriptAlreadyInstalledVerbose -f ($InstalledScriptInfo2.Version, $InstalledScriptInfo2.Name, $InstalledScriptInfo2.ScriptBase) + Write-Verbose $message + Continue + } + else + { + if($pkg.version -gt $InstalledScriptInfo2.Version) + { + $message = $LocalizedData.FoundScriptUpdate -f ($pkg.Name, $pkg.Version) + Write-Verbose $message + } + else + { + $message = $LocalizedData.NoScriptUpdateAvailable -f ($pkg.Name) + Write-Verbose $message + Continue + } + } + } + + if($IsSavePackage) + { + $DependencyInstallMessage = $LocalizedData.SavingDependencyScript -f ($pkg.Name, $pkg.Version, $packageName) + } + else + { + $DependencyInstallMessage = $LocalizedData.InstallingDependencyScript -f ($pkg.Name, $pkg.Version, $packageName) + } + + Write-Verbose $DependencyInstallMessage + } + + Write-Debug "SourceScriptPath is $sourceScriptPath and DestinationscriptPath is $destinationscriptPath" + Copy-ScriptFile -SourcePath $sourceScriptPath -DestinationPath $destinationscriptPath -PSGetItemInfo $psgItemInfo -Scope $Scope + + if(-not $IsSavePackage) + { + # Write warning messages if externally managed module dependencies are not installed. + foreach($ExternalDependency in $currentScriptInfo.ExternalModuleDependencies) + { + $depModuleInfo = Test-ModuleInstalled -Name $ExternalDependency + + if(-not $depModuleInfo) + { + Write-Warning -Message ($LocalizedData.ScriptMissingExternallyManagedModuleDependency -f $ExternalDependency,$pkg.Name,$ExternalDependency) + } + else + { + Write-Verbose -Message ($LocalizedData.ExternallyManagedModuleDependencyIsInstalled -f $ExternalDependency) + } + } + + # Write warning messages if externally managed script dependencies are not installed. + foreach($ExternalDependency in $currentScriptInfo.ExternalScriptDependencies) + { + $depScriptInfo = Test-ScriptInstalled -Name $ExternalDependency + + if(-not $depScriptInfo) + { + Write-Warning -Message ($LocalizedData.ScriptMissingExternallyManagedScriptDependency -f $ExternalDependency,$pkg.Name,$ExternalDependency) + } + else + { + Write-Verbose -Message ($LocalizedData.ScriptExternallyManagedScriptDependencyIsInstalled -f $ExternalDependency) + } + } + } + + # Remove the old scriptfile if it's path different from the required destination script path when -Force is specified + if($Force -and + $InstalledScriptInfo2 -and + -not $destinationscriptPath.StartsWith($InstalledScriptInfo2.ScriptBase, [System.StringComparison]::OrdinalIgnoreCase)) + { + Microsoft.PowerShell.Management\Remove-Item -Path $InstalledScriptInfo2.Path ` + -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + } + + if($IsSavePackage) + { + $message = $LocalizedData.ScriptSavedSuccessfully -f ($psgItemInfo.Name) + } + else + { + $message = $LocalizedData.ScriptInstalledSuccessfully -f ($psgItemInfo.Name) + } + Write-Verbose $message + } + + Write-Output -InputObject $sid + } + } + finally + { + Microsoft.PowerShell.Management\Remove-Item $tempDestination -Force -Recurse -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + } +} + +function Uninstall-Package +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $fastPackageReference + ) + + Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Uninstall-Package')) + + Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference) + + # take the fastPackageReference and get the package object again. + $parts = $fastPackageReference -Split '[|]' + $Force = $false + + $options = $request.Options + if($options) + { + foreach( $o in $options.Keys ) + { + Write-Debug -Message ("OPTION: {0} => {1}" -f ($o, $request.Options[$o]) ) + } + } + + if($parts.Length -eq 5) + { + $providerName = $parts[0] + $packageName = $parts[1] + $version = $parts[2] + $sourceLocation= $parts[3] + $artfactType = $parts[4] + + if($request.IsCanceled) + { + return + } + + if($options.ContainsKey('Force')) + { + $Force = $options['Force'] + + if($Force.GetType().ToString() -eq 'System.String') + { + if($Force -eq 'false') + { + $Force = $false + } + elseif($Force -eq 'true') + { + $Force = $true + } + } + } + + if($artfactType -eq $script:PSArtifactTypeModule) + { + $moduleName = $packageName + $InstalledModuleInfo = $script:PSGetInstalledModules["$($moduleName)$($version)"] + + if(-not $InstalledModuleInfo) + { + $message = $LocalizedData.ModuleUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet -f $moduleName + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "ModuleUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + + return + } + + $moduleBase = $InstalledModuleInfo.PSGetItemInfo.InstalledLocation + + if(-not (Test-RunningAsElevated) -and $moduleBase.StartsWith($script:programFilesModulesPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + $message = $LocalizedData.AdminPrivilegesRequiredForUninstall -f ($moduleName, $moduleBase) + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "AdminPrivilegesRequiredForUninstall" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return + } + + $dependentModuleScript = { + param ([string] $moduleName) + Microsoft.PowerShell.Core\Get-Module -ListAvailable | + Microsoft.PowerShell.Core\Where-Object { + ($moduleName -ne $_.Name) -and ( + ($_.RequiredModules -and $_.RequiredModules.Name -contains $moduleName) -or + ($_.NestedModules -and $_.NestedModules.Name -contains $moduleName)) + } + } + $dependentModulesJob = Microsoft.PowerShell.Core\Start-Job -ScriptBlock $dependentModuleScript -ArgumentList $moduleName + Microsoft.PowerShell.Core\Wait-Job -job $dependentModulesJob + $dependentModules = Microsoft.PowerShell.Core\Receive-Job -job $dependentModulesJob + + if(-not $Force -and $dependentModules) + { + $message = $LocalizedData.UnableToUninstallAsOtherModulesNeedThisModule -f ($moduleName, $version, $moduleBase, $(($dependentModules.Name | Select-Object -Unique) -join ','), $moduleName) + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "UnableToUninstallAsOtherModulesNeedThisModule" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return + } + + $moduleInUse = Test-ModuleInUse -ModuleBasePath $moduleBase ` + -ModuleName $InstalledModuleInfo.PSGetItemInfo.Name` + -ModuleVersion $InstalledModuleInfo.PSGetItemInfo.Version ` + -Verbose:$VerbosePreference ` + -WarningAction $WarningPreference ` + -ErrorAction $ErrorActionPreference ` + -Debug:$DebugPreference + + if($moduleInUse) + { + $message = $LocalizedData.ModuleIsInUse -f ($moduleName) + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "ModuleIsInUse" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return + } + + $ModuleBaseFolderToBeRemoved = $moduleBase + + # With SxS version support, more than one version of the module can be installed. + # - Remove the parent directory of the module version base when only one version is installed + # - Don't remove the modulebase when it was installed before SxS version support and + # other versions are installed under the module base folder + # + if(Test-ModuleSxSVersionSupport) + { + $ModuleBaseWithoutVersion = $moduleBase + $IsModuleInstalledAsSxSVersion = $false + + if($moduleBase.EndsWith("$version", [System.StringComparison]::OrdinalIgnoreCase)) + { + $IsModuleInstalledAsSxSVersion = $true + $ModuleBaseWithoutVersion = Microsoft.PowerShell.Management\Split-Path -Path $moduleBase -Parent + } + + $InstalledVersionsWithSameModuleBase = @() + Get-Module -Name $moduleName -ListAvailable | + Microsoft.PowerShell.Core\ForEach-Object { + if($_.ModuleBase.StartsWith($ModuleBaseWithoutVersion, [System.StringComparison]::OrdinalIgnoreCase)) + { + $InstalledVersionsWithSameModuleBase += $_.ModuleBase + } + } + + # Remove ..\ModuleName directory when only one module is installed with the same ..\ModuleName path + # like ..\ModuleName\1.0 or ..\ModuleName + if($InstalledVersionsWithSameModuleBase.Count -eq 1) + { + $ModuleBaseFolderToBeRemoved = $ModuleBaseWithoutVersion + } + elseif($ModuleBaseWithoutVersion -eq $moduleBase) + { + # There are version specific folders under the same module base dir + # Throw an error saying uninstall other versions then uninstall this current version + $message = $LocalizedData.UnableToUninstallModuleVersion -f ($moduleName, $version, $moduleBase) + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "UnableToUninstallModuleVersion" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return + } + # Otherwise specified version folder will be removed as current module base is assigned to $ModuleBaseFolderToBeRemoved + } + + Microsoft.PowerShell.Management\Remove-Item -Path $ModuleBaseFolderToBeRemoved ` + -Force -Recurse ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + + $message = $LocalizedData.ModuleUninstallationSucceeded -f $moduleName, $moduleBase + Write-Verbose $message + + Write-Output -InputObject $InstalledModuleInfo.SoftwareIdentity + } + elseif($artfactType -eq $script:PSArtifactTypeScript) + { + $scriptName = $packageName + $InstalledScriptInfo = $script:PSGetInstalledScripts["$($scriptName)$($version)"] + + if(-not $InstalledScriptInfo) + { + $message = $LocalizedData.ScriptUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet -f $scriptName + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "ScriptUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + + return + } + + $scriptBase = $InstalledScriptInfo.PSGetItemInfo.InstalledLocation + $installedScriptInfoPath = $script:MyDocumentsInstalledScriptInfosPath + + if($scriptBase.StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + if(-not (Test-RunningAsElevated)) + { + $message = $LocalizedData.AdminPrivilegesRequiredForScriptUninstall -f ($scriptName, $scriptBase) + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "AdminPrivilegesRequiredForUninstall" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + + return + } + + $installedScriptInfoPath = $script:ProgramFilesInstalledScriptInfosPath + } + + # Check if there are any dependent scripts + $dependentScriptDetails = $script:PSGetInstalledScripts.Values | + Microsoft.PowerShell.Core\Where-Object { + $_.PSGetItemInfo.Dependencies -contains $scriptName + } + + $dependentScriptNames = $dependentScriptDetails | + Microsoft.PowerShell.Core\ForEach-Object { $_.PSGetItemInfo.Name } + + if(-not $Force -and $dependentScriptNames) + { + $message = $LocalizedData.UnableToUninstallAsOtherScriptsNeedThisScript -f + ($scriptName, + $version, + $scriptBase, + $(($dependentScriptNames | Select-Object -Unique) -join ','), + $scriptName) + + ThrowError -ExceptionName 'System.InvalidOperationException' ` + -ExceptionMessage $message ` + -ErrorId 'UnableToUninstallAsOtherScriptsNeedThisScript' ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidOperation + return + } + + $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $scriptBase ` + -ChildPath "$($scriptName).ps1" + + $installledScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $installedScriptInfoPath ` + -ChildPath "$($scriptName)_$($script:InstalledScriptInfoFileName)" + + # Remove the script file and it's corresponding InstalledScriptInfo.xml + if(Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf) + { + Microsoft.PowerShell.Management\Remove-Item -Path $scriptFilePath ` + -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + } + + if(Microsoft.PowerShell.Management\Test-Path -Path $installledScriptInfoFilePath -PathType Leaf) + { + Microsoft.PowerShell.Management\Remove-Item -Path $installledScriptInfoFilePath ` + -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + } + + $message = $LocalizedData.ScriptUninstallationSucceeded -f $scriptName, $scriptBase + Write-Verbose $message + + Write-Output -InputObject $InstalledScriptInfo.SoftwareIdentity + } + } +} + +function Get-InstalledPackage +{ + [CmdletBinding()] + param + ( + [Parameter()] + [string] + $Name, + + [Parameter()] + [Version] + $RequiredVersion, + + [Parameter()] + [Version] + $MinimumVersion, + + [Parameter()] + [Version] + $MaximumVersion + ) + + Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Get-InstalledPackage')) + + $options = $request.Options + + foreach( $o in $options.Keys ) + { + Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) ) + } + + $artifactTypes = $script:PSArtifactTypeModule + if($options.ContainsKey($script:PSArtifactType)) + { + $artifactTypes = $options[$script:PSArtifactType] + } + + if($artifactTypes -eq $script:All) + { + $artifactTypes = @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript) + } + + if($artifactTypes -contains $script:PSArtifactTypeModule) + { + Get-InstalledModuleDetails -Name $Name ` + -RequiredVersion $RequiredVersion ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion | Microsoft.PowerShell.Core\ForEach-Object {$_.SoftwareIdentity} + } + + if($artifactTypes -contains $script:PSArtifactTypeScript) + { + Get-InstalledScriptDetails -Name $Name ` + -RequiredVersion $RequiredVersion ` + -MinimumVersion $MinimumVersion ` + -MaximumVersion $MaximumVersion | Microsoft.PowerShell.Core\ForEach-Object {$_.SoftwareIdentity} + } +} + +#endregion + +#region Internal Utility functions for the PackageManagement Provider Implementation + +function Set-InstalledScriptsVariable +{ + # Initialize list of scripts installed by the PowerShellGet provider + $script:PSGetInstalledScripts = [ordered]@{} + $scriptPaths = @($script:ProgramFilesInstalledScriptInfosPath, $script:MyDocumentsInstalledScriptInfosPath) + + foreach ($location in $scriptPaths) + { + # find all scripts installed using PowerShellGet + $scriptInfoFiles = Get-ChildItem -Path $location ` + -Filter "*$script:InstalledScriptInfoFileName" ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + + if($scriptInfoFiles) + { + foreach ($scriptInfoFile in $scriptInfoFiles) + { + $psgetItemInfo = DeSerialize-PSObject -Path $scriptInfoFile.FullName + + $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $psgetItemInfo.InstalledLocation ` + -ChildPath "$($psgetItemInfo.Name).ps1" + + # Remove the InstalledScriptInfo.xml file if the actual script file was manually uninstalled by the user + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item -Path $scriptInfoFile.FullName -Force -ErrorAction SilentlyContinue + + continue + } + + $package = New-SoftwareIdentityFromPSGetItemInfo -PSGetItemInfo $psgetItemInfo + + if($package) + { + $script:PSGetInstalledScripts["$($psgetItemInfo.Name)$($psgetItemInfo.Version)"] = @{ + SoftwareIdentity = $package + PSGetItemInfo = $psgetItemInfo + } + } + } + } + } +} + +function Get-InstalledScriptDetails +{ + [CmdletBinding()] + param + ( + [Parameter()] + [string] + $Name, + + [Parameter()] + [Version] + $RequiredVersion, + + [Parameter()] + [Version] + $MinimumVersion, + + [Parameter()] + [Version] + $MaximumVersion + ) + + Set-InstalledScriptsVariable + + # Keys in $script:PSGetInstalledScripts are "", + # first filter the installed scripts using "$Name*" wildcard search + # then apply $Name wildcard search to get the script name which meets the specified name with wildcards. + # + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern "$Name*",$script:wildcardOptions + $nameWildcardPattern = New-Object System.Management.Automation.WildcardPattern $Name,$script:wildcardOptions + + $script:PSGetInstalledScripts.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { + if($wildcardPattern.IsMatch($_.Key)) + { + $InstalledScriptDetails = $_.Value + + if(-not $Name -or $nameWildcardPattern.IsMatch($InstalledScriptDetails.PSGetItemInfo.Name)) + { + if($RequiredVersion) + { + if($RequiredVersion -eq $InstalledScriptDetails.PSGetItemInfo.Version) + { + $InstalledScriptDetails + } + } + else + { + if( (-not $MinimumVersion -or ($MinimumVersion -le $InstalledScriptDetails.PSGetItemInfo.Version)) -and + (-not $MaximumVersion -or ($MaximumVersion -ge $InstalledScriptDetails.PSGetItemInfo.Version))) + { + $InstalledScriptDetails + } + } + } + } + } +} + +function Get-InstalledModuleDetails +{ + [CmdletBinding()] + param + ( + [Parameter()] + [string] + $Name, + + [Parameter()] + [Version] + $RequiredVersion, + + [Parameter()] + [Version] + $MinimumVersion, + + [Parameter()] + [Version] + $MaximumVersion + ) + + Set-InstalledModulesVariable + + # Keys in $script:PSGetInstalledModules are "", + # first filter the installed modules using "$Name*" wildcard search + # then apply $Name wildcard search to get the module name which meets the specified name with wildcards. + # + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern "$Name*",$script:wildcardOptions + $nameWildcardPattern = New-Object System.Management.Automation.WildcardPattern $Name,$script:wildcardOptions + + $script:PSGetInstalledModules.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { + if($wildcardPattern.IsMatch($_.Key)) + { + $InstalledModuleDetails = $_.Value + + if(-not $Name -or $nameWildcardPattern.IsMatch($InstalledModuleDetails.PSGetItemInfo.Name)) + { + if($RequiredVersion) + { + if($RequiredVersion -eq $InstalledModuleDetails.PSGetItemInfo.Version) + { + $InstalledModuleDetails + } + } + else + { + if( (-not $MinimumVersion -or ($MinimumVersion -le $InstalledModuleDetails.PSGetItemInfo.Version)) -and + (-not $MaximumVersion -or ($MaximumVersion -ge $InstalledModuleDetails.PSGetItemInfo.Version))) + { + $InstalledModuleDetails + } + } + } + } + } +} + +function New-SoftwareIdentityFromPackage +{ + param + ( + [Parameter(Mandatory=$true)] + $Package, + + [Parameter(Mandatory=$true)] + [string] + $PackageManagementProviderName, + + [Parameter(Mandatory=$true)] + [string] + $SourceLocation, + + [Parameter()] + [switch] + $IsFromTrustedSource, + + [Parameter(Mandatory=$true)] + $request, + + [Parameter(Mandatory=$true)] + [string] + $Type, + + [Parameter()] + [string] + $InstalledLocation, + + [Parameter()] + [System.DateTime] + $InstalledDate, + + [Parameter()] + [System.DateTime] + $UpdatedDate + ) + + $fastPackageReference = New-FastPackageReference -ProviderName $PackageManagementProviderName ` + -PackageName $Package.Name ` + -Version $Package.Version ` + -Source $SourceLocation ` + -ArtifactType $Type + + $links = New-Object -TypeName System.Collections.ArrayList + foreach($lnk in $Package.Links) + { + if( $lnk.Relationship -eq "icon" -or $lnk.Relationship -eq "license" -or $lnk.Relationship -eq "project" ) + { + $links.Add( (New-Link -Href $lnk.HRef -RelationShip $lnk.Relationship ) ) + } + } + + $entities = New-Object -TypeName System.Collections.ArrayList + foreach( $entity in $Package.Entities ) + { + if( $entity.Role -eq "author" -or $entity.Role -eq "owner" ) + { + $entities.Add( (New-Entity -Name $entity.Name -Role $entity.Role -RegId $entity.RegId -Thumbprint $entity.Thumbprint) ) + } + } + + $deps = (new-Object -TypeName System.Collections.ArrayList) + foreach( $dep in $pkg.Dependencies ) + { + # Add each dependency and say it's from this provider. + $newDep = New-Dependency -ProviderName $script:PSModuleProviderName ` + -PackageName $request.Services.ParsePackageName($dep) ` + -Version $request.Services.ParsePackageVersion($dep) ` + -Source $SourceLocation + + $deps.Add( $newDep ) + } + + + $details = New-Object -TypeName System.Collections.Hashtable + + foreach ( $key in $Package.Metadata.Keys.LocalName) + { + if (!$details.ContainsKey($key)) + { + $details.Add($key, (Get-First $Package.Metadata[$key]) ) + } + } + + $details.Add( "PackageManagementProvider" , $PackageManagementProviderName ) + $details.Add( "Type" , $Type ) + + if($InstalledLocation) + { + $details.Add( $script:InstalledLocation , $InstalledLocation ) + } + + if($InstalledDate) + { + $details.Add( 'installeddate' , $InstalledDate.ToString() ) + } + + if($UpdatedDate) + { + $details.Add( 'updateddate' , $UpdatedDate.ToString() ) + } + + # Initialize package source name to the source location + $sourceNameForSoftwareIdentity = $SourceLocation + + $sourceName = (Get-SourceName -Location $SourceLocation) + + if($sourceName) + { + $details.Add( "SourceName" , $sourceName ) + + # Override the source name only if we are able to map source location to source name + $sourceNameForSoftwareIdentity = $sourceName + } + + $params = @{FastPackageReference = $fastPackageReference; + Name = $Package.Name; + Version = $Package.Version; + versionScheme = "MultiPartNumeric"; + Source = $sourceNameForSoftwareIdentity; + Summary = $Package.Summary; + SearchKey = $Package.Name; + FullPath = $Package.FullPath; + FileName = $Package.Name; + Details = $details; + Entities = $entities; + Links = $links; + Dependencies = $deps; + } + + if($IsFromTrustedSource) + { + $params["FromTrustedSource"] = $true + } + + $sid = New-SoftwareIdentity @params + + return $sid +} + +function New-PackageSourceFromModuleSource +{ + param + ( + [Parameter(Mandatory=$true)] + $ModuleSource + ) + + $ScriptSourceLocation = $null + if(Get-Member -InputObject $ModuleSource -Name $script:ScriptSourceLocation) + { + $ScriptSourceLocation = $ModuleSource.ScriptSourceLocation + } + + $ScriptPublishLocation = $ModuleSource.PublishLocation + if(Get-Member -InputObject $ModuleSource -Name $script:ScriptPublishLocation) + { + $ScriptPublishLocation = $ModuleSource.ScriptPublishLocation + } + + $packageSourceDetails = @{} + $packageSourceDetails["InstallationPolicy"] = $ModuleSource.InstallationPolicy + $packageSourceDetails["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $ModuleSource) + $packageSourceDetails[$script:PublishLocation] = $ModuleSource.PublishLocation + $packageSourceDetails[$script:ScriptSourceLocation] = $ScriptSourceLocation + $packageSourceDetails[$script:ScriptPublishLocation] = $ScriptPublishLocation + + $ModuleSource.ProviderOptions.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { + $packageSourceDetails[$_.Key] = $_.Value + } + + # create a new package source + $src = New-PackageSource -Name $ModuleSource.Name ` + -Location $ModuleSource.SourceLocation ` + -Trusted $ModuleSource.Trusted ` + -Registered $ModuleSource.Registered ` + -Details $packageSourceDetails + + Write-Verbose ( $LocalizedData.RepositoryDetails -f ($src.Name, $src.Location, $src.IsTrusted, $src.IsRegistered) ) + + # return the package source object. + Write-Output -InputObject $src +} + +function New-ModuleSourceFromPackageSource +{ + param + ( + [Parameter(Mandatory=$true)] + $PackageSource + ) + + $moduleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + Name = $PackageSource.Name + SourceLocation = $PackageSource.Location + Trusted=$PackageSource.IsTrusted + Registered=$PackageSource.IsRegistered + InstallationPolicy = $PackageSource.Details['InstallationPolicy'] + PackageManagementProvider=$PackageSource.Details['PackageManagementProvider'] + PublishLocation=$PackageSource.Details[$script:PublishLocation] + ScriptSourceLocation=$PackageSource.Details[$script:ScriptSourceLocation] + ScriptPublishLocation=$PackageSource.Details[$script:ScriptPublishLocation] + ProviderOptions = @{} + }) + + $PackageSource.Details.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { + if($_.Key -ne 'PackageManagementProvider' -and + $_.Key -ne $script:PublishLocation -and + $_.Key -ne $script:ScriptPublishLocation -and + $_.Key -ne $script:ScriptSourceLocation -and + $_.Key -ne 'InstallationPolicy') + { + $moduleSource.ProviderOptions[$_.Key] = $_.Value + } + } + + $moduleSource.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository") + + # return the module source object. + Write-Output -InputObject $moduleSource +} + +function New-FastPackageReference +{ + param + ( + [Parameter(Mandatory=$true)] + [string] + $ProviderName, + + [Parameter(Mandatory=$true)] + [string] + $PackageName, + + [Parameter(Mandatory=$true)] + [string] + $Version, + + [Parameter(Mandatory=$true)] + [string] + $Source, + + [Parameter(Mandatory=$true)] + [string] + $ArtifactType + ) + + return "$ProviderName|$PackageName|$Version|$Source|$ArtifactType" +} + +function Get-First +{ + param + ( + [Parameter(Mandatory=$true)] + $IEnumerator + ) + + foreach($item in $IEnumerator) + { + return $item + } + + return $null +} + +function Set-InstalledModulesVariable +{ + # Initialize list of modules installed by the PowerShellGet provider + $script:PSGetInstalledModules = [ordered]@{} + + $modulePaths = @($script:ProgramFilesModulesPath, $script:MyDocumentsModulesPath) + + foreach ($location in $modulePaths) + { + # find all modules installed using PowerShellGet + $moduleBases = Get-ChildItem $location -Recurse ` + -Attributes Hidden -Filter $script:PSGetItemInfoFileName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + | Foreach-Object { $_.Directory } + + + foreach ($moduleBase in $moduleBases) + { + $PSGetItemInfoPath = Microsoft.PowerShell.Management\Join-Path $moduleBase.FullName $script:PSGetItemInfoFileName + + # Check if this module got installed using PSGet, read its contents to create a SoftwareIdentity object + if (Microsoft.PowerShell.Management\Test-Path $PSGetItemInfoPath) + { + $psgetItemInfo = DeSerialize-PSObject -Path $PSGetItemInfoPath + + # Add InstalledLocation if this module was installed with older version of PowerShellGet + if(-not (Get-Member -InputObject $psgetItemInfo -Name $script:InstalledLocation)) + { + Microsoft.PowerShell.Utility\Add-Member -InputObject $psgetItemInfo ` + -MemberType NoteProperty ` + -Name $script:InstalledLocation ` + -Value $moduleBase.FullName + } + + $package = New-SoftwareIdentityFromPSGetItemInfo -PSGetItemInfo $psgetItemInfo + + if($package) + { + $script:PSGetInstalledModules["$($psgetItemInfo.Name)$($psgetItemInfo.Version)"] = @{ + SoftwareIdentity = $package + PSGetItemInfo = $psgetItemInfo + } + } + } + } + } +} + +function New-SoftwareIdentityFromPSGetItemInfo +{ + param + ( + [Parameter(Mandatory=$true)] + $PSGetItemInfo + ) + + $SourceLocation = $psgetItemInfo.RepositorySourceLocation + + if(Get-Member -InputObject $PSGetItemInfo -Name $script:PSArtifactType) + { + $artifactType = $psgetItemInfo.Type + } + else + { + $artifactType = $script:PSArtifactTypeModule + } + + $fastPackageReference = New-FastPackageReference -ProviderName (Get-ProviderName -PSCustomObject $psgetItemInfo) ` + -PackageName $psgetItemInfo.Name ` + -Version $psgetItemInfo.Version ` + -Source $SourceLocation ` + -ArtifactType $artifactType + + $links = New-Object -TypeName System.Collections.ArrayList + if($psgetItemInfo.IconUri) + { + $links.Add( (New-Link -Href $psgetItemInfo.IconUri -RelationShip "icon") ) + } + + if($psgetItemInfo.LicenseUri) + { + $links.Add( (New-Link -Href $psgetItemInfo.LicenseUri -RelationShip "license") ) + } + + if($psgetItemInfo.ProjectUri) + { + $links.Add( (New-Link -Href $psgetItemInfo.ProjectUri -RelationShip "project") ) + } + + $entities = New-Object -TypeName System.Collections.ArrayList + if($psgetItemInfo.Author) + { + $entities.Add( (New-Entity -Name $psgetItemInfo.Author -Role 'author') ) + } + + if($psgetItemInfo.CompanyName -and $psgetItemInfo.CompanyName.ToString()) + { + $entities.Add( (New-Entity -Name $psgetItemInfo.CompanyName -Role 'owner') ) + } + + $details = @{ + description = $psgetItemInfo.Description + copyright = $psgetItemInfo.Copyright + published = $psgetItemInfo.PublishedDate.ToString() + installeddate = $null + updateddate = $null + tags = $psgetItemInfo.Tags + releaseNotes = $psgetItemInfo.ReleaseNotes + PackageManagementProvider = (Get-ProviderName -PSCustomObject $psgetItemInfo) + } + + if((Get-Member -InputObject $psgetItemInfo -Name 'InstalledDate') -and $psgetItemInfo.InstalledDate) + { + $details['installeddate'] = $psgetItemInfo.InstalledDate.ToString() + } + + if((Get-Member -InputObject $psgetItemInfo -Name 'UpdatedDate') -and $psgetItemInfo.UpdatedDate) + { + $details['updateddate'] = $psgetItemInfo.UpdatedDate.ToString() + } + + if(Get-Member -InputObject $psgetItemInfo -Name $script:InstalledLocation) + { + $details[$script:InstalledLocation] = $psgetItemInfo.InstalledLocation + } + + $details[$script:PSArtifactType] = $artifactType + + $sourceName = Get-SourceName -Location $SourceLocation + if($sourceName) + { + $details["SourceName"] = $sourceName + } + + $params = @{ + FastPackageReference = $fastPackageReference; + Name = $psgetItemInfo.Name; + Version = $psgetItemInfo.Version; + versionScheme = "MultiPartNumeric"; + Source = $SourceLocation; + Summary = $psgetItemInfo.Description; + Details = $details; + Entities = $entities; + Links = $links + } + + if($sourceName -and $script:PSGetModuleSources[$sourceName].Trusted) + { + $params["FromTrustedSource"] = $true + } + + $sid = New-SoftwareIdentity @params + + return $sid +} + +#endregion + +#region Common functions + +function Get-EnvironmentVariable +{ + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + [parameter(Mandatory = $true)] + [int] + $Target + ) + + if ($Target -eq $script:EnvironmentVariableTarget.Process) + { + return [System.Environment]::GetEnvironmentVariable($Name) + } + elseif ($Target -eq $script:EnvironmentVariableTarget.Machine) + { + $itemPropertyValue = Microsoft.PowerShell.Management\Get-ItemProperty -Path $script:SystemEnvironmentKey -Name $Name -ErrorAction SilentlyContinue + + if($itemPropertyValue) + { + return $itemPropertyValue.$Name + } + } + elseif ($Target -eq $script:EnvironmentVariableTarget.User) + { + $itemPropertyValue = Microsoft.PowerShell.Management\Get-ItemProperty -Path $script:UserEnvironmentKey -Name $Name -ErrorAction SilentlyContinue + + if($itemPropertyValue) + { + return $itemPropertyValue.$Name + } + } +} + +function Set-EnvironmentVariable +{ + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + [parameter()] + [String] + $Value, + + [parameter(Mandatory = $true)] + [int] + $Target + ) + + if ($Target -eq $script:EnvironmentVariableTarget.Process) + { + [System.Environment]::SetEnvironmentVariable($Name, $Value) + + return + } + elseif ($Target -eq $script:EnvironmentVariableTarget.Machine) + { + if ($Name.Length -ge $script:SystemEnvironmentVariableMaximumLength) + { + $message = $LocalizedData.InvalidEnvironmentVariableName -f ($Name, $script:SystemEnvironmentVariableMaximumLength) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'InvalidEnvironmentVariableName' ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + return + } + + $Path = $script:SystemEnvironmentKey + } + elseif ($Target -eq $script:EnvironmentVariableTarget.User) + { + if ($Name.Length -ge $script:UserEnvironmentVariableMaximumLength) + { + $message = $LocalizedData.InvalidEnvironmentVariableName -f ($Name, $script:UserEnvironmentVariableMaximumLength) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId 'InvalidEnvironmentVariableName' ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Name + return + } + + $Path = $script:UserEnvironmentKey + } + + if (!$Value) + { + Microsoft.PowerShell.Management\Remove-ItemProperty $Path -Name $Name -ErrorAction SilentlyContinue + } + else + { + Microsoft.PowerShell.Management\Set-ItemProperty $Path -Name $Name -Value $Value + } +} + +function DeSerialize-PSObject +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + $Path + ) + $filecontent = Microsoft.PowerShell.Management\Get-Content -Path $Path + [System.Management.Automation.PSSerializer]::Deserialize($filecontent) +} + +function Log-ArtifactNotFoundInPSGallery +{ + [CmdletBinding()] + Param + ( + [Parameter()] + [string[]] + $SearchedName, + + [Parameter()] + [string[]] + $FoundName, + + [Parameter(Mandatory=$true)] + [string] + $operationName + ) + + if (-not $script:TelemetryEnabled) + { + return + } + + if(-not $SearchedName) + { + return + } + + $SearchedNameNoWildCards = @() + + # Ignore wild cards + foreach ($artifactName in $SearchedName) + { + if (-not (Test-WildcardPattern $artifactName)) + { + $SearchedNameNoWildCards += $artifactName + } + } + + # Find artifacts searched, but not found in the specified gallery + $notFoundArtifacts = @() + foreach ($element in $SearchedNameNoWildCards) + { + if (-not ($FoundName -contains $element)) + { + $notFoundArtifacts += $element + } + } + + # Perform Telemetry only if searched artifacts are not available in specified Gallery + if ($notFoundArtifacts) + { + [Microsoft.PowerShell.Get.Telemetry]::TraceMessageArtifactsNotFound($notFoundArtifacts, $operationName) + } +} + +# Function to record non-PSGallery registration for telemetry +# Function consumes the type of registration (i.e hosted (http(s)), non-hosted (file/unc)), locations, installation policy, provider and event name +function Log-NonPSGalleryRegistration +{ + [CmdletBinding()] + Param + ( + [Parameter()] + [string] + $sourceLocation, + + [Parameter()] + [string] + $installationPolicy, + + [Parameter()] + [string] + $packageManagementProvider, + + [Parameter()] + [string] + $publishLocation, + + [Parameter()] + [string] + $scriptSourceLocation, + + [Parameter()] + [string] + $scriptPublishLocation, + + [Parameter(Mandatory=$true)] + [string] + $operationName + ) + + if (-not $script:TelemetryEnabled) + { + return + } + + # Initialize source location type - this can be hosted (http(s)) or not hosted (unc/file) + $sourceLocationType = "NON_WEB_HOSTED" + if (Test-WebUri -uri $sourceLocation) + { + $sourceLocationType = "WEB_HOSTED" + } + + # Create a hash of the source location + # We cannot log the actual source location, since this might contain PII (Personally identifiable information) data + $sourceLocationHash = Get-Hash -locationString $sourceLocation + $publishLocationHash = Get-Hash -locationString $publishLocation + $scriptSourceLocationHash = Get-Hash -locationString $scriptSourceLocation + $scriptPublishLocationHash = Get-Hash -locationString $scriptPublishLocation + + # Log the telemetry event + [Microsoft.PowerShell.Get.Telemetry]::TraceMessageNonPSGalleryRegistration($sourceLocationType, $sourceLocationHash, $installationPolicy, $packageManagementProvider, $publishLocationHash, $scriptSourceLocationHash, $scriptPublishLocationHash, $operationName) +} + +# Returns a SHA1 hash of the specified string +function Get-Hash +{ + [CmdletBinding()] + Param + ( + [string] + $locationString + ) + + if(-not $locationString) + { + return "" + } + + $sha1Object = New-Object System.Security.Cryptography.SHA1Managed + $stringHash = $sha1Object.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($locationString)); + $stringHashInHex = [System.BitConverter]::ToString($stringHash) + + if ($stringHashInHex) + { + # Remove all dashes in the hex string + return $stringHashInHex.Replace('-', '') + } + + return "" +} + +function Get-ValidModuleLocation +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $LocationString, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $ParameterName + ) + + # Get the actual Uri from the Location + if(-not (Microsoft.PowerShell.Management\Test-Path $LocationString)) + { + # Append '/api/v2/' to the $LocationString, return if that URI works. + if(($LocationString -notmatch 'LinkID') -and + -not ($LocationString.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase)) -and + -not ($LocationString.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase)) + ) + { + $tempLocation = $null + + if($LocationString.EndsWith('/', [System.StringComparison]::OrdinalIgnoreCase)) + { + $tempLocation = $LocationString + 'api/v2/' + } + else + { + $tempLocation = $LocationString + '/api/v2/' + } + + if($tempLocation) + { + # Ping and resolve the specified location + $tempLocation = Resolve-Location -Location $tempLocation ` + -LocationParameterName $ParameterName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + if($tempLocation) + { + return $tempLocation + } + # No error if we can't resolve the URL appended with '/api/v2/' + } + } + + # Ping and resolve the specified location + $LocationString = Resolve-Location -Location $LocationString ` + -LocationParameterName $ParameterName ` + -CallerPSCmdlet $PSCmdlet + } + + return $LocationString +} + +function Save-ModuleSources +{ + if($script:PSGetModuleSources) + { + if(-not (Microsoft.PowerShell.Management\Test-Path $script:PSGetAppLocalPath)) + { + $null = Microsoft.PowerShell.Management\New-Item -Path $script:PSGetAppLocalPath ` + -ItemType Directory -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false -WhatIf:$false + } + Microsoft.PowerShell.Utility\Out-File -FilePath $script:PSGetModuleSourcesFilePath -Force -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:PSGetModuleSources)) + } +} + +function Test-ModuleSxSVersionSupport +{ + # Side-by-Side module version is avialable on PowerShell 5.0 or later versions only + # By default, PowerShell module versions will be installed/updated Side-by-Side. + $PSVersionTable.PSVersion -ge [Version]"5.0" +} + +function Test-ModuleInstalled +{ + [CmdletBinding(PositionalBinding=$false)] + [OutputType("PSModuleInfo")] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Name, + + [Parameter()] + [Version] + $RequiredVersion + ) + + # Check if module is already installed + $availableModule = Microsoft.PowerShell.Core\Get-Module -ListAvailable -Name $Name -Verbose:$false | + Microsoft.PowerShell.Core\Where-Object {-not (Test-ModuleSxSVersionSupport) -or -not $RequiredVersion -or ($RequiredVersion -eq $_.Version)} | + Microsoft.PowerShell.Utility\Select-Object -Unique + + return $availableModule +} + +function Test-ScriptInstalled +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Name, + + [Parameter()] + [Version] + $RequiredVersion + ) + + $scriptInfo = $null + $scriptFileName = "$Name.ps1" + $scriptPaths = @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath) + $scriptInfos = @() + + foreach ($location in $scriptPaths) + { + $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $location -ChildPath $scriptFileName + + if(Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf) + { + $scriptInfo = $null + try + { + $scriptInfo = Test-ScriptFileInfo -Path $scriptFilePath -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + } + catch + { + # Ignore any terminating error from the Test-ScriptFileInfo cmdlet, + # if it does not contain valid Script metadata + Write-Verbose -Message "$_" + } + + if($scriptInfo) + { + $scriptInfos += $scriptInfo + } + else + { + # Since the script file doesn't contain the valid script metadata, + # create dummy PSScriptInfo object with 0.0 version + $scriptInfo = New-PSScriptInfoObject -Path $scriptFilePath + $scriptInfo.$script:Version = [Version]'0.0' + + $scriptInfos += $scriptInfo + } + } + } + + $scriptInfo = $scriptInfos | Microsoft.PowerShell.Core\Where-Object { + (-not $RequiredVersion) -or ($RequiredVersion -eq $_.Version) + } | Microsoft.PowerShell.Utility\Select-Object -First 1 + + return $scriptInfo +} + +function New-PSScriptInfoObject +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [string] + $Path + ) + + $PSScriptInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{}) + $script:PSScriptInfoProperties | Microsoft.PowerShell.Core\ForEach-Object { + Microsoft.PowerShell.Utility\Add-Member -InputObject $PSScriptInfo ` + -MemberType NoteProperty ` + -Name $_ ` + -Value $null + } + + $PSScriptInfo.$script:Name = [System.IO.Path]::GetFileNameWithoutExtension($Path) + $PSScriptInfo.$script:Path = $Path + $PSScriptInfo.$script:ScriptBase = (Microsoft.PowerShell.Management\Split-Path -Path $Path -Parent) + + return $PSScriptInfo +} + +function Get-OrderedPSScriptInfoObject +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [PSCustomObject] + $PSScriptInfo + ) + + $NewPSScriptInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ + $script:Name = $PSScriptInfo.$script:Name + $script:Version = $PSScriptInfo.$script:Version + $script:Guid = $PSScriptInfo.$script:Guid + $script:Path = $PSScriptInfo.$script:Path + $script:ScriptBase = $PSScriptInfo.$script:ScriptBase + $script:Description = $PSScriptInfo.$script:Description + $script:Author = $PSScriptInfo.$script:Author + $script:CompanyName = $PSScriptInfo.$script:CompanyName + $script:Copyright = $PSScriptInfo.$script:Copyright + $script:Tags = $PSScriptInfo.$script:Tags + $script:ReleaseNotes = $PSScriptInfo.$script:ReleaseNotes + $script:RequiredModules = $PSScriptInfo.$script:RequiredModules + $script:ExternalModuleDependencies = $PSScriptInfo.$script:ExternalModuleDependencies + $script:RequiredScripts = $PSScriptInfo.$script:RequiredScripts + $script:ExternalScriptDependencies = $PSScriptInfo.$script:ExternalScriptDependencies + $script:LicenseUri = $PSScriptInfo.$script:LicenseUri + $script:ProjectUri = $PSScriptInfo.$script:ProjectUri + $script:IconUri = $PSScriptInfo.$script:IconUri + $script:DefinedCommands = $PSScriptInfo.$script:DefinedCommands + $script:DefinedFunctions = $PSScriptInfo.$script:DefinedFunctions + $script:DefinedWorkflows = $PSScriptInfo.$script:DefinedWorkflows + }) + + $NewPSScriptInfo.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSScriptInfo") + + return $NewPSScriptInfo +} + +function Get-AvailableScriptFilePath +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter()] + [string] + $Name + ) + + $scriptInfo = $null + $scriptFileName = '*.ps1' + $scriptBasePaths = @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath) + $scriptFilePaths = @() + $wildcardPattern = $null + + if($Name) + { + if(Test-WildcardPattern -Name $Name) + { + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $Name,$script:wildcardOptions + } + else + { + $scriptFileName = "$Name.ps1" + } + + } + + foreach ($location in $scriptBasePaths) + { + $scriptFiles = Get-ChildItem -Path $location ` + -Filter $scriptFileName ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + + if($wildcardPattern) + { + $scriptFiles | Microsoft.PowerShell.Core\ForEach-Object { + if($wildcardPattern.IsMatch($_.BaseName)) + { + $scriptFilePaths += $_.FullName + } + } + } + else + { + $scriptFiles | Microsoft.PowerShell.Core\ForEach-Object { $scriptFilePaths += $_.FullName } + } + } + + return $scriptFilePaths +} + +function Get-InstalledScriptFilePath +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter()] + [string] + $Name + ) + + $installedScriptFilePaths = @() + $scriptFilePaths = Get-AvailableScriptFilePath @PSBoundParameters + + foreach ($scriptFilePath in $scriptFilePaths) + { + $scriptInfo = Test-ScriptInstalled -Name ([System.IO.Path]::GetFileNameWithoutExtension($scriptFilePath)) + + if($scriptInfo) + { + $installedScriptInfoFilePath = $null + $installedScriptInfoFileName = "$($scriptInfo.Name)_$script:InstalledScriptInfoFileName" + + if($scriptInfo.Path.StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesInstalledScriptInfosPath ` + -ChildPath $installedScriptInfoFileName + } + elseif($scriptInfo.Path.StartsWith($script:MyDocumentsScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) + { + $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsInstalledScriptInfosPath ` + -ChildPath $installedScriptInfoFileName + } + + if($installedScriptInfoFilePath -and (Microsoft.PowerShell.Management\Test-Path -Path $installedScriptInfoFilePath -PathType Leaf)) + { + $installedScriptFilePaths += $scriptInfo.Path + } + } + } + + return $installedScriptFilePaths +} + + +function Update-ModuleManifest +{ +<# +.ExternalHelp PSGet.psm1-help.xml +#> +[CmdletBinding(SupportsShouldProcess=$true, + PositionalBinding=$false, + HelpUri='http://go.microsoft.com/fwlink/?LinkId=619311')] + Param + ( + [Parameter(Mandatory=$true, + Position=0, + ValueFromPipelineByPropertyName=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Path, + + [ValidateNotNullOrEmpty()] + [Object[]] + $NestedModules, + + [ValidateNotNullOrEmpty()] + [Guid] + $Guid, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Author, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String] + $CompanyName, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Copyright, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $RootModule, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $ModuleVersion, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Description, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Reflection.ProcessorArchitecture] + $ProcessorArchitecture, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $PowerShellVersion, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $ClrVersion, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $DotNetFrameworkVersion, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String] + $PowerShellHostName, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Version] + $PowerShellHostVersion, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Object[]] + $RequiredModules, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $TypesToProcess, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $FormatsToProcess, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $ScriptsToProcess, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $RequiredAssemblies, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $FileList, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [object[]] + $ModuleList, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $FunctionsToExport, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $AliasesToExport, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $VariablesToExport, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $CmdletsToExport, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $DscResourcesToExport, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Collections.Hashtable] + $PrivateData, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]] + $Tags, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $ProjectUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $LicenseUri, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $IconUri, + + [Parameter()] + [string[]] + $ReleaseNotes, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Uri] + $HelpInfoUri, + + [Parameter()] + [switch] + $PassThru, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String] + $DefaultCommandPrefix, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $ExternalModuleDependencies, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $PackageManagementProviders + ) + + + Import-LocalizedData -BindingVariable ModuleManifestHashTable ` + -FileName (Microsoft.PowerShell.Management\Split-Path $Path -Leaf) ` + -BaseDirectory (Microsoft.PowerShell.Management\Split-Path $Path -Parent) ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + + if(-not (Microsoft.PowerShell.Management\Test-Path $Path)) + { + $message = $LocalizedData.UpdateModuleManifestPathCannotFound -f ($Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidModuleManifestFilePath" ` + -ExceptionObject $Path ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + + #Get the original module manifest and migrate all the fields to the new module manifest, including the specified parameter values + try + { + $moduleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $Path -ErrorAction Stop + } + catch + { + $message = $LocalizedData.TestModuleManifestFail -f ($_.Exception.Message) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidModuleManifestFile" ` + -ExceptionObject $Path ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + #Params to pass to New-ModuleManifest module + $params = @{} + + #NestedModules is read-only property + if($NestedModules) + { + $params.Add("NestedModules",$NestedModules) + } + elseif($moduleInfo.NestedModules) + { + #Get the original module info from ManifestHashTab + if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("NestedModules")) + { + $params.Add("NestedModules",$ModuleManifestHashtable.NestedModules) + } + } + + #Guid is read-only property + if($Guid) + { + $params.Add("Guid",$Guid) + } + elseif($moduleInfo.Guid) + { + $params.Add("Guid",$moduleInfo.Guid) + } + + if($Author) + { + $params.Add("Author",$Author) + } + elseif($moduleInfo.Author) + { + $params.Add("Author",$moduleInfo.Author) + } + + if($CompanyName) + { + $params.Add("CompanyName",$CompanyName) + } + elseif($moduleInfo.CompanyName) + { + $params.Add("CompanyName",$moduleInfo.CompanyName) + } + + if($Copyright) + { + $params.Add("CopyRight",$Copyright) + } + elseif($moduleInfo.Copyright) + { + $params.Add("Copyright",$moduleInfo.Copyright) + } + + if($RootModule) + { + $params.Add("RootModule",$RootModule) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("RootModule") -and $moduleInfo.RootModule) + { + $params.Add("RootModule",$ModuleManifestHashTable.RootModule) + } + + if($ModuleVersion) + { + $params.Add("ModuleVersion",$ModuleVersion) + } + elseif($moduleInfo.Version) + { + $params.Add("ModuleVersion",$moduleInfo.Version) + } + + if($Description) + { + $params.Add("Description",$Description) + } + elseif($moduleInfo.Description) + { + $params.Add("Description",$moduleInfo.Description) + } + + if($ProcessorArchitecture) + { + $params.Add("ProcessorArchitecture",$ProcessorArchitecture) + } + #Check if ProcessorArchitecture has a value and is not 'None' on lower verison PS + elseif($moduleInfo.ProcessorArchitecture -and $moduleInfo.ProcessorArchitecture -ne 'None') + { + $params.Add("ProcessorArchitecture",$moduleInfo.ProcessorArchitecture) + } + + if($PowerShellVersion) + { + $params.Add("PowerShellVersion",$PowerShellVersion) + } + elseif($moduleinfo.PowerShellVersion) + { + $params.Add("PowerShellVersion",$moduleinfo.PowerShellVersion) + } + + if($ClrVersion) + { + $params.Add("ClrVersion",$ClrVersion) + } + elseif($moduleInfo.ClrVersion) + { + $params.Add("ClrVersion",$moduleInfo.ClrVersion) + } + + if($DotNetFrameworkVersion) + { + $params.Add("DotNetFrameworkVersion",$DotNetFrameworkVersion) + } + elseif($moduleInfo.DotNetFrameworkVersion) + { + $params.Add("DotNetFrameworkVersion",$moduleInfo.DotNetFrameworkVersion) + } + + if($PowerShellHostName) + { + $params.Add("PowerShellHostName",$PowerShellHostName) + } + elseif($moduleInfo.PowerShellHostName) + { + $params.Add("PowerShellHostName",$moduleInfo.PowerShellHostName) + } + + if($PowerShellHostVersion) + { + $params.Add("PowerShellHostVersion",$PowerShellHostVersion) + } + elseif($moduleInfo.PowerShellHostVersion) + { + $params.Add("PowerShellHostVersion",$moduleInfo.PowerShellHostVersion) + } + + if($RequiredModules) + { + $params.Add("RequiredModules",$RequiredModules) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("RequiredModules") -and $moduleInfo.RequiredModules) + { + $params.Add("RequiredModules",$ModuleManifestHashtable.RequiredModules) + } + + if($TypesToProcess) + { + $params.Add("TypesToProcess",$TypesToProcess) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("TypesToProcess") -and $moduleInfo.ExportedTypeFiles) + { + $params.Add("TypesToProcess",$ModuleManifestHashTable.TypesToProcess) + } + + if($FormatsToProcess) + { + $params.Add("FormatsToProcess",$FormatsToProcess) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("FormatsToProcess") -and $moduleInfo.ExportedFormatFiles) + { + $params.Add("FormatsToProcess",$ModuleManifestHashTable.FormatsToProcess) + } + + if($ScriptsToProcess) + { + $params.Add("ScriptsToProcess",$ScriptstoProcess) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("ScriptsToProcess") -and $moduleInfo.Scripts) + { + $params.Add("ScriptsToProcess",$ModuleManifestHashTable.ScriptsToProcess) + } + + if($RequiredAssemblies) + { + $params.Add("RequiredAssemblies",$RequiredAssemblies) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("RequiredAssemblies") -and $moduleInfo.RequiredAssemblies) + { + $params.Add("RequiredAssemblies",$moduleInfo.RequiredAssemblies) + } + + if($FileList) + { + $params.Add("FileList",$FileList) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("FileList") -and $moduleInfo.FileList) + { + $params.Add("FileList",$ModuleManifestHashTable.FileList) + } + + #Make sure every path defined under FileList is within module base + $moduleBase = $moduleInfo.ModuleBase + foreach($file in $params["FileList"]) + { + #If path is not root path, append the module base to it and check if the file exists + if(-not [System.IO.Path]::IsPathRooted($file)) + { + $combinedPath = Join-Path $moduleBase -ChildPath $file + } + else + { + $combinedPath = $file + } + if(-not (Microsoft.PowerShell.Management\Test-Path -Type Leaf -LiteralPath $combinedPath)) + { + $message = $LocalizedData.FilePathInFileListNotWithinModuleBase -f ($file,$moduleBase) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "FilePathInFileListNotWithinModuleBase" ` + -ExceptionObject $file ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + + return + } + } + + if($ModuleList) + { + $params.Add("ModuleList",$ModuleList) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("ModuleList") -and $moduleInfo.ModuleList) + { + $params.Add("ModuleList",$ModuleManifestHashtable.ModuleList) + } + + if($FunctionsToExport) + { + $params.Add("FunctionsToExport",$FunctionsToExport) + } + + elseif($moduleInfo.ExportedFunctions) + { + #Since $moduleInfo.ExportedFunctions is a hashtable, we need to take the name of the + #functions and make them into a list + $params.Add("FunctionsToExport",($moduleInfo.ExportedFunctions.Keys -split ' ')) + } + + + if($AliasesToExport) + { + $params.Add("AliasesToExport",$AliasesToExport) + } + elseif($moduleInfo.ExportedAliases) + { + $params.Add("AliasesToExport",($moduleInfo.ExportedAliases.Keys -split ' ')) + } + if($VariablesToExport) + { + $params.Add("VariablesToExport",$VariablesToExport) + } + elseif($moduleInfo.ExportedVariables) + { + $params.Add("VariablesToExport",($moduleInfo.ExportedVariables.Keys -split ' ')) + } + if($CmdletsToExport) + { + $params.Add("CmdletsToExport", $CmdletsToExport) + } + elseif($moduleInfo.ExportedCmdlets) + { + $params.Add("CmdletsToExport",($moduleInfo.ExportedCmdlets.Keys -split ' ')) + } + if($DscResourcesToExport) + { + #DscResourcesToExport field is not available in PowerShell version lower than 5.0 + + if (($PSVersionTable.PSVersion -lt [Version]"5.0") -or ($PowerShellVersion -and $PowerShellVersion -lt [Version]"5.0") ` + -or (-not $PowerShellVersion -and $moduleInfo.PowerShellVersion -and $moduleInfo.PowerShellVersion -lt [Version]"5.0") ` + -or (-not $PowerShellVersion -and -not $moduleInfo.PowerShellVersion)) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $LocalizedData.ExportedDscResourcesNotSupportedOnLowerPowerShellVersion ` + -ErrorId "ExportedDscResourcesNotSupported" ` + -ExceptionObject $DscResourcesToExport ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + $params.Add("DscResourcesToExport",$DscResourcesToExport) + } + elseif(Microsoft.PowerShell.Utility\Get-Member -InputObject $moduleInfo -name "ExportedDscResources") + { + if($moduleInfo.ExportedDscResources) + { + $params.Add("DscResourcesToExport",$moduleInfo.ExportedDscResources) + } + } + + if($HelpInfoUri) + { + $params.Add("HelpInfoUri",$HelpInfoUri) + } + elseif($moduleInfo.HelpInfoUri) + { + $params.Add("HelpInfoUri",$moduleInfo.HelpInfoUri) + } + + if($DefaultCommandPrefix) + { + $params.Add("DefaultCommandPrefix",$DefaultCommandPrefix) + } + elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("DefaultCommandPrefix") -and $ModuleManifestHashTable.DefaultCommandPrefix) + { + $params.Add("DefaultCommandPrefix",$ModuleManifestHashTable.DefaultCommandPrefix) + } + + #Create a temp file within the directory and generate a new temporary manifest with the input + $tempPath = Microsoft.PowerShell.Management\Join-Path -Path $moduleInfo.ModuleBase -ChildPath "PSGet_$($moduleInfo.Name).psd1" + $params.Add("Path",$tempPath) + + try + { + #Terminates if there is error creating new module manifest + try{ + Microsoft.PowerShell.Core\New-ModuleManifest @params -Confirm:$false -WhatIf:$false + } + catch + { + $ErrorMessage = $LocalizedData.UpdatedModuleManifestNotValid -f ($Path, $_.Exception.Message) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $ErrorMessage ` + -ErrorId "NewModuleManifestFailure" ` + -ExceptionObject $params ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + #Manually update the section in PrivateData since New-ModuleManifest works differently on different PS version + $PrivateDataInput = "" + $ExistingData = $moduleInfo.PrivateData + $Data = @{} + if($ExistingData) + { + foreach($key in $ExistingData.Keys) + { + if($key -ne "PSData"){ + $Data.Add($key,$ExistingData[$key]) + } + else + { + $PSData = $ExistingData["PSData"] + foreach($entry in $PSData.Keys) + { + $Data.Add($entry,$PSData[$Entry]) + } + } + } + } + + if($PrivateData) + { + foreach($key in $PrivateData.Keys) + { + #if user provides PSData within PrivateData, we will parse through the PSData + if($key -ne "PSData") + { + $Data[$key] = $PrivateData[$Key] + } + + else + { + $PSData = $ExistingData["PSData"] + foreach($entry in $PSData.Keys) + { + $Data[$entry] = $PSData[$entry] + } + } + } + } + + #Tags is a read-only property + if($Tags) + { + $Data["Tags"] = $Tags + } + + + #The following Uris and ReleaseNotes cannot be empty + if($ProjectUri) + { + $Data["ProjectUri"] = $ProjectUri + } + + if($LicenseUri) + { + $Data["LicenseUri"] = $LicenseUri + } + if($IconUri) + { + $Data["IconUri"] = $IconUri + } + + if($ReleaseNotes) + { + #If value is provided as an array, we append the string. + $Data["ReleaseNotes"] = $($ReleaseNotes -join "`r`n") + } + + if($ExternalModuleDependencies) + { + #ExternalModuleDependencies have to be specified either under $RequiredModules or $NestedModules + #Extract all the module names specified in the moduleInfo of NestedModules and RequiredModules + $DependentModuleNames = @() + foreach($moduleInfo in $params["NestedModules"]) + { + if($moduleInfo.GetType() -eq [System.Collections.Hashtable]) + { + $DependentModuleNames += $moduleInfo.ModuleName + } + } + + foreach($moduleInfo in $params["RequiredModules"]) + { + if($moduleInfo.GetType() -eq [System.Collections.Hashtable]) + { + $DependentModuleNames += $moduleInfo.ModuleName + } + } + + foreach($dependency in $ExternalModuleDependencies) + { + if($params["NestedModules"] -notcontains $dependency -and + $params["RequiredModules"] -notContains $dependency -and + $DependentModuleNames -notcontains $dependency) + { + $message = $LocalizedData.ExternalModuleDependenciesNotSpecifiedInRequiredOrNestedModules -f ($dependency) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidExternalModuleDependencies" ` + -ExceptionObject $Exception ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + } + if($Data.ContainsKey("ExternalModuleDependencies")) + { + $Data["ExternalModuleDependencies"] = $ExternalModuleDependencies + } + else + { + $Data.Add("ExternalModuleDependencies", $ExternalModuleDependencies) + } + } + if($PackageManagementProviders) + { + #Check if the provided value is within the relative path + $ModuleBase = Microsoft.PowerShell.Management\Split-Path $Path -Parent + $Files = Microsoft.PowerShell.Management\Get-ChildItem -Path $ModuleBase + foreach($provider in $PackageManagementProviders) + { + if ($Files.Name -notcontains $provider) + { + $message = $LocalizedData.PackageManagementProvidersNotInModuleBaseFolder -f ($provider,$ModuleBase) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidPackageManagementProviders" ` + -ExceptionObject $PackageManagementProviders ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + } + + $Data["PackageManagementProviders"] = $PackageManagementProviders + } + $PrivateDataInput = Get-PrivateData -PrivateData $Data + + #Repleace the PrivateData section by first locating the linenumbers of start line and endline. + $PrivateDataBegin = Select-String -Path $tempPath -Pattern "PrivateData =" + $PrivateDataBeginLine = $PrivateDataBegin.LineNumber + + $newManifest = Microsoft.PowerShell.Management\Get-Content -Path $tempPath + #Look up the endline of PrivateData section by finding the matching brackets since private data could + #consist of multiple pairs of brackets. + $PrivateDataEndLine=0 + if($PrivateDataBegin -match "@{") + { + $leftBrace = 0 + $EndLineOfFile = $newManifest.Length-1 + + For($i = $PrivateDataBeginLine;$i -lt $EndLineOfFile; $i++) + { + if($newManifest[$i] -match "{") + { + $leftBrace ++ + } + elseif($newManifest[$i] -match "}") + { + if($leftBrace -gt 0) + { + $leftBrace -- + } + else + { + $PrivateDataEndLine = $i + break + } + } + } + } + + + try + { + if($PrivateDataEndLine -ne 0) + { + #If PrivateData section has more than one line, we will remove the old content and insert the new PrivataData + $newManifest | where {$_.readcount -le $PrivateDataBeginLine -or $_.readcount -gt $PrivateDataEndLine+1} ` + | ForEach-Object { + $_ + if($_ -match "PrivateData = ") + { + $PrivateDataInput + } + } | Set-Content -Path $tempPath -Confirm:$false -WhatIf:$false + } + + #In lower version, PrivateData is just a single line + else + { + $PrivateDataForDownlevelPS = "PrivateData = @{ `n"+$PrivateDataInput + + $newManifest | where {$_.readcount -le $PrivateDataBeginLine -or $_.readcount -gt $PrivateDataBeginLine } ` + | ForEach-Object { + $_ + if($_ -match "PrivateData = ") + { + $PrivateDataForDownlevelPS + } + } | Set-Content -Path $tempPath -Confirm:$false -WhatIf:$false + } + + #Verify the new module manifest is valid + $testModuleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $tempPath ` + -Verbose:$VerbosePreference ` + } + #Catch the exceptions from Test-ModuleManifest + catch + { + $message = $LocalizedData.UpdatedModuleManifestNotValid -f ($Path, $_.Exception.Message) + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "UpdateManifestFileFail" ` + -ExceptionObject $_.Exception ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + return + } + + + $newContent = Microsoft.PowerShell.Management\Get-Content -Path $tempPath + + try{ + #Ask for confirmation of the new manifest before replacing the original one + if($PSCmdlet.ShouldProcess($Path,$LocalizedData.UpdateManifestContentMessage+$newContent)) + { + Microsoft.PowerShell.Management\Set-Content -Path $Path -Value $newContent -Confirm:$false -WhatIf:$false + } + + #Return the new content if -PassThru is specified + if($PassThru) + { + return $newContent + } + } + catch + { + $message = $LocalizedData.ManifestFileReadWritePermissionDenied -f ($Path) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "ManifestFileReadWritePermissionDenied" ` + -ExceptionObject $Path ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + } + finally + { + Microsoft.PowerShell.Management\Remove-Item -LiteralPath $tempPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } +} + +#Utility function to help form the content string for PrivateData +function Get-PrivateData +{ + param + ( + [System.Collections.Hashtable] + $PrivateData + ) + + if($PrivateData.Keys.Count -eq 0) + { + $content = " + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # External dependent modules of this module + # ExternalModuleDependencies = '' + + } # End of PSData hashtable + +} # End of PrivateData hashtable" + return $content + } + + + #Validate each of the property of PSData is of the desired data type + $Tags= $PrivateData["Tags"] -join "','" | %{"'$_'"} + $LicenseUri = $PrivateData["LicenseUri"]| %{"'$_'"} + $ProjectUri = $PrivateData["ProjectUri"] | %{"'$_'"} + $IconUri = $PrivateData["IconUri"] | %{"'$_'"} + $ReleaseNotesEscape = $PrivateData["ReleaseNotes"] -Replace "'","''" + $ReleaseNotes = $ReleaseNotesEscape | %{"'$_'"} + $ExternalModuleDependencies = $PrivateData["ExternalModuleDependencies"] -join "','" | %{"'$_'"} + + $DefaultProperties = @("Tags","LicenseUri","ProjectUri","IconUri","ReleaseNotes","ExternalModuleDependencies") + + $ExtraProperties = @() + foreach($key in $PrivateData.Keys) + { + if($DefaultProperties -notcontains $key) + { + $PropertyString = "#"+"$key"+ " of this module" + $PropertyString += "`r`n " + $PropertyString += $key +" = " + "'"+$PrivateData[$key]+"'" + $ExtraProperties += ,$PropertyString + } + } + + $ExtraPropertiesString = "" + $firstProperty = $true + foreach($property in $ExtraProperties) + { + if($firstProperty) + { + $firstProperty = $false + } + else + { + $ExtraPropertiesString += "`r`n`r`n " + } + $ExtraPropertiesString += $Property + } + + $TagsLine ="# Tags = @()" + if($Tags -ne "''") + { + $TagsLine = "Tags = "+$Tags + } + $LicenseUriLine = "# LicenseUri = ''" + if($LicenseUri -ne "''") + { + $LicenseUriLine = "LicenseUri = "+$LicenseUri + } + $ProjectUriLine = "# ProjectUri = ''" + if($ProjectUri -ne "''") + { + $ProjectUriLine = "ProjectUri = " +$ProjectUri + } + $IconUriLine = "# IconUri = ''" + if($IconUri -ne "''") + { + $IconUriLine = "IconUri = " +$IconUri + } + $ReleaseNotesLine = "# ReleaseNotes = ''" + if($ReleaseNotes -ne "''") + { + $ReleaseNotesLine = "ReleaseNotes = "+$ReleaseNotes + } + $ExternalModuleDependenciesLine ="# ExternalModuleDependencies = ''" + if($ExternalModuleDependencies -ne "''") + { + $ExternalModuleDependenciesLine = "ExternalModuleDependencies = "+$ExternalModuleDependencies + } + + if(-not $ExtraPropertiesString -eq "") + { + $Content = " + ExtraProperties + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + $TagsLine + + # A URL to the license for this module. + $LicenseUriLine + + # A URL to the main website for this project. + $ProjectUriLine + + # A URL to an icon representing this module. + $IconUriLine + + # ReleaseNotes of this module + $ReleaseNotesLine + + # External dependent modules of this module + $ExternalModuleDependenciesLine + + } # End of PSData hashtable + +} # End of PrivateData hashtable" + + #Replace the Extra PrivateData in the block + $Content -replace "ExtraProperties", $ExtraPropertiesString + } + else + { + $content = " + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + $TagsLine + + # A URL to the license for this module. + $LicenseUriLine + + # A URL to the main website for this project. + $ProjectUriLine + + # A URL to an icon representing this module. + $IconUriLine + + # ReleaseNotes of this module + $ReleaseNotesLine + + # External dependent modules of this module + $ExternalModuleDependenciesLine + + } # End of PSData hashtable + + } # End of PrivateData hashtable" + return $content + } +} + +function Copy-ScriptFile +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $SourcePath, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $DestinationPath, + + [Parameter(Mandatory=$true)] + [ValidateNotNull()] + [PSCustomObject] + $PSGetItemInfo, + + [Parameter()] + [string] + $Scope + ) + + # Copy the script file to destination + if(-not (Microsoft.PowerShell.Management\Test-Path -Path $DestinationPath)) + { + $null = Microsoft.PowerShell.Management\New-Item -Path $DestinationPath ` + -ItemType Directory ` + -Force ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue ` + -Confirm:$false ` + -WhatIf:$false + } + + Microsoft.PowerShell.Management\Copy-Item -Path $SourcePath -Destination $DestinationPath -Force -Confirm:$false -WhatIf:$false -Verbose + + if($Scope) + { + # Create _InstalledScriptInfo.xml + $InstalledScriptInfoFileName = "$($PSGetItemInfo.Name)_$script:InstalledScriptInfoFileName" + + if($scope -eq 'AllUsers') + { + $scriptInfopath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesInstalledScriptInfosPath ` + -ChildPath $InstalledScriptInfoFileName + } + else + { + $scriptInfopath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsInstalledScriptInfosPath ` + -ChildPath $InstalledScriptInfoFileName + } + + Microsoft.PowerShell.Utility\Out-File -FilePath $scriptInfopath ` + -Force ` + -InputObject ([System.Management.Automation.PSSerializer]::Serialize($PSGetItemInfo)) + } +} + +function Copy-Module +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $SourcePath, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $DestinationPath, + + [Parameter(Mandatory=$true)] + [ValidateNotNull()] + [PSCustomObject] + $PSGetItemInfo + ) + + if(Microsoft.PowerShell.Management\Test-Path $DestinationPath) + { + Microsoft.PowerShell.Management\Remove-Item -Path $DestinationPath -Recurse -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + # Copy the module to destination + $null = Microsoft.PowerShell.Management\New-Item -Path $DestinationPath -ItemType Directory -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + Microsoft.PowerShell.Management\Copy-Item -Path "$SourcePath\*" -Destination $DestinationPath -Force -Recurse -Confirm:$false -WhatIf:$false + + # Remove the *.nupkg file + if(Microsoft.PowerShell.Management\Test-Path "$DestinationPath\$($PSGetItemInfo.Name).nupkg") + { + Microsoft.PowerShell.Management\Remove-Item -Path "$DestinationPath\$($PSGetItemInfo.Name).nupkg" -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + # Create PSGetModuleInfo.xml + $psgetItemInfopath = Microsoft.PowerShell.Management\Join-Path $DestinationPath $script:PSGetItemInfoFileName + + Microsoft.PowerShell.Utility\Out-File -FilePath $psgetItemInfopath -Force -InputObject ([System.Management.Automation.PSSerializer]::Serialize($PSGetItemInfo)) + + [System.IO.File]::SetAttributes($psgetItemInfopath, [System.IO.FileAttributes]::Hidden) +} + +function Test-FileInUse +{ + [CmdletBinding()] + [OutputType([bool])] + param + ( + [string] + $FilePath + ) + + if(Microsoft.PowerShell.Management\Test-Path -LiteralPath $FilePath -PathType Leaf) + { + # Attempts to open a file and handles the exception if the file is already open/locked + try + { + $fileInfo = New-Object System.IO.FileInfo $FilePath + $fileStream = $fileInfo.Open( [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None ) + + if ($fileStream) + { + $fileStream.Close() + } + } + catch + { + Write-Debug "In Test-FileInUse function, unable to open the $FilePath file in ReadWrite access. $_" + return $true + } + } + + return $false +} + +function Test-ModuleInUse +{ + [CmdletBinding()] + [OutputType([bool])] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $ModuleBasePath, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $ModuleName, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Version] + $ModuleVersion + ) + + $FileList = Get-ChildItem -Path $ModuleBasePath ` + -File ` + -Recurse ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + $IsModuleInUse = $false + + foreach($file in $FileList) + { + $IsModuleInUse = Test-FileInUse -FilePath $file.FullName + + if($IsModuleInUse) + { + break + } + } + + if($IsModuleInUse) + { + $message = $LocalizedData.ModuleVersionInUse -f ($ModuleVersion, $ModuleName) + Write-Error -Message $message -ErrorId 'ModuleIsInUse' -Category InvalidOperation + + return $true + } + + return $false +} + +function Test-ValidManifestModule +{ + [CmdletBinding()] + [OutputType([bool])] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $ModuleBasePath + ) + + $moduleName = Microsoft.PowerShell.Management\Split-Path $ModuleBasePath -Leaf + $manifestPath = Microsoft.PowerShell.Management\Join-Path $ModuleBasePath "$moduleName.psd1" + $PSModuleInfo = $null + + if(Microsoft.PowerShell.Management\Test-Path $manifestPath) + { + $PSModuleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $manifestPath -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + } + + return $PSModuleInfo +} + +function Get-ScriptSourceLocation +{ + [CmdletBinding()] + Param + ( + [Parameter()] + [String] + $Location + ) + + $scriptLocation = $null + + if($Location) + { + # For local dir or SMB-share locations, ScriptSourceLocation is SourceLocation. + if(Microsoft.PowerShell.Management\Test-Path -Path $Location) + { + $scriptLocation = $Location + } + else + { + $tempScriptLocation = $null + + if($Location.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase)) + { + $tempScriptLocation = $Location + '/items/psscript/' + } + elseif($Location.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase)) + { + $tempScriptLocation = $Location + 'items/psscript/' + } + + if($tempScriptLocation) + { + # Ping and resolve the specified location + $scriptLocation = Resolve-Location -Location $tempScriptLocation ` + -LocationParameterName 'ScriptSourceLocation' ` + -ErrorAction SilentlyContinue ` + -WarningAction SilentlyContinue + } + } + } + + return $scriptLocation +} + +function Get-PublishLocation +{ + [CmdletBinding()] + Param + ( + [Parameter()] + [String] + $Location + ) + + $PublishLocation = $null + + if($Location) + { + # For local dir or SMB-share locations, ScriptPublishLocation is PublishLocation. + if(Microsoft.PowerShell.Management\Test-Path -Path $Location) + { + $PublishLocation = $Location + } + else + { + $tempPublishLocation = $null + + if($Location.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase)) + { + $tempPublishLocation = $Location + '/package/' + } + elseif($Location.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase)) + { + $tempPublishLocation = $Location + 'package/' + } + + if($tempPublishLocation) + { + $PublishLocation = $tempPublishLocation + } + } + } + + return $PublishLocation +} + +function Resolve-Location +{ + [CmdletBinding()] + [OutputType([string])] + Param + ( + [Parameter(Mandatory=$true)] + [string] + $Location, + + [Parameter(Mandatory=$true)] + [string] + $LocationParameterName, + + [Parameter()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet + ) + + # Ping and resolve the specified location + if(-not (Test-WebUri -uri $Location)) + { + if(Microsoft.PowerShell.Management\Test-Path -Path $Location) + { + return $Location + } + elseif($CallerPSCmdlet) + { + $message = $LocalizedData.PathNotFound -f ($Location) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "PathNotFound" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Location + } + } + else + { + $pingResult = Ping-Endpoint -Endpoint $Location + $statusCode = $null + $exception = $null + $resolvedLocation = $null + if($pingResult -and $pingResult.ContainsKey($Script:ResponseUri)) + { + $resolvedLocation = $pingResult[$Script:ResponseUri] + } + + if($pingResult -and $pingResult.ContainsKey($Script:StatusCode)) + { + $statusCode = $pingResult[$Script:StatusCode] + } + + Write-Debug -Message "Ping-Endpoint: location=$Location, statuscode=$statusCode, resolvedLocation=$resolvedLocation" + + if((($statusCode -eq 200) -or ($statusCode -eq 401)) -and $resolvedLocation) + { + return $resolvedLocation + } + elseif($CallerPSCmdlet) + { + $message = $LocalizedData.InvalidWebUri -f ($Location, $LocationParameterName) + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "InvalidWebUri" ` + -CallerPSCmdlet $CallerPSCmdlet ` + -ErrorCategory InvalidArgument ` + -ExceptionObject $Location + } + } +} + +function Test-WebUri +{ + [CmdletBinding()] + [OutputType([bool])] + Param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Uri] + $uri + ) + + return ($uri.AbsoluteURI -ne $null) -and ($uri.Scheme -match '[http|https]') +} + +function Test-WildcardPattern +{ + [CmdletBinding()] + [OutputType([bool])] + param( + [Parameter(Mandatory=$true)] + [ValidateNotNull()] + $Name + ) + + return [System.Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Name) +} + +# Utility to throw an errorrecord +function ThrowError +{ + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $CallerPSCmdlet, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $ExceptionName, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $ExceptionMessage, + + [System.Object] + $ExceptionObject, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $ErrorId, + + [parameter(Mandatory = $true)] + [ValidateNotNull()] + [System.Management.Automation.ErrorCategory] + $ErrorCategory + ) + + $exception = New-Object $ExceptionName $ExceptionMessage; + $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $ErrorId, $ErrorCategory, $ExceptionObject + $CallerPSCmdlet.ThrowTerminatingError($errorRecord) +} + + +#endregion + +# Create install locations for scripts if they are not already created +if(-not (Microsoft.PowerShell.Management\Test-Path -Path $script:ProgramFilesInstalledScriptInfosPath) -and (Test-RunningAsElevated)) +{ + $null = Microsoft.PowerShell.Management\New-Item -Path $script:ProgramFilesInstalledScriptInfosPath ` + -ItemType Directory ` + -Force ` + -Confirm:$false ` + -WhatIf:$false +} + +if(-not (Microsoft.PowerShell.Management\Test-Path -Path $script:MyDocumentsInstalledScriptInfosPath)) +{ + $null = Microsoft.PowerShell.Management\New-Item -Path $script:MyDocumentsInstalledScriptInfosPath ` + -ItemType Directory ` + -Force ` + -Confirm:$false ` + -WhatIf:$false +} + +Set-Alias -Name fimo -Value Find-Module +Set-Alias -Name inmo -Value Install-Module +Set-Alias -Name upmo -Value Update-Module +Set-Alias -Name pumo -Value Publish-Module +Set-Alias -Name uimo -Value Uninstall-Module + +Export-ModuleMember -Function Find-Module, ` + Save-Module, ` + Install-Module, ` + Update-Module, ` + Publish-Module, ` + Uninstall-Module, ` + Get-InstalledModule, ` + Find-Command, ` + Find-DscResource, ` + Find-RoleCapability, ` + Install-Script, ` + Find-Script, ` + Save-Script, ` + Update-Script, ` + Publish-Script, ` + Get-InstalledScript, ` + Uninstall-Script, ` + Test-ScriptFileInfo, ` + New-ScriptFileInfo, ` + Update-ScriptFileInfo, ` + Get-PSRepository, ` + Register-PSRepository, ` + Unregister-PSRepository, ` + Set-PSRepository, ` + Find-Package, ` + Get-PackageDependencies, ` + Download-Package, ` + Install-Package, ` + Uninstall-Package, ` + Get-InstalledPackage, ` + Remove-PackageSource, ` + Resolve-PackageSource, ` + Add-PackageSource, ` + Get-DynamicOptions, ` + Initialize-Provider, ` + Get-Feature, ` + Get-PackageProviderName, ` + Update-ModuleManifest ` + -Alias fimo, ` + inmo, ` + upmo, ` + pumo From 5a1666c9844c872bc830f73488bd30f5a3a2ffeb Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 19:15:41 -0700 Subject: [PATCH 321/342] Fix programatic references to Linux.Host --- PowerShellGitHubDev.psm1 | 2 +- appveyor.yml | 2 +- build.sh | 2 +- src/Microsoft.PowerShell.Host/host.cs | 2 +- src/Microsoft.PowerShell.Host/main.cs | 2 +- src/Microsoft.PowerShell.Host/rawui.cs | 2 +- src/Microsoft.PowerShell.Host/readline.cs | 2 +- src/Microsoft.PowerShell.Host/ui.cs | 2 +- src/TypeCatalogParser/Main.cs | 2 +- src/libpsl-native/CMakeLists.txt | 2 +- test/csharp/fixture_AssemblyLoadContext.cs | 2 +- test/csharp/project.json | 2 +- test/csharp/test_FileSystemProvider.cs | 2 +- test/csharp/test_Runspace.cs | 2 +- test/csharp/test_SessionState.cs | 2 +- xunit.sh | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index e2dfc192d..c80c50e24 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -116,7 +116,7 @@ function Start-PSBuild { $Top = "$PSScriptRoot\src\Microsoft.PowerShell.ConsoleHost" $Framework = 'net451' } else { - $Top = "$PSScriptRoot/src/Microsoft.PowerShell.Linux.Host" + $Top = "$PSScriptRoot/src/Microsoft.PowerShell.Host" $Framework = 'netstandardapp1.5' } diff --git a/appveyor.yml b/appveyor.yml index 64a1438a3..c2ac6a59d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,7 +20,7 @@ install: - ps: $fileContent += "`n-----END RSA PRIVATE KEY-----`n" - ps: Set-Content c:\users\appveyor\.ssh\id_rsa $fileContent - git config --global url.git@github.com:.insteadOf https://github.com/ - - git submodule update --init -- src/windows-build src/Microsoft.PowerShell.Linux.Host/Modules/Pester + - git submodule update --init -- src/windows-build src/Modules/Pester - ps: Invoke-WebRequest -Uri https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/install.ps1 -OutFile install.ps1 - ps: ./install.ps1 -version 1.0.0-beta-002198 diff --git a/build.sh b/build.sh index 5287ae1bb..149910f03 100755 --- a/build.sh +++ b/build.sh @@ -5,7 +5,7 @@ hash cmake 2>/dev/null || { echo >&2 "No cmake, please run 'sudo apt-get install hash g++ 2>/dev/null || { echo >&2 "No g++, please run 'sudo apt-get install g++'"; exit 1; } hash dotnet 2>/dev/null || { echo >&2 "No dotnet, please visit https://dotnet.github.io/getting-started/"; exit 1; } -TOP="$(pwd)/src/Microsoft.PowerShell.Linux.Host" +TOP="$(pwd)/src/Microsoft.PowerShell.Host" # Test for lock file test -r "$TOP/project.lock.json" || { echo >&2 "Please run 'dotnet restore' to download .NET Core packages"; exit 2; } diff --git a/src/Microsoft.PowerShell.Host/host.cs b/src/Microsoft.PowerShell.Host/host.cs index f4fa3e253..5849c99c2 100644 --- a/src/Microsoft.PowerShell.Host/host.cs +++ b/src/Microsoft.PowerShell.Host/host.cs @@ -1,4 +1,4 @@ -namespace Microsoft.PowerShell.Linux.Host +namespace Microsoft.PowerShell.Host { using System; using System.Globalization; diff --git a/src/Microsoft.PowerShell.Host/main.cs b/src/Microsoft.PowerShell.Host/main.cs index cef1bb1a2..133b0c428 100644 --- a/src/Microsoft.PowerShell.Host/main.cs +++ b/src/Microsoft.PowerShell.Host/main.cs @@ -1,4 +1,4 @@ -namespace Microsoft.PowerShell.Linux.Host +namespace Microsoft.PowerShell.Host { using System; using System.Collections.Generic; diff --git a/src/Microsoft.PowerShell.Host/rawui.cs b/src/Microsoft.PowerShell.Host/rawui.cs index 9b359a2da..e4b221420 100644 --- a/src/Microsoft.PowerShell.Host/rawui.cs +++ b/src/Microsoft.PowerShell.Host/rawui.cs @@ -10,7 +10,7 @@ using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; -namespace Microsoft.PowerShell.Linux.Host +namespace Microsoft.PowerShell.Host { // this is all from https://msdn.microsoft.com/en-us/library/ee706570%28v=vs.85%29.aspx diff --git a/src/Microsoft.PowerShell.Host/readline.cs b/src/Microsoft.PowerShell.Host/readline.cs index f44bdbb76..8d6c4bda8 100644 --- a/src/Microsoft.PowerShell.Host/readline.cs +++ b/src/Microsoft.PowerShell.Host/readline.cs @@ -1,4 +1,4 @@ -namespace Microsoft.PowerShell.Linux.Host +namespace Microsoft.PowerShell.Host { using System; using System.Collections.ObjectModel; diff --git a/src/Microsoft.PowerShell.Host/ui.cs b/src/Microsoft.PowerShell.Host/ui.cs index 04aed71c5..ad325690a 100644 --- a/src/Microsoft.PowerShell.Host/ui.cs +++ b/src/Microsoft.PowerShell.Host/ui.cs @@ -1,4 +1,4 @@ -namespace Microsoft.PowerShell.Linux.Host +namespace Microsoft.PowerShell.Host { using System; using System.Collections.Generic; diff --git a/src/TypeCatalogParser/Main.cs b/src/TypeCatalogParser/Main.cs index 2bca648ef..4a8fa2f0a 100644 --- a/src/TypeCatalogParser/Main.cs +++ b/src/TypeCatalogParser/Main.cs @@ -17,7 +17,7 @@ namespace ConsoleApplication var outputPath = "../TypeCatalogGen/powershell.inc"; // Get a context for our top level project - var context = ProjectContext.Create("../Microsoft.PowerShell.Linux.Host", NuGetFramework.Parse("netstandardapp1.5")); + var context = ProjectContext.Create("../Microsoft.PowerShell.Host", NuGetFramework.Parse("netstandardapp1.5")); System.IO.File.WriteAllLines(outputPath, // Get the target for the current runtime diff --git a/src/libpsl-native/CMakeLists.txt b/src/libpsl-native/CMakeLists.txt index d0e83e6bb..8aa098887 100644 --- a/src/libpsl-native/CMakeLists.txt +++ b/src/libpsl-native/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8.4) project(PSL-NATIVE) add_compile_options(-std=c++11 -Wall -Werror) -set(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/../Microsoft.PowerShell.Linux.Host") +set(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/../Microsoft.PowerShell.Host") # test in BUILD_DIR enable_testing() diff --git a/test/csharp/fixture_AssemblyLoadContext.cs b/test/csharp/fixture_AssemblyLoadContext.cs index 71362729e..7afc15263 100644 --- a/test/csharp/fixture_AssemblyLoadContext.cs +++ b/test/csharp/fixture_AssemblyLoadContext.cs @@ -1,7 +1,7 @@ using Xunit; using System; using System.Management.Automation; -using Microsoft.PowerShell.Linux.Host; +using Microsoft.PowerShell.Host; // This collection fixture initializes Core PowerShell's AssemblyLoadContext once and only // once. Attempting to initialize in a class level fixture will cause multiple diff --git a/test/csharp/project.json b/test/csharp/project.json index cf6679345..1ba03831e 100644 --- a/test/csharp/project.json +++ b/test/csharp/project.json @@ -5,7 +5,7 @@ "authors": [ "andschwa" ], "dependencies": { - "Microsoft.PowerShell.Linux.Host": "1.0.0-*" + "Microsoft.PowerShell.Host": "1.0.0-*" }, "frameworks": { diff --git a/test/csharp/test_FileSystemProvider.cs b/test/csharp/test_FileSystemProvider.cs index 3c720f28a..c1e7a42f8 100644 --- a/test/csharp/test_FileSystemProvider.cs +++ b/test/csharp/test_FileSystemProvider.cs @@ -13,7 +13,7 @@ using System.Management.Automation.Provider; using System.Management.Automation.Runspaces; using Microsoft.PowerShell; using Microsoft.PowerShell.Commands; -using Microsoft.PowerShell.Linux.Host; +using Microsoft.PowerShell.Host; namespace PSTests { diff --git a/test/csharp/test_Runspace.cs b/test/csharp/test_Runspace.cs index 0a7b00eb9..3115077d9 100644 --- a/test/csharp/test_Runspace.cs +++ b/test/csharp/test_Runspace.cs @@ -2,7 +2,7 @@ using Xunit; using System; using System.Management.Automation; using System.Management.Automation.Runspaces; -using Microsoft.PowerShell.Linux.Host; +using Microsoft.PowerShell.Host; namespace PSTests { diff --git a/test/csharp/test_SessionState.cs b/test/csharp/test_SessionState.cs index adfc9e7a3..bdc4f01be 100644 --- a/test/csharp/test_SessionState.cs +++ b/test/csharp/test_SessionState.cs @@ -9,7 +9,7 @@ using System.Management.Automation.Internal; using System.Management.Automation.Internal.Host; using System.Management.Automation.Runspaces; using Microsoft.PowerShell; -using Microsoft.PowerShell.Linux.Host; +using Microsoft.PowerShell.Host; namespace PSTests { diff --git a/xunit.sh b/xunit.sh index 2813b4274..199737330 100755 --- a/xunit.sh +++ b/xunit.sh @@ -13,7 +13,7 @@ pushd test/csharp ## Build dotnet build -c Linux ## Work-around dotnet/cli#753 -cp -r -f ../../src/Microsoft.PowerShell.Linux.Host/{Modules,*.so,*.dylib} bin/Linux/netstandardapp1.5/ubuntu.14.04-x64 2>/dev/null +cp -r -f ../../src/Microsoft.PowerShell.Host/{Modules,*.so,*.dylib} bin/Linux/netstandardapp1.5/ubuntu.14.04-x64 2>/dev/null ## Test dotnet test -c Linux result=$? From 6d691de6659ca93b72fb9e0313b4a0cd86ea609f Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 19:15:52 -0700 Subject: [PATCH 322/342] Log location of PowerShell build output --- PowerShellGitHubDev.psm1 | 1 + 1 file changed, 1 insertion(+) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index c80c50e24..4feac9cb3 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -202,6 +202,7 @@ function Start-PSBuild { log "Run `dotnet build $Arguments` from $pwd" Push-Location $Top dotnet build $Arguments + log "PowerShell output: $script:Output" } finally { Pop-Location } From 9d1dca0ef105ed0cfcfb9211e4a24a89c694081b Mon Sep 17 00:00:00 2001 From: PowerShell Team Date: Fri, 1 Apr 2016 19:26:02 -0700 Subject: [PATCH 323/342] Correct "Move files from psl-monad submodule to super-project" Commit 45140c57520890b9bc7e0b4357faad14f7edf52b incorrectly stated that it imported from psl-monad repository commit 860eb5d211b8fff4e015ac59ccb58da2f59a6b58; but it actually imported from commit 8abffd25ebc33cbc0b4ce224b46e699704b01728. From 151b5525c6a12e74d5afa261f3e3c346d7f10f1f Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 19:40:18 -0700 Subject: [PATCH 324/342] Merge src/Modules and host specific Modules --- src/Microsoft.PowerShell.ConsoleHost/project.json | 2 ++ src/Microsoft.PowerShell.Host/project.json | 1 + 2 files changed, 3 insertions(+) diff --git a/src/Microsoft.PowerShell.ConsoleHost/project.json b/src/Microsoft.PowerShell.ConsoleHost/project.json index 1a22616bb..999371d72 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/project.json +++ b/src/Microsoft.PowerShell.ConsoleHost/project.json @@ -15,6 +15,8 @@ }, "content": [ + "Modules", + "../Modules", "powershell.exe" ], diff --git a/src/Microsoft.PowerShell.Host/project.json b/src/Microsoft.PowerShell.Host/project.json index a70785c07..1473ec447 100644 --- a/src/Microsoft.PowerShell.Host/project.json +++ b/src/Microsoft.PowerShell.Host/project.json @@ -19,6 +19,7 @@ "content": [ "Modules", + "../Modules", "*_profile.ps1", "*.so", "*.dylib" From 067609cdce2ff4d506f71ad483f0448df2af658f Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 20:25:12 -0700 Subject: [PATCH 325/342] Add runtimes back to xUnit runner Per dotnet/cli#2201 --- test/csharp/project.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/csharp/project.json b/test/csharp/project.json index 1ba03831e..bcef76661 100644 --- a/test/csharp/project.json +++ b/test/csharp/project.json @@ -18,5 +18,15 @@ } }, - "testRunner": "xunit" + "testRunner": "xunit", + + "runtimes": { + "ubuntu.14.04-x64": { }, + "centos.7.1-x64": { }, + "win7-x64": { }, + "win81-x64": { }, + "win10-x64": { }, + "osx.10.10-x64": { }, + "osx.10.11-x64": { } + } } From 8e397ec1a1bbe7ee58b99aadc86fd9c1bd749637 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 20:45:32 -0700 Subject: [PATCH 326/342] Add Start-PSxUnit function Replaces `./xunit.sh` to run xUnit tests on Linux. Pretty basic, can definitely be extended to support other flavors. --- PowerShellGitHubDev.psm1 | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index 4feac9cb3..131653bc4 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -213,6 +213,28 @@ function Get-PSOutput { $script:Output } +function Start-PSxUnit { + if ($IsWindows) { + throw "xUnit tests are only currently supported on Linux / OS X" + } + if (-Not $script:Output) { + throw '$script:Output is not defined, run Start-PSBuild' + } + $Content = Split-Path -Parent $script:Output + $Arguments = "--configuration", "Linux" + try { + Push-Location $PSScriptRoot/test/csharp + dotnet build $Arguments + Copy-Item -ErrorAction SilentlyContinue -Recurse -Path $Content/* -Include Modules,libpsl-native* -Destination "./bin/Linux/netstandardapp1.5/ubuntu.14.04-x64" + dotnet test $Arguments + if ($LASTEXITCODE -ne 0) { + throw "$LASTEXITCODE xUnit tests failed" + } + } finally { + Pop-Location + } +} + function Start-PSPackage { # PowerShell packages use Semantic Versioning http://semver.org/ # From b8cec0a00e63ac0fc14cdb83385edcc4362c2733 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 20:46:24 -0700 Subject: [PATCH 327/342] Remove deprecated xunit.sh script --- xunit.sh | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100755 xunit.sh diff --git a/xunit.sh b/xunit.sh deleted file mode 100755 index 199737330..000000000 --- a/xunit.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -# Test for build dependencies -hash cmake 2>/dev/null || { echo >&2 "No cmake, please run 'sudo apt-get install cmake'"; exit 1; } -hash g++ 2>/dev/null || { echo >&2 "No g++, please run 'sudo apt-get install g++'"; exit 1; } -hash dotnet 2>/dev/null || { echo >&2 "No dotnet, please visit https://dotnet.github.io/getting-started/"; exit 1; } - -# Test for lock file -test -r test/csharp/project.lock.json || { echo >&2 "Please run 'dotnet restore' to download .NET Core packages"; exit 2; } - -# Run xUnit tests -pushd test/csharp -## Build -dotnet build -c Linux -## Work-around dotnet/cli#753 -cp -r -f ../../src/Microsoft.PowerShell.Host/{Modules,*.so,*.dylib} bin/Linux/netstandardapp1.5/ubuntu.14.04-x64 2>/dev/null -## Test -dotnet test -c Linux -result=$? -popd - -exit $result From 3895492da1908b34237525d3a41bed4b01ecb044 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 20:47:58 -0700 Subject: [PATCH 328/342] Remove deprecated update-content.sh --- .../update-content.sh | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100755 src/Microsoft.PowerShell.Host/update-content.sh diff --git a/src/Microsoft.PowerShell.Host/update-content.sh b/src/Microsoft.PowerShell.Host/update-content.sh deleted file mode 100755 index 967d10f98..000000000 --- a/src/Microsoft.PowerShell.Host/update-content.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -# Types files -cp ../monad/monad/miscfiles/types/CoreClr/types.ps1xml . -cp ../monad/monad/miscfiles/types/CoreClr/typesv3.ps1xml . - -# Format files -cp ../monad/monad/miscfiles/display/Certificate.format.ps1xml . -cp ../monad/monad/miscfiles/display/Diagnostics.Format.ps1xml Diagnostics.format.ps1xml -cp ../monad/monad/miscfiles/display/DotNetTypes.format.ps1xml . -cp ../monad/monad/miscfiles/display/Event.format.ps1xml . -cp ../monad/monad/miscfiles/display/FileSystem.format.ps1xml . -cp ../monad/monad/miscfiles/display/Help.format.ps1xml . -cp ../monad/monad/miscfiles/display/HelpV3.format.ps1xml . -cp ../monad/monad/miscfiles/display/PowerShellCore.format.ps1xml . -cp ../monad/monad/miscfiles/display/PowerShellTrace.format.ps1xml . -cp ../monad/monad/miscfiles/display/Registry.format.ps1xml . -cp ../monad/monad/miscfiles/display/WSMan.format.ps1xml . - -mkdir Modules -cp -r ../monad/monad/miscfiles/modules/Microsoft.PowerShell.Utility Modules -UTILSCLR=Modules/Microsoft.PowerShell.Utility/CoreClr -mv $UTILSCLR/* Modules/Microsoft.PowerShell.Utility && rmdir $UTILSCLR -cp -r ../monad/monad/miscfiles/modules/Microsoft.PowerShell.Security Modules -cp -r ../monad/monad/miscfiles/modules/Microsoft.PowerShell.Management Modules -cp -r ../monad/monad/miscfiles/modules/PSDiagnostics Modules From 4601340f54bf1fa40fab3d52197b4de8af14bd07 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 20:49:03 -0700 Subject: [PATCH 329/342] Use Start-PSxUnit on Travis --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7680f2faf..98c835713 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,9 +14,8 @@ before_install: - ./download.sh - sudo dpkg -i ./powershell.deb script: - - powershell -c "Import-Module ./PowerShellGitHubDev.psm1; Start-PSBuild" + - powershell -c "Import-Module ./PowerShellGitHubDev.psm1; Start-PSBuild; Start-PSxUnit" - ./pester.sh - - ./xunit.sh notifications: slack: secure: sKYd4n61+ZFzGZuWGUl8V1kN0NM16wRVOFVlNhlFCwnkrEsKROb++EvXf5uwnKuzxkhEjvPWO+UFgeshQDoR93y4s5YLfhC5JupK4nUzjPzWs208KTrh8u/x9MY8X6Ojxi85EEAiku5GzMoMlkucSStZUYwbIfnelzqdw8uoRwmm2MW4XCPwsuEuDUVghyiva0Mdx1G6MopCrK8T96WywJXT3chhfZQgVt+sQCBt9g+2kjDaObKrzG0P07IVK43ZpDgnu6AoxlyBzIx9mJH2Oa/tki3/kTO72Wcp3ps3qvmiStADamzVKR9p1VlWCLWAd6VOehxuByCGEyujpzk135Wud2DZYO+8LD6inZVhFe3Wt5pCU9BDXZppiATfMCqgXEH7nK54pEn79yHcjthRJ2+Z9ot7As2fu3RSBmTAi8nRP0fxRyX/jctR3S6P0qt0y1ynx9nzBfhmhPQW0PMVazWS/nruQIvK/3iiYXjZxM5bBwIvabmwV00EYeTdbL6ufXWNgQcG1ZWkDsi2I3vst/ytUbHwaFYg83bXWpxg9DCzJeWLVUvE5/3NfBxRAuCTot/fgTEA9IYScvrlL7Q/bT0cOt0vEM98MPf1UO+WP85uxhsRgHtwDEo+jMaL6ZFkPhlV6mmmED4NdY2//a571cLNXdnuMAze5O3TWGBG53g= From a158bf654d8d30475ef8ceed991822ec1e4e85cc Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 20:49:23 -0700 Subject: [PATCH 330/342] Disable Travis cache --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 98c835713..896c2e697 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,6 @@ language: cpp sudo: required dist: trusty -cache: - apt: true - directories: - - $HOME/.nuget git: submodules: false before_install: From c66375e82d177b8599403e40d039ece42593ad5f Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 21:01:10 -0700 Subject: [PATCH 331/342] Fix paths for AppVeyor --- appveyor.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c2ac6a59d..ca3ac5a31 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -38,15 +38,17 @@ test_script: $ErrorActionPreference = 'Stop' # # CoreCLR + $env:CoreOutput = "$pwd\src\Microsoft.PowerShell.Host\bin\Debug\netstandardapp1.5\win81-x64" Write-Host -Foreground Green 'Run CoreCLR tests' $testResultsFile = "$pwd\TestsResults.xml" - .\bin\powershell.exe --noprofile -c "Import-Module .\bin\Modules\Microsoft.PowerShell.Platform; Invoke-Pester test/powershell -OutputFormat NUnitXml -OutputFile $testResultsFile" + & ("$env:CoreOutput\powershell.exe") -c "Invoke-Pester test/powershell -OutputFormat NUnitXml -OutputFile $testResultsFile" (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultsFile)) # # FullCLR + $env:FullOutput = "$pwd\src\Microsoft.PowerShell.ConsoleHost\bin\Debug\net451\win81-x64" Write-Host -Foreground Green 'Run FullCLR tests' $testResultsFileFullCLR = "$pwd\TestsResults.FullCLR.xml" - Start-DevPSGitHub -binDir $pwd\binFull -NoNewWindow -ArgumentList '-command', "Import-Module .\src\Microsoft.PowerShell.Linux.Host\Modules\Pester; Import-Module .\bin\Modules\Microsoft.PowerShell.Platform; Invoke-Pester test/fullCLR -OutputFormat NUnitXml -OutputFile $testResultsFileFullCLR" + Start-DevPSGitHub -binDir $env:FullOutput -NoNewWindow -ArgumentList '-command', "Import-Module .\src\Modules\Pester; Import-Module .\bin\Modules\Microsoft.PowerShell.Platform; Invoke-Pester test/fullCLR -OutputFormat NUnitXml -OutputFile $testResultsFileFullCLR" (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultsFileFullCLR)) # # Fail the build, if tests failed @@ -71,8 +73,8 @@ on_finish: $zipFilePath = Join-Path $pwd "$name.zip" $zipFileFullPath = Join-Path $pwd "$name.FullCLR.zip" Add-Type -assemblyname System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::CreateFromDirectory("$pwd\bin", $zipFilePath) - [System.IO.Compression.ZipFile]::CreateFromDirectory("$pwd\binFull", $zipFileFullPath) + [System.IO.Compression.ZipFile]::CreateFromDirectory($env:CoreOutput, $zipFilePath) + [System.IO.Compression.ZipFile]::CreateFromDirectory($env:FullOutput, $zipFileFullPath) @( # You can add other artifacts here From f3f0bc0b111ed1ab5c1452800b6eeb6230f70047 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 21:02:15 -0700 Subject: [PATCH 332/342] Fix Pester path for Travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 896c2e697..8a7a475ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ git: submodules: false before_install: - git config --global url.git@github.com:.insteadOf https://github.com/ - - git submodule update --init -- src/windows-build src/Microsoft.PowerShell.Linux.Host/Modules/Pester src/libpsl-native/test/googletest + - git submodule update --init -- src/windows-build src/Modules/Pester src/libpsl-native/test/googletest - ./bootstrap.sh - ./download.sh - sudo dpkg -i ./powershell.deb From 68879655a527ce57221250b234b0fceaa26c5efd Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 22:01:05 -0700 Subject: [PATCH 333/342] Formatting and function extractions --- PowerShellGitHubDev.psm1 | 234 +++++++++++++++++---------------------- 1 file changed, 102 insertions(+), 132 deletions(-) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index 131653bc4..ee374b426 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -17,6 +17,7 @@ try { $IsWindows = $true } + function Start-PSBuild { [CmdletBinding(DefaultParameterSetName='CoreCLR')] param( @@ -47,20 +48,6 @@ function Start-PSBuild { [string]$msbuildConfiguration = "Release" ) - function precheck([string]$command, [string]$missedMessage) { - $c = Get-Command $command -ErrorAction SilentlyContinue - if (-not $c) { - Write-Warning $missedMessage - return $false - } else { - return $true - } - } - - function log([string]$message) { - Write-Host -Foreground Green $message - } - # simplify ParameterSetNames if ($PSCmdlet.ParameterSetName -eq 'FullCLR') { $FullCLR = $true @@ -209,11 +196,14 @@ function Start-PSBuild { } + function Get-PSOutput { $script:Output } + function Start-PSxUnit { + [CmdletBinding()]param() if ($IsWindows) { throw "xUnit tests are only currently supported on Linux / OS X" } @@ -239,7 +229,7 @@ function Start-PSPackage { # PowerShell packages use Semantic Versioning http://semver.org/ # # Ubuntu and OS X packages are supported. - param( + [CmdletBinding()]param( [string]$Version, [int]$Iteration = 1, [ValidateSet("deb", "osxpkg", "rpm")] @@ -302,8 +292,8 @@ function Start-PSPackage { "$PSScriptRoot/package/powershell=/usr/local/bin" } -function Start-DevPSGitHub -{ + +function Start-DevPSGitHub { param( [switch]$ZapDisable, [string[]]$ArgumentList = '', @@ -312,27 +302,23 @@ function Start-DevPSGitHub [switch]$NoNewWindow ) - try - { - if ($LoadProfile -eq $false) - { + try { + if ($LoadProfile -eq $false) { $ArgumentList = @('-noprofile') + $ArgumentList } $env:DEVPATH = $binDir - if ($ZapDisable) - { + if ($ZapDisable) { $env:COMPLUS_ZapDisable = 1 } - if (-Not (Test-Path $binDir\powershell.exe.config)) - { + if (-Not (Test-Path $binDir\powershell.exe.config)) { $configContents = @" - - - + + + "@ $configContents | Out-File -Encoding Ascii $binDir\powershell.exe.config @@ -350,55 +336,14 @@ function Start-DevPSGitHub } Start-Process @startProcessArgs - } - finally - { + } finally { ri env:DEVPATH - if ($ZapDisable) - { + if ($ZapDisable) { ri env:COMPLUS_ZapDisable } } } -## this function is from Dave Wyatt's answer on -## http://stackoverflow.com/questions/22002748/hashtables-from-convertfrom-json-have-different-type-from-powershells-built-in-h -function Convert-PSObjectToHashtable -{ - param ( - [Parameter(ValueFromPipeline)] - $InputObject - ) - - process - { - if ($null -eq $InputObject) { return $null } - - if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) - { - $collection = @( - foreach ($object in $InputObject) { Convert-PSObjectToHashtable $object } - ) - - Write-Output -NoEnumerate $collection - } - elseif ($InputObject -is [psobject]) - { - $hash = @{} - - foreach ($property in $InputObject.PSObject.Properties) - { - $hash[$property.Name] = Convert-PSObjectToHashtable $property.Value - } - - $hash - } - else - { - $InputObject - } - } -} <# .EXAMPLE Copy-SubmoduleFiles # copy files FROM submodule TO src/ folders @@ -413,8 +358,7 @@ function Copy-SubmoduleFiles { ) - if (-not (Test-Path $mappingFilePath)) - { + if (-not (Test-Path $mappingFilePath)) { throw "Mapping file not found in $mappingFilePath" } @@ -422,47 +366,38 @@ function Copy-SubmoduleFiles { # mapping.json assumes the root folder Push-Location $PSScriptRoot - try - { + try { $m.GetEnumerator() | % { - if ($ToSubmodule) - { + if ($ToSubmodule) { cp $_.Value $_.Key -Verbose:$Verbose - } - else - { + } else { mkdir (Split-Path $_.Value) -ErrorAction SilentlyContinue > $null cp $_.Key $_.Value -Verbose:$Verbose } } - } - finally - { + } finally { Pop-Location } } + <# - .EXAMPLE Create-MappingFile # create mapping.json in the root folder from project.json files +.EXAMPLE Create-MappingFile # create mapping.json in the root folder from project.json files #> -function New-MappingFile -{ +function New-MappingFile { param( [string]$mappingFilePath = "$PSScriptRoot/mapping.json", [switch]$IgnoreCompileFiles, [switch]$Ignoreresource ) - function Get-MappingPath([string]$project, [string]$path) - { - if ($project -match 'TypeCatalogGen') - { + function Get-MappingPath([string]$project, [string]$path) { + if ($project -match 'TypeCatalogGen') { return Split-Path $path -Leaf } - if ($project -match 'Microsoft.Management.Infrastructure') - { + if ($project -match 'Microsoft.Management.Infrastructure') { return Split-Path $path -Leaf } @@ -473,8 +408,7 @@ function New-MappingFile # assumes the root folder Push-Location $PSScriptRoot - try - { + try { $projects = ls .\src\ -Recurse -Depth 2 -Filter 'project.json' $projects | % { $project = Split-Path $_.FullName @@ -482,8 +416,7 @@ function New-MappingFile if (-not $IgnoreCompileFiles) { $json.compileFiles | % { if ($_) { - if (-not $_.EndsWith('AssemblyInfo.cs')) - { + if (-not $_.EndsWith('AssemblyInfo.cs')) { $fullPath = Join-Path $project (Get-MappingPath -project $project -path $_) $mapping[$_.Replace('../', 'src/')] = ($fullPath.Replace("$($pwd.Path)\",'')).Replace('\', '/') } @@ -502,38 +435,19 @@ function New-MappingFile } } } - } - finally - { + } finally { Pop-Location } Set-Content -Value ($mapping | ConvertTo-Json) -Path $mappingFilePath -Encoding Ascii } -function Get-InvertedOrderedMap -{ - param( - $h - ) - $res = [ordered]@{} - foreach ($q in $h.GetEnumerator()) { - if ($res.Contains($q.Value)) - { - throw "Cannot invert hashtable: duplicated key $($q.Value)" - } - - $res[$q.Value] = $q.Key - } - return $res -} <# .EXAMPLE Send-GitDiffToSd -diffArg1 45555786714d656bd31cbce67dbccb89c433b9cb -diffArg2 45555786714d656bd31cbce67dbccb89c433b9cb~1 -pathToAdmin d:\e\ps_dev\admin Apply a signle commit to admin folder #> -function Send-GitDiffToSd -{ +function Send-GitDiffToSd { param( [Parameter(Mandatory)] [string]$diffArg1, @@ -550,32 +464,88 @@ function Send-GitDiffToSd $affectedFiles = git diff --name-only $diffArg1 $diffArg2 $rev = Get-InvertedOrderedMap $m foreach ($file in $affectedFiles) { - if ($rev.Contains) - { + if ($rev.Contains) { $sdFilePath = Join-Path $pathToAdmin $rev[$file].Substring('src/monad/'.Length) $diff = git diff $diffArg1 $diffArg2 -- $file - if ($diff) - { + if ($diff) { Write-Host -Foreground Green "Apply patch to $sdFilePath" Set-Content -Value $diff -Path $env:TEMP\diff -Encoding Ascii - if ($WhatIf) - { + if ($WhatIf) { Write-Host -Foreground Green "Patch content" cat $env:TEMP\diff - } - else - { + } else { & $patchPath --binary -p1 $sdFilePath $env:TEMP\diff } - } - else - { + } else { Write-Host -Foreground Green "No changes in $file" } - } - else - { + } else { Write-Host -Foreground Green "Ignore changes in $file, because there is no mapping for it" } } } + + +function script:log([string]$message) { + Write-Host -Foreground Green $message +} + + +function script:precheck([string]$command, [string]$missedMessage) { + $c = Get-Command $command -ErrorAction SilentlyContinue + if (-not $c) { + Write-Warning $missedMessage + return $false + } else { + return $true + } +} + + +function script:Get-InvertedOrderedMap { + param( + $h + ) + $res = [ordered]@{} + foreach ($q in $h.GetEnumerator()) { + if ($res.Contains($q.Value)) { + throw "Cannot invert hashtable: duplicated key $($q.Value)" + } + + $res[$q.Value] = $q.Key + } + return $res +} + + +## this function is from Dave Wyatt's answer on +## http://stackoverflow.com/questions/22002748/hashtables-from-convertfrom-json-have-different-type-from-powershells-built-in-h +function script:Convert-PSObjectToHashtable { + param ( + [Parameter(ValueFromPipeline)] + $InputObject + ) + + process { + if ($null -eq $InputObject) { return $null } + + if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) { + $collection = @( + foreach ($object in $InputObject) { Convert-PSObjectToHashtable $object } + ) + + Write-Output -NoEnumerate $collection + } elseif ($InputObject -is [psobject]) { + $hash = @{} + + foreach ($property in $InputObject.PSObject.Properties) + { + $hash[$property.Name] = Convert-PSObjectToHashtable $property.Value + } + + $hash + } else { + $InputObject + } + } +} From b19fdb24ac6000a363d06e7bfd324d316e4b4921 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 22:01:37 -0700 Subject: [PATCH 334/342] Throw in Get-PSOutput --- PowerShellGitHubDev.psm1 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index ee374b426..84b8aaee1 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -198,7 +198,12 @@ function Start-PSBuild { function Get-PSOutput { - $script:Output + [CmdletBinding()]param() + if (-Not $Output) { + throw '$script:Output is not defined, run Start-PSBuild' + } + + $Output } @@ -207,10 +212,8 @@ function Start-PSxUnit { if ($IsWindows) { throw "xUnit tests are only currently supported on Linux / OS X" } - if (-Not $script:Output) { - throw '$script:Output is not defined, run Start-PSBuild' - } - $Content = Split-Path -Parent $script:Output + + $Content = Split-Path -Parent (Get-PSOutput) $Arguments = "--configuration", "Linux" try { Push-Location $PSScriptRoot/test/csharp From a3cd2b3453aabffb8714c44b16fbe4b7ecb92f98 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 22:01:45 -0700 Subject: [PATCH 335/342] Add Start-PSPester function to replace pester.sh Super basic function that should be rewritten. --- PowerShellGitHubDev.psm1 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index 84b8aaee1..74a281c06 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -207,6 +207,21 @@ function Get-PSOutput { } +function Start-PSPester { + [CmdletBinding()]param( + [string]$Flags = '-EnableExit -OutputFile pester-tests.xml -OutputFormat NUnitXml', + [string]$Tests = "*", + [ValidateScript({ Test-Path -PathType Container $_})] + [string]$Directory = "$PSScriptRoot/test/powershell" + ) + + & (Get-PSOutput) -c "Invoke-Pester $Flags $Directory/$Tests" + if ($LASTEXITCODE -ne 0) { + throw "$LASTEXITCODE Pester tests failed" + } +} + + function Start-PSxUnit { [CmdletBinding()]param() if ($IsWindows) { From aa21bfc635dd635e15ebe9180ef5a7ab66a81801 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 22:02:27 -0700 Subject: [PATCH 336/342] Use Start-PSPester on Travis --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8a7a475ee..0ea3ad8e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,7 @@ before_install: - ./download.sh - sudo dpkg -i ./powershell.deb script: - - powershell -c "Import-Module ./PowerShellGitHubDev.psm1; Start-PSBuild; Start-PSxUnit" - - ./pester.sh + - powershell -c "Import-Module ./PowerShellGitHubDev.psm1; Start-PSBuild; Start-PSxUnit; Start-PSPester" notifications: slack: secure: sKYd4n61+ZFzGZuWGUl8V1kN0NM16wRVOFVlNhlFCwnkrEsKROb++EvXf5uwnKuzxkhEjvPWO+UFgeshQDoR93y4s5YLfhC5JupK4nUzjPzWs208KTrh8u/x9MY8X6Ojxi85EEAiku5GzMoMlkucSStZUYwbIfnelzqdw8uoRwmm2MW4XCPwsuEuDUVghyiva0Mdx1G6MopCrK8T96WywJXT3chhfZQgVt+sQCBt9g+2kjDaObKrzG0P07IVK43ZpDgnu6AoxlyBzIx9mJH2Oa/tki3/kTO72Wcp3ps3qvmiStADamzVKR9p1VlWCLWAd6VOehxuByCGEyujpzk135Wud2DZYO+8LD6inZVhFe3Wt5pCU9BDXZppiATfMCqgXEH7nK54pEn79yHcjthRJ2+Z9ot7As2fu3RSBmTAi8nRP0fxRyX/jctR3S6P0qt0y1ynx9nzBfhmhPQW0PMVazWS/nruQIvK/3iiYXjZxM5bBwIvabmwV00EYeTdbL6ufXWNgQcG1ZWkDsi2I3vst/ytUbHwaFYg83bXWpxg9DCzJeWLVUvE5/3NfBxRAuCTot/fgTEA9IYScvrlL7Q/bT0cOt0vEM98MPf1UO+WP85uxhsRgHtwDEo+jMaL6ZFkPhlV6mmmED4NdY2//a571cLNXdnuMAze5O3TWGBG53g= From b9d8e890c54c8b2b2817778396786fc2b0fbd452 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 22:02:44 -0700 Subject: [PATCH 337/342] Remove deprecated pester.sh script --- pester.sh | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100755 pester.sh diff --git a/pester.sh b/pester.sh deleted file mode 100755 index 400b3c79a..000000000 --- a/pester.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -test -x bin/powershell || { echo >&2 "No bin/powershell, please run './build.sh'"; exit 1; } - -./bin/powershell --noprofile -c "Import-Module Microsoft.PowerShell.Platform; Invoke-Pester test/powershell/$1 -OutputFile pester-tests.xml -OutputFormat NUnitXml -EnableExit" -failed_tests=$? - -# XML files are not executable -chmod -x pester-tests.xml - -# Return number of failed tests as exit code (more than 0 will be an error) -exit $failed_tests From d27ae18ca0d62f6146e10f036065deb570f62052 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 22:23:58 -0700 Subject: [PATCH 338/342] Skip Add-Type.Tests.ps1 This broke and needs to be fixed. --- test/powershell/Add-Type.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Add-Type.Tests.ps1 b/test/powershell/Add-Type.Tests.ps1 index 142e7e0f5..f0a4e7f97 100644 --- a/test/powershell/Add-Type.Tests.ps1 +++ b/test/powershell/Add-Type.Tests.ps1 @@ -1,5 +1,5 @@ Describe "Add-Type" { - It "Should not throw given a simple class definition" { + It "Should not throw given a simple class definition" -Skip { { Add-Type -TypeDefinition "public static class foo { }" } | Should Not Throw } } From 1b3bd12230cde3974bbe2c1bad34c228e32c86e8 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 22:24:21 -0700 Subject: [PATCH 339/342] Don't load Netwonsoft.Json from path It's already loaded. --- test/powershell/Json.Tests.ps1 | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/powershell/Json.Tests.ps1 b/test/powershell/Json.Tests.ps1 index 53305d2a0..978f11f64 100644 --- a/test/powershell/Json.Tests.ps1 +++ b/test/powershell/Json.Tests.ps1 @@ -1,15 +1,6 @@ -# While Core PowerShell does not support the JSON cmdlets, a third -# party C# library, [Json.NET](http://www.newtonsoft.com/json), can be -# loaded into PowerShell and used directly. - # http://www.newtonsoft.com/json/help/html/ParsingLINQtoJSON.htm Describe "Json.NET LINQ Parsing" { - # load third party Json.NET library - $base = [System.AppContext]::BaseDirectory - $path = Join-Path $base Newtonsoft.Json.dll - [Microsoft.PowerShell.CoreCLR.AssemblyExtensions]::LoadFrom($path) - BeforeEach { $jsonFile = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath TestJson.json $jsonData = (Get-Content $jsonFile | Out-String) From 4a7a521077e8c17e062c5bcc73f8d1b0f17b8d91 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 23:05:45 -0700 Subject: [PATCH 340/342] Fix powershell-native output directory Thanks Stack Overflow https://stackoverflow.com/a/7750816 --- src/powershell-native/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/powershell-native/CMakeLists.txt b/src/powershell-native/CMakeLists.txt index 738bcd033..581179158 100644 --- a/src/powershell-native/CMakeLists.txt +++ b/src/powershell-native/CMakeLists.txt @@ -4,7 +4,11 @@ project(PowerShell) add_compile_options() # set the output path for `powershell.exe` -set(EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/../Microsoft.PowerShell.ConsoleHost") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/../Microsoft.PowerShell.ConsoleHost") +foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) # set these flags, so build does static linking for msvcr120.dll # otherwise this dll need to be present on the system From a6fd5c70d9c5ae219793812f3f858e4b33c90cd9 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 1 Apr 2016 23:09:39 -0700 Subject: [PATCH 341/342] Fix FullCLR build script for build instead of publish --- PowerShellGitHubDev.psm1 | 21 ++++++++++++--------- appveyor.yml | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index 74a281c06..1b6605fcd 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -119,7 +119,13 @@ function Start-PSBuild { $Arguments += "--framework", $Framework $Arguments += "--configuration", $Configuration $Arguments += "--runtime", $Runtime - $script:Output = [IO.Path]::Combine($Top, "bin", $Configuration, $Framework, $Runtime, $Executable) + + # FullCLR only builds a library, so there is no runtime component + if ($FullCLR) { + $script:Output = [IO.Path]::Combine($Top, "bin", $Configuration, $Framework, $Executable) + } else { + $script:Output = [IO.Path]::Combine($Top, "bin", $Configuration, $Framework, $Runtime, $Executable) + } Write-Verbose "script:Output is $script:Output" # handle Restore @@ -164,21 +170,18 @@ function Start-PSBuild { } } elseif ($FullCLR) { log "Start building native powershell.exe" - $build = "$PSScriptRoot/build" - if ($Clean) { - Remove-Item -Force -Recurse $build -ErrorAction SilentlyContinue - } - mkdir $build -ErrorAction SilentlyContinue try { - Push-Location $build + Push-Location .\src\powershell-native if ($cmakeGenerator) { - cmake -G $cmakeGenerator ..\src\powershell-native + cmake -G $cmakeGenerator . } else { - cmake ..\src\powershell-native + cmake . } + msbuild powershell.vcxproj /p:Configuration=$msbuildConfiguration + } finally { Pop-Location } diff --git a/appveyor.yml b/appveyor.yml index ca3ac5a31..49c48df32 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -45,7 +45,7 @@ test_script: (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultsFile)) # # FullCLR - $env:FullOutput = "$pwd\src\Microsoft.PowerShell.ConsoleHost\bin\Debug\net451\win81-x64" + $env:FullOutput = "$pwd\src\Microsoft.PowerShell.ConsoleHost\bin\Debug\net451" Write-Host -Foreground Green 'Run FullCLR tests' $testResultsFileFullCLR = "$pwd\TestsResults.FullCLR.xml" Start-DevPSGitHub -binDir $env:FullOutput -NoNewWindow -ArgumentList '-command', "Import-Module .\src\Modules\Pester; Import-Module .\bin\Modules\Microsoft.PowerShell.Platform; Invoke-Pester test/fullCLR -OutputFormat NUnitXml -OutputFile $testResultsFileFullCLR" From 2275048791cf037fe6e08dcb610df712841b9513 Mon Sep 17 00:00:00 2001 From: Sergei Vorobev Date: Mon, 4 Apr 2016 11:25:22 -0700 Subject: [PATCH 342/342] Disable AppVeyor cache --- appveyor.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 49c48df32..6b01530a3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,9 +6,6 @@ environment: priv_key: secure: -cache: - - '%LocalAppData%\Microsoft\dotnet' - notifications: - provider: Slack incoming_webhook: