From 47ec733ba79b196e4e09d0c89bad245155002353 Mon Sep 17 00:00:00 2001 From: Swaroop Sridhar Date: Fri, 1 May 2020 09:24:13 -0700 Subject: [PATCH] [release/5.0-preview4] Revert processing bundles in framework (#35679) This commit reverts: Revert "Single-File: Process bundles in the framework (#34274)" This reverts commit 78b303df8fbb242985d049a277d0d199cafd51b5. Revert "Single-File Bundler: Add a FileSize test (#35149)" This reverts commit 779588a509b81d909ac5d496c172949ec1f1ddcc. *Customer Scenario* Publishing apps as a self-contained single-file doesn't work as expected. * Publish needs to generate hostpolicy and hostfxr separate from the single file bundle * Cross-platform publishing is incorrect *Problem* Since Static-apphost is not yet ready, processing bundle content in hostpolicy means that hostpolicy and hostfxr DLLs need to be separate from the bundle. This causes self-contained single-file apps to not be a "single file" temporarily. The change also requires supporting changes from the SDK, to publish hostfxr and hostpolicy as separate files, and to invoke HostModel library with arguments that facilitate cross-platform publishing. *Solution* To solve these, problem, this change reverts: Revert "Single-File: Process bundles in the framework (#34274)" commit 78b303df8fbb242985d049a277d0d199cafd51b5. and a dependent test-only change: Revert "Single-File Bundler: Add a FileSize test (#35149)" commit 779588a509b81d909ac5d496c172949ec1f1ddcc. *Risk* Medium The change is contained to only host components: apphost, hostpolicy, and hostfxr. However, the change is big, and needs testing in runtime and SDK repos. *Testing* Manually tested the SDK by inserting apphost, hostfxr, hostpolicy, and hostmodel library from this build into the `dotnet/packs` preview-4 SDK from https://github.com/dotnet/sdk/pull/11518 build. Verified that: * Singlefile apps can be published and run OK for { Windows, Linux, Osx } x {netcoreapp3.0, netcoreapp3.1, netcoreapp5.0} * Cross-targeting builds of single-file apps build and run OK (ex: built on Windos, run on Mac). --- .../corehost/cli/apphost/CMakeLists.txt | 19 ++- .../cli/{ => apphost}/bundle/dir_utils.cpp | 0 .../cli/{ => apphost}/bundle/dir_utils.h | 0 .../cli/{ => apphost}/bundle/extractor.cpp | 10 +- .../cli/{ => apphost}/bundle/extractor.h | 0 .../cli/{ => apphost}/bundle/file_entry.cpp | 15 -- .../cli/{ => apphost}/bundle/file_entry.h | 1 - .../cli/{ => apphost}/bundle/file_type.h | 0 .../cli/{ => apphost}/bundle/header.cpp | 24 ++- .../cli/{ => apphost}/bundle/header.h | 24 ++- .../cli/{ => apphost}/bundle/manifest.cpp | 4 +- .../cli/{ => apphost}/bundle/manifest.h | 8 - .../{bundle_marker.cpp => bundle/marker.cpp} | 8 +- .../{bundle_marker.h => bundle/marker.h} | 12 +- .../cli/{ => apphost}/bundle/reader.cpp | 11 +- .../cli/{ => apphost}/bundle/reader.h | 19 +-- .../corehost/cli/apphost/bundle/runner.cpp | 65 ++++++++ .../corehost/cli/apphost/bundle/runner.h | 40 +++++ src/installer/corehost/cli/bundle/info.cpp | 157 ------------------ src/installer/corehost/cli/bundle/info.h | 91 ---------- src/installer/corehost/cli/bundle/runner.cpp | 83 --------- src/installer/corehost/cli/bundle/runner.h | 49 ------ src/installer/corehost/cli/deps_entry.cpp | 118 ++++--------- src/installer/corehost/cli/deps_entry.h | 14 +- src/installer/corehost/cli/deps_format.cpp | 7 +- .../corehost/cli/fxr/command_line.cpp | 3 +- .../corehost/cli/fxr/corehost_init.cpp | 3 - .../corehost/cli/fxr/corehost_init.h | 3 +- src/installer/corehost/cli/fxr/fx_muxer.cpp | 8 - src/installer/corehost/cli/fxr/hostfxr.cpp | 18 -- .../corehost/cli/fxr/hostpolicy_resolver.cpp | 1 + src/installer/corehost/cli/host_interface.h | 5 +- .../corehost/cli/host_startup_info.h | 1 - .../corehost/cli/hostcommon/CMakeLists.txt | 6 - src/installer/corehost/cli/hostfxr.h | 7 - src/installer/corehost/cli/hostmisc/pal.h | 8 +- .../corehost/cli/hostmisc/pal.unix.cpp | 30 +--- .../corehost/cli/hostmisc/pal.windows.cpp | 31 +--- src/installer/corehost/cli/hostmisc/utils.cpp | 19 +-- src/installer/corehost/cli/hostmisc/utils.h | 2 - .../corehost/cli/hostpolicy/CMakeLists.txt | 10 -- .../corehost/cli/hostpolicy/args.cpp | 46 +---- .../corehost/cli/hostpolicy/deps_resolver.cpp | 6 +- .../corehost/cli/hostpolicy/deps_resolver.h | 12 -- .../corehost/cli/hostpolicy/hostpolicy.cpp | 15 +- .../cli/hostpolicy/hostpolicy_init.cpp | 10 -- .../corehost/cli/hostpolicy/hostpolicy_init.h | 1 - .../corehost/cli/ijwhost/ijwthunk.cpp | 6 +- .../corehost/cli/json/rapidjson/document.h | 4 +- src/installer/corehost/cli/json_parser.cpp | 62 ++----- src/installer/corehost/cli/json_parser.h | 20 +-- src/installer/corehost/cli/runtime_config.cpp | 5 +- .../test/mockhostpolicy/mockhostpolicy.cpp | 1 - src/installer/corehost/corehost.cpp | 141 +++++++--------- .../Microsoft.NET.HostModel/Bundle/Bundler.cs | 18 +- .../Bundle/Manifest.cs | 2 +- .../Bundle/TargetInfo.cs | 17 +- .../TestProjects/AppWithSubDirs/Program.cs | 6 +- .../BundleExtractToSpecificPath.cs | 64 ++++--- .../AppHost.Bundle.Tests/BundleRename.cs | 4 +- .../BundledAppWithSubDirs.cs | 34 ++-- .../Helpers/BundleHelper.cs | 97 ++--------- .../BundleAndRun.cs | 5 +- .../BundleLegacy.cs | 1 + .../BundlerConsistencyTests.cs | 76 ++++++--- src/installer/test/TestUtils/TestApp.cs | 2 - src/installer/test/TestUtils/TestProject.cs | 1 - 67 files changed, 477 insertions(+), 1113 deletions(-) rename src/installer/corehost/cli/{ => apphost}/bundle/dir_utils.cpp (100%) rename src/installer/corehost/cli/{ => apphost}/bundle/dir_utils.h (100%) rename src/installer/corehost/cli/{ => apphost}/bundle/extractor.cpp (98%) rename src/installer/corehost/cli/{ => apphost}/bundle/extractor.h (100%) rename src/installer/corehost/cli/{ => apphost}/bundle/file_entry.cpp (77%) rename src/installer/corehost/cli/{ => apphost}/bundle/file_entry.h (98%) rename src/installer/corehost/cli/{ => apphost}/bundle/file_type.h (100%) rename src/installer/corehost/cli/{ => apphost}/bundle/header.cpp (53%) rename src/installer/corehost/cli/{ => apphost}/bundle/header.h (76%) rename src/installer/corehost/cli/{ => apphost}/bundle/manifest.cpp (71%) rename src/installer/corehost/cli/{ => apphost}/bundle/manifest.h (76%) rename src/installer/corehost/cli/apphost/{bundle_marker.cpp => bundle/marker.cpp} (86%) rename src/installer/corehost/cli/apphost/{bundle_marker.h => bundle/marker.h} (83%) rename src/installer/corehost/cli/{ => apphost}/bundle/reader.cpp (88%) rename src/installer/corehost/cli/{ => apphost}/bundle/reader.h (74%) create mode 100644 src/installer/corehost/cli/apphost/bundle/runner.cpp create mode 100644 src/installer/corehost/cli/apphost/bundle/runner.h delete mode 100644 src/installer/corehost/cli/bundle/info.cpp delete mode 100644 src/installer/corehost/cli/bundle/info.h delete mode 100644 src/installer/corehost/cli/bundle/runner.cpp delete mode 100644 src/installer/corehost/cli/bundle/runner.h diff --git a/src/installer/corehost/cli/apphost/CMakeLists.txt b/src/installer/corehost/cli/apphost/CMakeLists.txt index ba01e32ec47..d77f2bfa981 100644 --- a/src/installer/corehost/cli/apphost/CMakeLists.txt +++ b/src/installer/corehost/cli/apphost/CMakeLists.txt @@ -18,11 +18,26 @@ endif() set(SKIP_VERSIONING 1) set(SOURCES - ./bundle_marker.cpp + ./bundle/file_entry.cpp + ./bundle/manifest.cpp + ./bundle/header.cpp + ./bundle/marker.cpp + ./bundle/reader.cpp + ./bundle/extractor.cpp + ./bundle/runner.cpp + ./bundle/dir_utils.cpp ) set(HEADERS - ./bundle_marker.h + ./bundle/file_type.h + ./bundle/file_entry.h + ./bundle/manifest.h + ./bundle/header.h + ./bundle/marker.h + ./bundle/reader.h + ./bundle/extractor.h + ./bundle/runner.h + ./bundle/dir_utils.h ) if(CLR_CMAKE_TARGET_WIN32) diff --git a/src/installer/corehost/cli/bundle/dir_utils.cpp b/src/installer/corehost/cli/apphost/bundle/dir_utils.cpp similarity index 100% rename from src/installer/corehost/cli/bundle/dir_utils.cpp rename to src/installer/corehost/cli/apphost/bundle/dir_utils.cpp diff --git a/src/installer/corehost/cli/bundle/dir_utils.h b/src/installer/corehost/cli/apphost/bundle/dir_utils.h similarity index 100% rename from src/installer/corehost/cli/bundle/dir_utils.h rename to src/installer/corehost/cli/apphost/bundle/dir_utils.h diff --git a/src/installer/corehost/cli/bundle/extractor.cpp b/src/installer/corehost/cli/apphost/bundle/extractor.cpp similarity index 98% rename from src/installer/corehost/cli/bundle/extractor.cpp rename to src/installer/corehost/cli/apphost/bundle/extractor.cpp index 04c5205da9d..71bb2259e9d 100644 --- a/src/installer/corehost/cli/bundle/extractor.cpp +++ b/src/installer/corehost/cli/apphost/bundle/extractor.cpp @@ -197,10 +197,7 @@ void extractor_t::extract_new(reader_t& reader) begin(); for (const file_entry_t& entry : m_manifest.files) { - if (entry.needs_extraction()) - { - extract(entry, reader); - } + extract(entry, reader); } commit_dir(); } @@ -214,11 +211,6 @@ void extractor_t::verify_recover_extraction(reader_t& reader) for (const file_entry_t& entry : m_manifest.files) { - if (!entry.needs_extraction()) - { - continue; - } - pal::string_t file_path = ext_dir; append_path(&file_path, entry.relative_path().c_str()); diff --git a/src/installer/corehost/cli/bundle/extractor.h b/src/installer/corehost/cli/apphost/bundle/extractor.h similarity index 100% rename from src/installer/corehost/cli/bundle/extractor.h rename to src/installer/corehost/cli/apphost/bundle/extractor.h diff --git a/src/installer/corehost/cli/bundle/file_entry.cpp b/src/installer/corehost/cli/apphost/bundle/file_entry.cpp similarity index 77% rename from src/installer/corehost/cli/bundle/file_entry.cpp rename to src/installer/corehost/cli/apphost/bundle/file_entry.cpp index 775117fb9a1..ba4b235fa93 100644 --- a/src/installer/corehost/cli/bundle/file_entry.cpp +++ b/src/installer/corehost/cli/apphost/bundle/file_entry.cpp @@ -33,18 +33,3 @@ file_entry_t file_entry_t::read(reader_t &reader) return entry; } - -bool file_entry_t::needs_extraction() const -{ - switch (m_type) - { - // Once the runtime can load assemblies from bundle, - // file_type_t::assembly should be in this category - case file_type_t::deps_json: - case file_type_t::runtime_config_json: - return false; - - default: - return true; - } -} diff --git a/src/installer/corehost/cli/bundle/file_entry.h b/src/installer/corehost/cli/apphost/bundle/file_entry.h similarity index 98% rename from src/installer/corehost/cli/bundle/file_entry.h rename to src/installer/corehost/cli/apphost/bundle/file_entry.h index c89d3ce0a5f..efe405cc9a6 100644 --- a/src/installer/corehost/cli/bundle/file_entry.h +++ b/src/installer/corehost/cli/apphost/bundle/file_entry.h @@ -58,7 +58,6 @@ namespace bundle int64_t offset() const { return m_offset; } int64_t size() const { return m_size; } file_type_t type() const { return m_type; } - bool needs_extraction() const; static file_entry_t read(reader_t &reader); diff --git a/src/installer/corehost/cli/bundle/file_type.h b/src/installer/corehost/cli/apphost/bundle/file_type.h similarity index 100% rename from src/installer/corehost/cli/bundle/file_type.h rename to src/installer/corehost/cli/apphost/bundle/file_type.h diff --git a/src/installer/corehost/cli/bundle/header.cpp b/src/installer/corehost/cli/apphost/bundle/header.cpp similarity index 53% rename from src/installer/corehost/cli/bundle/header.cpp rename to src/installer/corehost/cli/apphost/bundle/header.cpp index 7e6f778464d..23695bb93f1 100644 --- a/src/installer/corehost/cli/bundle/header.cpp +++ b/src/installer/corehost/cli/apphost/bundle/header.cpp @@ -9,23 +9,29 @@ using namespace bundle; -bool header_fixed_t::is_valid() const +// The AppHost expects the bundle_header to be an exact_match for which it was built. +// The framework accepts backwards compatible header versions. +bool header_fixed_t::is_valid(bool exact_match) const { if (num_embedded_files <= 0) { return false; } - // .net 5 host expects the version information to be 2.0 - // .net core 3 single-file bundles are handled within the netcoreapp3.x apphost, and are not processed here in the framework. - return (major_version == header_t::major_version) && (minor_version == header_t::minor_version); + if (exact_match) + { + return (major_version == header_t::major_version) && (minor_version == header_t::minor_version); + } + + return ((major_version < header_t::major_version) || + (major_version == header_t::major_version && minor_version <= header_t::minor_version)); } -header_t header_t::read(reader_t& reader) +header_t header_t::read(reader_t& reader, bool need_exact_version) { const header_fixed_t* fixed_header = reinterpret_cast(reader.read_direct(sizeof(header_fixed_t))); - if (!fixed_header->is_valid()) + if (!fixed_header->is_valid(need_exact_version)) { trace::error(_X("Failure processing application bundle.")); trace::error(_X("Bundle header version compatibility check failed.")); @@ -38,8 +44,10 @@ header_t header_t::read(reader_t& reader) // bundle_id is a component of the extraction path reader.read_path_string(header.m_bundle_id); - const header_fixed_v2_t *v2_header = reinterpret_cast(reader.read_direct(sizeof(header_fixed_v2_t))); - header.m_v2_header = *v2_header; + if (fixed_header->major_version > 1) + { + header.m_v2_header = reinterpret_cast(reader.read_direct(sizeof(header_fixed_v2_t))); + } return header; } diff --git a/src/installer/corehost/cli/bundle/header.h b/src/installer/corehost/cli/apphost/bundle/header.h similarity index 76% rename from src/installer/corehost/cli/bundle/header.h rename to src/installer/corehost/cli/apphost/bundle/header.h index f9ec85f4221..1b1696219dc 100644 --- a/src/installer/corehost/cli/bundle/header.h +++ b/src/installer/corehost/cli/apphost/bundle/header.h @@ -32,8 +32,9 @@ namespace bundle uint32_t minor_version; int32_t num_embedded_files; - bool is_valid() const; + bool is_valid(bool exact_match = false) const; }; +#pragma pack(pop) // netcoreapp3_compat_mode flag is set on a .net5 app, which chooses to build single-file apps in .netcore3.x compat mode, // This indicates that: @@ -45,13 +46,12 @@ namespace bundle netcoreapp3_compat_mode = 1 }; +#pragma pack(push, 1) struct location_t { public: int64_t offset; int64_t size; - - bool is_valid() const { return offset != 0; } }; // header_fixed_v2_t is available in single-file apps targetting .net5+ frameworks. @@ -65,8 +65,6 @@ namespace bundle location_t deps_json_location; location_t runtimeconfig_json_location; header_flags_t flags; - - bool is_netcoreapp3_compat_mode() const { return (flags & header_flags_t::netcoreapp3_compat_mode) != 0; } }; #pragma pack(pop) @@ -76,17 +74,14 @@ namespace bundle header_t(int32_t num_embedded_files = 0) : m_num_embedded_files(num_embedded_files) , m_bundle_id() - , m_v2_header() + , m_v2_header(NULL) + { } - static header_t read(reader_t& reader); - const pal::string_t& bundle_id() const { return m_bundle_id; } - int32_t num_embedded_files() const { return m_num_embedded_files; } - - const location_t& deps_json_location() const { return m_v2_header.deps_json_location; } - const location_t& runtimeconfig_json_location() const { return m_v2_header.runtimeconfig_json_location; } - bool is_netcoreapp3_compat_mode() const { return m_v2_header.is_netcoreapp3_compat_mode(); } + static header_t read(reader_t& reader, bool need_exact_version); + const pal::string_t& bundle_id() { return m_bundle_id; } + int32_t num_embedded_files() { return m_num_embedded_files; } static const uint32_t major_version = 2; static const uint32_t minor_version = 0; @@ -94,7 +89,8 @@ namespace bundle private: int32_t m_num_embedded_files; pal::string_t m_bundle_id; - header_fixed_v2_t m_v2_header; + const header_fixed_v2_t* m_v2_header; + }; } #endif // __HEADER_H__ diff --git a/src/installer/corehost/cli/bundle/manifest.cpp b/src/installer/corehost/cli/apphost/bundle/manifest.cpp similarity index 71% rename from src/installer/corehost/cli/bundle/manifest.cpp rename to src/installer/corehost/cli/apphost/bundle/manifest.cpp index 55f1ff1e639..6de65d3a96b 100644 --- a/src/installer/corehost/cli/bundle/manifest.cpp +++ b/src/installer/corehost/cli/apphost/bundle/manifest.cpp @@ -12,9 +12,7 @@ manifest_t manifest_t::read(reader_t& reader, int32_t num_files) for (int32_t i = 0; i < num_files; i++) { - file_entry_t entry = file_entry_t::read(reader); - manifest.files.push_back(std::move(entry)); - manifest.m_need_extraction |= entry.needs_extraction(); + manifest.files.emplace_back(file_entry_t::read(reader)); } return manifest; diff --git a/src/installer/corehost/cli/bundle/manifest.h b/src/installer/corehost/cli/apphost/bundle/manifest.h similarity index 76% rename from src/installer/corehost/cli/bundle/manifest.h rename to src/installer/corehost/cli/apphost/bundle/manifest.h index af1f9fa9198..ee8cd1edab5 100644 --- a/src/installer/corehost/cli/bundle/manifest.h +++ b/src/installer/corehost/cli/apphost/bundle/manifest.h @@ -16,17 +16,9 @@ namespace bundle class manifest_t { public: - manifest_t() - : m_need_extraction(false) {} - std::vector files; static manifest_t read(reader_t &reader, int32_t num_files); - - bool files_need_extraction() { return m_need_extraction; } - - private: - bool m_need_extraction; }; } #endif // __MANIFEST_H__ diff --git a/src/installer/corehost/cli/apphost/bundle_marker.cpp b/src/installer/corehost/cli/apphost/bundle/marker.cpp similarity index 86% rename from src/installer/corehost/cli/apphost/bundle_marker.cpp rename to src/installer/corehost/cli/apphost/bundle/marker.cpp index d8ea15bdd4f..d2302923226 100644 --- a/src/installer/corehost/cli/apphost/bundle_marker.cpp +++ b/src/installer/corehost/cli/apphost/bundle/marker.cpp @@ -2,12 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#include "bundle_marker.h" +#include "marker.h" #include "pal.h" #include "trace.h" #include "utils.h" -int64_t bundle_marker_t::header_offset() +using namespace bundle; + +int64_t marker_t::header_offset() { // Contains the bundle_placeholder default value at compile time. // If this is a single-file bundle, the last 8 bytes are replaced @@ -25,7 +27,7 @@ int64_t bundle_marker_t::header_offset() 0xee, 0x3b, 0x2d, 0xce, 0x24, 0xb3, 0x6a, 0xae }; - volatile bundle_marker_t* marker = reinterpret_cast(placeholder); + volatile marker_t* marker = reinterpret_cast(placeholder); return marker->locator.bundle_header_offset; } diff --git a/src/installer/corehost/cli/apphost/bundle_marker.h b/src/installer/corehost/cli/apphost/bundle/marker.h similarity index 83% rename from src/installer/corehost/cli/apphost/bundle_marker.h rename to src/installer/corehost/cli/apphost/bundle/marker.h index c5065fdac19..52e185fbe79 100644 --- a/src/installer/corehost/cli/apphost/bundle_marker.h +++ b/src/installer/corehost/cli/apphost/bundle/marker.h @@ -2,13 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#ifndef __BUNDLE_MARKER_H__ -#define __BUNDLE_MARKER_H__ +#ifndef __MARKER_H__ +#define __MARKER_H__ #include +namespace bundle +{ #pragma pack(push, 1) - union bundle_marker_t + union marker_t { public: uint8_t placeholder[40]; @@ -26,5 +28,5 @@ }; #pragma pack(pop) - -#endif // __BUNDLE_MARKER_H__ +} +#endif // __MARKER_H__ diff --git a/src/installer/corehost/cli/bundle/reader.cpp b/src/installer/corehost/cli/apphost/bundle/reader.cpp similarity index 88% rename from src/installer/corehost/cli/bundle/reader.cpp rename to src/installer/corehost/cli/apphost/bundle/reader.cpp index 2e5135da564..e2fa9b6574c 100644 --- a/src/installer/corehost/cli/bundle/reader.cpp +++ b/src/installer/corehost/cli/apphost/bundle/reader.cpp @@ -8,9 +8,9 @@ using namespace bundle; -const char* reader_t::add_without_overflow(const char* ptr, int64_t len) +const int8_t* reader_t::add_without_overflow(const int8_t* ptr, int64_t len) { - const char* new_ptr = ptr + len; + const int8_t* new_ptr = ptr + len; // The following check will fail in case len < 0 (which is also an error while reading) // even if the actual arthmetic didn't overflow. @@ -38,7 +38,7 @@ void reader_t::set_offset(int64_t offset) void reader_t::bounds_check(int64_t len) { - const char* post_read_ptr = add_without_overflow(m_ptr, len); + const int8_t* post_read_ptr = add_without_overflow(m_ptr, len); // It is legal for post_read_ptr == m_bound_ptr after reading the last byte. if (m_ptr < m_base_ptr || post_read_ptr > m_bound_ptr) @@ -88,14 +88,11 @@ size_t reader_t::read_path_length() return length; } -size_t reader_t::read_path_string(pal::string_t &str) +void reader_t::read_path_string(pal::string_t &str) { - const char* start_ptr = m_ptr; size_t size = read_path_length(); std::unique_ptr buffer{ new uint8_t[size + 1] }; read(buffer.get(), size); buffer[size] = 0; // null-terminator pal::clr_palstring(reinterpret_cast(buffer.get()), &str); - - return m_ptr - start_ptr; // This subtraction can't overflow because addition above is bounds_checked } diff --git a/src/installer/corehost/cli/bundle/reader.h b/src/installer/corehost/cli/apphost/bundle/reader.h similarity index 74% rename from src/installer/corehost/cli/bundle/reader.h rename to src/installer/corehost/cli/apphost/bundle/reader.h index 8a1212d94b8..1824ece515a 100644 --- a/src/installer/corehost/cli/bundle/reader.h +++ b/src/installer/corehost/cli/apphost/bundle/reader.h @@ -13,20 +13,19 @@ namespace bundle // Helper class for reading sequentially from the memory-mapped bundle file. struct reader_t { - reader_t(const char* base_ptr, int64_t bound, int64_t start_offset = 0) + reader_t(const int8_t* base_ptr, int64_t bound) : m_base_ptr(base_ptr) , m_ptr(base_ptr) , m_bound(bound) , m_bound_ptr(add_without_overflow(base_ptr, bound)) { - set_offset(start_offset); } public: void set_offset(int64_t offset); - operator const char*() const + operator const int8_t*() const { return m_ptr; } @@ -47,26 +46,26 @@ namespace bundle // Return a pointer to the requested bytes within the memory-mapped file. // Skip over len bytes. - const char* read_direct(int64_t len) + const int8_t* read_direct(int64_t len) { bounds_check(len); - const char *ptr = m_ptr; + const int8_t *ptr = m_ptr; m_ptr += len; return ptr; } size_t read_path_length(); - size_t read_path_string(pal::string_t &str); + void read_path_string(pal::string_t &str); private: void bounds_check(int64_t len = 1); - static const char* add_without_overflow(const char* ptr, int64_t len); + static const int8_t* add_without_overflow(const int8_t* ptr, int64_t len); - const char* const m_base_ptr; - const char* m_ptr; + const int8_t* const m_base_ptr; + const int8_t* m_ptr; const int64_t m_bound; - const char* const m_bound_ptr; + const int8_t* const m_bound_ptr; }; } diff --git a/src/installer/corehost/cli/apphost/bundle/runner.cpp b/src/installer/corehost/cli/apphost/bundle/runner.cpp new file mode 100644 index 00000000000..50d74235d7a --- /dev/null +++ b/src/installer/corehost/cli/apphost/bundle/runner.cpp @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include "extractor.h" +#include "runner.h" +#include "trace.h" +#include "header.h" +#include "marker.h" +#include "manifest.h" + +using namespace bundle; + +void runner_t::map_host() +{ + m_bundle_map = (int8_t *) pal::map_file_readonly(m_bundle_path, m_bundle_length); + + if (m_bundle_map == nullptr) + { + trace::error(_X("Failure processing application bundle.")); + trace::error(_X("Couldn't memory map the bundle file for reading.")); + throw StatusCode::BundleExtractionIOError; + } +} + +void runner_t::unmap_host() +{ + if (!pal::unmap_file(m_bundle_map, m_bundle_length)) + { + trace::warning(_X("Failed to unmap bundle after extraction.")); + } +} + +// Current support for executing single-file bundles involves +// extraction of embedded files to actual files on disk. +// This method implements the file extraction functionality at startup. +StatusCode runner_t::extract() +{ + try + { + map_host(); + reader_t reader(m_bundle_map, m_bundle_length); + + // Read the bundle header + reader.set_offset(marker_t::header_offset()); + header_t header = header_t::read(reader, /* need_exact_version: */ true); + + // Read the bundle manifest + // Reader is at the correct offset + manifest_t manifest = manifest_t::read(reader, header.num_embedded_files()); + + // Extract the files + extractor_t extractor(header.bundle_id(), m_bundle_path, manifest); + m_extraction_dir = extractor.extract(reader); + + unmap_host(); + return StatusCode::Success; + } + catch (StatusCode e) + { + return e; + } +} + diff --git a/src/installer/corehost/cli/apphost/bundle/runner.h b/src/installer/corehost/cli/apphost/bundle/runner.h new file mode 100644 index 00000000000..07dadede0fd --- /dev/null +++ b/src/installer/corehost/cli/apphost/bundle/runner.h @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#ifndef __RUNNER_H__ +#define __RUNNER_H__ + +#include "error_codes.h" + +namespace bundle +{ + class runner_t + { + public: + runner_t(const pal::string_t& bundle_path) + : m_bundle_path(bundle_path) + , m_bundle_map(nullptr) + , m_bundle_length(0) + { + } + + StatusCode extract(); + + pal::string_t extraction_dir() + { + return m_extraction_dir; + } + + private: + void map_host(); + void unmap_host(); + + pal::string_t m_bundle_path; + pal::string_t m_extraction_dir; + int8_t* m_bundle_map; + size_t m_bundle_length; + }; +} + +#endif // __RUNNER_H__ diff --git a/src/installer/corehost/cli/bundle/info.cpp b/src/installer/corehost/cli/bundle/info.cpp deleted file mode 100644 index 3fef4220890..00000000000 --- a/src/installer/corehost/cli/bundle/info.cpp +++ /dev/null @@ -1,157 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#include "trace.h" -#include "info.h" -#include "utils.h" - -using namespace bundle; - -// Global single-file bundle information, if any -const info_t* info_t::the_app = nullptr; - -info_t::info_t(const pal::char_t* bundle_path, - const pal::char_t* app_path, - int64_t header_offset) - : m_bundle_path(bundle_path) - , m_bundle_size(0) - , m_header_offset(header_offset) -{ - m_base_path = get_directory(m_bundle_path); - - // Single-file bundles currently only support deps/runtime config json files - // named based on the app.dll. Any other name for these configuration files - // mentioned via the command line are assumed to be actual files on disk. - // - // Supporting custom names for these config files is straightforward (with associated changes in bundler and SDK). - // There is no known use-case for it yet, and the facility is TBD. - - m_deps_json = config_t(get_deps_from_app_binary(m_base_path, app_path)); - m_runtimeconfig_json = config_t(get_runtime_config_path(m_base_path, get_filename_without_ext(app_path))); -} - -StatusCode info_t::process_bundle(const pal::char_t* bundle_path, const pal::char_t* app_path, int64_t header_offset) -{ - if (header_offset == 0) - { - // Not a single-file bundle. - return StatusCode::Success; - } - - static info_t info(bundle_path, app_path, header_offset); - StatusCode status = info.process_header(); - - if (status != StatusCode::Success) - { - return status; - } - - trace::info(_X("Single-File bundle details:")); - trace::info(_X("DepsJson Offset:[%lx] Size[%lx]"), info.m_header.deps_json_location().offset, info.m_header.deps_json_location().size); - trace::info(_X("RuntimeConfigJson Offset:[%lx] Size[%lx]"), info.m_header.runtimeconfig_json_location().offset, info.m_header.runtimeconfig_json_location().size); - trace::info(_X(".net core 3 compatibility mode: [%s]"), info.m_header.is_netcoreapp3_compat_mode() ? _X("Yes") : _X("No")); - - the_app = &info; - - return StatusCode::Success; -} - -StatusCode info_t::process_header() -{ - try - { - const char* addr = map_bundle(); - - reader_t reader(addr, m_bundle_size, m_header_offset); - - m_header = header_t::read(reader); - m_deps_json.set_location(&m_header.deps_json_location()); - m_runtimeconfig_json.set_location(&m_header.runtimeconfig_json_location()); - - unmap_bundle(addr); - - return StatusCode::Success; - } - catch (StatusCode e) - { - return e; - } -} - -char* info_t::config_t::map(const pal::string_t& path, const location_t* &location) -{ - assert(is_single_file_bundle()); - - const bundle::info_t* app = bundle::info_t::the_app; - if (app->m_deps_json.matches(path)) - { - location = app->m_deps_json.m_location; - } - else if (app->m_runtimeconfig_json.matches(path)) - { - location = app->m_runtimeconfig_json.m_location; - } - else - { - return nullptr; - } - - // When necessary to map the deps.json or runtimeconfig.json files, we map the whole single-file bundle, - // and return the address at the appropriate offset. - // This is because: - // * The host is the only code that is currently running and trying to map the bundle. - // * Files can only be memory mapped at page-aligned offsets, and in whole page units. - // Therefore, mapping only portions of the bundle will involve align-down/round-up calculations, and associated offset adjustments. - // We choose the simpler approach of rounding to the whole file - // * There is no performance limitation due to a larger sized mapping, since we actually only read the pages with relevant contents. - // * Files that are too large to be mapped (ex: that exhaust 32-bit virtual address space) are not supported. - - char* addr = (char*)pal::mmap_copy_on_write(app->m_bundle_path); - if (addr == nullptr) - { - trace::error(_X("Failure processing application bundle.")); - trace::error(_X("Failed to map bundle file [%s]"), path.c_str()); - } - - trace::info(_X("Mapped bundle for [%s]"), path.c_str()); - - return addr + location->offset; -} - -void info_t::config_t::unmap(const char* addr, const location_t* location) -{ - // Adjust to the beginning of the bundle. - addr -= location->offset; - bundle::info_t::the_app->unmap_bundle(addr); -} - -const char* info_t::map_bundle() -{ - const void *addr = pal::mmap_read(m_bundle_path, &m_bundle_size); - - if (addr == nullptr) - { - trace::error(_X("Failure processing application bundle.")); - trace::error(_X("Couldn't memory map the bundle file for reading.")); - throw StatusCode::BundleExtractionIOError; - } - - trace::info(_X("Mapped application bundle")); - - return (const char *)addr; -} - -void info_t::unmap_bundle(const char* addr) const -{ - if (!pal::munmap((void*)addr, m_bundle_size)) - { - trace::warning(_X("Failed to unmap bundle after extraction.")); - } - else - { - trace::info(_X("Unmapped application bundle")); - } -} - - diff --git a/src/installer/corehost/cli/bundle/info.h b/src/installer/corehost/cli/bundle/info.h deleted file mode 100644 index 0f3db559fc2..00000000000 --- a/src/installer/corehost/cli/bundle/info.h +++ /dev/null @@ -1,91 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#ifndef __INFO_H_ -#define __INFO_H_ - -#include "error_codes.h" -#include "header.h" - -// bundle::info supports: -// * API for identification of a single-file app bundle, and -// * Minimal probing and mapping functionality only for the app.runtimeconfig.json and app.deps.json files. -// bundle::info is used by HostFxr to read the above config files. - -namespace bundle -{ - struct info_t - { - struct config_t - { - config_t() - : m_location(nullptr) {} - - config_t(const config_t& config) - { - m_path = config.m_path; - m_location = config.m_location; - } - - config_t(const pal::string_t& path, const location_t *location=nullptr) - { - m_path = path; - m_location = location; - } - - bool matches(const pal::string_t& path) const - { - return m_location->is_valid() && path.compare(m_path) == 0; - } - - static bool probe(const pal::string_t& path) - { - return is_single_file_bundle() && - (the_app->m_deps_json.matches(path) || the_app->m_runtimeconfig_json.matches(path)); - } - - void set_location(const location_t* location) - { - m_location = location; - } - - static char* map(const pal::string_t& path, const location_t* &location); - static void unmap(const char* addr, const location_t* location); - - private: - pal::string_t m_path; - const location_t *m_location; - }; - - static StatusCode process_bundle(const pal::char_t* bundle_path, const pal::char_t *app_path, int64_t header_offset); - static bool is_single_file_bundle() { return the_app != nullptr; } - - bool is_netcoreapp3_compat_mode() const { return m_header.is_netcoreapp3_compat_mode(); } - const pal::string_t& base_path() const { return m_base_path; } - int64_t header_offset() const { return m_header_offset; } - - // Global single-file info object - static const info_t* the_app; - - protected: - info_t(const pal::char_t* bundle_path, - const pal::char_t* app_path, - int64_t header_offset); - - const char* map_bundle(); - void unmap_bundle(const char* addr) const; - - pal::string_t m_bundle_path; - pal::string_t m_base_path; - size_t m_bundle_size; - int64_t m_header_offset; - header_t m_header; - config_t m_deps_json; - config_t m_runtimeconfig_json; - - private: - StatusCode process_header(); - }; -} -#endif // __INFO_H_ diff --git a/src/installer/corehost/cli/bundle/runner.cpp b/src/installer/corehost/cli/bundle/runner.cpp deleted file mode 100644 index 58d10a81785..00000000000 --- a/src/installer/corehost/cli/bundle/runner.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#include -#include "extractor.h" -#include "runner.h" -#include "trace.h" -#include "header.h" -#include "manifest.h" -#include "utils.h" - -using namespace bundle; - -// This method processes the bundle manifest. -// It also implements the extraction of files that cannot be directly processed from the bundle. -StatusCode runner_t::extract() -{ - try - { - const char* addr = map_bundle(); - - // Set the Reader at header_offset - reader_t reader(addr, m_bundle_size, m_header_offset); - - // Read the bundle header - m_header = header_t::read(reader); - m_deps_json.set_location(&m_header.deps_json_location()); - m_runtimeconfig_json.set_location(&m_header.runtimeconfig_json_location()); - - // Read the bundle manifest - m_manifest = manifest_t::read(reader, m_header.num_embedded_files()); - - // Extract the files if necessary - if (m_manifest.files_need_extraction()) - { - extractor_t extractor(m_header.bundle_id(), m_bundle_path, m_manifest); - m_extraction_path = extractor.extract(reader); - } - - unmap_bundle(addr); - - return StatusCode::Success; - } - catch (StatusCode e) - { - return e; - } -} - -const file_entry_t* runner_t::probe(const pal::string_t& path) const -{ - for (const file_entry_t& entry : m_manifest.files) - { - if (entry.relative_path() == path) - { - return &entry; - } - } - - return nullptr; -} - -bool runner_t::locate(const pal::string_t& relative_path, pal::string_t& full_path) const -{ - const bundle::runner_t* app = bundle::runner_t::app(); - const bundle::file_entry_t* entry = app->probe(relative_path); - - if (entry == nullptr) - { - full_path.clear(); - return false; - } - - // Currently, all files except deps.json and runtimeconfig.json are extracted to disk. - // The json files are not queried by the host using this method. - assert(entry->needs_extraction()); - - full_path.assign(app->extraction_path()); - append_path(&full_path, relative_path.c_str()); - - return true; -} diff --git a/src/installer/corehost/cli/bundle/runner.h b/src/installer/corehost/cli/bundle/runner.h deleted file mode 100644 index fb4d74bf877..00000000000 --- a/src/installer/corehost/cli/bundle/runner.h +++ /dev/null @@ -1,49 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#ifndef __RUNNER_H__ -#define __RUNNER_H__ - -#include "error_codes.h" -#include "header.h" -#include "manifest.h" -#include "info.h" - -// bundle::runner extends bundle::info to supports: -// * Reading the bundle manifest and identifying file locations for the runtime -// * Extracting bundled files to disk when necessary -// bundle::runner is used by HostPolicy. - -namespace bundle -{ - class runner_t : public info_t - { - public: - runner_t(const pal::char_t* bundle_path, - const pal::char_t *app_path, - int64_t header_offset) - : info_t(bundle_path, app_path, header_offset) {} - - const pal::string_t& extraction_path() const { return m_extraction_path; } - - const file_entry_t *probe(const pal::string_t& path) const; - bool locate(const pal::string_t& relative_path, pal::string_t& full_path) const; - - static StatusCode process_manifest_and_extract() - { - return ((runner_t*) the_app)->extract(); - } - - static const runner_t* app() { return (const runner_t*)the_app; } - - private: - - StatusCode extract(); - - manifest_t m_manifest; - pal::string_t m_extraction_path; - }; -} - -#endif // __RUNNER_H__ diff --git a/src/installer/corehost/cli/deps_entry.cpp b/src/installer/corehost/cli/deps_entry.cpp index 449403fa038..08d196c1741 100644 --- a/src/installer/corehost/cli/deps_entry.cpp +++ b/src/installer/corehost/cli/deps_entry.cpp @@ -6,39 +6,9 @@ #include "utils.h" #include "deps_entry.h" #include "trace.h" -#include "bundle/runner.h" -static pal::string_t normalize_dir_separator(const pal::string_t& path) -{ - // Entry relative path contains '/' separator, sanitize it to use - // platform separator. Perf: avoid extra copy if it matters. - pal::string_t normalized_path = path; - if (_X('/') != DIR_SEPARATOR) - { - replace_char(&normalized_path, _X('/'), DIR_SEPARATOR); - } - - return normalized_path; -} -// ----------------------------------------------------------------------------- -// Given a "base" directory, determine the resolved path for this file. -// -// * If this file exists within the single-file bundle candidate is -// the full-path to the extracted file. -// * Otherwise, candidate is the full local path of the file. -// -// Parameters: -// base - The base directory to look for the relative path of this entry -// ietf_dir - If this is a resource asset, the IETF intermediate directory -// look_in_base - Whether to search as a relative path -// look_in_bundle - Whether to look within the single-file bundle -// str - If the method returns true, contains the file path for this deps entry -// -// Returns: -// If the file exists in the path relative to the "base" directory within the -// single-file or on disk. -bool deps_entry_t::to_path(const pal::string_t& base, const pal::string_t& ietf_dir, bool look_in_base, bool look_in_bundle, pal::string_t* str) const +bool deps_entry_t::to_path(const pal::string_t& base, bool look_in_base, pal::string_t* str) const { pal::string_t& candidate = *str; @@ -50,41 +20,20 @@ bool deps_entry_t::to_path(const pal::string_t& base, const pal::string_t& ietf_ return false; } - pal::string_t normalized_path = normalize_dir_separator(asset.relative_path); - - // Reserve space for the path below - candidate.reserve(base.length() + ietf_dir.length() + normalized_path.length() + 3); - - pal::string_t file_path = look_in_base ? get_filename(normalized_path) : normalized_path; - pal::string_t sub_path = ietf_dir; - append_path(&sub_path, file_path.c_str()); - - if (look_in_bundle && bundle::info_t::is_single_file_bundle()) + // Entry relative path contains '/' separator, sanitize it to use + // platform separator. Perf: avoid extra copy if it matters. + pal::string_t pal_relative_path = asset.relative_path; + if (_X('/') != DIR_SEPARATOR) { - const bundle::runner_t* app = bundle::runner_t::app(); - - if (base.compare(app->base_path()) == 0) - { - // If sub_path is found in the single-file bundle, - // app::locate() will set candidate to the full-path to the assembly extracted out to disk. - if (app->locate(sub_path, candidate)) - { - trace::verbose(_X(" %s found in bundle [%s]"), sub_path.c_str(), candidate.c_str()); - return true; - } - else - { - trace::verbose(_X(" %s not found in bundle"), sub_path.c_str()); - } - } - else - { - trace::verbose(_X(" %s not searched in bundle base path %s doesn't match bundle base %s."), - sub_path.c_str(), base.c_str(), app->base_path().c_str()); - } + replace_char(&pal_relative_path, _X('/'), DIR_SEPARATOR); } + // Reserve space for the path below + candidate.reserve(base.length() + + pal_relative_path.length() + 3); + candidate.assign(base); + pal::string_t sub_path = look_in_base ? get_filename(pal_relative_path) : pal_relative_path; append_path(&candidate, sub_path.c_str()); bool exists = pal::file_exists(candidate); @@ -98,7 +47,6 @@ bool deps_entry_t::to_path(const pal::string_t& base, const pal::string_t& ietf_ { trace::verbose(_X(" %s path query exists %s"), query_type, candidate.c_str()); } - return exists; } @@ -107,50 +55,55 @@ bool deps_entry_t::to_path(const pal::string_t& base, const pal::string_t& ietf_ // // Parameters: // base - The base directory to look for the relative path of this entry -// str - If the method returns true, contains the file path for this deps entry +// str - If the method returns true, contains the file path for this deps +// entry relative to the "base" directory // // Returns: // If the file exists in the path relative to the "base" directory. // -bool deps_entry_t::to_dir_path(const pal::string_t& base, bool look_in_bundle, pal::string_t* str) const +bool deps_entry_t::to_dir_path(const pal::string_t& base, pal::string_t* str) const { - pal::string_t ietf_dir; - if (asset_type == asset_types::resources) { - pal::string_t pal_relative_path = normalize_dir_separator(asset.relative_path); + pal::string_t pal_relative_path = asset.relative_path; + if (_X('/') != DIR_SEPARATOR) + { + replace_char(&pal_relative_path, _X('/'), DIR_SEPARATOR); + } // Resources are represented as "lib///" in the deps.json. // The is the "directory" in the pal_relative_path below, so extract it. - ietf_dir = get_directory(pal_relative_path); + pal::string_t ietf_dir = get_directory(pal_relative_path); + pal::string_t ietf = ietf_dir; // get_directory returns with DIR_SEPARATOR appended that we need to remove. - remove_trailing_dir_seperator(&ietf_dir); + remove_trailing_dir_seperator(&ietf); // Extract IETF code from "lib//" - ietf_dir = get_filename(ietf_dir); - - trace::verbose(_X("Detected a resource asset, will query dir/ietf-tag/resource base: %s ietf: %s asset: %s"), - base.c_str(), ietf_dir.c_str(), asset.name.c_str()); + ietf = get_filename(ietf); + + pal::string_t base_ietf_dir = base; + append_path(&base_ietf_dir, ietf.c_str()); + trace::verbose(_X("Detected a resource asset, will query dir/ietf-tag/resource base: %s asset: %s"), base_ietf_dir.c_str(), asset.name.c_str()); + return to_path(base_ietf_dir, true, str); } - - return to_path(base, ietf_dir, true, look_in_bundle, str); + return to_path(base, true, str); } - // ----------------------------------------------------------------------------- // Given a "base" directory, yield the relative path of this file in the package // layout. // // Parameters: // base - The base directory to look for the relative path of this entry -// str - If the method returns true, contains the file path for this deps entry +// str - If the method returns true, contains the file path for this deps +// entry relative to the "base" directory // // Returns: // If the file exists in the path relative to the "base" directory. // -bool deps_entry_t::to_rel_path(const pal::string_t& base, bool look_in_bundle, pal::string_t* str) const +bool deps_entry_t::to_rel_path(const pal::string_t& base, pal::string_t* str) const { - return to_path(base, _X(""), false, look_in_bundle, str); + return to_path(base, false, str); } // ----------------------------------------------------------------------------- @@ -159,7 +112,8 @@ bool deps_entry_t::to_rel_path(const pal::string_t& base, bool look_in_bundle, p // // Parameters: // base - The base directory to look for the relative path of this entry -// str - If the method returns true, contains the file path for this deps entry +// str - If the method returns true, contains the file path for this deps +// entry relative to the "base" directory // // Returns: // If the file exists in the path relative to the "base" directory. @@ -186,5 +140,5 @@ bool deps_entry_t::to_full_path(const pal::string_t& base, pal::string_t* str) c append_path(&new_base, library_path.c_str()); } - return to_rel_path(new_base, false, str); + return to_rel_path(new_base, str); } diff --git a/src/installer/corehost/cli/deps_entry.h b/src/installer/corehost/cli/deps_entry.h index 2c66b1f0552..d06e2988aa3 100644 --- a/src/installer/corehost/cli/deps_entry.h +++ b/src/installer/corehost/cli/deps_entry.h @@ -52,19 +52,17 @@ struct deps_entry_t bool is_serviceable; bool is_rid_specific; - // Given a "base" dir, yield the file path within this directory or single-file bundle. - bool to_dir_path(const pal::string_t& base, bool look_in_bundle, pal::string_t* str) const; + // Given a "base" dir, yield the filepath within this directory or relative to this directory based on "look_in_base" + bool to_path(const pal::string_t& base, bool look_in_base, pal::string_t* str) const; + + // Given a "base" dir, yield the file path within this directory. + bool to_dir_path(const pal::string_t& base, pal::string_t* str) const; // Given a "base" dir, yield the relative path in the package layout. - bool to_rel_path(const pal::string_t& base, bool look_in_bundle, pal::string_t* str) const; + bool to_rel_path(const pal::string_t& base, pal::string_t* str) const; // Given a "base" dir, yield the relative path with package name, version in the package layout. bool to_full_path(const pal::string_t& root, pal::string_t* str) const; - -private: - // Given a "base" dir, yield the filepath within this directory or relative to this directory based on "look_in_base" - // Returns a path within the single-file bundle, or a file on disk, - bool to_path(const pal::string_t& base, const pal::string_t& ietf_code, bool look_in_base, bool look_in_bundle, pal::string_t* str) const; }; #endif // __DEPS_ENTRY_H_ diff --git a/src/installer/corehost/cli/deps_format.cpp b/src/installer/corehost/cli/deps_format.cpp index 873dd815c7a..b098d953025 100644 --- a/src/installer/corehost/cli/deps_format.cpp +++ b/src/installer/corehost/cli/deps_format.cpp @@ -6,7 +6,6 @@ #include "deps_format.h" #include "utils.h" #include "trace.h" -#include "bundle/info.h" #include #include #include @@ -427,16 +426,16 @@ bool deps_json_t::has_package(const pal::string_t& name, const pal::string_t& ve bool deps_json_t::load(bool is_framework_dependent, const pal::string_t& deps_path, const rid_fallback_graph_t& rid_fallback_graph) { m_deps_file = deps_path; - m_file_exists = bundle::info_t::config_t::probe(deps_path) || pal::file_exists(deps_path); + m_file_exists = pal::file_exists(deps_path); - json_parser_t json; + // If file doesn't exist, then assume parsed. if (!m_file_exists) { - // If file doesn't exist, then assume parsed. trace::verbose(_X("Could not locate the dependencies manifest file [%s]. Some libraries may fail to resolve."), deps_path.c_str()); return true; } + json_parser_t json; if (!json.parse_file(deps_path)) { return false; diff --git a/src/installer/corehost/cli/fxr/command_line.cpp b/src/installer/corehost/cli/fxr/command_line.cpp index 045f7700e74..e3563947c3c 100644 --- a/src/installer/corehost/cli/fxr/command_line.cpp +++ b/src/installer/corehost/cli/fxr/command_line.cpp @@ -9,7 +9,6 @@ #include "sdk_info.h" #include #include -#include "bundle/info.h" namespace { @@ -145,7 +144,7 @@ namespace if (mode == host_mode_t::apphost) { app_candidate = host_info.app_path; - doesAppExist = bundle::info_t::is_single_file_bundle() || pal::realpath(&app_candidate); + doesAppExist = pal::realpath(&app_candidate); } else { diff --git a/src/installer/corehost/cli/fxr/corehost_init.cpp b/src/installer/corehost/cli/fxr/corehost_init.cpp index d8a5f249829..22a3921f8e9 100644 --- a/src/installer/corehost/cli/fxr/corehost_init.cpp +++ b/src/installer/corehost/cli/fxr/corehost_init.cpp @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. #include "corehost_init.h" -#include "bundle/info.h" void make_cstr_arr(const std::vector& arr, std::vector* out) { @@ -133,8 +132,6 @@ const host_interface_t& corehost_init_t::get_host_init_data() hi.host_info_dotnet_root = m_host_info_dotnet_root.c_str(); hi.host_info_app_path = m_host_info_app_path.c_str(); - hi.single_file_bundle_header_offset = bundle::info_t::is_single_file_bundle() ? bundle::info_t::the_app->header_offset() : 0; - return hi; } diff --git a/src/installer/corehost/cli/fxr/corehost_init.h b/src/installer/corehost/cli/fxr/corehost_init.h index 0d7f87ae92f..eedc2e70d22 100644 --- a/src/installer/corehost/cli/fxr/corehost_init.h +++ b/src/installer/corehost/cli/fxr/corehost_init.h @@ -8,7 +8,7 @@ #include "host_interface.h" #include "host_startup_info.h" #include "fx_definition.h" - + class corehost_init_t { private: @@ -37,7 +37,6 @@ private: const pal::string_t m_host_info_host_path; const pal::string_t m_host_info_dotnet_root; const pal::string_t m_host_info_app_path; - public: corehost_init_t( const pal::string_t& host_command, diff --git a/src/installer/corehost/cli/fxr/fx_muxer.cpp b/src/installer/corehost/cli/fxr/fx_muxer.cpp index 31c8c177978..00584e4a91e 100644 --- a/src/installer/corehost/cli/fxr/fx_muxer.cpp +++ b/src/installer/corehost/cli/fxr/fx_muxer.cpp @@ -27,7 +27,6 @@ #include "sdk_info.h" #include "sdk_resolver.h" #include "roll_fwd_on_no_candidate_fx_option.h" -#include "bundle/info.h" namespace { @@ -263,7 +262,6 @@ namespace pal::string_t& runtime_config, const runtime_config_t::settings_t& override_settings) { - // Check for the runtimeconfig.json file specified at the command line if (!runtime_config.empty() && !pal::realpath(&runtime_config)) { trace::error(_X("The specified runtimeconfig.json [%s] does not exist"), runtime_config.c_str()); @@ -295,11 +293,6 @@ namespace host_mode_t detect_operating_mode(const host_startup_info_t& host_info) { - if (bundle::info_t::is_single_file_bundle()) - { - return host_mode_t::apphost; - } - if (coreclr_exists_in_dir(host_info.dotnet_root)) { // Detect between standalone apphost or legacy split mode (specifying --depsfile and --runtimeconfig) @@ -364,7 +357,6 @@ namespace { pal::string_t runtime_config = command_line::get_option_value(opts, known_options::runtime_config, _X("")); - // This check is for --depsfile option, which must be an actual file. pal::string_t deps_file = command_line::get_option_value(opts, known_options::deps_file, _X("")); if (!deps_file.empty() && !pal::realpath(&deps_file)) { diff --git a/src/installer/corehost/cli/fxr/hostfxr.cpp b/src/installer/corehost/cli/fxr/hostfxr.cpp index 1fdfa210489..c9a346b799b 100644 --- a/src/installer/corehost/cli/fxr/hostfxr.cpp +++ b/src/installer/corehost/cli/fxr/hostfxr.cpp @@ -14,7 +14,6 @@ #include "sdk_resolver.h" #include "hostfxr.h" #include "host_context.h" -#include "bundle/info.h" namespace { @@ -25,23 +24,6 @@ namespace } } -SHARED_API int HOSTFXR_CALLTYPE hostfxr_main_bundle_startupinfo(const int argc, const pal::char_t* argv[], const pal::char_t* host_path, const pal::char_t* dotnet_root, const pal::char_t* app_path, int64_t bundle_header_offset) -{ - trace_hostfxr_entry_point(_X("hostfxr_main_bundle_startupinfo")); - - StatusCode bundleStatus = bundle::info_t::process_bundle(host_path, app_path, bundle_header_offset); - if (bundleStatus != StatusCode::Success) - { - trace::error(_X("A fatal error occured while processing application bundle")); - return bundleStatus; - } - - host_startup_info_t startup_info(host_path, dotnet_root, app_path); - - return fx_muxer_t::execute(pal::string_t(), argc, argv, startup_info, nullptr, 0, nullptr); -} - - SHARED_API int HOSTFXR_CALLTYPE hostfxr_main_startupinfo(const int argc, const pal::char_t* argv[], const pal::char_t* host_path, const pal::char_t* dotnet_root, const pal::char_t* app_path) { trace_hostfxr_entry_point(_X("hostfxr_main_startupinfo")); diff --git a/src/installer/corehost/cli/fxr/hostpolicy_resolver.cpp b/src/installer/corehost/cli/fxr/hostpolicy_resolver.cpp index de3291fecc5..049d61a62a5 100644 --- a/src/installer/corehost/cli/fxr/hostpolicy_resolver.cpp +++ b/src/installer/corehost/cli/fxr/hostpolicy_resolver.cpp @@ -29,6 +29,7 @@ namespace trace::verbose(_X("--- Resolving %s version from deps json [%s]"), LIBHOSTPOLICY_NAME, deps_json.c_str()); pal::string_t retval; + json_parser_t json; if (!json.parse_file(deps_json)) { diff --git a/src/installer/corehost/cli/host_interface.h b/src/installer/corehost/cli/host_interface.h index 72295aee99e..c7148e0ddc6 100644 --- a/src/installer/corehost/cli/host_interface.h +++ b/src/installer/corehost/cli/host_interface.h @@ -7,7 +7,6 @@ #include #include "pal.h" -#include "bundle/info.h" enum host_mode_t { @@ -59,7 +58,6 @@ struct host_interface_t const pal::char_t* host_info_host_path; const pal::char_t* host_info_dotnet_root; const pal::char_t* host_info_app_path; - size_t single_file_bundle_header_offset; // !! WARNING / WARNING / WARNING / WARNING / WARNING / WARNING / WARNING / WARNING / WARNING // !! 1. Only append to this structure to maintain compat. // !! 2. Any nested structs should not use compiler specific padding (pack with _HOST_INTERFACE_PACK) @@ -93,8 +91,7 @@ static_assert(offsetof(host_interface_t, host_command) == 26 * sizeof(size_t), " static_assert(offsetof(host_interface_t, host_info_host_path) == 27 * sizeof(size_t), "Struct offset breaks backwards compatibility"); static_assert(offsetof(host_interface_t, host_info_dotnet_root) == 28 * sizeof(size_t), "Struct offset breaks backwards compatibility"); static_assert(offsetof(host_interface_t, host_info_app_path) == 29 * sizeof(size_t), "Struct offset breaks backwards compatibility"); -static_assert(offsetof(host_interface_t, single_file_bundle_header_offset) == 30 * sizeof(size_t), "Struct offset breaks backwards compatibility"); -static_assert(sizeof(host_interface_t) == 31 * sizeof(size_t), "Did you add static asserts for the newly added fields?"); +static_assert(sizeof(host_interface_t) == 30 * sizeof(size_t), "Did you add static asserts for the newly added fields?"); #define HOST_INTERFACE_LAYOUT_VERSION_HI 0x16041101 // YYMMDD:nn always increases when layout breaks compat. #define HOST_INTERFACE_LAYOUT_VERSION_LO sizeof(host_interface_t) diff --git a/src/installer/corehost/cli/host_startup_info.h b/src/installer/corehost/cli/host_startup_info.h index cdc2746021a..4cb4b3e92b9 100644 --- a/src/installer/corehost/cli/host_startup_info.h +++ b/src/installer/corehost/cli/host_startup_info.h @@ -11,7 +11,6 @@ struct host_startup_info_t { host_startup_info_t() {} - host_startup_info_t( const pal::char_t* host_path_value, const pal::char_t* dotnet_root_value, diff --git a/src/installer/corehost/cli/hostcommon/CMakeLists.txt b/src/installer/corehost/cli/hostcommon/CMakeLists.txt index 8ad0c8d09f4..deac26114aa 100644 --- a/src/installer/corehost/cli/hostcommon/CMakeLists.txt +++ b/src/installer/corehost/cli/hostcommon/CMakeLists.txt @@ -23,9 +23,6 @@ set(SOURCES ../version.cpp ../version_compatibility_range.cpp ../runtime_config.cpp - ../bundle/info.cpp - ../bundle/reader.cpp - ../bundle/header.cpp ) set(HEADERS @@ -40,9 +37,6 @@ set(HEADERS ../version.h ../version_compatibility_range.h ../runtime_config.h - ../bundle/info.h - ../bundle/reader.h - ../bundle/header.h ) set(SKIP_VERSIONING 1) diff --git a/src/installer/corehost/cli/hostfxr.h b/src/installer/corehost/cli/hostfxr.h index f0bc0a53e22..040b7c78d87 100644 --- a/src/installer/corehost/cli/hostfxr.h +++ b/src/installer/corehost/cli/hostfxr.h @@ -37,13 +37,6 @@ typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_main_startupinfo_fn)( const char_t *host_path, const char_t *dotnet_root, const char_t *app_path); -typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_main_bundle_startupinfo_fn)( - const int argc, - const char_t** argv, - const char_t* host_path, - const char_t* dotnet_root, - const char_t* app_path, - int64_t bundle_header_offset); typedef void(HOSTFXR_CALLTYPE *hostfxr_error_writer_fn)(const char_t *message); typedef hostfxr_error_writer_fn(HOSTFXR_CALLTYPE *hostfxr_set_error_writer_fn)(hostfxr_error_writer_fn error_writer); diff --git a/src/installer/corehost/cli/hostmisc/pal.h b/src/installer/corehost/cli/hostmisc/pal.h index 10cb0e2c302..432756a3f37 100644 --- a/src/installer/corehost/cli/hostmisc/pal.h +++ b/src/installer/corehost/cli/hostmisc/pal.h @@ -165,7 +165,7 @@ namespace pal inline bool rmdir (const char_t* path) { return RemoveDirectoryW(path) != 0; } inline int rename(const char_t* old_name, const char_t* new_name) { return ::_wrename(old_name, new_name); } inline int remove(const char_t* path) { return ::_wremove(path); } - inline bool munmap(void* addr, size_t length) { return UnmapViewOfFile(addr) != 0; } + inline bool unmap_file(void* addr, size_t length) { return UnmapViewOfFile(addr) != 0; } inline int get_pid() { return GetCurrentProcessId(); } inline void sleep(uint32_t milliseconds) { Sleep(milliseconds); } #else @@ -222,7 +222,7 @@ namespace pal inline bool rmdir(const char_t* path) { return ::rmdir(path) == 0; } inline int rename(const char_t* old_name, const char_t* new_name) { return ::rename(old_name, new_name); } inline int remove(const char_t* path) { return ::remove(path); } - inline bool munmap(void* addr, size_t length) { return ::munmap(addr, length) == 0; } + inline bool unmap_file(void* addr, size_t length) { return munmap(addr, length) == 0; } inline int get_pid() { return getpid(); } inline void sleep(uint32_t milliseconds) { usleep(milliseconds * 1000); } @@ -257,9 +257,7 @@ namespace pal return fallbackRid; } - const void* mmap_read(const string_t& path, size_t* length = nullptr); - void* mmap_copy_on_write(const string_t& path, size_t* length = nullptr); - + void* map_file_readonly(const string_t& path, size_t& length); bool touch_file(const string_t& path); bool realpath(string_t* path, bool skip_error_logging = false); bool file_exists(const string_t& path); diff --git a/src/installer/corehost/cli/hostmisc/pal.unix.cpp b/src/installer/corehost/cli/hostmisc/pal.unix.cpp index 3626761b0ec..2ca39c3793a 100644 --- a/src/installer/corehost/cli/hostmisc/pal.unix.cpp +++ b/src/installer/corehost/cli/hostmisc/pal.unix.cpp @@ -70,7 +70,7 @@ bool pal::touch_file(const pal::string_t& path) return true; } -static void* map_file(const pal::string_t& path, size_t* length, int prot, int flags) +void* pal::map_file_readonly(const pal::string_t& path, size_t& length) { int fd = open(path.c_str(), O_RDONLY); if (fd == -1) @@ -86,35 +86,21 @@ static void* map_file(const pal::string_t& path, size_t* length, int prot, int f close(fd); return nullptr; } - size_t size = buf.st_size; - if (length != nullptr) - { - *length = size; - } - - void* address = mmap(nullptr, size, prot, flags, fd, 0); + length = buf.st_size; + void* address = mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, 0); - if (address == MAP_FAILED) + if(address == nullptr) { trace::error(_X("Failed to map file. mmap(%s) failed with error %d"), path.c_str(), errno); - address = nullptr; + close(fd); + return nullptr; } close(fd); return address; } -const void* pal::mmap_read(const string_t& path, size_t* length) -{ - return map_file(path, length, PROT_READ, MAP_SHARED); -} - -void* pal::mmap_copy_on_write(const string_t& path, size_t* length) -{ - return map_file(path, length, PROT_READ | PROT_WRITE, MAP_PRIVATE); -} - bool pal::getcwd(pal::string_t* recv) { recv->clear(); @@ -504,10 +490,10 @@ bool pal::get_default_installation_dir(pal::string_t* recv) pal::string_t trim_quotes(pal::string_t stringToCleanup) { pal::char_t quote_array[2] = {'\"', '\''}; - for (size_t index = 0; index < sizeof(quote_array)/sizeof(quote_array[0]); index++) + for(size_t index = 0; index < sizeof(quote_array)/sizeof(quote_array[0]); index++) { size_t pos = stringToCleanup.find(quote_array[index]); - while (pos != std::string::npos) + while(pos != std::string::npos) { stringToCleanup = stringToCleanup.erase(pos, 1); pos = stringToCleanup.find(quote_array[index]); diff --git a/src/installer/corehost/cli/hostmisc/pal.windows.cpp b/src/installer/corehost/cli/hostmisc/pal.windows.cpp index f8348a05d16..0cb6d2f91d9 100644 --- a/src/installer/corehost/cli/hostmisc/pal.windows.cpp +++ b/src/installer/corehost/cli/hostmisc/pal.windows.cpp @@ -76,7 +76,7 @@ bool pal::touch_file(const pal::string_t& path) return true; } -static void* map_file(const pal::string_t& path, size_t *length, DWORD mapping_protect, DWORD view_desired_access) +void* pal::map_file_readonly(const pal::string_t& path, size_t &length) { HANDLE file = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -86,19 +86,16 @@ static void* map_file(const pal::string_t& path, size_t *length, DWORD mapping_p return nullptr; } - if (length != nullptr) + LARGE_INTEGER fileSize; + if (GetFileSizeEx(file, &fileSize) == 0) { - LARGE_INTEGER fileSize; - if (GetFileSizeEx(file, &fileSize) == 0) - { - trace::error(_X("Failed to map file. GetFileSizeEx(%s) failed with error %d"), path.c_str(), GetLastError()); - CloseHandle(file); - return nullptr; - } - *length = (size_t)fileSize.QuadPart; + trace::error(_X("Failed to map file. GetFileSizeEx(%s) failed with error %d"), path.c_str(), GetLastError()); + CloseHandle(file); + return nullptr; } + length = (size_t)fileSize.QuadPart; - HANDLE map = CreateFileMappingW(file, NULL, mapping_protect, 0, 0, NULL); + HANDLE map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL); if (map == NULL) { @@ -107,7 +104,7 @@ static void* map_file(const pal::string_t& path, size_t *length, DWORD mapping_p return nullptr; } - void *address = MapViewOfFile(map, view_desired_access, 0, 0, 0); + void *address = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); if (address == NULL) { @@ -123,16 +120,6 @@ static void* map_file(const pal::string_t& path, size_t *length, DWORD mapping_p return address; } -const void* pal::mmap_read(const string_t& path, size_t* length) -{ - return map_file(path, length, PAGE_READONLY, FILE_MAP_READ); -} - -void* pal::mmap_copy_on_write(const string_t& path, size_t* length) -{ - return map_file(path, length, PAGE_WRITECOPY, FILE_MAP_READ | FILE_MAP_COPY); -} - bool pal::getcwd(pal::string_t* recv) { recv->clear(); diff --git a/src/installer/corehost/cli/hostmisc/utils.cpp b/src/installer/corehost/cli/hostmisc/utils.cpp index 4a3208af237..4e0d8ab3170 100644 --- a/src/installer/corehost/cli/hostmisc/utils.cpp +++ b/src/installer/corehost/cli/hostmisc/utils.cpp @@ -4,7 +4,6 @@ #include "utils.h" #include "trace.h" -#include "bundle/info.h" bool library_exists_in_dir(const pal::string_t& lib_dir, const pal::string_t& lib_name, pal::string_t* p_lib_path) { @@ -366,7 +365,6 @@ pal::string_t get_deps_from_app_binary(const pal::string_t& app_base, const pal: { pal::string_t deps_file; auto app_name = get_filename(app); - deps_file.reserve(app_base.length() + 1 + app_name.length() + 5); deps_file.append(app_base); @@ -379,28 +377,19 @@ pal::string_t get_deps_from_app_binary(const pal::string_t& app_base, const pal: return deps_file; } -pal::string_t get_runtime_config_path(const pal::string_t& path, const pal::string_t& name) +void get_runtime_config_paths(const pal::string_t& path, const pal::string_t& name, pal::string_t* cfg, pal::string_t* dev_cfg) { auto json_path = path; auto json_name = name + _X(".runtimeconfig.json"); append_path(&json_path, json_name.c_str()); - return json_path; -} + cfg->assign(json_path); -pal::string_t get_runtime_config_dev_path(const pal::string_t& path, const pal::string_t& name) -{ auto dev_json_path = path; auto dev_json_name = name + _X(".runtimeconfig.dev.json"); append_path(&dev_json_path, dev_json_name.c_str()); - return dev_json_path; -} - -void get_runtime_config_paths(const pal::string_t& path, const pal::string_t& name, pal::string_t* cfg, pal::string_t* dev_cfg) -{ - cfg->assign(get_runtime_config_path(path, name)); - dev_cfg->assign(get_runtime_config_dev_path(path, name)); + dev_cfg->assign(dev_json_path); - trace::verbose(_X("Runtime config is cfg=%s dev=%s"), cfg->c_str(), dev_cfg->c_str()); + trace::verbose(_X("Runtime config is cfg=%s dev=%s"), json_path.c_str(), dev_json_path.c_str()); } pal::string_t get_dotnet_root_from_fxr_path(const pal::string_t &fxr_path) diff --git a/src/installer/corehost/cli/hostmisc/utils.h b/src/installer/corehost/cli/hostmisc/utils.h index 7de346c7bce..2f13193e608 100644 --- a/src/installer/corehost/cli/hostmisc/utils.h +++ b/src/installer/corehost/cli/hostmisc/utils.h @@ -45,8 +45,6 @@ size_t index_of_non_numeric(const pal::string_t& str, unsigned i); bool try_stou(const pal::string_t& str, unsigned* num); pal::string_t get_dotnet_root_env_var_name(); pal::string_t get_deps_from_app_binary(const pal::string_t& app_base, const pal::string_t& app); -pal::string_t get_runtime_config_path(const pal::string_t& path, const pal::string_t& name); -pal::string_t get_runtime_config_dev_path(const pal::string_t& path, const pal::string_t& name); void get_runtime_config_paths(const pal::string_t& path, const pal::string_t& name, pal::string_t* cfg, pal::string_t* dev_cfg); pal::string_t get_dotnet_root_from_fxr_path(const pal::string_t &fxr_path); diff --git a/src/installer/corehost/cli/hostpolicy/CMakeLists.txt b/src/installer/corehost/cli/hostpolicy/CMakeLists.txt index ca2c78fa279..c05c876e1d9 100644 --- a/src/installer/corehost/cli/hostpolicy/CMakeLists.txt +++ b/src/installer/corehost/cli/hostpolicy/CMakeLists.txt @@ -19,11 +19,6 @@ set(SOURCES ./hostpolicy_context.cpp ./hostpolicy.cpp ./hostpolicy_init.cpp - ../bundle/dir_utils.cpp - ../bundle/extractor.cpp - ../bundle/file_entry.cpp - ../bundle/manifest.cpp - ../bundle/runner.cpp ) set(HEADERS @@ -35,11 +30,6 @@ set(HEADERS ./hostpolicy_context.h ../hostpolicy.h ./hostpolicy_init.h - ../bundle/dir_utils.h - ../bundle/extractor.h - ../bundle/file_entry.h - ../bundle/manifest.h - ../bundle/runner.h ) include(../lib.cmake) diff --git a/src/installer/corehost/cli/hostpolicy/args.cpp b/src/installer/corehost/cli/hostpolicy/args.cpp index f022d23ae5f..562f70baea8 100644 --- a/src/installer/corehost/cli/hostpolicy/args.cpp +++ b/src/installer/corehost/cli/hostpolicy/args.cpp @@ -4,7 +4,6 @@ #include "args.h" #include -#include "bundle/runner.h" arguments_t::arguments_t() : host_mode(host_mode_t::invalid) @@ -102,47 +101,6 @@ bool parse_arguments( args); } -bool set_root_from_app(const pal::string_t& managed_application_path, - arguments_t& args) -{ - args.managed_application = managed_application_path; - - if (args.managed_application.empty()) - { - // Managed app being empty by itself is not a failure. Host may be initialized from a config file. - assert(args.host_mode != host_mode_t::apphost); - return true; - } - - if (bundle::info_t::is_single_file_bundle()) - { - const bundle::runner_t* app = bundle::runner_t::app(); - args.app_root = app->base_path(); - - // Check for the main app within the bundle. - // locate() sets args.managed_application to the full path of the app extracted to disk. - pal::string_t managed_application_name = get_filename(managed_application_path); - if (app->locate(managed_application_name, args.managed_application)) - { - return true; - } - - trace::info(_X("Managed application [%s] not found in single-file bundle"), managed_application_name.c_str()); - - // If the main assembly is not found in the bundle, continue checking on disk - // for very unlikely case where the main app.dll was itself excluded from the app bundle. - return pal::realpath(&args.managed_application); - } - - if (pal::realpath(&args.managed_application)) - { - args.app_root = get_directory(args.managed_application); - return true; - } - - return false; -} - bool init_arguments( const pal::string_t& managed_application_path, const host_startup_info_t& host_info, @@ -157,11 +115,13 @@ bool init_arguments( args.host_path = host_info.host_path; args.additional_deps_serialized = additional_deps_serialized; - if (!set_root_from_app(managed_application_path, args)) + args.managed_application = managed_application_path; + if (!args.managed_application.empty() && !pal::realpath(&args.managed_application)) { trace::error(_X("Failed to locate managed application [%s]"), args.managed_application.c_str()); return false; } + args.app_root = get_directory(args.managed_application); if (!deps_file.empty()) { diff --git a/src/installer/corehost/cli/hostpolicy/deps_resolver.cpp b/src/installer/corehost/cli/hostpolicy/deps_resolver.cpp index 06ededa7e60..2e245b56dee 100644 --- a/src/installer/corehost/cli/hostpolicy/deps_resolver.cpp +++ b/src/installer/corehost/cli/hostpolicy/deps_resolver.cpp @@ -316,7 +316,7 @@ bool deps_resolver_t::probe_deps_entry(const deps_entry_t& entry, const pal::str // If the deps json has the package name and version, then someone has already done rid selection and // put the right asset in the dir. So checking just package name and version would suffice. // No need to check further for the exact asset relative sub path. - if (config.probe_deps_json->has_package(entry.library_name, entry.library_version) && entry.to_dir_path(probe_dir, false, candidate)) + if (config.probe_deps_json->has_package(entry.library_name, entry.library_version) && entry.to_dir_path(probe_dir, candidate)) { trace::verbose(_X(" Probed deps json and matched '%s'"), candidate->c_str()); return true; @@ -334,7 +334,7 @@ bool deps_resolver_t::probe_deps_entry(const deps_entry_t& entry, const pal::str { if (entry.is_rid_specific) { - if (entry.to_rel_path(deps_dir, true, candidate)) + if (entry.to_rel_path(deps_dir, candidate)) { trace::verbose(_X(" Probed deps dir and matched '%s'"), candidate->c_str()); return true; @@ -343,7 +343,7 @@ bool deps_resolver_t::probe_deps_entry(const deps_entry_t& entry, const pal::str else { // Non-rid assets, lookup in the published dir. - if (entry.to_dir_path(deps_dir, true, candidate)) + if (entry.to_dir_path(deps_dir, candidate)) { trace::verbose(_X(" Probed deps dir and matched '%s'"), candidate->c_str()); return true; diff --git a/src/installer/corehost/cli/hostpolicy/deps_resolver.h b/src/installer/corehost/cli/hostpolicy/deps_resolver.h index f2b27d4620a..d61a78c3179 100644 --- a/src/installer/corehost/cli/hostpolicy/deps_resolver.h +++ b/src/installer/corehost/cli/hostpolicy/deps_resolver.h @@ -14,7 +14,6 @@ #include "deps_format.h" #include "deps_entry.h" #include "runtime_config.h" -#include "bundle/runner.h" // Probe paths to be resolved for ordering struct probe_paths_t @@ -186,17 +185,6 @@ public: static const pal::string_t s_empty; return s_empty; } - if (m_host_mode == host_mode_t::apphost) - { - if (bundle::info_t::is_single_file_bundle()) - { - const bundle::runner_t* app = bundle::runner_t::app(); - if (app->is_netcoreapp3_compat_mode()) - { - return app->extraction_path(); - } - } - } return m_app_dir; } diff --git a/src/installer/corehost/cli/hostpolicy/hostpolicy.cpp b/src/installer/corehost/cli/hostpolicy/hostpolicy.cpp index c2a933ec364..5c7d766a87d 100644 --- a/src/installer/corehost/cli/hostpolicy/hostpolicy.cpp +++ b/src/installer/corehost/cli/hostpolicy/hostpolicy.cpp @@ -18,7 +18,6 @@ #include #include #include "hostpolicy_context.h" -#include "bundle/runner.h" namespace { @@ -355,7 +354,7 @@ int corehost_init( } int corehost_main_init( - hostpolicy_init_t& hostpolicy_init, + hostpolicy_init_t &hostpolicy_init, const int argc, const pal::char_t* argv[], const pal::string_t& location, @@ -368,15 +367,6 @@ int corehost_main_init( hostpolicy_init.host_info.parse(argc, argv); } - if (bundle::info_t::is_single_file_bundle()) - { - StatusCode status = bundle::runner_t::process_manifest_and_extract(); - if (status != StatusCode::Success) - { - return status; - } - } - return corehost_init(hostpolicy_init, argc, argv, location, args); } @@ -444,9 +434,6 @@ int corehost_libhost_init(const hostpolicy_init_t &hostpolicy_init, const pal::s // Host info should always be valid in the delegate scenario assert(hostpolicy_init.host_info.is_valid(host_mode_t::libhost)); - // Single-file bundle is only expected in apphost mode. - assert(!bundle::info_t::is_single_file_bundle()); - return corehost_init(hostpolicy_init, 0, nullptr, location, args); } diff --git a/src/installer/corehost/cli/hostpolicy/hostpolicy_init.cpp b/src/installer/corehost/cli/hostpolicy/hostpolicy_init.cpp index 3e0d02a17c5..c6103f7af91 100644 --- a/src/installer/corehost/cli/hostpolicy/hostpolicy_init.cpp +++ b/src/installer/corehost/cli/hostpolicy/hostpolicy_init.cpp @@ -4,7 +4,6 @@ #include "hostpolicy_init.h" #include -#include "bundle/runner.h" void make_palstr_arr(int argc, const pal::char_t** argv, std::vector* out) { @@ -127,15 +126,6 @@ bool hostpolicy_init_t::init(host_interface_t* input, hostpolicy_init_t* init) // For the backwards compat case, this will be later initialized with argv[0] } - if (input->version_lo >= offsetof(host_interface_t, single_file_bundle_header_offset) + sizeof(input->single_file_bundle_header_offset)) - { - if (input->single_file_bundle_header_offset != 0) - { - static bundle::runner_t bundle_runner(input->host_info_host_path, input->host_info_app_path, input->single_file_bundle_header_offset); - bundle::info_t::the_app = &bundle_runner; - } - } - return true; } diff --git a/src/installer/corehost/cli/hostpolicy/hostpolicy_init.h b/src/installer/corehost/cli/hostpolicy/hostpolicy_init.h index 8d2ea616fcc..18af97c9c25 100644 --- a/src/installer/corehost/cli/hostpolicy/hostpolicy_init.h +++ b/src/installer/corehost/cli/hostpolicy/hostpolicy_init.h @@ -8,7 +8,6 @@ #include "host_interface.h" #include "host_startup_info.h" #include "fx_definition.h" -#include "bundle/info.h" struct hostpolicy_init_t { diff --git a/src/installer/corehost/cli/ijwhost/ijwthunk.cpp b/src/installer/corehost/cli/ijwhost/ijwthunk.cpp index 2b05bcfe708..b2329112162 100644 --- a/src/installer/corehost/cli/ijwhost/ijwthunk.cpp +++ b/src/installer/corehost/cli/ijwhost/ijwthunk.cpp @@ -73,7 +73,7 @@ bool patch_vtable_entries(PEDecoder& pe) error_writer_scope_t writer_scope(swallow_trace); size_t currentThunk = 0; - for (size_t i = 0; i < numFixupRecords; ++i) + for(size_t i = 0; i < numFixupRecords; ++i) { if (pFixupTable[i].Type & COR_VTABLE_PTRSIZED) { @@ -81,7 +81,7 @@ bool patch_vtable_entries(PEDecoder& pe) #ifdef _WIN64 DWORD oldProtect; - if (!VirtualProtect(pointers, (sizeof(BYTE*) * pFixupTable[i].Count), PAGE_READWRITE, &oldProtect)) + if(!VirtualProtect(pointers, (sizeof(BYTE*) * pFixupTable[i].Count), PAGE_READWRITE, &oldProtect)) { trace::error(_X("Failed to change the vtfixup table from RO to R/W failed.\n")); return false; @@ -101,7 +101,7 @@ bool patch_vtable_entries(PEDecoder& pe) #ifdef _WIN64 DWORD _; - if (!VirtualProtect(pointers, (sizeof(BYTE*) * pFixupTable[i].Count), oldProtect, &_)) + if(!VirtualProtect(pointers, (sizeof(BYTE*) * pFixupTable[i].Count), oldProtect, &_)) { trace::warning(_X("Failed to change the vtfixup table from R/W back to RO failed.\n")); } diff --git a/src/installer/corehost/cli/json/rapidjson/document.h b/src/installer/corehost/cli/json/rapidjson/document.h index 74666e3423e..9783fe4acc9 100644 --- a/src/installer/corehost/cli/json/rapidjson/document.h +++ b/src/installer/corehost/cli/json/rapidjson/document.h @@ -2094,11 +2094,11 @@ private: const SizeType len1 = GetStringLength(); const SizeType len2 = rhs.GetStringLength(); - if (len1 != len2) { return false; } + if(len1 != len2) { return false; } const Ch* const str1 = GetString(); const Ch* const str2 = rhs.GetString(); - if (str1 == str2) { return true; } // fast path for constant string + if(str1 == str2) { return true; } // fast path for constant string return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); } diff --git a/src/installer/corehost/cli/json_parser.cpp b/src/installer/corehost/cli/json_parser.cpp index c6f0cbbf0c9..9814f3215d6 100644 --- a/src/installer/corehost/cli/json_parser.cpp +++ b/src/installer/corehost/cli/json_parser.cpp @@ -42,9 +42,9 @@ std::streampos get_utf8_bom_length(pal::istream_t& stream) return 3; } -void get_line_column_from_offset(const char* data, uint64_t size, size_t offset, int *line, int *column) +void get_line_column_from_offset(const std::vector& json, size_t offset, int *line, int *column) { - assert(offset < size); + assert(offset < json.size()); *line = *column = 1; @@ -52,12 +52,12 @@ void get_line_column_from_offset(const char* data, uint64_t size, size_t offset, { (*column)++; - if (data[i] == '\n') + if (json[i] == '\n') { (*line)++; *column = 1; } - else if (data[i] == '\r' && data[i + 1] == '\n') + else if (json[i] == '\r' && json[i + 1] == '\n') { (*line)++; *column = 1; @@ -75,30 +75,32 @@ void json_parser_t::realloc_buffer(size_t size) m_json[size] = '\0'; } -bool json_parser_t::parse_json(char* data, int64_t size, const pal::string_t& context) +bool json_parser_t::parse_json(const pal::string_t& context) { + assert(!m_json.empty()); + #ifdef _WIN32 // Can't use in-situ parsing on Windows, as JSON data is encoded in // UTF-8 and the host expects wide strings. m_document will store // data in UTF-16 (with pal::char_t as the character type), but it // has to know that data is encoded in UTF-8 to convert during parsing. constexpr auto flags = rapidjson::ParseFlag::kParseStopWhenDoneFlag - | rapidjson::ParseFlag::kParseCommentsFlag; - m_document.Parse>(data); -#else // _WIN32 - m_document.ParseInsitu(data); -#endif // _WIN32 + | rapidjson::ParseFlag::kParseCommentsFlag; + m_document.Parse>(m_json.data()); +#else + m_document.ParseInsitu(m_json.data()); +#endif if (m_document.HasParseError()) { int line, column; size_t offset = m_document.GetErrorOffset(); - get_line_column_from_offset(data, size, offset, &line, &column); + get_line_column_from_offset(m_json, offset, &line, &column); trace::error(_X("A JSON parsing exception occurred in [%s], offset %zu (line %d, column %d): %s"), - context.c_str(), offset, line, column, - rapidjson::GetParseError_En(m_document.GetParseError())); + context.c_str(), offset, line, column, + rapidjson::GetParseError_En(m_document.GetParseError())); return false; } @@ -128,37 +130,5 @@ bool json_parser_t::parse_stream(pal::istream_t& stream, realloc_buffer(stream_size - current_pos); stream.read(m_json.data(), stream_size - current_pos); - return parse_json(m_json.data(), m_json.size(), context); -} - -bool json_parser_t::parse_file(const pal::string_t& path) -{ - // This code assumes that the caller has checked that the file `path` exists - // either within the bundle, or as a real file on disk. - assert(m_bundle_data == nullptr); - assert(m_bundle_location == nullptr); - - if (bundle::info_t::is_single_file_bundle()) - { - m_bundle_data = bundle::info_t::config_t::map(path, m_bundle_location); - // The mapping will be unmapped by the json_parser destructor. - // The mapping cannot be immediately released due to in-situ parsing on Linux. - - if (m_bundle_data != nullptr) - { - bool result = parse_json(m_bundle_data, m_bundle_location->size, path); - return result; - } - } - - pal::ifstream_t file{ path }; - return parse_stream(file, path); -} - -json_parser_t::~json_parser_t() -{ - if (m_bundle_data != nullptr) - { - bundle::info_t::config_t::unmap(m_bundle_data, m_bundle_location); - } + return parse_json(context); } diff --git a/src/installer/corehost/cli/json_parser.h b/src/installer/corehost/cli/json_parser.h index 16ed21bd033..e5c477b1171 100644 --- a/src/installer/corehost/cli/json_parser.h +++ b/src/installer/corehost/cli/json_parser.h @@ -9,7 +9,6 @@ #include "rapidjson/document.h" #include "rapidjson/fwd.h" #include -#include "bundle/info.h" class json_parser_t { public: @@ -22,15 +21,12 @@ class json_parser_t { using document_t = rapidjson::GenericDocument; const document_t& document() const { return m_document; } - bool parse_stream(pal::istream_t& stream, const pal::string_t& context); - bool parse_file(const pal::string_t& path); - - json_parser_t() - : m_bundle_data(nullptr) - , m_bundle_location(nullptr) {} - - ~json_parser_t(); + bool parse_file(const pal::string_t& path) + { + pal::ifstream_t file{path}; + return parse_stream(file, path); + } private: // This is a vector of char and not pal::char_t because JSON data @@ -40,12 +36,8 @@ class json_parser_t { std::vector m_json; document_t m_document; - // If a json file is parsed from a single-file bundle, the following two fields represent: - char* m_bundle_data; // The memory mapped bytes of the application bundle. - const bundle::location_t* m_bundle_location; // Location of this json file within the bundle. - void realloc_buffer(size_t size); - bool parse_json(char* data, int64_t size, const pal::string_t& context); + bool parse_json(const pal::string_t& context); }; #endif // __JSON_PARSER_H__ diff --git a/src/installer/corehost/cli/runtime_config.cpp b/src/installer/corehost/cli/runtime_config.cpp index d41aa2a0573..2026da52d81 100644 --- a/src/installer/corehost/cli/runtime_config.cpp +++ b/src/installer/corehost/cli/runtime_config.cpp @@ -9,7 +9,6 @@ #include "runtime_config.h" #include "trace.h" #include "utils.h" -#include "bundle/info.h" #include // The semantics of applying the runtimeconfig.json values follows, in the following steps from @@ -339,8 +338,6 @@ bool runtime_config_t::ensure_dev_config_parsed() return true; } - // runtimeconfig.dev.json is never bundled into the single-file app. - // So, only a file on disk is processed. json_parser_t json; if (!json.parse_file(m_dev_path)) { @@ -401,7 +398,7 @@ bool runtime_config_t::ensure_parsed() trace::verbose(_X("Did not successfully parse the runtimeconfig.dev.json")); } - if (!bundle::info_t::config_t::probe(m_path) && !pal::file_exists(m_path)) + if (!pal::file_exists(m_path)) { // Not existing is not an error. return true; diff --git a/src/installer/corehost/cli/test/mockhostpolicy/mockhostpolicy.cpp b/src/installer/corehost/cli/test/mockhostpolicy/mockhostpolicy.cpp index 2130fe7b2f9..4a0567f3f35 100644 --- a/src/installer/corehost/cli/test/mockhostpolicy/mockhostpolicy.cpp +++ b/src/installer/corehost/cli/test/mockhostpolicy/mockhostpolicy.cpp @@ -66,7 +66,6 @@ SHARED_API int HOSTPOLICY_CALLTYPE corehost_load(host_interface_t* init) std::cout << "mock host_info_host_path:" << tostr(init->host_info_host_path).data() << std::endl; std::cout << "mock host_info_dotnet_root:" << tostr(init->host_info_dotnet_root).data() << std::endl; std::cout << "mock host_info_app_path:" << tostr(init->host_info_app_path).data() << std::endl; - std::cout << "mock single_file_bundle_header_offset:" << std::hex << init->single_file_bundle_header_offset << std::endl; if (init->fx_names.len == 0) { diff --git a/src/installer/corehost/corehost.cpp b/src/installer/corehost/corehost.cpp index 55b8ed62982..bb6b4ce60e5 100644 --- a/src/installer/corehost/corehost.cpp +++ b/src/installer/corehost/corehost.cpp @@ -11,7 +11,8 @@ #include "utils.h" #if defined(FEATURE_APPHOST) -#include "bundle_marker.h" +#include "cli/apphost/bundle/marker.h" +#include "cli/apphost/bundle/runner.h" #if defined(_WIN32) #include "cli/apphost/apphost.windows.h" @@ -83,14 +84,6 @@ bool is_exe_enabled_for_execution(pal::string_t* app_dll) #define CURHOST_EXE #endif -void need_newer_framework_error() -{ - pal::string_t url = get_download_url(); - trace::error(_X(" _ To run this application, you need to install a newer version of .NET Core.")); - trace::error(_X("")); - trace::error(_X(" - %s&apphost_version=%s"), url.c_str(), _STRINGIFY(COMMON_HOST_PKG_VER)); -} - #if defined(CURHOST_EXE) int exe_start(const int argc, const pal::char_t* argv[]) @@ -104,8 +97,8 @@ int exe_start(const int argc, const pal::char_t* argv[]) pal::string_t app_path; pal::string_t app_root; - bool requires_hostfxr_startupinfo_interface = false; - + bool requires_v2_hostfxr_interface = false; + #if defined(FEATURE_APPHOST) pal::string_t embedded_app_name; if (!is_exe_enabled_for_execution(&embedded_app_name)) @@ -122,17 +115,29 @@ int exe_start(const int argc, const pal::char_t* argv[]) auto pos_path_char = embedded_app_name.find(DIR_SEPARATOR); if (pos_path_char != pal::string_t::npos) { - requires_hostfxr_startupinfo_interface = true; + requires_v2_hostfxr_interface = true; } - app_path.assign(get_directory(host_path)); - append_path(&app_path, embedded_app_name.c_str()); + if (bundle::marker_t::is_bundle()) + { + bundle::runner_t bundle_runner(host_path); + StatusCode bundle_status = bundle_runner.extract(); + + if (bundle_status != StatusCode::Success) + { + trace::error(_X("A fatal error was encountered. Could not extract contents of the bundle")); + return bundle_status; + } - if (bundle_marker_t::is_bundle()) + app_path.assign(bundle_runner.extraction_dir()); + } + else { - trace::info(_X("Detected Single-File app bundle")); + app_path.assign(get_directory(host_path)); } - else if (!pal::realpath(&app_path)) + + append_path(&app_path, embedded_app_name.c_str()); + if (!pal::realpath(&app_path)) { trace::error(_X("The application to execute does not exist: '%s'."), app_path.c_str()); return StatusCode::LibHostAppRootFindFailure; @@ -195,88 +200,58 @@ int exe_start(const int argc, const pal::char_t* argv[]) // Obtain the entrypoints. int rc; -#if defined(FEATURE_APPHOST) - if (bundle_marker_t::is_bundle()) - { - hostfxr_main_bundle_startupinfo_fn hostfxr_main_bundle_startupinfo = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_main_bundle_startupinfo")); - if (hostfxr_main_bundle_startupinfo != nullptr) - { - const pal::char_t* host_path_cstr = host_path.c_str(); - const pal::char_t* dotnet_root_cstr = dotnet_root.empty() ? nullptr : dotnet_root.c_str(); - const pal::char_t* app_path_cstr = app_path.empty() ? nullptr : app_path.c_str(); - int64_t bundle_header_offset = bundle_marker_t::header_offset(); - - trace::info(_X("Invoking fx resolver [%s] hostfxr_main_bundle_startupinfo"), fxr_path.c_str()); - trace::info(_X("Host path: [%s]"), host_path.c_str()); - trace::info(_X("Dotnet path: [%s]"), dotnet_root.c_str()); - trace::info(_X("App path: [%s]"), app_path.c_str()); - trace::info(_X("Bundle Header Offset: [%lx]"), bundle_header_offset); - - hostfxr_set_error_writer_fn set_error_writer_fn = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_set_error_writer")); - propagate_error_writer_t propagate_error_writer_to_hostfxr(set_error_writer_fn); - rc = hostfxr_main_bundle_startupinfo(argc, argv, host_path_cstr, dotnet_root_cstr, app_path_cstr, bundle_header_offset); - } - else - { - // The host components will be statically linked with the app-host: https://github.com/dotnet/runtime/issues/32823 - // Once this work is completed, an outdated hostfxr can only be found for framework-related apps. - trace::error(_X("The required library %s does not support single-file apps."), fxr_path.c_str()); - need_newer_framework_error(); - rc = StatusCode::FrameworkMissingFailure; - } - } - else -#endif // defined(FEATURE_APPHOST) + hostfxr_main_startupinfo_fn main_fn_v2 = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_main_startupinfo")); + if (main_fn_v2 != nullptr) { - hostfxr_main_startupinfo_fn hostfxr_main_startupinfo = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_main_startupinfo")); - if (hostfxr_main_startupinfo != nullptr) - { - const pal::char_t* host_path_cstr = host_path.c_str(); - const pal::char_t* dotnet_root_cstr = dotnet_root.empty() ? nullptr : dotnet_root.c_str(); - const pal::char_t* app_path_cstr = app_path.empty() ? nullptr : app_path.c_str(); + const pal::char_t* host_path_cstr = host_path.c_str(); + const pal::char_t* dotnet_root_cstr = dotnet_root.empty() ? nullptr : dotnet_root.c_str(); + const pal::char_t* app_path_cstr = app_path.empty() ? nullptr : app_path.c_str(); - trace::info(_X("Invoking fx resolver [%s] hostfxr_main_startupinfo"), fxr_path.c_str()); - trace::info(_X("Host path: [%s]"), host_path.c_str()); - trace::info(_X("Dotnet path: [%s]"), dotnet_root.c_str()); - trace::info(_X("App path: [%s]"), app_path.c_str()); + trace::info(_X("Invoking fx resolver [%s] v2"), fxr_path.c_str()); + trace::info(_X("Host path: [%s]"), host_path.c_str()); + trace::info(_X("Dotnet path: [%s]"), dotnet_root.c_str()); + trace::info(_X("App path: [%s]"), app_path.c_str()); - hostfxr_set_error_writer_fn set_error_writer_fn = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_set_error_writer")); + hostfxr_set_error_writer_fn set_error_writer_fn = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_set_error_writer")); + { propagate_error_writer_t propagate_error_writer_to_hostfxr(set_error_writer_fn); - rc = hostfxr_main_startupinfo(argc, argv, host_path_cstr, dotnet_root_cstr, app_path_cstr); + rc = main_fn_v2(argc, argv, host_path_cstr, dotnet_root_cstr, app_path_cstr); - // This check exists to provide an error message for UI apps when running 3.0 apps on 2.0 only hostfxr, which doesn't support error writer redirection. if (trace::get_error_writer() != nullptr && rc == static_cast(StatusCode::FrameworkMissingFailure) && !set_error_writer_fn) { - need_newer_framework_error(); + pal::string_t url = get_download_url(); + trace::error(_X(" _ To run this application, you need to install a newer version of .NET.")); + trace::error(_X("")); + trace::error(_X(" - %s"), url.c_str()); } } + } + else + { + if (requires_v2_hostfxr_interface) + { + trace::error(_X("The required library %s does not support relative app dll paths."), fxr_path.c_str()); + rc = StatusCode::CoreHostEntryPointFailure; + } else { - if (requires_hostfxr_startupinfo_interface) + trace::info(_X("Invoking fx resolver [%s] v1"), fxr_path.c_str()); + + // Previous corehost trace messages must be printed before calling trace::setup in hostfxr + trace::flush(); + + // For compat, use the v1 interface. This requires additional file I\O to re-parse parameters and + // for apphost, does not support DOTNET_ROOT or dll with different name for exe. + hostfxr_main_fn main_fn_v1 = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_main")); + if (main_fn_v1 != nullptr) { - trace::error(_X("The required library %s does not support relative app dll paths."), fxr_path.c_str()); - rc = StatusCode::CoreHostEntryPointFailure; + rc = main_fn_v1(argc, argv); } else { - trace::info(_X("Invoking fx resolver [%s] v1"), fxr_path.c_str()); - - // Previous corehost trace messages must be printed before calling trace::setup in hostfxr - trace::flush(); - - // For compat, use the v1 interface. This requires additional file I\O to re-parse parameters and - // for apphost, does not support DOTNET_ROOT or dll with different name for exe. - hostfxr_main_fn main_fn_v1 = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_main")); - if (main_fn_v1 != nullptr) - { - rc = main_fn_v1(argc, argv); - } - else - { - trace::error(_X("The required library %s does not contain the expected entry point."), fxr_path.c_str()); - rc = StatusCode::CoreHostEntryPointFailure; - } + trace::error(_X("The required library %s does not contain the expected entry point."), fxr_path.c_str()); + rc = StatusCode::CoreHostEntryPointFailure; } } } diff --git a/src/installer/managed/Microsoft.NET.HostModel/Bundle/Bundler.cs b/src/installer/managed/Microsoft.NET.HostModel/Bundle/Bundler.cs index 29e9635d4fd..320969c101d 100644 --- a/src/installer/managed/Microsoft.NET.HostModel/Bundle/Bundler.cs +++ b/src/installer/managed/Microsoft.NET.HostModel/Bundle/Bundler.cs @@ -90,7 +90,7 @@ bool ShouldIgnore(string fileRelativePath) return fileRelativePath.Equals(RuntimeConfigDevJson); } - bool ShouldExclude(FileType type, string relativePath) + bool ShouldExclude(FileType type) { switch (type) { @@ -100,7 +100,7 @@ bool ShouldExclude(FileType type, string relativePath) return false; case FileType.NativeBinary: - return !Options.HasFlag(BundleOptions.BundleNativeBinaries) || Target.ShouldExclude(relativePath); + return !Options.HasFlag(BundleOptions.BundleNativeBinaries); case FileType.Symbols: return !Options.HasFlag(BundleOptions.BundleSymbolFiles); @@ -229,24 +229,22 @@ public string GenerateBundle(IReadOnlyList fileSpecs) foreach (var fileSpec in fileSpecs) { - string relativePath = fileSpec.BundleRelativePath; - - if (IsHost(relativePath)) + if (IsHost(fileSpec.BundleRelativePath)) { continue; } - if (ShouldIgnore(relativePath)) + if (ShouldIgnore(fileSpec.BundleRelativePath)) { - Tracer.Log($"Ignore: {relativePath}"); + Tracer.Log($"Ignore: {fileSpec.BundleRelativePath}"); continue; } FileType type = InferType(fileSpec); - if (ShouldExclude(type, relativePath)) + if (ShouldExclude(type)) { - Tracer.Log($"Exclude [{type}]: {relativePath}"); + Tracer.Log($"Exclude [{type}]: {fileSpec.BundleRelativePath}"); fileSpec.Excluded = true; continue; } @@ -255,7 +253,7 @@ public string GenerateBundle(IReadOnlyList fileSpecs) { FileType targetType = Target.TargetSpecificFileType(type); long startOffset = AddToBundle(bundle, file, targetType); - FileEntry entry = BundleManifest.AddEntry(targetType, relativePath, startOffset, file.Length); + FileEntry entry = BundleManifest.AddEntry(targetType, fileSpec.BundleRelativePath, startOffset, file.Length); Tracer.Log($"Embed: {entry}"); } } diff --git a/src/installer/managed/Microsoft.NET.HostModel/Bundle/Manifest.cs b/src/installer/managed/Microsoft.NET.HostModel/Bundle/Manifest.cs index 9c171ae2da7..bd2b340971e 100644 --- a/src/installer/managed/Microsoft.NET.HostModel/Bundle/Manifest.cs +++ b/src/installer/managed/Microsoft.NET.HostModel/Bundle/Manifest.cs @@ -59,7 +59,7 @@ public class Manifest enum HeaderFlags : ulong { None = 0, - NetcoreApp3CompatMode = 1 + NetcoreApp3CompatMode = 2 } // Bundle ID is a string that is used to uniquely diff --git a/src/installer/managed/Microsoft.NET.HostModel/Bundle/TargetInfo.cs b/src/installer/managed/Microsoft.NET.HostModel/Bundle/TargetInfo.cs index 87b1c65202e..1f6f61a7eee 100644 --- a/src/installer/managed/Microsoft.NET.HostModel/Bundle/TargetInfo.cs +++ b/src/installer/managed/Microsoft.NET.HostModel/Bundle/TargetInfo.cs @@ -27,6 +27,8 @@ public class TargetInfo public TargetInfo(OSPlatform? os, Version targetFrameworkVersion) { + Version net50 = new Version(5, 0); + OS = os ?? HostOS; FrameworkVersion = targetFrameworkVersion ?? net50; @@ -69,21 +71,6 @@ public override string ToString() // The .net core 3 apphost doesn't care about semantics of FileType -- all files are extracted at startup. // However, the apphost checks that the FileType value is within expected bounds, so set it to the first enumeration. public FileType TargetSpecificFileType(FileType fileType) => (BundleVersion == 1) ? FileType.Unknown : fileType; - - // In .net core 3.x, bundle processing happens within the AppHost. - // Therefore HostFxr and HostPolicy can be bundled within the single-file app. - // In .net 5, bundle processing happens in HostFxr and HostPolicy libraries. - // Therefore, these libraries themselves cannot be bundled into the single-file app. - // This problem is mitigated by statically linking these host components with the AppHost. - // https://github.com/dotnet/runtime/issues/32823 - public bool ShouldExclude(string relativePath) => - (FrameworkVersion.Major != 3) && (relativePath.Equals(HostFxr) || relativePath.Equals(HostPolicy)); - - readonly Version net50 = new Version(5, 0); - string HostFxr => IsWindows ? "hostfxr.dll" : IsLinux ? "libhostfxr.so" : "libhostfxr.dylib"; - string HostPolicy => IsWindows ? "hostpolicy.dll" : IsLinux ? "libhostpolicy.so" : "libhostpolicy.dylib"; - - } } diff --git a/src/installer/test/Assets/TestProjects/AppWithSubDirs/Program.cs b/src/installer/test/Assets/TestProjects/AppWithSubDirs/Program.cs index 5b51c37991b..20c24839186 100644 --- a/src/installer/test/Assets/TestProjects/AppWithSubDirs/Program.cs +++ b/src/installer/test/Assets/TestProjects/AppWithSubDirs/Program.cs @@ -4,6 +4,7 @@ using System; using System.IO; +using System.Reflection; namespace AppWithSubDirs { @@ -11,7 +12,10 @@ public static class Program { public static void Main(string[] args) { - string baseDir = Path.Combine(AppContext.BaseDirectory, "Sentence"); + string baseDir = + Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + "Sentence"); string Part(string dir="", string subdir="", string subsubdir="") { diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs index 26dbc3a00ef..5f35a406c91 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs @@ -7,7 +7,9 @@ using Microsoft.DotNet.CoreSetup.Test; using Microsoft.NET.HostModel.Bundle; using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using Xunit; @@ -27,19 +29,24 @@ private void Bundle_Extraction_To_Specific_Path_Succeeds() { var fixture = sharedTestState.TestFixture.Copy(); var hostName = BundleHelper.GetHostName(fixture); + var appName = Path.GetFileNameWithoutExtension(hostName); + string publishPath = BundleHelper.GetPublishPath(fixture); // Publish the bundle - string singleFile; - Bundler bundler = BundleHelper.BundleApp(fixture, out singleFile); + var bundleDir = BundleHelper.GetBundleDir(fixture); + var bundler = new Bundler(hostName, bundleDir.FullName, BundleOptions.BundleAllContent); + string singleFile = BundleHelper.GenerateBundle(bundler, publishPath); + + // Compute bundled files + var bundledFiles = bundler.BundleManifest.Files.Select(file => file.RelativePath).ToList(); // Verify expected files in the bundle directory - var bundleDir = BundleHelper.GetBundleDir(fixture); bundleDir.Should().HaveFile(hostName); - bundleDir.Should().NotHaveFiles(BundleHelper.GetBundledFiles(fixture)); + bundleDir.Should().NotHaveFiles(bundledFiles); // Create a directory for extraction. - var extractBaseDir = BundleHelper.GetExtractionRootDir(fixture); - extractBaseDir.Should().NotHaveDirectory(BundleHelper.GetAppBaseName(fixture)); + var extractBaseDir = BundleHelper.GetExtractDir(fixture); + extractBaseDir.Should().NotHaveDirectory(appName); // Run the bundled app for the first time, and extract files to // $DOTNET_BUNDLE_EXTRACT_BASE_DIR//bundle-id @@ -53,22 +60,27 @@ private void Bundle_Extraction_To_Specific_Path_Succeeds() .And .HaveStdOutContaining("Hello World"); - var extractDir = BundleHelper.GetExtractionDir(fixture, bundler); - extractDir.Should().HaveFiles(BundleHelper.GetExtractedFiles(fixture)); - extractDir.Should().NotHaveFiles(BundleHelper.GetFilesNeverExtracted(fixture)); + string extractPath = Path.Combine(extractBaseDir.FullName, appName, bundler.BundleManifest.BundleID); + var extractDir = new DirectoryInfo(extractPath); + extractDir.Should().OnlyHaveFiles(bundledFiles); + extractDir.Should().NotHaveFile(hostName); } [Fact] private void Bundle_extraction_is_reused() { var fixture = sharedTestState.TestFixture.Copy(); + var hostName = BundleHelper.GetHostName(fixture); + var appName = Path.GetFileNameWithoutExtension(hostName); + string publishPath = BundleHelper.GetPublishPath(fixture); // Publish the bundle - string singleFile; - Bundler bundler = BundleHelper.BundleApp(fixture, out singleFile, BundleOptions.BundleNativeBinaries); + var bundleDir = BundleHelper.GetBundleDir(fixture); + var bundler = new Bundler(hostName, bundleDir.FullName, BundleOptions.BundleAllContent); + string singleFile = BundleHelper.GenerateBundle(bundler, publishPath); // Create a directory for extraction. - var extractBaseDir = BundleHelper.GetExtractionRootDir(fixture); + var extractBaseDir = BundleHelper.GetExtractDir(fixture); // Run the bunded app for the first time, and extract files to // $DOTNET_BUNDLE_EXTRACT_BASE_DIR//bundle-id @@ -82,8 +94,8 @@ private void Bundle_extraction_is_reused() .And .HaveStdOutContaining("Hello World"); - var appBaseName = BundleHelper.GetAppBaseName(fixture); - var extractDir = BundleHelper.GetExtractionDir(fixture, bundler); + string extractPath = Path.Combine(extractBaseDir.FullName, appName, bundler.BundleManifest.BundleID); + var extractDir = new DirectoryInfo(extractPath); extractDir.Refresh(); DateTime firstWriteTime = extractDir.LastWriteTimeUtc; @@ -113,14 +125,20 @@ private void Bundle_extraction_can_recover_missing_files() var fixture = sharedTestState.TestFixture.Copy(); var hostName = BundleHelper.GetHostName(fixture); var appName = Path.GetFileNameWithoutExtension(hostName); + string publishPath = BundleHelper.GetPublishPath(fixture); // Publish the bundle - string singleFile; - Bundler bundler = BundleHelper.BundleApp(fixture, out singleFile, BundleOptions.BundleNativeBinaries); + var bundleDir = BundleHelper.GetBundleDir(fixture); + var bundler = new Bundler(hostName, bundleDir.FullName, BundleOptions.BundleAllContent); + string singleFile = BundleHelper.GenerateBundle(bundler, publishPath); + + // Compute bundled files + List bundledFiles = bundler.BundleManifest.Files.Select(file => file.RelativePath).ToList(); // Create a directory for extraction. - var extractBaseDir = BundleHelper.GetExtractionRootDir(fixture); - + var extractBaseDir = BundleHelper.GetExtractDir(fixture); + string extractPath = Path.Combine(extractBaseDir.FullName, appName, bundler.BundleManifest.BundleID); + var extractDir = new DirectoryInfo(extractPath); // Run the bunded app for the first time, and extract files to // $DOTNET_BUNDLE_EXTRACT_BASE_DIR//bundle-id @@ -134,14 +152,10 @@ private void Bundle_extraction_can_recover_missing_files() .And .HaveStdOutContaining("Hello World"); - // Remove the extracted files, but keep the extraction directory - var extractDir = BundleHelper.GetExtractionDir(fixture, bundler); - var extractedFiles = BundleHelper.GetExtractedFiles(fixture); - - Array.ForEach(extractedFiles, file => File.Delete(Path.Combine(extractDir.FullName, file))); + bundledFiles.ForEach(file => File.Delete(Path.Combine(extractPath, file))); extractDir.Should().Exist(); - extractDir.Should().NotHaveFiles(extractedFiles); + extractDir.Should().NotHaveFiles(bundledFiles); // Run the bundled app again (recover deleted files) Command.Create(singleFile) @@ -154,7 +168,7 @@ private void Bundle_extraction_can_recover_missing_files() .And .HaveStdOutContaining("Hello World"); - extractDir.Should().HaveFiles(extractedFiles); + extractDir.Should().HaveFiles(bundledFiles); } diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleRename.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleRename.cs index 581a1155c98..5466743fc5d 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleRename.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleRename.cs @@ -51,13 +51,11 @@ private void Bundle_can_be_renamed_while_running(bool renameFirstRun) .CaptureStdOut() .Start(); - while (!File.Exists(waitFile) && !singleExe.Process.HasExited) + while (!File.Exists(waitFile)) { Thread.Sleep(100); } - Assert.True(File.Exists(waitFile)); - File.Move(singleFile, renameFile); File.Create(resumeFile).Close(); diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs index 33e05b5c050..59360c09f99 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using BundleTests.Helpers; -using Microsoft.DotNet.Cli.Build.Framework; -using Microsoft.NET.HostModel.Bundle; -using Microsoft.DotNet.CoreSetup.Test; using System; using Xunit; +using Microsoft.DotNet.Cli.Build.Framework; +using BundleTests.Helpers; +using Microsoft.DotNet.CoreSetup.Test; namespace AppHost.Bundle.Tests { @@ -32,16 +31,11 @@ private void RunTheApp(string path) .HaveStdOutContaining("Wow! We now say hello to the big world and you."); } - // BundleOptions.BundleNativeBinaries: Test when the payload data files are unbundled, and beside the single-file app. - // BundleOptions.BundleAllContent: Test when the payload data files are bundled and extracted to temporary directory. - // Once the runtime can load assemblies from the bundle, BundleOptions.None can be used in place of BundleOptions.BundleNativeBinaries. - [InlineData(BundleOptions.BundleNativeBinaries)] - [InlineData(BundleOptions.BundleAllContent)] - [Theory] - public void Bundled_Framework_dependent_App_Run_Succeeds(BundleOptions options) + [Fact] + public void Bundled_Framework_dependent_App_Run_Succeeds() { var fixture = sharedTestState.TestFrameworkDependentFixture.Copy(); - var singleFile = BundleHelper.BundleApp(fixture, options); + var singleFile = BundleHelper.BundleApp(fixture); // Run the bundled app (extract files) RunTheApp(singleFile); @@ -50,13 +44,11 @@ public void Bundled_Framework_dependent_App_Run_Succeeds(BundleOptions options) RunTheApp(singleFile); } - [InlineData(BundleOptions.BundleNativeBinaries)] - [InlineData(BundleOptions.BundleAllContent)] - [Theory] - public void Bundled_Self_Contained_App_Run_Succeeds(BundleOptions options) + [Fact] + public void Bundled_Self_Contained_App_Run_Succeeds() { var fixture = sharedTestState.TestSelfContainedFixture.Copy(); - var singleFile = BundleHelper.BundleApp(fixture, options); + var singleFile = BundleHelper.BundleApp(fixture); // Run the bundled app (extract files) RunTheApp(singleFile); @@ -65,13 +57,11 @@ public void Bundled_Self_Contained_App_Run_Succeeds(BundleOptions options) RunTheApp(singleFile); } - [InlineData(BundleOptions.BundleNativeBinaries)] - [InlineData(BundleOptions.BundleAllContent)] - [Theory] - public void Bundled_With_Empty_File_Succeeds(BundleOptions options) + [Fact] + public void Bundled_With_Empty_File_Succeeds() { var fixture = sharedTestState.TestAppWithEmptyFileFixture.Copy(); - var singleFile = BundleHelper.BundleApp(fixture, options); + var singleFile = BundleHelper.BundleApp(fixture); // Run the app RunTheApp(singleFile); diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs index c5f77179436..e941becc236 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs @@ -40,32 +40,6 @@ public static string GetAppName(TestProjectFixture fixture) return Path.GetFileName(fixture.TestProject.AppDll); } - public static string GetAppBaseName(TestProjectFixture fixture) - { - return Path.GetFileNameWithoutExtension(GetAppName(fixture)); - } - - public static string[] GetBundledFiles(TestProjectFixture fixture) - { - string appBaseName = GetAppBaseName(fixture); - return new string[] { $"{appBaseName}.dll", $"{appBaseName}.deps.json", $"{appBaseName}.runtimeconfig.json" }; - } - - public static string[] GetExtractedFiles(TestProjectFixture fixture) - { - string appBaseName = GetAppBaseName(fixture); - return new string[] { $"{appBaseName}.dll" }; - } - - public static string[] GetFilesNeverExtracted(TestProjectFixture fixture) - { - string appBaseName = GetAppBaseName(fixture); - return new string[] { $"{appBaseName}.deps.json", - $"{appBaseName}.runtimeconfig.json", - Path.GetFileName(fixture.TestProject.HostFxrDll), - Path.GetFileName(fixture.TestProject.HostPolicyDll) }; - } - public static string GetPublishPath(TestProjectFixture fixture) { return Path.Combine(fixture.TestProject.ProjectDirectory, "publish"); @@ -76,28 +50,13 @@ public static DirectoryInfo GetBundleDir(TestProjectFixture fixture) return Directory.CreateDirectory(Path.Combine(fixture.TestProject.ProjectDirectory, "bundle")); } - public static string GetExtractionRootPath(TestProjectFixture fixture) - { - return Path.Combine(fixture.TestProject.ProjectDirectory, "extract"); - } - - public static DirectoryInfo GetExtractionRootDir(TestProjectFixture fixture) + public static DirectoryInfo GetExtractDir(TestProjectFixture fixture) { - return Directory.CreateDirectory(GetExtractionRootPath(fixture)); - } - - public static string GetExtractionPath(TestProjectFixture fixture, Bundler bundler) - { - return Path.Combine(GetExtractionRootPath(fixture), GetAppBaseName(fixture), bundler.BundleManifest.BundleID); - - } - public static DirectoryInfo GetExtractionDir(TestProjectFixture fixture, Bundler bundler) - { - return new DirectoryInfo(GetExtractionPath(fixture, bundler)); + return Directory.CreateDirectory(Path.Combine(fixture.TestProject.ProjectDirectory, "extract")); } /// Generate a bundle containind the (embeddable) files in sourceDir - public static string GenerateBundle(Bundler bundler, string sourceDir, string outputDir, bool copyExludedFiles=true) + public static string GenerateBundle(Bundler bundler, string sourceDir) { // Convert sourceDir to absolute path sourceDir = Path.GetFullPath(sourceDir); @@ -114,22 +73,7 @@ public static string GenerateBundle(Bundler bundler, string sourceDir, string ou fileSpecs.Add(new FileSpec(file, Path.GetRelativePath(sourceDir, file))); } - var singleFile = bundler.GenerateBundle(fileSpecs); - - if (copyExludedFiles) - { - foreach (var spec in fileSpecs) - { - if (spec.Excluded) - { - var outputFilePath = Path.Combine(outputDir, spec.BundleRelativePath); - Directory.CreateDirectory(Path.GetDirectoryName(outputFilePath)); - File.Copy(spec.SourcePath, outputFilePath, true); - } - } - } - - return singleFile; + return bundler.GenerateBundle(fileSpecs); } // Bundle to a single-file @@ -137,40 +81,23 @@ public static string GenerateBundle(Bundler bundler, string sourceDir, string ou // instead of the SDK via /p:PublishSingleFile=true. // This is necessary when the test needs the latest changes in the AppHost, // which may not (yet) be available in the SDK. - public static Bundler BundleApp(TestProjectFixture fixture, - out string singleFile, - BundleOptions options = BundleOptions.BundleNativeBinaries, - Version targetFrameworkVersion = null, - bool copyExcludedFiles = true) + // + // Currently, AppHost can only handle bundles if all content is extracted to disk on startup. + // Therefore, the BundleOption is BundleAllContent by default. + // The default should be BundleOptions.None once host/runtime no longer requires full-extraction. + public static string BundleApp(TestProjectFixture fixture, + BundleOptions options = BundleOptions.BundleAllContent, + Version targetFrameworkVersion = null) { var hostName = GetHostName(fixture); string publishPath = GetPublishPath(fixture); var bundleDir = GetBundleDir(fixture); var bundler = new Bundler(hostName, bundleDir.FullName, options, targetFrameworkVersion: targetFrameworkVersion); - singleFile = GenerateBundle(bundler, publishPath, bundleDir.FullName, copyExcludedFiles); - - return bundler; - } - - // The defaut option for Bundling apps is BundleOptions.BundleNativeBinaries - // Until CoreCLR runtime can learn how to process assemblies from the bundle. - // This is because CoreCLR expects System.Private.Corelib.dll to be beside CoreCLR.dll - public static string BundleApp(TestProjectFixture fixture, - BundleOptions options = BundleOptions.BundleNativeBinaries, - Version targetFrameworkVersion = null) - { - string singleFile; - BundleApp(fixture, out singleFile, options, targetFrameworkVersion); + string singleFile = GenerateBundle(bundler, publishPath); return singleFile; } - public static Bundler Bundle(TestProjectFixture fixture, BundleOptions options = BundleOptions.None) - { - string singleFile; - return BundleApp(fixture, out singleFile, options, copyExcludedFiles:false); - } - public static void AddLongNameContentToAppWithSubDirs(TestProjectFixture fixture) { // For tests using the AppWithSubDirs, One of the sub-directories with a really long name diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleAndRun.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleAndRun.cs index e4949b47750..3199b1559ff 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleAndRun.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleAndRun.cs @@ -7,6 +7,7 @@ using Xunit; using Microsoft.DotNet.Cli.Build.Framework; using Microsoft.DotNet.CoreSetup.Test; +using Microsoft.NET.HostModel.Bundle; using BundleTests.Helpers; namespace Microsoft.NET.HostModel.Tests @@ -40,7 +41,9 @@ private void BundleRun(TestProjectFixture fixture, string publishPath, string si RunTheApp(Path.Combine(publishPath, hostName)); // Bundle to a single-file - string singleFile = BundleHelper.BundleApp(fixture); + // Bundle all content, until the host can handle other scenarios. + Bundler bundler = new Bundler(hostName, singleFileDir, BundleOptions.BundleAllContent); + string singleFile = BundleHelper.GenerateBundle(bundler, publishPath); // Run the extracted app RunTheApp(singleFile); diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleLegacy.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleLegacy.cs index 7b9d6863607..a9c9b700064 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleLegacy.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleLegacy.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.IO; using Xunit; using Microsoft.DotNet.Cli.Build.Framework; using Microsoft.DotNet.CoreSetup.Test; diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundlerConsistencyTests.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundlerConsistencyTests.cs index 00f3b1cc843..efa13283bd1 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundlerConsistencyTests.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundlerConsistencyTests.cs @@ -92,10 +92,18 @@ public void TestWithDuplicateEntriesFails() public void TestFilesAlwaysBundled(BundleOptions options) { var fixture = sharedTestState.TestFixture.Copy(); - var bundler = BundleHelper.Bundle(fixture, options); - var bundledFiles = BundleHelper.GetBundledFiles(fixture); - Array.ForEach(bundledFiles, file => bundler.BundleManifest.Contains(file).Should().BeTrue()); + var hostName = BundleHelper.GetHostName(fixture); + var appName = Path.GetFileNameWithoutExtension(hostName); + string publishPath = BundleHelper.GetPublishPath(fixture); + var bundleDir = BundleHelper.GetBundleDir(fixture); + + var bundler = new Bundler(hostName, bundleDir.FullName, options); + BundleHelper.GenerateBundle(bundler, publishPath); + + bundler.BundleManifest.Contains($"{appName}.dll").Should().BeTrue(); + bundler.BundleManifest.Contains($"{appName}.deps.json").Should().BeTrue(); + bundler.BundleManifest.Contains($"{appName}.runtimeconfig.json").Should().BeTrue(); } [InlineData(BundleOptions.None)] @@ -107,16 +115,20 @@ public void TestFilesAlwaysBundled(BundleOptions options) public void TestFilesNeverBundled(BundleOptions options) { var fixture = sharedTestState.TestFixture.Copy(); - var appBaseName = BundleHelper.GetAppBaseName(fixture); + + var hostName = BundleHelper.GetHostName(fixture); + var appName = Path.GetFileNameWithoutExtension(hostName); string publishPath = BundleHelper.GetPublishPath(fixture); + var bundleDir = BundleHelper.GetBundleDir(fixture); // Make up a app.runtimeconfig.dev.json file in the publish directory. - File.Copy(Path.Combine(publishPath, $"{appBaseName}.runtimeconfig.json"), - Path.Combine(publishPath, $"{appBaseName}.runtimeconfig.dev.json")); + File.Copy(Path.Combine(publishPath, $"{appName}.runtimeconfig.json"), + Path.Combine(publishPath, $"{appName}.runtimeconfig.dev.json")); - var bundler = BundleHelper.Bundle(fixture, options); + var bundler = new Bundler(hostName, bundleDir.FullName, options); + BundleHelper.GenerateBundle(bundler, publishPath); - bundler.BundleManifest.Contains($"{appBaseName}.runtimeconfig.dev.json").Should().BeFalse(); + bundler.BundleManifest.Contains($"{appName}.runtimeconfig.dev.json").Should().BeFalse(); } [InlineData(BundleOptions.None)] @@ -125,10 +137,16 @@ public void TestFilesNeverBundled(BundleOptions options) public void TestBundlingSymbols(BundleOptions options) { var fixture = sharedTestState.TestFixture.Copy(); - var appBaseName = BundleHelper.GetAppBaseName(fixture); - var bundler = BundleHelper.Bundle(fixture, options); - bundler.BundleManifest.Contains($"{appBaseName}.pdb").Should().Be(options.HasFlag(BundleOptions.BundleSymbolFiles)); + var hostName = BundleHelper.GetHostName(fixture); + var appName = Path.GetFileNameWithoutExtension(hostName); + string publishPath = BundleHelper.GetPublishPath(fixture); + var bundleDir = BundleHelper.GetBundleDir(fixture); + + var bundler = new Bundler(hostName, bundleDir.FullName, options); + BundleHelper.GenerateBundle(bundler, publishPath); + + bundler.BundleManifest.Contains($"{appName}.pdb").Should().Be(options.HasFlag(BundleOptions.BundleSymbolFiles)); } [InlineData(BundleOptions.None)] @@ -137,28 +155,30 @@ public void TestBundlingSymbols(BundleOptions options) public void TestBundlingNativeBinaries(BundleOptions options) { var fixture = sharedTestState.TestFixture.Copy(); - var coreclr = Path.GetFileName(fixture.TestProject.CoreClrDll); - var bundler = BundleHelper.Bundle(fixture, options); - bundler.BundleManifest.Contains($"{coreclr}").Should().Be(options.HasFlag(BundleOptions.BundleNativeBinaries)); - } + var hostName = BundleHelper.GetHostName(fixture); + var hostfxr = Path.GetFileName(fixture.TestProject.HostFxrDll); + string publishPath = BundleHelper.GetPublishPath(fixture); + var bundleDir = BundleHelper.GetBundleDir(fixture); - [Fact] - public void TestFileSizes() - { - var fixture = sharedTestState.TestFixture.Copy(); - var bundler = BundleHelper.Bundle(fixture); - var publishPath = BundleHelper.GetPublishPath(fixture); + var bundler = new Bundler(hostName, bundleDir.FullName, options); + BundleHelper.GenerateBundle(bundler, publishPath); - bundler.BundleManifest.Files.ForEach(file => - Assert.True(file.Size == new FileInfo(Path.Combine(publishPath, file.RelativePath)).Length)); + bundler.BundleManifest.Contains($"{hostfxr}").Should().Be(options.HasFlag(BundleOptions.BundleNativeBinaries)); } [Fact] public void TestAssemblyAlignment() { var fixture = sharedTestState.TestFixture.Copy(); - var bundler = BundleHelper.Bundle(fixture); + + var hostName = BundleHelper.GetHostName(fixture); + var appName = Path.GetFileNameWithoutExtension(hostName); + string publishPath = BundleHelper.GetPublishPath(fixture); + var bundleDir = BundleHelper.GetBundleDir(fixture); + + var bundler = new Bundler(hostName, bundleDir.FullName, BundleOptions.BundleAllContent); + BundleHelper.GenerateBundle(bundler, publishPath); bundler.BundleManifest.Files.ForEach(file => Assert.True((file.Type != FileType.Assembly) || (file.Offset % Bundler.AssemblyAlignment == 0))); @@ -168,7 +188,13 @@ public void TestAssemblyAlignment() public void TestWithAdditionalContentAfterBundleMetadata() { var fixture = sharedTestState.TestFixture.Copy(); - string singleFile = BundleHelper.BundleApp(fixture); + + var hostName = BundleHelper.GetHostName(fixture); + var bundleDir = BundleHelper.GetBundleDir(fixture); + string publishPath = BundleHelper.GetPublishPath(fixture); + + var bundler = new Bundler(hostName, bundleDir.FullName, BundleOptions.BundleAllContent); + string singleFile = BundleHelper.GenerateBundle(bundler, publishPath); using (var file = File.OpenWrite(singleFile)) { diff --git a/src/installer/test/TestUtils/TestApp.cs b/src/installer/test/TestUtils/TestApp.cs index a1ff67d95c8..3e4e72f1fe7 100644 --- a/src/installer/test/TestUtils/TestApp.cs +++ b/src/installer/test/TestUtils/TestApp.cs @@ -16,7 +16,6 @@ public class TestApp : TestArtifact public string RuntimeDevConfigJson { get; private set; } public string HostPolicyDll { get; private set; } public string HostFxrDll { get; private set; } - public string CoreClrDll { get; private set; } public string AssemblyName { get; } @@ -56,7 +55,6 @@ private void LoadAssets() RuntimeDevConfigJson = Path.Combine(Location, $"{AssemblyName}.runtimeconfig.dev.json"); HostPolicyDll = Path.Combine(Location, RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostpolicy")); HostFxrDll = Path.Combine(Location, RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr")); - CoreClrDll = Path.Combine(Location, RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("coreclr")); } } } diff --git a/src/installer/test/TestUtils/TestProject.cs b/src/installer/test/TestUtils/TestProject.cs index b512f4c1e6b..5fd9135beec 100644 --- a/src/installer/test/TestUtils/TestProject.cs +++ b/src/installer/test/TestUtils/TestProject.cs @@ -22,7 +22,6 @@ public class TestProject : TestArtifact public string AppExe { get => BuiltApp?.AppExe; } public string HostPolicyDll { get => BuiltApp?.HostPolicyDll; } public string HostFxrDll { get => BuiltApp?.HostFxrDll; } - public string CoreClrDll { get => BuiltApp?.CoreClrDll; } public TestApp BuiltApp { get; private set; } -- GitLab