blob: bcd03c5e92bfe5b103209b1805a405713eaa0120 [file] [log] [blame]
// Copyright 2016 The Chromium 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 "services/catalog/catalog.h"
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ptr_util.h"
#include "base/path_service.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/filesystem/directory_impl.h"
#include "components/filesystem/lock_table.h"
#include "components/filesystem/public/interfaces/types.mojom.h"
#include "services/catalog/constants.h"
#include "services/catalog/instance.h"
#include "services/catalog/reader.h"
#include "services/shell/public/cpp/connection.h"
#include "services/shell/public/cpp/service_context.h"
namespace catalog {
namespace {
bool IsPathNameValid(const std::string& name) {
if (name.empty() || name == "." || name == "..")
return false;
for (auto c : name) {
if (!base::IsAsciiAlpha(c) && !base::IsAsciiDigit(c) &&
c != '_' && c != '.')
return false;
}
return true;
}
base::FilePath GetPathForApplicationName(const std::string& application_name) {
std::string path = application_name;
const bool is_mojo =
base::StartsWith(path, "mojo:", base::CompareCase::INSENSITIVE_ASCII);
const bool is_exe =
!is_mojo &&
base::StartsWith(path, "exe:", base::CompareCase::INSENSITIVE_ASCII);
if (!is_mojo && !is_exe)
return base::FilePath();
if (path.find('.') != std::string::npos)
return base::FilePath();
if (is_mojo)
path.erase(path.begin(), path.begin() + 5);
else
path.erase(path.begin(), path.begin() + 4);
base::TrimString(path, "/", &path);
size_t end_of_name = path.find('/');
if (end_of_name != std::string::npos)
path.erase(path.begin() + end_of_name, path.end());
if (!IsPathNameValid(path))
return base::FilePath();
base::FilePath base_path;
PathService::Get(base::DIR_EXE, &base_path);
// TODO(beng): this won't handle user-specific components.
return base_path.AppendASCII(kPackagesDirName).AppendASCII(path).
AppendASCII("resources");
}
} // namespace
Catalog::Catalog(base::SequencedWorkerPool* worker_pool,
std::unique_ptr<Store> store,
ManifestProvider* manifest_provider)
: Catalog(std::move(store)) {
system_reader_.reset(new Reader(worker_pool, manifest_provider));
ScanSystemPackageDir();
}
Catalog::Catalog(base::SingleThreadTaskRunner* task_runner,
std::unique_ptr<Store> store,
ManifestProvider* manifest_provider)
: Catalog(std::move(store)) {
system_reader_.reset(new Reader(task_runner, manifest_provider));
ScanSystemPackageDir();
}
Catalog::~Catalog() {}
shell::mojom::ServicePtr Catalog::TakeService() {
return std::move(service_);
}
Catalog::Catalog(std::unique_ptr<Store> store)
: store_(std::move(store)), weak_factory_(this) {
shell::mojom::ServiceRequest request = GetProxy(&service_);
shell_connection_.reset(new shell::ServiceContext(this, std::move(request)));
}
void Catalog::ScanSystemPackageDir() {
base::FilePath system_package_dir;
PathService::Get(base::DIR_MODULE, &system_package_dir);
system_package_dir = system_package_dir.AppendASCII(kPackagesDirName);
system_reader_->Read(system_package_dir, &system_cache_,
base::Bind(&Catalog::SystemPackageDirScanned,
weak_factory_.GetWeakPtr()));
}
bool Catalog::OnConnect(const shell::Identity& remote_identity,
shell::InterfaceRegistry* registry) {
registry->AddInterface<mojom::Catalog>(this);
registry->AddInterface<filesystem::mojom::Directory>(this);
registry->AddInterface<shell::mojom::Resolver>(this);
return true;
}
void Catalog::Create(const shell::Identity& remote_identity,
shell::mojom::ResolverRequest request) {
Instance* instance = GetInstanceForUserId(remote_identity.user_id());
instance->BindResolver(std::move(request));
}
void Catalog::Create(const shell::Identity& remote_identity,
mojom::CatalogRequest request) {
Instance* instance = GetInstanceForUserId(remote_identity.user_id());
instance->BindCatalog(std::move(request));
}
void Catalog::Create(const shell::Identity& remote_identity,
filesystem::mojom::DirectoryRequest request) {
if (!lock_table_)
lock_table_ = new filesystem::LockTable;
base::FilePath resources_path =
GetPathForApplicationName(remote_identity.name());
new filesystem::DirectoryImpl(std::move(request), resources_path,
scoped_refptr<filesystem::SharedTempDir>(),
lock_table_);
}
Instance* Catalog::GetInstanceForUserId(const std::string& user_id) {
auto it = instances_.find(user_id);
if (it != instances_.end())
return it->second.get();
// TODO(beng): There needs to be a way to load the store from different users.
Instance* instance = new Instance(std::move(store_), system_reader_.get());
instances_[user_id] = base::WrapUnique(instance);
if (loaded_)
instance->CacheReady(&system_cache_);
return instance;
}
void Catalog::SystemPackageDirScanned() {
loaded_ = true;
for (auto& instance : instances_)
instance.second->CacheReady(&system_cache_);
}
} // namespace catalog