Commit cbb33eaa authored by Joel Hockey's avatar Joel Hockey Committed by Commit Bot

Add crostini unshare path

Unshares a path previously shared, and removes path from prefs.

Bug: 878324
Change-Id: I9655c16851eed2eccca225fc3d9642db21b51dde
Reviewed-on: https://chromium-review.googlesource.com/c/1317212
Commit-Queue: Joel Hockey <joelhockey@chromium.org>
Reviewed-by: default avatarRyo Hashimoto <hashimoto@chromium.org>
Reviewed-by: default avatarNicholas Verne <nverne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#608290}
parent 3cb93d0a
...@@ -59,6 +59,17 @@ void OnVmRestartedForSeneschal( ...@@ -59,6 +59,17 @@ void OnVmRestartedForSeneschal(
base::BindOnce(&OnSeneschalSharePathResponse, std::move(callback))); base::BindOnce(&OnSeneschalSharePathResponse, std::move(callback)));
} }
void OnSeneschalUnsharePathResponse(
base::OnceCallback<void(bool, std::string)> callback,
base::Optional<vm_tools::seneschal::UnsharePathResponse> response) {
if (!response) {
std::move(callback).Run(false, "System error");
return;
}
std::move(callback).Run(response.value().success(),
response.value().failure_reason());
}
// Barrier Closure that captures the first instance of error. // Barrier Closure that captures the first instance of error.
class ErrorCapture { class ErrorCapture {
public: public:
...@@ -223,6 +234,48 @@ void CrostiniSharePath::CallSeneschalSharePath( ...@@ -223,6 +234,48 @@ void CrostiniSharePath::CallSeneschalSharePath(
base::BindOnce(&OnSeneschalSharePathResponse, std::move(callback))); base::BindOnce(&OnSeneschalSharePathResponse, std::move(callback)));
} }
void CrostiniSharePath::CallSeneschalUnsharePath(
std::string vm_name,
const base::FilePath& path,
base::OnceCallback<void(bool, std::string)> callback) {
// Return success if VM is not currently running.
auto* crostini_manager = crostini::CrostiniManager::GetForProfile(profile_);
base::Optional<vm_tools::concierge::VmInfo> vm_info =
crostini_manager->GetVmInfo(vm_name);
if (!vm_info) {
std::move(callback).Run(true, "VM not running");
return;
}
// Convert path to a virtual path relative to one of the external mounts,
// then get it as a FilesSystemURL to convert to a path inside crostini,
// then remove /mnt/chromeos/ base dir prefix to get the path to unshare.
storage::ExternalMountPoints* mount_points =
storage::ExternalMountPoints::GetSystemInstance();
base::FilePath virtual_path;
base::FilePath inside;
bool result = mount_points->GetVirtualPath(path, &virtual_path);
if (result) {
storage::FileSystemURL url = mount_points->CreateCrackedFileSystemURL(
GURL(), storage::kFileSystemTypeExternal, virtual_path);
result = file_manager::util::ConvertFileSystemURLToPathInsideCrostini(
profile_, url, &inside);
}
base::FilePath unshare_path;
if (!result || !crostini::ContainerChromeOSBaseDirectory().AppendRelativePath(
inside, &unshare_path)) {
std::move(callback).Run(false, "Invalid path to unshare");
return;
}
vm_tools::seneschal::UnsharePathRequest request;
request.set_handle(vm_info->seneschal_server_handle());
request.set_path(unshare_path.value());
chromeos::DBusThreadManager::Get()->GetSeneschalClient()->UnsharePath(
request,
base::BindOnce(&OnSeneschalUnsharePathResponse, std::move(callback)));
}
void CrostiniSharePath::SharePath( void CrostiniSharePath::SharePath(
std::string vm_name, std::string vm_name,
const base::FilePath& path, const base::FilePath& path,
...@@ -246,7 +299,7 @@ void CrostiniSharePath::SharePaths( ...@@ -246,7 +299,7 @@ void CrostiniSharePath::SharePaths(
&ErrorCapture::Run, &ErrorCapture::Run,
base::Owned(new ErrorCapture(paths.size(), std::move(callback)))); base::Owned(new ErrorCapture(paths.size(), std::move(callback))));
for (const auto& path : paths) { for (const auto& path : paths) {
CallSeneschalSharePath(kCrostiniDefaultVmName, path, persist, CallSeneschalSharePath(vm_name, path, persist,
base::BindOnce(barrier, std::move(path))); base::BindOnce(barrier, std::move(path)));
} }
} }
...@@ -258,10 +311,9 @@ void CrostiniSharePath::UnsharePath( ...@@ -258,10 +311,9 @@ void CrostiniSharePath::UnsharePath(
PrefService* pref_service = profile_->GetPrefs(); PrefService* pref_service = profile_->GetPrefs();
ListPrefUpdate update(pref_service, crostini::prefs::kCrostiniSharedPaths); ListPrefUpdate update(pref_service, crostini::prefs::kCrostiniSharedPaths);
base::ListValue* shared_paths = update.Get(); base::ListValue* shared_paths = update.Get();
shared_paths->Remove(base::Value(path.value()), nullptr); if (!shared_paths->Remove(base::Value(path.value()), nullptr))
// TODO(joelhockey): Call to seneschal once UnsharePath is supported, LOG(WARNING) << "Unshared path not in prefs: " << path.value();
// and update FilesApp to watch for changes. CallSeneschalUnsharePath(vm_name, path, std::move(callback));
std::move(callback).Run(true, "");
for (Observer& observer : observers_) { for (Observer& observer : observers_) {
observer.OnUnshare(path); observer.OnUnshare(path);
} }
......
...@@ -65,14 +65,17 @@ class CrostiniSharePathTest : public testing::Test { ...@@ -65,14 +65,17 @@ class CrostiniSharePathTest : public testing::Test {
EXPECT_EQ(fake_seneschal_client_->share_path_called(), EXPECT_EQ(fake_seneschal_client_->share_path_called(),
expected_seneschal_client_called == SeneschalClientCalled::YES); expected_seneschal_client_called == SeneschalClientCalled::YES);
if (expected_seneschal_client_called == SeneschalClientCalled::YES) { if (expected_seneschal_client_called == SeneschalClientCalled::YES) {
EXPECT_EQ(fake_seneschal_client_->last_request().storage_location(), EXPECT_EQ(
*expected_seneschal_storage_location); fake_seneschal_client_->last_share_path_request().storage_location(),
EXPECT_EQ(fake_seneschal_client_->last_request().shared_path().path(), *expected_seneschal_storage_location);
EXPECT_EQ(fake_seneschal_client_->last_share_path_request()
.shared_path()
.path(),
expected_seneschal_path); expected_seneschal_path);
} }
EXPECT_EQ(success, expected_success == Success::YES); EXPECT_EQ(success, expected_success == Success::YES);
EXPECT_EQ(failure_reason, expected_failure_reason); EXPECT_EQ(failure_reason, expected_failure_reason);
run_loop()->QuitClosure().Run(); run_loop()->Quit();
} }
void SharePersistedPathsCallback(bool success, std::string failure_reason) { void SharePersistedPathsCallback(bool success, std::string failure_reason) {
...@@ -80,7 +83,7 @@ class CrostiniSharePathTest : public testing::Test { ...@@ -80,7 +83,7 @@ class CrostiniSharePathTest : public testing::Test {
EXPECT_EQ( EXPECT_EQ(
profile()->GetPrefs()->GetList(prefs::kCrostiniSharedPaths)->GetSize(), profile()->GetPrefs()->GetList(prefs::kCrostiniSharedPaths)->GetSize(),
2U); 2U);
run_loop()->QuitClosure().Run(); run_loop()->Quit();
} }
void SharePathErrorVmNotRunningCallback(base::OnceClosure closure, void SharePathErrorVmNotRunningCallback(base::OnceClosure closure,
...@@ -92,6 +95,28 @@ class CrostiniSharePathTest : public testing::Test { ...@@ -92,6 +95,28 @@ class CrostiniSharePathTest : public testing::Test {
std::move(closure).Run(); std::move(closure).Run();
} }
void UnsharePathCallback(
const base::FilePath& path,
SeneschalClientCalled expected_seneschal_client_called,
std::string expected_seneschal_path,
Success expected_success,
std::string expected_failure_reason,
bool success,
std::string failure_reason) {
const base::ListValue* prefs =
profile()->GetPrefs()->GetList(prefs::kCrostiniSharedPaths);
EXPECT_EQ(prefs->Find(base::Value(path.value())), prefs->end());
EXPECT_EQ(fake_seneschal_client_->unshare_path_called(),
expected_seneschal_client_called == SeneschalClientCalled::YES);
if (expected_seneschal_client_called == SeneschalClientCalled::YES) {
EXPECT_EQ(fake_seneschal_client_->last_unshare_path_request().path(),
expected_seneschal_path);
}
EXPECT_EQ(success, expected_success == Success::YES);
EXPECT_EQ(failure_reason, expected_failure_reason);
run_loop()->Quit();
}
CrostiniSharePathTest() CrostiniSharePathTest()
: scoped_task_environment_( : scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI), base::test::ScopedTaskEnvironment::MainThreadType::UI),
...@@ -481,4 +506,34 @@ TEST_F(CrostiniSharePathTest, RegisterPersistedPaths) { ...@@ -481,4 +506,34 @@ TEST_F(CrostiniSharePathTest, RegisterPersistedPaths) {
EXPECT_EQ(path, "/"); EXPECT_EQ(path, "/");
} }
TEST_F(CrostiniSharePathTest, UnsharePathSuccess) {
crostini_share_path()->UnsharePath(
"vm-running", shared_path_,
base::BindOnce(&CrostiniSharePathTest::UnsharePathCallback,
base::Unretained(this), shared_path_,
SeneschalClientCalled::YES,
"MyFiles/Downloads/already-shared", Success::YES, ""));
run_loop()->Run();
}
TEST_F(CrostiniSharePathTest, UnsharePathVmNotRunning) {
crostini_share_path()->UnsharePath(
"vm-not-running", shared_path_,
base::BindOnce(&CrostiniSharePathTest::UnsharePathCallback,
base::Unretained(this), shared_path_,
SeneschalClientCalled::NO, "", Success::YES,
"VM not running"));
run_loop()->Run();
}
TEST_F(CrostiniSharePathTest, UnsharePathInvalidPath) {
base::FilePath invalid("invalid/path");
crostini_share_path()->UnsharePath(
"vm-running", invalid,
base::BindOnce(&CrostiniSharePathTest::UnsharePathCallback,
base::Unretained(this), invalid, SeneschalClientCalled::NO,
"", Success::NO, "Invalid path to unshare"));
run_loop()->Run();
}
} // namespace crostini } // namespace crostini
...@@ -13,6 +13,7 @@ namespace chromeos { ...@@ -13,6 +13,7 @@ namespace chromeos {
FakeSeneschalClient::FakeSeneschalClient() { FakeSeneschalClient::FakeSeneschalClient() {
share_path_response_.set_success(true); share_path_response_.set_success(true);
share_path_response_.set_path("foo"); share_path_response_.set_path("foo");
unshare_path_response_.set_success(true);
} }
FakeSeneschalClient::~FakeSeneschalClient() = default; FakeSeneschalClient::~FakeSeneschalClient() = default;
...@@ -21,9 +22,18 @@ void FakeSeneschalClient::SharePath( ...@@ -21,9 +22,18 @@ void FakeSeneschalClient::SharePath(
const vm_tools::seneschal::SharePathRequest& request, const vm_tools::seneschal::SharePathRequest& request,
DBusMethodCallback<vm_tools::seneschal::SharePathResponse> callback) { DBusMethodCallback<vm_tools::seneschal::SharePathResponse> callback) {
share_path_called_ = true; share_path_called_ = true;
last_request_ = request; last_share_path_request_ = request;
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), share_path_response_)); FROM_HERE, base::BindOnce(std::move(callback), share_path_response_));
} }
void FakeSeneschalClient::UnsharePath(
const vm_tools::seneschal::UnsharePathRequest& request,
DBusMethodCallback<vm_tools::seneschal::UnsharePathResponse> callback) {
unshare_path_called_ = true;
last_unshare_path_request_ = request;
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), unshare_path_response_));
}
} // namespace chromeos } // namespace chromeos
...@@ -21,16 +21,30 @@ class CHROMEOS_EXPORT FakeSeneschalClient : public SeneschalClient { ...@@ -21,16 +21,30 @@ class CHROMEOS_EXPORT FakeSeneschalClient : public SeneschalClient {
void SharePath(const vm_tools::seneschal::SharePathRequest& request, void SharePath(const vm_tools::seneschal::SharePathRequest& request,
DBusMethodCallback<vm_tools::seneschal::SharePathResponse> DBusMethodCallback<vm_tools::seneschal::SharePathResponse>
callback) override; callback) override;
void UnsharePath(const vm_tools::seneschal::UnsharePathRequest& request,
DBusMethodCallback<vm_tools::seneschal::UnsharePathResponse>
callback) override;
bool share_path_called() const { return share_path_called_; } bool share_path_called() const { return share_path_called_; }
bool unshare_path_called() const { return unshare_path_called_; }
void set_share_path_response( void set_share_path_response(
const vm_tools::seneschal::SharePathResponse& share_path_response) { const vm_tools::seneschal::SharePathResponse& share_path_response) {
share_path_response_ = share_path_response; share_path_response_ = share_path_response;
} }
const vm_tools::seneschal::SharePathRequest& last_request() const { void set_unshare_path_response(
return last_request_; const vm_tools::seneschal::UnsharePathResponse& unshare_path_response) {
unshare_path_response_ = unshare_path_response;
}
const vm_tools::seneschal::SharePathRequest& last_share_path_request() const {
return last_share_path_request_;
}
const vm_tools::seneschal::UnsharePathRequest& last_unshare_path_request()
const {
return last_unshare_path_request_;
} }
protected: protected:
...@@ -40,9 +54,12 @@ class CHROMEOS_EXPORT FakeSeneschalClient : public SeneschalClient { ...@@ -40,9 +54,12 @@ class CHROMEOS_EXPORT FakeSeneschalClient : public SeneschalClient {
void InitializeProtoResponses(); void InitializeProtoResponses();
bool share_path_called_ = false; bool share_path_called_ = false;
bool unshare_path_called_ = false;
vm_tools::seneschal::SharePathRequest last_request_; vm_tools::seneschal::SharePathRequest last_share_path_request_;
vm_tools::seneschal::UnsharePathRequest last_unshare_path_request_;
vm_tools::seneschal::SharePathResponse share_path_response_; vm_tools::seneschal::SharePathResponse share_path_response_;
vm_tools::seneschal::UnsharePathResponse unshare_path_response_;
DISALLOW_COPY_AND_ASSIGN(FakeSeneschalClient); DISALLOW_COPY_AND_ASSIGN(FakeSeneschalClient);
}; };
......
...@@ -44,6 +44,27 @@ class SeneschalClientImpl : public SeneschalClient { ...@@ -44,6 +44,27 @@ class SeneschalClientImpl : public SeneschalClient {
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} }
void UnsharePath(const vm_tools::seneschal::UnsharePathRequest& request,
DBusMethodCallback<vm_tools::seneschal::UnsharePathResponse>
callback) override {
dbus::MethodCall method_call(vm_tools::seneschal::kSeneschalInterface,
vm_tools::seneschal::kUnsharePathMethod);
dbus::MessageWriter writer(&method_call);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode UnsharePath protobuf";
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
return;
}
seneschal_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&SeneschalClientImpl::OnDBusProtoResponse<
vm_tools::seneschal::UnsharePathResponse>,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
protected: protected:
void Init(dbus::Bus* bus) override { void Init(dbus::Bus* bus) override {
seneschal_proxy_ = bus->GetObjectProxy( seneschal_proxy_ = bus->GetObjectProxy(
......
...@@ -28,6 +28,13 @@ class CHROMEOS_EXPORT SeneschalClient : public DBusClient { ...@@ -28,6 +28,13 @@ class CHROMEOS_EXPORT SeneschalClient : public DBusClient {
const vm_tools::seneschal::SharePathRequest& request, const vm_tools::seneschal::SharePathRequest& request,
DBusMethodCallback<vm_tools::seneschal::SharePathResponse> callback) = 0; DBusMethodCallback<vm_tools::seneschal::SharePathResponse> callback) = 0;
// Unshares a path in the Chrome OS host with the container.
// |callback| is called after the method call finishes.
virtual void UnsharePath(
const vm_tools::seneschal::UnsharePathRequest& request,
DBusMethodCallback<vm_tools::seneschal::UnsharePathResponse>
callback) = 0;
protected: protected:
// Create() should be used instead. // Create() should be used instead.
SeneschalClient(); SeneschalClient();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment