| Index: src/trusted/plugin/manifest.cc
|
| diff --git a/src/trusted/plugin/manifest.cc b/src/trusted/plugin/manifest.cc
|
| deleted file mode 100644
|
| index ca452f8f2fdc0c11e3cbf1a6bfc42b1be34355a6..0000000000000000000000000000000000000000
|
| --- a/src/trusted/plugin/manifest.cc
|
| +++ /dev/null
|
| @@ -1,506 +0,0 @@
|
| -/*
|
| - * Copyright (c) 2011 The Native Client Authors. All rights reserved.
|
| - * Use of this source code is governed by a BSD-style license that can be
|
| - * found in the LICENSE file.
|
| - */
|
| -
|
| -#include <algorithm>
|
| -
|
| -#include "native_client/src/trusted/plugin/manifest.h"
|
| -
|
| -#include <stdlib.h>
|
| -
|
| -#include "native_client/src/include/nacl_base.h"
|
| -#include "native_client/src/include/nacl_macros.h"
|
| -#include "native_client/src/include/nacl_string.h"
|
| -#include "native_client/src/include/portability.h"
|
| -#include "native_client/src/shared/platform/nacl_check.h"
|
| -#include "native_client/src/trusted/plugin/plugin_error.h"
|
| -#include "native_client/src/trusted/plugin/utility.h"
|
| -#include "native_client/src/third_party_mod/jsoncpp/include/json/reader.h"
|
| -#include "ppapi/cpp/dev/url_util_dev.h"
|
| -#include "ppapi/cpp/var.h"
|
| -
|
| -namespace plugin {
|
| -
|
| -namespace {
|
| -// Top-level section name keys
|
| -const char* const kProgramKey = "program";
|
| -const char* const kInterpreterKey = "interpreter";
|
| -const char* const kFilesKey = "files";
|
| -
|
| -// ISA Dictionary keys
|
| -const char* const kX8632Key = "x86-32";
|
| -const char* const kX8664Key = "x86-64";
|
| -const char* const kArmKey = "arm";
|
| -const char* const kPortableKey = "portable";
|
| -const char* const kUrlKey = "url";
|
| -
|
| -// Sample manifest file:
|
| -// {
|
| -// "program": {
|
| -// "x86-32": {"url": "myprogram_x86-32.nexe"},
|
| -// "x86-64": {"url": "myprogram_x86-64.nexe"},
|
| -// "arm": {"url": "myprogram_arm.nexe"},
|
| -// "portable": {"url": "myprogram.pexe"}
|
| -// },
|
| -// "interpreter": {
|
| -// "x86-32": {"url": "interpreter_x86-32.nexe"},
|
| -// "x86-64": {"url": "interpreter_x86-64.nexe"},
|
| -// "arm": {"url": "interpreter_arm.nexe"}
|
| -// },
|
| -// "files": {
|
| -// "foo.txt": {
|
| -// "portable": {"url": "foo.txt"}
|
| -// },
|
| -// "bar.txt": {
|
| -// "x86-32": {"url": "x86-32/bar.txt"},
|
| -// "portable": {"url": "bar.txt"}
|
| -// }
|
| -// }
|
| -// }
|
| -
|
| -// TODO(jvoung): Remove these when we find a better way to store/install them.
|
| -const char* const kPnaclLlcKey = "pnacl-llc";
|
| -const char* const kPnaclLdKey = "pnacl-ld";
|
| -
|
| -// Looks up |property_name| in the vector |valid_names| with length
|
| -// |valid_name_count|. Returns true if |property_name| is found.
|
| -bool FindMatchingProperty(nacl::string property_name,
|
| - const char** valid_names,
|
| - size_t valid_name_count) {
|
| - for (size_t i = 0; i < valid_name_count; ++i) {
|
| - if (property_name == valid_names[i]) {
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -// Validates that |dictionary| is a valid ISA dictionary. An ISA dictionary
|
| -// is validated to have keys from within the set of recognized ISAs. Unknown
|
| -// ISAs are allowed, but ignored and warnings are produced. It is also validated
|
| -// that it must have an entry to match the ISA specified in |sandbox_isa| or
|
| -// have a fallback 'portable' entry if there is no match. Returns true if
|
| -// |dictionary| is an ISA to URL map. Sets |error_string| to something
|
| -// descriptive if it fails.
|
| -bool IsValidISADictionary(const Json::Value& dictionary,
|
| - const nacl::string& sandbox_isa,
|
| - nacl::string* error_string) {
|
| - if (error_string == NULL)
|
| - return false;
|
| -
|
| - // An ISA to URL dictionary has to be an object.
|
| - if (!dictionary.isObject()) {
|
| - *error_string = " property is not an ISA to URL dictionary";
|
| - return false;
|
| - }
|
| - // The keys to the dictionary have to be valid ISA names.
|
| - Json::Value::Members members = dictionary.getMemberNames();
|
| - for (size_t i = 0; i < members.size(); ++i) {
|
| - // The known ISA values for ISA dictionaries in the manifest.
|
| - static const char* kManifestISAProperties[] = {
|
| - kX8632Key,
|
| - kX8664Key,
|
| - kArmKey,
|
| - kPortableKey
|
| - };
|
| - nacl::string property_name = members[i];
|
| - if (!FindMatchingProperty(property_name,
|
| - kManifestISAProperties,
|
| - NACL_ARRAY_SIZE(kManifestISAProperties))) {
|
| - PLUGIN_PRINTF(("IsValidISADictionary: unrecognized ISA '%s'.\n",
|
| - property_name.c_str()));
|
| - }
|
| - Json::Value url_spec = dictionary[property_name];
|
| - if (!url_spec.isObject()) {
|
| - *error_string = " ISA property '" + property_name +
|
| - "' has non-dictionary value'" + url_spec.toStyledString() + "'.";
|
| - return false;
|
| - }
|
| - // Check properties of the arch-specific 'URL spec' dictionary
|
| - static const char* kManifestUrlSpecProperties[] = {
|
| - kUrlKey
|
| - };
|
| - Json::Value::Members ISA_members = url_spec.getMemberNames();
|
| - for (size_t j = 0; j < ISA_members.size(); ++j) {
|
| - nacl::string ISA_property_name = ISA_members[j];
|
| - if (!FindMatchingProperty(ISA_property_name,
|
| - kManifestUrlSpecProperties,
|
| - NACL_ARRAY_SIZE(kManifestUrlSpecProperties))) {
|
| - PLUGIN_PRINTF(("IsValidISADictionary: unrecognized property for '%s'"
|
| - ": '%s'.",
|
| - property_name.c_str(), ISA_property_name.c_str()));
|
| - }
|
| - }
|
| - // A "url" key is required for each URL spec.
|
| - if (!url_spec.isMember(kUrlKey)) {
|
| - *error_string = " ISA property '" + property_name +
|
| - "' has no key '" + kUrlKey + "'.";
|
| - return false;
|
| - }
|
| - Json::Value url = url_spec[kUrlKey];
|
| - if (!url.isString()) {
|
| - *error_string = " ISA property '" + property_name +
|
| - "' has non-string value '" + url.toStyledString() +
|
| - "' for key '" + kUrlKey + "'.";
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include
|
| - // micro-architectures that can resolve to multiple valid sandboxes.
|
| - bool has_isa = dictionary.isMember(sandbox_isa);
|
| - bool has_portable = dictionary.isMember(kPortableKey);
|
| -
|
| - if (!has_isa && !has_portable) {
|
| - *error_string =
|
| - " no version given for current arch and no portable version found.";
|
| - return false;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool GetURLFromISADictionary(const Json::Value& dictionary,
|
| - const nacl::string& sandbox_isa,
|
| - nacl::string* url,
|
| - nacl::string* error_string,
|
| - bool* is_portable) {
|
| - if (url == NULL || error_string == NULL || is_portable == NULL)
|
| - return false;
|
| -
|
| - if (!IsValidISADictionary(dictionary, sandbox_isa, error_string))
|
| - return false;
|
| -
|
| - const char* isa_string;
|
| - // The call to IsValidISADictionary() above guarantees that either
|
| - // sandbox_isa or kPortableKey is present in the dictionary.
|
| - bool has_portable = dictionary.isMember(kPortableKey);
|
| - bool has_isa = dictionary.isMember(sandbox_isa);
|
| - if ((has_portable && Manifest::PreferPortable()) || !has_isa) {
|
| - *is_portable = true;
|
| - isa_string = kPortableKey;
|
| - } else {
|
| - *is_portable = false;
|
| - isa_string = sandbox_isa.c_str();
|
| - }
|
| -
|
| - const Json::Value& json_url = dictionary[isa_string][kUrlKey];
|
| - *url = json_url.asString();
|
| -
|
| - return true;
|
| -}
|
| -
|
| -// this will probably be replaced by jvoung's version that exposes
|
| -// is_portable checks
|
| -bool GetKeyUrl(const Json::Value& dictionary,
|
| - const nacl::string& key,
|
| - const nacl::string& sandbox_isa,
|
| - nacl::string* full_url,
|
| - nacl::string* error_string,
|
| - bool* is_portable) {
|
| - CHECK(full_url != NULL && error_string != NULL);
|
| - if (!dictionary.isMember(key)) {
|
| - *error_string = "file key not found in manifest";
|
| - return false;
|
| - }
|
| - const Json::Value& isa_dict = dictionary[key];
|
| - if (isa_dict.isMember(sandbox_isa)) {
|
| - *full_url = isa_dict[sandbox_isa][kUrlKey].asString();
|
| - *is_portable = false;
|
| - return true;
|
| - }
|
| - if (isa_dict.isMember(kPortableKey)) {
|
| - *full_url = isa_dict[kPortableKey][kUrlKey].asString();
|
| - *is_portable = true;
|
| - return true;
|
| - }
|
| - *error_string = "neither ISA-specific nor portable representations exist";
|
| - return false;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -bool Manifest::PreferPortable() {
|
| - return getenv("NACL_PREFER_PORTABLE_IN_MANIFEST") != NULL;
|
| -}
|
| -
|
| -bool Manifest::Init(const nacl::string& manifest_json, ErrorInfo* error_info) {
|
| - if (error_info == NULL) {
|
| - return false;
|
| - }
|
| - Json::Reader reader;
|
| - if (!reader.parse(manifest_json, dictionary_)) {
|
| - std::string json_error = reader.getFormatedErrorMessages();
|
| - error_info->SetReport(ERROR_MANIFEST_PARSING,
|
| - "manifest JSON parsing failed: " + json_error);
|
| - return false;
|
| - }
|
| - // Parse has ensured the string was valid JSON. Check that it matches the
|
| - // manifest schema.
|
| - return MatchesSchema(error_info);
|
| -}
|
| -
|
| -bool Manifest::MatchesSchema(ErrorInfo* error_info) {
|
| - pp::Var exception;
|
| - if (error_info == NULL) {
|
| - return false;
|
| - }
|
| - if (!dictionary_.isObject()) {
|
| - error_info->SetReport(
|
| - ERROR_MANIFEST_SCHEMA_VALIDATE,
|
| - "manifest: is not a json dictionary.");
|
| - return false;
|
| - }
|
| - Json::Value::Members members = dictionary_.getMemberNames();
|
| - for (size_t i = 0; i < members.size(); ++i) {
|
| - // The top level dictionary entries valid in the manifest file.
|
| - static const char* kManifestTopLevelProperties[] = { kProgramKey,
|
| - kInterpreterKey,
|
| - kFilesKey };
|
| - nacl::string property_name = members[i];
|
| - if (!FindMatchingProperty(property_name,
|
| - kManifestTopLevelProperties,
|
| - NACL_ARRAY_SIZE(kManifestTopLevelProperties))) {
|
| - PLUGIN_PRINTF(("Manifest::MatchesSchema: WARNING: unknown top-level "
|
| - "section '%s' in manifest.\n", property_name.c_str()));
|
| - }
|
| - }
|
| -
|
| - nacl::string error_string;
|
| -
|
| - // A manifest file must have a program section.
|
| - if (!dictionary_.isMember(kProgramKey)) {
|
| - error_info->SetReport(
|
| - ERROR_MANIFEST_SCHEMA_VALIDATE,
|
| - nacl::string("manifest: missing '") + kProgramKey + "' section.");
|
| - return false;
|
| - }
|
| -
|
| - // Validate the program section.
|
| - if (!IsValidISADictionary(dictionary_[kProgramKey],
|
| - sandbox_isa_,
|
| - &error_string)) {
|
| - error_info->SetReport(
|
| - ERROR_MANIFEST_SCHEMA_VALIDATE,
|
| - nacl::string("manifest: ") + kProgramKey + error_string);
|
| - return false;
|
| - }
|
| -
|
| - // Validate the interpreter section (if given).
|
| - if (dictionary_.isMember(kInterpreterKey)) {
|
| - if (!IsValidISADictionary(dictionary_[kProgramKey],
|
| - sandbox_isa_,
|
| - &error_string)) {
|
| - error_info->SetReport(
|
| - ERROR_MANIFEST_SCHEMA_VALIDATE,
|
| - nacl::string("manifest: ") + kInterpreterKey + error_string);
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - // Validate the file dictionary (if given).
|
| - if (dictionary_.isMember(kFilesKey)) {
|
| - const Json::Value& files = dictionary_[kFilesKey];
|
| - if (!files.isObject()) {
|
| - error_info->SetReport(
|
| - ERROR_MANIFEST_SCHEMA_VALIDATE,
|
| - nacl::string("manifest: '") + kFilesKey + "' is not a dictionary.");
|
| - }
|
| - Json::Value::Members members = files.getMemberNames();
|
| - for (size_t i = 0; i < members.size(); ++i) {
|
| - nacl::string property_name = members[i];
|
| - if (!IsValidISADictionary(files[property_name],
|
| - sandbox_isa_,
|
| - &error_string)) {
|
| - error_info->SetReport(
|
| - ERROR_MANIFEST_SCHEMA_VALIDATE,
|
| - nacl::string("manifest: file '") + property_name + "'" +
|
| - error_string);
|
| - return false;
|
| - }
|
| - }
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool Manifest::ResolveURL(const nacl::string& relative_url,
|
| - nacl::string* full_url,
|
| - ErrorInfo* error_info) const {
|
| - // The contents of the manifest are resolved relative to the manifest URL.
|
| - CHECK(url_util_ != NULL);
|
| - pp::Var resolved_url =
|
| - url_util_->ResolveRelativeToURL(pp::Var(manifest_base_url_),
|
| - relative_url);
|
| - if (!resolved_url.is_string()) {
|
| - error_info->SetReport(
|
| - ERROR_MANIFEST_RESOLVE_URL,
|
| - "could not resolve url '" + relative_url +
|
| - "' relative to manifest base url '" + manifest_base_url_.c_str() +
|
| - "'.");
|
| - return false;
|
| - }
|
| - *full_url = resolved_url.AsString();
|
| - return true;
|
| -}
|
| -
|
| -bool Manifest::GetProgramURL(nacl::string* full_url,
|
| - ErrorInfo* error_info,
|
| - bool* is_portable) {
|
| - if (full_url == NULL || error_info == NULL || is_portable == NULL)
|
| - return false;
|
| -
|
| - Json::Value program = dictionary_[kProgramKey];
|
| -
|
| - nacl::string nexe_url;
|
| - nacl::string error_string;
|
| -
|
| - if (!GetURLFromISADictionary(program,
|
| - sandbox_isa_,
|
| - &nexe_url,
|
| - &error_string,
|
| - is_portable)) {
|
| - error_info->SetReport(ERROR_MANIFEST_GET_NEXE_URL,
|
| - nacl::string("program:") + sandbox_isa_ +
|
| - error_string);
|
| - return false;
|
| - }
|
| -
|
| - return ResolveURL(nexe_url, full_url, error_info);
|
| -}
|
| -
|
| -bool Manifest::GetFileKeys(std::set<nacl::string>* keys) const {
|
| - if (!dictionary_.isMember(kFilesKey)) {
|
| - // trivial success: no keys when there is no "files" section.
|
| - return true;
|
| - }
|
| - const Json::Value& files = dictionary_[kFilesKey];
|
| - CHECK(files.isObject());
|
| - Json::Value::Members members = files.getMemberNames();
|
| - for (size_t i = 0; i < members.size(); ++i) {
|
| - keys->insert(members[i]);
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool Manifest::ResolveKey(const nacl::string& key,
|
| - nacl::string* full_url,
|
| - ErrorInfo* error_info,
|
| - bool* is_portable) const {
|
| - NaClLog(3, "Manifest::ResolveKey(%s)\n", key.c_str());
|
| - // key must be one of kProgramKey or kFileKey '/' file-section-key
|
| -
|
| - *full_url = "";
|
| - if (key == kProgramKey) {
|
| - nacl::string error_string;
|
| - if (!GetKeyUrl(dictionary_, key, sandbox_isa_,
|
| - full_url, &error_string, is_portable)) {
|
| - error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, error_string);
|
| - return false;
|
| - }
|
| - return true;
|
| - }
|
| - nacl::string::const_iterator p = find(key.begin(), key.end(), '/');
|
| - if (p == key.end()) {
|
| - error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL,
|
| - nacl::string("ResolveKey: invalid key, no slash: ")
|
| - + key);
|
| - return false;
|
| - }
|
| -
|
| - // generalize to permit other sections?
|
| - nacl::string prefix(key.begin(), p);
|
| - if (prefix != kFilesKey) {
|
| - error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL,
|
| - nacl::string("ResolveKey: invalid key: not \"files\""
|
| - " prefix: ") + key);
|
| - return false;
|
| - }
|
| -
|
| - nacl::string rest(p + 1, key.end());
|
| -
|
| - const Json::Value& files = dictionary_[kFilesKey];
|
| - CHECK(files.isObject());
|
| - if (!files.isMember(rest)) {
|
| - error_info->SetReport(
|
| - ERROR_MANIFEST_RESOLVE_URL,
|
| - nacl::string("ResolveKey: no such \"files\" entry: ") + key);
|
| - *is_portable = false;
|
| - return false;
|
| - }
|
| - nacl::string error_string;
|
| - if (!GetKeyUrl(files, rest, sandbox_isa_,
|
| - full_url, &error_string, is_portable)) {
|
| - error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, error_string);
|
| - *full_url = "";
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -// TODO(jvoung): We won't need these if we figure out how to install llc and ld.
|
| -bool Manifest::GetLLCURL(nacl::string* full_url, ErrorInfo* error_info) {
|
| - if (full_url == NULL || error_info == NULL)
|
| - return false;
|
| -
|
| - Json::Value pnacl_llc = dictionary_[kPnaclLlcKey];
|
| -
|
| - nacl::string nexe_url;
|
| - nacl::string error_string;
|
| - bool is_portable;
|
| - if (!GetURLFromISADictionary(pnacl_llc,
|
| - sandbox_isa_,
|
| - &nexe_url,
|
| - &error_string,
|
| - &is_portable)) {
|
| - error_info->SetReport(ERROR_MANIFEST_GET_NEXE_URL,
|
| - nacl::string(kPnaclLlcKey) + ":" + sandbox_isa_ +
|
| - error_string);
|
| - return false;
|
| - }
|
| -
|
| - if (is_portable) {
|
| - // Bootstrap problem -- we need this to translate portable programs!
|
| - error_info->SetReport(ERROR_MANIFEST_GET_NEXE_URL,
|
| - nacl::string(kPnaclLlcKey) +
|
| - " must be pre-translated for " + sandbox_isa_ + "!");
|
| - return false;
|
| - }
|
| -
|
| - return ResolveURL(nexe_url, full_url, error_info);
|
| -}
|
| -
|
| -bool Manifest::GetLDURL(nacl::string* full_url, ErrorInfo* error_info) {
|
| - if (full_url == NULL || error_info == NULL)
|
| - return false;
|
| -
|
| - Json::Value pnacl_ld = dictionary_[kPnaclLdKey];
|
| -
|
| - nacl::string nexe_url;
|
| - nacl::string error_string;
|
| - bool is_portable;
|
| - if (!GetURLFromISADictionary(pnacl_ld,
|
| - sandbox_isa_,
|
| - &nexe_url,
|
| - &error_string,
|
| - &is_portable)) {
|
| - error_info->SetReport(ERROR_MANIFEST_GET_NEXE_URL,
|
| - nacl::string(kPnaclLdKey) + ":" + sandbox_isa_ +
|
| - error_string);
|
| - return false;
|
| - }
|
| -
|
| - if (is_portable) {
|
| - // Bootstrap problem -- we need this to translate portable programs!
|
| - error_info->SetReport(ERROR_MANIFEST_GET_NEXE_URL,
|
| - nacl::string(kPnaclLdKey) +
|
| - " must be pre-translated for " + sandbox_isa_ + "!");
|
| - return false;
|
| - }
|
| -
|
| - return ResolveURL(nexe_url, full_url, error_info);
|
| -}
|
| -
|
| -} // namespace plugin
|
|
|