Esempio n. 1
0
/**
 * Given a version and probing paths, find if package layout
 *    directory containing hostpolicy exists.
 */
bool resolve_hostpolicy_dir_from_probe_paths(const pal::string_t& version, const std::vector<pal::string_t>& probe_realpaths, pal::string_t* candidate)
{
    if (probe_realpaths.empty() || version.empty())
    {
        return false;
    }

    // Check if the package relative directory containing hostpolicy exists.
    for (const auto& probe_path : probe_realpaths)
    {
        trace::verbose(_X("Considering %s to probe for %s"), probe_path.c_str(), LIBHOSTPOLICY_NAME);
        if (to_hostpolicy_package_dir(probe_path, version, candidate))
        {
            return true;
        }
    }

    // Print detailed message about the file not found in the probe paths.
    trace::error(_X("Could not find required library %s in %d probing paths:"),
        LIBHOSTPOLICY_NAME, probe_realpaths.size());
    for (const auto& path : probe_realpaths)
    {
        trace::error(_X("  %s"), path.c_str());
    }
    return false;
}
Esempio n. 2
0
void get_framework_and_sdk_locations(const pal::string_t& dotnet_dir, std::vector<pal::string_t>* locations)
{
    bool multilevel_lookup = multilevel_lookup_enabled();

    // Multi-level lookup will look for the most appropriate version in several locations
    // by following the priority rank below:
    //  .exe directory
    //  Global .NET directories
    // If it is not activated, then only .exe directory will be considered

    pal::string_t dotnet_dir_temp;
    if (!dotnet_dir.empty())
    {
        // own_dir contains DIR_SEPARATOR appended that we need to remove.
        dotnet_dir_temp = dotnet_dir;
        remove_trailing_dir_seperator(&dotnet_dir_temp);

        locations->push_back(dotnet_dir_temp);
    }

    std::vector<pal::string_t> global_dirs;
    if (multilevel_lookup && pal::get_global_dotnet_dirs(&global_dirs))
    {
        for (pal::string_t dir : global_dirs)
        {
            // avoid duplicate paths
            if (!pal::are_paths_equal_with_normalized_casing(dir, dotnet_dir_temp))
            {
                locations->push_back(dir);
            }
        }
    }
}
Esempio n. 3
0
/**
 * Given a directory and a version, find if the package relative
 *     dir under the given directory contains hostpolicy.dll
 */
bool to_hostpolicy_package_dir(const pal::string_t& dir, const pal::string_t& version, pal::string_t* candidate)
{
    assert(!version.empty());

    candidate->clear();

    // Ensure the relative dir contains platform directory separators.
    pal::string_t rel_dir = _STRINGIFY(HOST_POLICY_PKG_REL_DIR);
    if (DIR_SEPARATOR != '/')
    {
        replace_char(&rel_dir, '/', DIR_SEPARATOR);
    }

    // Construct the path to directory containing hostpolicy.
    pal::string_t path = dir;
    append_path(&path, _STRINGIFY(HOST_POLICY_PKG_NAME)); // package name
    append_path(&path, version.c_str());                  // package version
    append_path(&path, rel_dir.c_str());                  // relative dir containing hostpolicy library

    // Check if "path" contains the required library.
    if (!library_exists_in_dir(path, LIBHOSTPOLICY_NAME, nullptr))
    {
        trace::verbose(_X("Did not find %s in directory %s"), LIBHOSTPOLICY_NAME, path.c_str());
        return false;
    }

    // "path" contains the directory containing hostpolicy library.
    *candidate = path;

    trace::verbose(_X("Found %s in directory %s"), LIBHOSTPOLICY_NAME, path.c_str());
    return true;
}
Esempio n. 4
0
bool pal::file_exists(const pal::string_t& path)
{
    if (path.empty())
    {
        return false;
    }
    struct stat buffer;
    return (::stat(path.c_str(), &buffer) == 0);
}
Esempio n. 5
0
bool starts_with(const pal::string_t& value, const pal::string_t& prefix, bool match_case)
{
    if (prefix.empty())
    {
        // Cannot start with an empty string.
        return false;
    }
    auto cmp = match_case ? pal::strncmp : pal::strncasecmp;
    return (value.size() >= prefix.size()) &&
        cmp(value.c_str(), prefix.c_str(), prefix.size()) == 0;
}
Esempio n. 6
0
/**
 * Given a nuget version, detect if a serviced hostpolicy is available at
 *   platform servicing location.
 */
bool hostpolicy_exists_in_svc(const pal::string_t& version, pal::string_t* resolved_dir)
{
    if (version.empty())
    {
        return false;
    }

    pal::string_t svc_dir;
    pal::get_default_servicing_directory(&svc_dir);
    append_path(&svc_dir, _X("pkgs"));
    return to_hostpolicy_package_dir(svc_dir, version, resolved_dir);
}
Esempio n. 7
0
pal::string_t get_filename_without_ext(const pal::string_t& path)
{
    if (path.empty())
    {
        return path;
    }

    size_t name_pos = path.find_last_of(_X("/\\"));
    size_t dot_pos = path.rfind(_X('.'));
    size_t start_pos = (name_pos == pal::string_t::npos) ? 0 : (name_pos + 1);
    size_t count = (dot_pos == pal::string_t::npos || dot_pos < start_pos) ? pal::string_t::npos : (dot_pos - start_pos);
    return path.substr(start_pos, count);
}
Esempio n. 8
0
bool try_stou(const pal::string_t& str, unsigned* num)
{
    if (str.empty())
    {
        return false;
    }
    if (index_of_non_numeric(str, 0) != pal::string_t::npos)
    {
        return false;
    }
    *num = (unsigned)std::stoul(str);
    return true;
}
Esempio n. 9
0
bool try_stou(const pal::string_t& str, unsigned* num)
{
    if (str.empty())
    {
        return false;
    }
    if (str.find_first_not_of(_X("0123456789")) != pal::string_t::npos)
    {
        return false;
    }
    *num = (unsigned) std::stoul(str);
    return true;
}
Esempio n. 10
0
pal::string_t strip_file_ext(const pal::string_t& path)
{
    if (path.empty())
    {
        return path;
    }
    size_t sep_pos = path.rfind(_X("/\\"));
    size_t dot_pos = path.rfind(_X('.'));
    if (sep_pos != pal::string_t::npos && sep_pos > dot_pos)
    {
        return path;
    }
    return path.substr(0, dot_pos);
}
Esempio n. 11
0
//For longpath names on windows, if the paths are normalized they are always prefixed with
//extended syntax, Windows does not do any more normalizations on this string and uses it as is
//So we should ensure that there are NO adjacent DirectorySeparatorChar 
bool AssertRepeatingDirSeparator(const pal::string_t& path)
{
    if (path.empty())
        return true;

    pal::string_t path_to_check = path;
    if (LongFile::IsDevice(path))
    {
        path_to_check.erase(0, LongFile::DevicePathPrefix.length());
    }
    else if (LongFile::IsExtended(path))
    {
        path_to_check.erase(0, LongFile::ExtendedPrefix.length());
    }
    else if (LongFile::IsUNCExtended(path))
    {
        path_to_check.erase(0, LongFile::UNCExtendedPathPrefix.length());
    }
    else if (path_to_check.compare(0, LongFile::UNCPathPrefix.length(), LongFile::UNCPathPrefix) == 0)
    {
        path_to_check.erase(0, LongFile::UNCPathPrefix.length());
    }

    pal::string_t dirSeparator;
    dirSeparator.push_back(LongFile::DirectorySeparatorChar);
    dirSeparator.push_back(LongFile::DirectorySeparatorChar);

    assert(path_to_check.find(dirSeparator) == pal::string_t::npos);

    pal::string_t altDirSeparator;
    altDirSeparator.push_back(LongFile::AltDirectorySeparatorChar);
    altDirSeparator.push_back(LongFile::AltDirectorySeparatorChar);

    assert(path_to_check.find(altDirSeparator) == pal::string_t::npos);

    pal::string_t combDirSeparator1;
    combDirSeparator1.push_back(LongFile::DirectorySeparatorChar);
    combDirSeparator1.push_back(LongFile::AltDirectorySeparatorChar);

    assert(path_to_check.find(combDirSeparator1) == pal::string_t::npos);

    pal::string_t combDirSeparator2;
    combDirSeparator2.push_back(LongFile::AltDirectorySeparatorChar);
    combDirSeparator2.push_back(LongFile::DirectorySeparatorChar);

    assert(path_to_check.find(combDirSeparator2) == pal::string_t::npos);

    assert(path_to_check.find(_X("..")) == pal::string_t::npos);
    return true;
}
Esempio n. 12
0
/**
* Given path to app binary, say app.dll or app.exe, retrieve the app.deps.json.
*/
pal::string_t get_deps_from_app_binary(const pal::string_t& app_base, const pal::string_t& app)
{
    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);

    if (!app_base.empty() && app_base.back() != DIR_SEPARATOR)
    {
        deps_file.push_back(DIR_SEPARATOR);
    }
    deps_file.append(app_name, 0, app_name.find_last_of(_X(".")));
    deps_file.append(_X(".deps.json"));
    return deps_file;
}
Esempio n. 13
0
pal::string_t get_filename(const pal::string_t& path)
{
    if (path.empty())
    {
        return path;
    }

    auto name_pos = path.find_last_of(DIR_SEPARATOR);
    if (name_pos == pal::string_t::npos)
    {
        return path;
    }

    return path.substr(name_pos + 1);
}
Esempio n. 14
0
// -----------------------------------------------------------------------------
// 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 relative to the "base" directory
//
// Returns:
//    If the file exists in the path relative to the "base" directory.
//
bool deps_entry_t::to_full_path(const pal::string_t& base, pal::string_t* str) const
{
    str->clear();

    // Base directory must be present to obtain full path
    if (base.empty())
    {
        return false;
    }

    pal::string_t new_base = base;
    append_path(&new_base, library_name.c_str());
    append_path(&new_base, library_version.c_str());

    return to_rel_path(new_base, str);
}
Esempio n. 15
0
/**
 * Given FX location, app binary and specified --depsfile, return deps that contains hostpolicy.dll
 */
pal::string_t get_deps_file(
    const pal::string_t& fx_dir,
    const pal::string_t& app_candidate,
    const pal::string_t& specified_deps_file,
    const runtime_config_t& config)
{
    if (config.get_portable())
    {
        // Portable app's hostpolicy is resolved from FX deps
        return fx_dir + DIR_SEPARATOR + config.get_fx_name() + _X(".deps.json");
    }
    else
    {
        // Standalone app's hostpolicy is from specified deps or from app deps.
        return !specified_deps_file.empty() ? specified_deps_file : get_deps_from_app_binary(app_candidate);
    }
}
Esempio n. 16
0
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;

    candidate.clear();

    // Base directory must be present to obtain full path
    if (base.empty())
    {
        return false;
    }

    // Entry relative path contains '/' separator, sanitize it to use
    // platform separator. Perf: avoid extra copy if it matters.
    pal::string_t pal_relative_path = relative_path;
    if (_X('/') != DIR_SEPARATOR)
    {
        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);
    const pal::char_t* query_type = look_in_base ? _X("Local") : _X("Relative");
    if (!exists)
    {
        trace::verbose(_X("    %s path query did not exist %s"), query_type, candidate.c_str());
        candidate.clear();
    }
    else
    {
        trace::verbose(_X("    %s path query exists %s"), query_type, candidate.c_str());
    }
    return exists;
}
Esempio n. 17
0
/**
 * Given own location, FX location, app binary and specified --depsfile and probe paths
 *     return location that is expected to contain hostpolicy
 */
bool fx_muxer_t::resolve_hostpolicy_dir(host_mode_t mode,
    const pal::string_t& own_dir,
    const pal::string_t& fx_dir,
    const pal::string_t& app_candidate,
    const pal::string_t& specified_deps_file,
    const pal::string_t& specified_fx_version,
    const std::vector<pal::string_t>& probe_realpaths,
    const runtime_config_t& config,
    pal::string_t* impl_dir)
{
    // Obtain deps file for the given configuration.
    pal::string_t resolved_deps = get_deps_file(fx_dir, app_candidate, specified_deps_file, config);

    // Resolve hostpolicy version out of the deps file.
    pal::string_t version = resolve_hostpolicy_version_from_deps(resolved_deps);
    if (trace::is_enabled() && version.empty() && pal::file_exists(resolved_deps))
    {
        trace::warning(_X("Dependency manifest %s does not contain an entry for %s"), resolved_deps.c_str(), _STRINGIFY(HOST_POLICY_PKG_NAME));
    }

    // Check if the given version of the hostpolicy exists in servicing.
    if (hostpolicy_exists_in_svc(version, impl_dir))
    {
        return true;
    }

    // Get the expected directory that would contain hostpolicy.
    pal::string_t expected;
    if (config.get_portable())
    {
        if (!pal::directory_exists(fx_dir))
        {
            pal::string_t fx_version = specified_fx_version.empty() ? config.get_fx_version() : specified_fx_version;
            handle_missing_framework_error(config.get_fx_name(), fx_version, fx_dir);
            return false;
        }
        
        expected = fx_dir;
    }
    else
    {
        // Standalone apps can be activated by muxer or by standalone host or "corehost"
        // 1. When activated with dotnet.exe or corehost.exe, check for hostpolicy in the deps dir or
        //    app dir.
        // 2. When activated with app.exe, the standalone host, check own directory.
        assert(mode == host_mode_t::muxer || mode == host_mode_t::standalone || mode == host_mode_t::split_fx);
        expected = (mode == host_mode_t::standalone)
            ? own_dir
            : get_directory(specified_deps_file.empty() ? app_candidate : specified_deps_file);
    }

    // Check if hostpolicy exists in "expected" directory.
    trace::verbose(_X("The expected %s directory is [%s]"), LIBHOSTPOLICY_NAME, expected.c_str());
    if (library_exists_in_dir(expected, LIBHOSTPOLICY_NAME, nullptr))
    {
        impl_dir->assign(expected);
        return true;
    }

    trace::verbose(_X("The %s was not found in [%s]"), LIBHOSTPOLICY_NAME, expected.c_str());

    // Start probing for hostpolicy in the specified probe paths.
    pal::string_t candidate;
    if (resolve_hostpolicy_dir_from_probe_paths(version, probe_realpaths, &candidate))
    {
        impl_dir->assign(candidate);
        return true;
    }

    // If it still couldn't be found, somebody upstack messed up. Flag an error for the "expected" location.
    trace::error(_X("A fatal error was encountered. The library '%s' required to execute the application was not found in '%s'."), LIBHOSTPOLICY_NAME, expected.c_str());
    return false;
}
Esempio n. 18
0
pal::string_t fx_muxer_t::resolve_fx_dir(host_mode_t mode, const pal::string_t& own_dir, const runtime_config_t& config, const pal::string_t& specified_fx_version)
{
    // No FX resolution for standalone apps.
    assert(mode != host_mode_t::standalone);

    // If invoking using FX dotnet.exe, use own directory.
    if (mode == host_mode_t::split_fx)
    {
        return own_dir;
    }
    assert(mode == host_mode_t::muxer);

    trace::verbose(_X("--- Resolving FX directory from muxer dir '%s', specified '%s'"), own_dir.c_str(), specified_fx_version.c_str());
    const auto fx_name = config.get_fx_name();
    const auto fx_ver = specified_fx_version.empty() ? config.get_fx_version() : specified_fx_version;

    fx_ver_t specified(-1, -1, -1);
    if (!fx_ver_t::parse(fx_ver, &specified, false))
    {
        trace::error(_X("The specified framework version '%s' could not be parsed"), fx_ver.c_str());
        return pal::string_t();
    }

    auto fx_dir = own_dir;
    append_path(&fx_dir, _X("shared"));
    append_path(&fx_dir, fx_name.c_str());

    bool do_roll_forward = false;
    if (specified_fx_version.empty())
    {
        if (!specified.is_prerelease())
        {
            // If production and no roll forward use given version.
            do_roll_forward = config.get_patch_roll_fwd();
        }
        else
        {
            // Prerelease, but roll forward only if version doesn't exist.
            pal::string_t ver_dir = fx_dir;
            append_path(&ver_dir, fx_ver.c_str());
            do_roll_forward = !pal::directory_exists(ver_dir);
        }
    }

    if (!do_roll_forward)
    {
        trace::verbose(_X("Did not roll forward because specified version='%s', patch_roll_fwd=%d, chose [%s]"), specified_fx_version.c_str(), config.get_patch_roll_fwd(), fx_ver.c_str());
        append_path(&fx_dir, fx_ver.c_str());
    }
    else
    {
        trace::verbose(_X("Attempting FX roll forward starting from [%s]"), fx_ver.c_str());

        std::vector<pal::string_t> list;
        pal::readdir(fx_dir, &list);
        fx_ver_t most_compatible = specified;
        for (const auto& version : list)
        {
            trace::verbose(_X("Inspecting version... [%s]"), version.c_str());
            fx_ver_t ver(-1, -1, -1);
            if (!specified.is_prerelease() && fx_ver_t::parse(version, &ver, true) && // true -- only prod. prevents roll forward to prerelease.
                ver.get_major() == specified.get_major() &&
                ver.get_minor() == specified.get_minor())
            {
                // Pick the greatest production that differs only in patch.
                most_compatible = std::max(ver, most_compatible);
            }
            if (specified.is_prerelease() && fx_ver_t::parse(version, &ver, false) && // false -- implies both production and prerelease.
                ver.is_prerelease() && // prevent roll forward to production.
                ver.get_major() == specified.get_major() &&
                ver.get_minor() == specified.get_minor() &&
                ver.get_patch() == specified.get_patch() &&
                ver > specified)
            {
                // Pick the smallest prerelease that is greater than specified.
                most_compatible = (most_compatible == specified) ? ver : std::min(ver, most_compatible);
            }
        }
        pal::string_t most_compatible_str = most_compatible.as_str();
        append_path(&fx_dir, most_compatible_str.c_str());
    }

    trace::verbose(_X("Chose FX version [%s]"), fx_dir.c_str());
    return fx_dir;
}
Esempio n. 19
0
// -----------------------------------------------------------------------------
// Given a "base" directory, yield the relative path of this file in the package
// layout if the entry hash matches the hash file in the "base" directory
//
// Parameters:
//    base - The base directory to look for the relative path of this entry and
//           the hash file.
//    str  - If the method returns true, contains the file path for this deps
//           entry relative to the "base" directory
//
// Description:
//    Looks for a file named "{PackageName}.{PackageVersion}.nupkg.{HashAlgorithm}"
//    If the deps entry's {HashAlgorithm}-{HashValue} matches the contents then
//    yields the relative path of this entry in the "base" dir.
//
// Returns:
//    If the file exists in the path relative to the "base" directory and there
//    was hash file match with this deps entry.
//
// See: to_full_path(base, str)
//
bool deps_entry_t::to_hash_matched_path(const pal::string_t& base, pal::string_t* str) const
{
    pal::string_t& candidate = *str;

    candidate.clear();

    // Base directory must be present to perform hash lookup.
    if (base.empty())
    {
        return false;
    }

    // First detect position of hyphen in [Algorithm]-[Hash] in the string.
    size_t pos = library_hash.find(_X("-"));
    if (pos == 0 || pos == pal::string_t::npos)
    {
        trace::verbose(_X("Invalid hash %s value for deps file entry: %s"), library_hash.c_str(), library_name.c_str());
        return false;
    }
    
    // Build the relative hash path (what is added to the package directory path).
    pal::string_t relative_hash_path;
    if (library_hash_path.empty())
    {
        // Reserve approx 8 char_t's for the algorithm name.
        relative_hash_path.reserve(library_name.length() + 1 + library_version.length() + 16);
        relative_hash_path.append(library_name);
        relative_hash_path.append(_X("."));
        relative_hash_path.append(library_version);
        relative_hash_path.append(_X(".nupkg."));
        relative_hash_path.append(library_hash.substr(0, pos));
    }
    else
    {
        relative_hash_path.assign(library_hash_path);
    }

    // Build the directory that contains the hash file.
    pal::string_t hash_file;
    if (library_path.empty())
    {
        hash_file.reserve(base.length() + 1 +
            library_name.length() + 1 + library_version.length() + 1 +
            relative_hash_path.length());
        hash_file.assign(base);

        append_path(&hash_file, library_name.c_str());
        append_path(&hash_file, library_version.c_str());
    }
    else
    {
        hash_file.reserve(base.length() + 1 +
            library_path.length() + 1 +
            relative_hash_path.length());
        hash_file.assign(base);

        append_path(&hash_file, library_path.c_str());
    }

    // Append the relative path to the hash file.
    append_path(&hash_file, relative_hash_path.c_str());
    
    // Read the contents of the hash file.
    pal::ifstream_t fstream(hash_file);
    if (!fstream.good())
    {
        trace::verbose(_X("The hash file is invalid [%s]"), hash_file.c_str());
        return false;
    }

    // Obtain the hash from the file.
    std::string hash;
    hash.assign(pal::istreambuf_iterator_t(fstream),
        pal::istreambuf_iterator_t());
    pal::string_t pal_hash;
    if (!pal::utf8_palstring(hash.c_str(), &pal_hash))
    {
        return false;
    }

    // Check if contents match deps entry.
    pal::string_t entry_hash = library_hash.substr(pos + 1);
    if (entry_hash != pal_hash)
    {
        trace::verbose(_X("The file hash [%s][%d] did not match entry hash [%s][%d]"),
            pal_hash.c_str(), pal_hash.length(), entry_hash.c_str(), entry_hash.length());
        return false;
    }

    // All good, just append the relative dir to base.
    return to_full_path(base, &candidate);
}
Esempio n. 20
0
bool LongFile::IsNormalized(const pal::string_t& path)
{
    return path.empty() || LongFile::IsDevice(path) || LongFile::IsExtended(path) || LongFile::IsUNCExtended(path);
}