Merge pull request #2546 from schellap/breadcrumb
Breadcrumbs for servicing
This commit is contained in:
commit
d02e09a5fb
12 changed files with 298 additions and 37 deletions
|
@ -13,7 +13,7 @@ arguments_t::arguments_t() :
|
|||
app_argc(0),
|
||||
app_argv(nullptr),
|
||||
dotnet_packages_cache(_X("")),
|
||||
dotnet_extensions(_X("")),
|
||||
core_servicing(_X("")),
|
||||
deps_path(_X(""))
|
||||
{
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ bool parse_arguments(
|
|||
}
|
||||
|
||||
pal::getenv(_X("DOTNET_HOSTING_OPTIMIZATION_CACHE"), &args.dotnet_packages_cache);
|
||||
pal::get_default_extensions_directory(&args.dotnet_extensions);
|
||||
pal::get_default_servicing_directory(&args.core_servicing);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ struct arguments_t
|
|||
pal::string_t own_path;
|
||||
pal::string_t app_dir;
|
||||
pal::string_t deps_path;
|
||||
pal::string_t dotnet_extensions;
|
||||
pal::string_t core_servicing;
|
||||
std::vector<pal::string_t> probe_paths;
|
||||
pal::string_t dotnet_packages_cache;
|
||||
pal::string_t managed_application;
|
||||
|
@ -105,8 +105,8 @@ struct arguments_t
|
|||
{
|
||||
if (trace::is_enabled())
|
||||
{
|
||||
trace::verbose(_X("-- arguments_t: own_path=%s app_dir=%s deps=%s extensions=%s packages_cache=%s mgd_app=%s"),
|
||||
own_path.c_str(), app_dir.c_str(), deps_path.c_str(), dotnet_extensions.c_str(), dotnet_packages_cache.c_str(), managed_application.c_str());
|
||||
trace::verbose(_X("-- arguments_t: own_path=%s app_dir=%s deps=%s core_svc=%s packages_cache=%s mgd_app=%s"),
|
||||
own_path.c_str(), app_dir.c_str(), deps_path.c_str(), core_servicing.c_str(), dotnet_packages_cache.c_str(), managed_application.c_str());
|
||||
for (const auto& probe : probe_paths)
|
||||
{
|
||||
trace::verbose(_X("-- arguments_t: probe dir: [%s]"), probe.c_str());
|
||||
|
|
91
src/corehost/cli/breadcrumbs.cpp
Normal file
91
src/corehost/cli/breadcrumbs.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include <thread>
|
||||
#include "pal.h"
|
||||
#include "utils.h"
|
||||
#include "trace.h"
|
||||
#include "breadcrumbs.h"
|
||||
|
||||
breadcrumb_writer_t::breadcrumb_writer_t(const std::unordered_set<pal::string_t>* files)
|
||||
: m_status(false)
|
||||
, m_files(files)
|
||||
{
|
||||
if (!pal::get_default_breadcrumb_store(&m_breadcrumb_store))
|
||||
{
|
||||
m_breadcrumb_store.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Begin breadcrumb writing: write synchronously or launch a
|
||||
// thread to write breadcrumbs.
|
||||
void breadcrumb_writer_t::begin_write()
|
||||
{
|
||||
trace::verbose(_X("--- Begin breadcrumb write"));
|
||||
if (m_breadcrumb_store.empty())
|
||||
{
|
||||
trace::verbose(_X("Breadcrumb store was not obtained... skipping write."));
|
||||
m_status = false;
|
||||
return;
|
||||
}
|
||||
|
||||
trace::verbose(_X("Number of breadcrumb files to write is %d"), m_files->size());
|
||||
if (m_files->empty())
|
||||
{
|
||||
m_status = true;
|
||||
return;
|
||||
}
|
||||
m_thread = std::thread(write_worker_callback, this);
|
||||
trace::verbose(_X("Breadcrumbs will be written using a background thread"));
|
||||
}
|
||||
|
||||
// Write the breadcrumbs. This method should be called
|
||||
// only from the background thread.
|
||||
void breadcrumb_writer_t::write_callback()
|
||||
{
|
||||
bool successful = true;
|
||||
for (const auto& file : *m_files)
|
||||
{
|
||||
pal::string_t file_path = m_breadcrumb_store;
|
||||
pal::string_t file_name = _X("netcore,") + file;
|
||||
append_path(&file_path, file_name.c_str());
|
||||
if (!pal::file_exists(file_path))
|
||||
{
|
||||
if (!pal::touch_file(file_path))
|
||||
{
|
||||
successful = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// m_status should not be modified by anyone else.
|
||||
m_status = successful;
|
||||
}
|
||||
|
||||
// ThreadProc for the background writer.
|
||||
void breadcrumb_writer_t::write_worker_callback(breadcrumb_writer_t* p_this)
|
||||
{
|
||||
try
|
||||
{
|
||||
trace::verbose(_X("Breadcrumb thread write callback..."));
|
||||
p_this->write_callback();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
trace::warning(_X("An unexpected exception was thrown while leaving breadcrumbs"));
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for completion of the background tasks, if any.
|
||||
bool breadcrumb_writer_t::end_write()
|
||||
{
|
||||
if (m_thread.joinable())
|
||||
{
|
||||
trace::verbose(_X("Waiting for breadcrumb thread to exit..."));
|
||||
|
||||
// Block on the thread to exit.
|
||||
m_thread.join();
|
||||
}
|
||||
trace::verbose(_X("--- End breadcrumb write %d"), m_status);
|
||||
return m_status;
|
||||
}
|
||||
|
27
src/corehost/cli/breadcrumbs.h
Normal file
27
src/corehost/cli/breadcrumbs.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __BREADCRUMBS_H__
|
||||
#define __BREADCRUMBS_H__
|
||||
|
||||
#include <thread>
|
||||
|
||||
class breadcrumb_writer_t
|
||||
{
|
||||
public:
|
||||
breadcrumb_writer_t(const std::unordered_set<pal::string_t>* files);
|
||||
|
||||
void begin_write();
|
||||
bool end_write();
|
||||
|
||||
private:
|
||||
void write_callback();
|
||||
static void write_worker_callback(breadcrumb_writer_t* p_this);
|
||||
|
||||
pal::string_t m_breadcrumb_store;
|
||||
std::thread m_thread;
|
||||
const std::unordered_set<pal::string_t>* m_files;
|
||||
volatile bool m_status;
|
||||
};
|
||||
|
||||
#endif // __BREADCRUMBS_H__
|
|
@ -187,9 +187,9 @@ void deps_resolver_t::setup_probe_config(
|
|||
const hostpolicy_init_t& init,
|
||||
const arguments_t& args)
|
||||
{
|
||||
if (pal::directory_exists(args.dotnet_extensions))
|
||||
if (pal::directory_exists(args.core_servicing))
|
||||
{
|
||||
pal::string_t ext_ni = args.dotnet_extensions;
|
||||
pal::string_t ext_ni = args.core_servicing;
|
||||
append_path(&ext_ni, get_arch());
|
||||
if (pal::directory_exists(ext_ni))
|
||||
{
|
||||
|
@ -198,7 +198,7 @@ void deps_resolver_t::setup_probe_config(
|
|||
}
|
||||
|
||||
// Servicing normal probe.
|
||||
pal::string_t ext_pkgs = args.dotnet_extensions;
|
||||
pal::string_t ext_pkgs = args.core_servicing;
|
||||
append_path(&ext_pkgs, _X("pkgs"));
|
||||
m_probes.push_back(probe_config_t::svc(ext_pkgs, false, false));
|
||||
}
|
||||
|
@ -384,7 +384,8 @@ pal::string_t deps_resolver_t::resolve_coreclr_dir()
|
|||
|
||||
void deps_resolver_t::resolve_tpa_list(
|
||||
const pal::string_t& clr_dir,
|
||||
pal::string_t* output)
|
||||
pal::string_t* output,
|
||||
std::unordered_set<pal::string_t>* breadcrumb)
|
||||
{
|
||||
const std::vector<deps_entry_t> empty(0);
|
||||
|
||||
|
@ -400,11 +401,15 @@ void deps_resolver_t::resolve_tpa_list(
|
|||
|
||||
auto process_entry = [&](const pal::string_t& deps_dir, deps_json_t* deps, const dir_assemblies_t& dir_assemblies, const deps_entry_t& entry)
|
||||
{
|
||||
if (entry.is_serviceable)
|
||||
{
|
||||
breadcrumb->insert(entry.library_name + _X(",") + entry.library_version);
|
||||
breadcrumb->insert(entry.library_name);
|
||||
}
|
||||
if (items.count(entry.asset_name))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pal::string_t candidate;
|
||||
|
||||
trace::info(_X("Processing TPA for deps entry [%s, %s, %s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str());
|
||||
|
@ -478,7 +483,8 @@ void deps_resolver_t::resolve_tpa_list(
|
|||
void deps_resolver_t::resolve_probe_dirs(
|
||||
deps_entry_t::asset_types asset_type,
|
||||
const pal::string_t& clr_dir,
|
||||
pal::string_t* output)
|
||||
pal::string_t* output,
|
||||
std::unordered_set<pal::string_t>* breadcrumb)
|
||||
{
|
||||
bool is_resources = asset_type == deps_entry_t::asset_types::resources;
|
||||
assert(is_resources || asset_type == deps_entry_t::asset_types::native);
|
||||
|
@ -504,6 +510,12 @@ void deps_resolver_t::resolve_probe_dirs(
|
|||
bool track_api_sets = true;
|
||||
auto add_package_cache_entry = [&](const deps_entry_t& entry)
|
||||
{
|
||||
if (entry.is_serviceable)
|
||||
{
|
||||
breadcrumb->insert(entry.library_name + _X(",") + entry.library_version);
|
||||
breadcrumb->insert(entry.library_name);
|
||||
}
|
||||
|
||||
if (probe_entry_in_configs(entry, &candidate))
|
||||
{
|
||||
// For standalone apps, on win7, coreclr needs ApiSets which has to be in the DLL search path.
|
||||
|
@ -587,10 +599,10 @@ void deps_resolver_t::resolve_probe_dirs(
|
|||
// resolved path ordering.
|
||||
//
|
||||
//
|
||||
bool deps_resolver_t::resolve_probe_paths(const pal::string_t& clr_dir, probe_paths_t* probe_paths)
|
||||
bool deps_resolver_t::resolve_probe_paths(const pal::string_t& clr_dir, probe_paths_t* probe_paths, std::unordered_set<pal::string_t>* breadcrumb)
|
||||
{
|
||||
resolve_tpa_list(clr_dir, &probe_paths->tpa);
|
||||
resolve_probe_dirs(deps_entry_t::asset_types::native, clr_dir, &probe_paths->native);
|
||||
resolve_probe_dirs(deps_entry_t::asset_types::resources, clr_dir, &probe_paths->resources);
|
||||
resolve_tpa_list(clr_dir, &probe_paths->tpa, breadcrumb);
|
||||
resolve_probe_dirs(deps_entry_t::asset_types::native, clr_dir, &probe_paths->native, breadcrumb);
|
||||
resolve_probe_dirs(deps_entry_t::asset_types::resources, clr_dir, &probe_paths->resources, breadcrumb);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -25,8 +25,6 @@ class deps_resolver_t
|
|||
{
|
||||
public:
|
||||
deps_resolver_t(const hostpolicy_init_t& init, const arguments_t& args)
|
||||
// Important: FX dir should come from "init" than "config",
|
||||
// since the host could be launching from FX dir.
|
||||
: m_fx_dir(init.fx_dir)
|
||||
, m_app_dir(args.app_dir)
|
||||
, m_coreclr_index(-1)
|
||||
|
@ -62,7 +60,8 @@ public:
|
|||
|
||||
bool resolve_probe_paths(
|
||||
const pal::string_t& clr_dir,
|
||||
probe_paths_t* probe_paths);
|
||||
probe_paths_t* probe_paths,
|
||||
std::unordered_set<pal::string_t>* breadcrumb);
|
||||
|
||||
pal::string_t resolve_coreclr_dir();
|
||||
|
||||
|
@ -93,13 +92,15 @@ private:
|
|||
// Resolve order for TPA lookup.
|
||||
void resolve_tpa_list(
|
||||
const pal::string_t& clr_dir,
|
||||
pal::string_t* output);
|
||||
pal::string_t* output,
|
||||
std::unordered_set<pal::string_t>* breadcrumb);
|
||||
|
||||
// Resolve order for culture and native DLL lookup.
|
||||
void resolve_probe_dirs(
|
||||
deps_entry_t::asset_types asset_type,
|
||||
const pal::string_t& clr_dir,
|
||||
pal::string_t* output);
|
||||
pal::string_t* output,
|
||||
std::unordered_set<pal::string_t>* breadcrumb);
|
||||
|
||||
// Populate assemblies from the directory.
|
||||
void get_dir_assemblies(
|
||||
|
|
|
@ -26,6 +26,7 @@ set(SOURCES
|
|||
../json/casablanca/src/json/json_serialization.cpp
|
||||
../json/casablanca/src/utilities/asyncrt_utils.cpp
|
||||
../fxr/fx_ver.cpp
|
||||
../breadcrumbs.cpp
|
||||
../args.cpp
|
||||
../hostpolicy.cpp
|
||||
../coreclr.cpp
|
||||
|
|
|
@ -60,7 +60,7 @@ int execute_app(
|
|||
|
||||
if (code != StatusCode::Success)
|
||||
{
|
||||
trace::error(_X("Could not load host policy library from [%s]"), impl_dll_dir.c_str());
|
||||
trace::error(_X("Expected to load %s from [%s]"), LIBHOSTPOLICY_NAME, impl_dll_dir.c_str());
|
||||
if (init->fx_dir() == impl_dll_dir)
|
||||
{
|
||||
pal::string_t name = init->fx_name();
|
||||
|
@ -68,6 +68,10 @@ int execute_app(
|
|||
trace::error(_X("This may be because the targeted framework [\"%s\": \"%s\"] was not found."),
|
||||
name.c_str(), version.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
trace::error(_X("This may be because of an invalid .NET Core FX configuration in the folder."));
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -86,7 +90,7 @@ int execute_app(
|
|||
bool hostpolicy_exists_in_svc(pal::string_t* resolved_dir)
|
||||
{
|
||||
pal::string_t svc_dir;
|
||||
pal::get_default_extensions_directory(&svc_dir);
|
||||
pal::get_default_servicing_directory(&svc_dir);
|
||||
append_path(&svc_dir, _X("pkgs"));
|
||||
|
||||
pal::string_t version = _STRINGIFY(HOST_POLICY_PKG_VER);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "cpprest/json.h"
|
||||
#include "libhost.h"
|
||||
#include "error_codes.h"
|
||||
#include "breadcrumbs.h"
|
||||
|
||||
hostpolicy_init_t g_init;
|
||||
|
||||
|
@ -36,8 +37,18 @@ int run(const arguments_t& args)
|
|||
trace::info(_X("CoreCLR directory: %s"), clr_path.c_str());
|
||||
}
|
||||
|
||||
|
||||
// Setup breadcrumbs
|
||||
pal::string_t policy_name = _STRINGIFY(HOST_POLICY_PKG_NAME);
|
||||
pal::string_t policy_version = _STRINGIFY(HOST_POLICY_PKG_VER);
|
||||
|
||||
// Always insert the hostpolicy that the code is running on.
|
||||
std::unordered_set<pal::string_t> breadcrumbs;
|
||||
breadcrumbs.insert(policy_name);
|
||||
breadcrumbs.insert(policy_name + _X(",") + policy_version);
|
||||
|
||||
probe_paths_t probe_paths;
|
||||
if (!resolver.resolve_probe_paths(clr_path, &probe_paths))
|
||||
if (!resolver.resolve_probe_paths(clr_path, &probe_paths, &breadcrumbs))
|
||||
{
|
||||
return StatusCode::ResolverResolveFailure;
|
||||
}
|
||||
|
@ -52,7 +63,8 @@ int run(const arguments_t& args)
|
|||
"AppDomainCompatSwitch",
|
||||
// Workaround: mscorlib does not resolve symlinks for AppContext.BaseDirectory dotnet/coreclr/issues/2128
|
||||
"APP_CONTEXT_BASE_DIRECTORY",
|
||||
"APP_CONTEXT_DEPS_FILES"
|
||||
"APP_CONTEXT_DEPS_FILES",
|
||||
"FX_DEPS_FILE"
|
||||
};
|
||||
|
||||
auto tpa_paths_cstr = pal::to_stdstring(probe_paths.tpa);
|
||||
|
@ -60,7 +72,8 @@ int run(const arguments_t& args)
|
|||
auto native_dirs_cstr = pal::to_stdstring(probe_paths.native);
|
||||
auto resources_dirs_cstr = pal::to_stdstring(probe_paths.resources);
|
||||
|
||||
std::string deps = pal::to_stdstring(resolver.get_deps_file() + _X(";") + resolver.get_fx_deps_file());
|
||||
std::string fx_deps = pal::to_stdstring(resolver.get_fx_deps_file());
|
||||
std::string deps = pal::to_stdstring(resolver.get_deps_file() + _X(";")) + fx_deps;
|
||||
|
||||
std::vector<const char*> property_values = {
|
||||
// TRUSTED_PLATFORM_ASSEMBLIES
|
||||
|
@ -79,6 +92,8 @@ int run(const arguments_t& args)
|
|||
app_base_cstr.c_str(),
|
||||
// APP_CONTEXT_DEPS_FILES,
|
||||
deps.c_str(),
|
||||
// FX_DEPS_FILE
|
||||
fx_deps.c_str()
|
||||
};
|
||||
|
||||
for (int i = 0; i < g_init.cfg_keys.size(); ++i)
|
||||
|
@ -155,6 +170,10 @@ int run(const arguments_t& args)
|
|||
|
||||
std::string managed_app = pal::to_stdstring(args.managed_application);
|
||||
|
||||
// Leave breadcrumbs for servicing.
|
||||
breadcrumb_writer_t writer(&breadcrumbs);
|
||||
writer.begin_write();
|
||||
|
||||
// Execute the application
|
||||
unsigned int exit_code = 1;
|
||||
hr = coreclr::execute_assembly(
|
||||
|
@ -164,6 +183,7 @@ int run(const arguments_t& args)
|
|||
argv.data(),
|
||||
managed_app.c_str(),
|
||||
&exit_code);
|
||||
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
trace::error(_X("Failed to execute managed app, HRESULT: 0x%X"), hr);
|
||||
|
@ -179,6 +199,9 @@ int run(const arguments_t& args)
|
|||
|
||||
coreclr::unload();
|
||||
|
||||
// Finish breadcrumb writing
|
||||
writer.end_write();
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
|
|
|
@ -165,6 +165,7 @@ namespace pal
|
|||
inline void to_stdstring(const char_t* str, std::string* out) { out->assign(str); }
|
||||
#endif
|
||||
|
||||
bool touch_file(const pal::string_t& path);
|
||||
bool realpath(string_t* path);
|
||||
bool file_exists(const string_t& path);
|
||||
inline bool directory_exists(const string_t& path) { return file_exists(path); }
|
||||
|
@ -173,7 +174,8 @@ namespace pal
|
|||
|
||||
bool get_own_executable_path(string_t* recv);
|
||||
bool getenv(const char_t* name, string_t* recv);
|
||||
bool get_default_extensions_directory(string_t* recv);
|
||||
bool get_default_servicing_directory(string_t* recv);
|
||||
bool get_default_breadcrumb_store(string_t* recv);
|
||||
bool is_path_rooted(const string_t& path);
|
||||
|
||||
int xtoi(const char_t* input);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
@ -34,6 +34,18 @@ pal::string_t pal::to_lower(const pal::string_t& in)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool pal::touch_file(const pal::string_t& path)
|
||||
{
|
||||
int fd = open(path.c_str(), (O_CREAT | O_EXCL), (S_IRUSR | S_IRGRP | S_IROTH));
|
||||
if (fd == -1)
|
||||
{
|
||||
trace::warning(_X("Failed to open() file descriptor in %s(%s)"), __FUNCTION__, path.c_str());
|
||||
return false;
|
||||
}
|
||||
(void) close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pal::getcwd(pal::string_t* recv)
|
||||
{
|
||||
recv->clear();
|
||||
|
@ -112,11 +124,68 @@ bool pal::is_path_rooted(const pal::string_t& path)
|
|||
return path.front() == '/';
|
||||
}
|
||||
|
||||
bool pal::get_default_extensions_directory(string_t* recv)
|
||||
bool pal::get_default_breadcrumb_store(string_t* recv)
|
||||
{
|
||||
recv->clear();
|
||||
append_path(recv, _X("opt"));
|
||||
append_path(recv, _X("dotnetextensions"));
|
||||
pal::string_t ext;
|
||||
if (pal::getenv(_X("CORE_BREADCRUMBS"), &ext) && pal::realpath(&ext))
|
||||
{
|
||||
// We should have the path in ext.
|
||||
trace::info(_X("Realpath CORE_BREADCRUMBS [%s]"), ext.c_str());
|
||||
}
|
||||
|
||||
if (!pal::directory_exists(ext))
|
||||
{
|
||||
trace::info(_X("Directory core breadcrumbs [%s] was not specified or found"), ext.c_str());
|
||||
ext.clear();
|
||||
append_path(&ext, _X("opt"));
|
||||
append_path(&ext, _X("corebreadcrumbs"));
|
||||
if (!pal::directory_exists(ext))
|
||||
{
|
||||
trace::info(_X("Fallback directory core breadcrumbs at [%s] was not found"), ext.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (access(ext.c_str(), (R_OK | W_OK)) != 0)
|
||||
{
|
||||
trace::info(_X("Breadcrumb store [%s] is not ACL-ed with rw-"), ext.c_str());
|
||||
}
|
||||
|
||||
recv->assign(ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pal::get_default_servicing_directory(string_t* recv)
|
||||
{
|
||||
recv->clear();
|
||||
pal::string_t ext;
|
||||
if (pal::getenv(_X("CORE_SERVICING"), &ext) && pal::realpath(&ext))
|
||||
{
|
||||
// We should have the path in ext.
|
||||
trace::info(_X("Realpath CORE_SERVICING [%s]"), ext.c_str());
|
||||
}
|
||||
|
||||
if (!pal::directory_exists(ext))
|
||||
{
|
||||
trace::info(_X("Directory core servicing at [%s] was not specified or found"), ext.c_str());
|
||||
ext.clear();
|
||||
append_path(&ext, _X("opt"));
|
||||
append_path(&ext, _X("coreservicing"));
|
||||
if (!pal::directory_exists(ext))
|
||||
{
|
||||
trace::info(_X("Fallback directory core servicing at [%s] was not found"), ext.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (access(ext.c_str(), R_OK) != 0)
|
||||
{
|
||||
trace::info(_X("Directory core servicing at [%s] was not ACL-ed properly"), ext.c_str());
|
||||
}
|
||||
|
||||
recv->assign(ext);
|
||||
trace::info(_X("Using core servicing at [%s]"), ext.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
#include <cassert>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
#include <ShlObj.h>
|
||||
|
||||
static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> g_converter;
|
||||
static thread_local std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> t_converter;
|
||||
|
||||
pal::string_t pal::to_lower(const pal::string_t& in)
|
||||
{
|
||||
|
@ -54,6 +55,18 @@ bool pal::find_coreclr(pal::string_t* recv)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool pal::touch_file(const pal::string_t& path)
|
||||
{
|
||||
HANDLE hnd = ::CreateFileW(path.c_str(), 0, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hnd == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
trace::verbose(_X("Failed to leave breadcrumb"), HRESULT_FROM_WIN32(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
::CloseHandle(hnd);
|
||||
return true;
|
||||
}
|
||||
|
||||
void pal::setup_api_sets(const std::unordered_set<pal::string_t>& api_sets)
|
||||
{
|
||||
if (api_sets.empty())
|
||||
|
@ -154,7 +167,25 @@ void pal::unload_library(dll_t library)
|
|||
// No-op. On windows, we pin the library, so it can't be unloaded.
|
||||
}
|
||||
|
||||
bool pal::get_default_extensions_directory(string_t* recv)
|
||||
bool pal::get_default_breadcrumb_store(string_t* recv)
|
||||
{
|
||||
recv->clear();
|
||||
|
||||
pal::char_t* prog_dat;
|
||||
HRESULT hr = ::SHGetKnownFolderPath(FOLDERID_ProgramData, 0, NULL, &prog_dat);
|
||||
if (hr != S_OK)
|
||||
{
|
||||
trace::verbose(_X("Failed to read default breadcrumb store 0x%X"), hr);
|
||||
return false;
|
||||
}
|
||||
recv->assign(prog_dat);
|
||||
append_path(recv, _X("Microsoft"));
|
||||
append_path(recv, _X("NetFramework"));
|
||||
append_path(recv, _X("BreadcrumbStore"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pal::get_default_servicing_directory(string_t* recv)
|
||||
{
|
||||
recv->clear();
|
||||
|
||||
|
@ -169,7 +200,7 @@ bool pal::get_default_extensions_directory(string_t* recv)
|
|||
return false;
|
||||
}
|
||||
|
||||
append_path(recv, _X("dotnetextensions"));
|
||||
append_path(recv, _X("coreservicing"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -224,22 +255,22 @@ bool pal::get_own_executable_path(string_t* recv)
|
|||
|
||||
std::string pal::to_stdstring(const string_t& str)
|
||||
{
|
||||
return g_converter.to_bytes(str);
|
||||
return t_converter.to_bytes(str);
|
||||
}
|
||||
|
||||
pal::string_t pal::to_palstring(const std::string& str)
|
||||
{
|
||||
return g_converter.from_bytes(str);
|
||||
return t_converter.from_bytes(str);
|
||||
}
|
||||
|
||||
void pal::to_palstring(const char* str, pal::string_t* out)
|
||||
{
|
||||
out->assign(g_converter.from_bytes(str));
|
||||
out->assign(t_converter.from_bytes(str));
|
||||
}
|
||||
|
||||
void pal::to_stdstring(const pal::char_t* str, std::string* out)
|
||||
{
|
||||
out->assign(g_converter.to_bytes(str));
|
||||
out->assign(t_converter.to_bytes(str));
|
||||
}
|
||||
|
||||
bool pal::realpath(string_t* path)
|
||||
|
|
Loading…
Reference in a new issue