Commit 455760fe authored by Joel Hockey's avatar Joel Hockey Committed by Commit Bot

Crostini: re-share all paths with container at startup

Read list of persisted shared paths from prefs, and re-share
with seneschal/9p when container starts.

Bug: 878324
Change-Id: Iea0ff71b79e5787d06b9d1b42a985cea2fb2631b
Reviewed-on: https://chromium-review.googlesource.com/1232793
Commit-Queue: Joel Hockey <joelhockey@chromium.org>
Commit-Queue: Nicholas Verne <nverne@chromium.org>
Reviewed-by: default avatarNicholas Verne <nverne@chromium.org>
Reviewed-by: default avatarStuart Langley <slangley@chromium.org>
Cr-Commit-Position: refs/heads/master@{#592724}
parent 62cc38ff
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/crostini/crostini_manager_factory.h" #include "chrome/browser/chromeos/crostini/crostini_manager_factory.h"
#include "chrome/browser/chromeos/crostini/crostini_remover.h" #include "chrome/browser/chromeos/crostini/crostini_remover.h"
#include "chrome/browser/chromeos/crostini/crostini_share_path.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/chromeos/file_manager/path_util.h" #include "chrome/browser/chromeos/file_manager/path_util.h"
#include "chrome/browser/chromeos/file_manager/volume_manager.h" #include "chrome/browser/chromeos/file_manager/volume_manager.h"
...@@ -271,7 +272,8 @@ class CrostiniManager::CrostiniRestarter ...@@ -271,7 +272,8 @@ class CrostiniManager::CrostiniRestarter
return; return;
} }
// If default termina/penguin, then do sshfs mount, else we are finished. // If default termina/penguin, then do sshfs mount and reshare folders,
// else we are finished.
if (vm_name_ == kCrostiniDefaultVmName && if (vm_name_ == kCrostiniDefaultVmName &&
container_name_ == kCrostiniDefaultContainerName) { container_name_ == kCrostiniDefaultContainerName) {
crostini_manager_->GetContainerSshKeys( crostini_manager_->GetContainerSshKeys(
...@@ -348,11 +350,15 @@ class CrostiniManager::CrostiniRestarter ...@@ -348,11 +350,15 @@ class CrostiniManager::CrostiniRestarter
vmgr->AddSshfsCrostiniVolume(mount_path); vmgr->AddSshfsCrostiniVolume(mount_path);
} }
// Abort not checked until end of function. On abort, do not call // Abort not checked until end of function. On abort, do not continue,
// FinishRestart, but still remove observer and add volume as per above. // but still remove observer and add volume as per above.
if (is_aborted_) if (is_aborted_)
return; return;
FinishRestart(ConciergeClientResult::SUCCESS);
// Share folders from Downloads, etc with container.
ShareAllPaths(profile_,
base::BindOnce(&CrostiniRestarter::FinishRestart, this,
ConciergeClientResult::SUCCESS));
} }
Profile* profile_; Profile* profile_;
......
...@@ -4,67 +4,110 @@ ...@@ -4,67 +4,110 @@
#include "chrome/browser/chromeos/crostini/crostini_share_path.h" #include "chrome/browser/chromeos/crostini/crostini_share_path.h"
#include "base/barrier_closure.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file_util.h"
#include "base/optional.h" #include "base/optional.h"
#include "chrome/browser/chromeos/crostini/crostini_manager.h" #include "chrome/browser/chromeos/crostini/crostini_manager.h"
#include "chrome/browser/chromeos/crostini/crostini_pref_names.h" #include "chrome/browser/chromeos/crostini/crostini_pref_names.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/chromeos/file_manager/path_util.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chromeos/dbus/concierge/service.pb.h" #include "chromeos/dbus/concierge/service.pb.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/seneschal_client.h" #include "chromeos/dbus/seneschal_client.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "content/public/browser/browser_thread.h"
namespace crostini { namespace {
// static void OnSeneschalSharePathResponse(
CrostiniSharePath* CrostiniSharePath::GetInstance() { base::FilePath path,
return base::Singleton<CrostiniSharePath>::get(); base::OnceCallback<void(bool, std::string)> callback,
base::Optional<vm_tools::seneschal::SharePathResponse> response) {
if (!response) {
std::move(callback).Run(false, "System error");
return;
}
std::move(callback).Run(response.value().success(),
response.value().failure_reason());
} }
CrostiniSharePath::CrostiniSharePath() : weak_ptr_factory_(this) {} void CallSeneschalSharePath(
CrostiniSharePath::~CrostiniSharePath() {}
void CrostiniSharePath::SharePath(
Profile* profile, Profile* profile,
std::string vm_name, std::string vm_name,
std::string path, const base::FilePath path,
base::OnceCallback<void(bool, std::string)> callback) { base::OnceCallback<void(bool, std::string)> callback) {
// TODO(joelhockey): Save new path into prefs once management UI is ready. // Verify path is in one of the allowable mount points.
// This logic is similar to DownloadPrefs::SanitizeDownloadTargetPath().
// TODO(joelhockey): Seneschal currently only support sharing directories
// under Downloads.
if (!path.IsAbsolute()) {
std::move(callback).Run(false, "Path must be absolute");
return;
}
base::FilePath downloads =
file_manager::util::GetDownloadsFolderForProfile(profile);
base::FilePath relative_path;
if (!downloads.AppendRelativePath(path, &relative_path)) {
std::move(callback).Run(false, "Path must be under Downloads");
return;
}
// VM must be running.
base::Optional<vm_tools::concierge::VmInfo> vm_info = base::Optional<vm_tools::concierge::VmInfo> vm_info =
crostini::CrostiniManager::GetForProfile(profile)->GetVmInfo( crostini::CrostiniManager::GetForProfile(profile)->GetVmInfo(
std::move(vm_name)); std::move(vm_name));
if (!vm_info) { if (!vm_info) {
std::move(callback).Run(false, "Cannot share, VM not running"); std::move(callback).Run(false, "VM not running");
return;
}
// Path must be a valid directory.
if (!base::DirectoryExists(path)) {
std::move(callback).Run(false, "Path is not a valid directory");
return; return;
} }
vm_tools::seneschal::SharePathRequest request; vm_tools::seneschal::SharePathRequest request;
request.set_handle(vm_info->seneschal_server_handle()); request.set_handle(vm_info->seneschal_server_handle());
request.mutable_shared_path()->set_path(path); request.mutable_shared_path()->set_path(relative_path.value());
request.mutable_shared_path()->set_writable(true); request.mutable_shared_path()->set_writable(true);
request.set_storage_location( request.set_storage_location(
vm_tools::seneschal::SharePathRequest::DOWNLOADS); vm_tools::seneschal::SharePathRequest::DOWNLOADS);
request.set_owner_id(CryptohomeIdForProfile(profile)); request.set_owner_id(CryptohomeIdForProfile(profile));
chromeos::DBusThreadManager::Get()->GetSeneschalClient()->SharePath( chromeos::DBusThreadManager::Get()->GetSeneschalClient()->SharePath(
request, base::BindOnce(&CrostiniSharePath::OnSharePathResponse, request, base::BindOnce(&OnSeneschalSharePathResponse, std::move(path),
weak_ptr_factory_.GetWeakPtr(), std::move(path),
std::move(callback))); std::move(callback)));
} }
void CrostiniSharePath::OnSharePathResponse( void SharePathLogErrorCallback(std::string path,
std::string path, base::RepeatingClosure barrier,
base::OnceCallback<void(bool, std::string)> callback, bool success,
base::Optional<vm_tools::seneschal::SharePathResponse> response) const { std::string failure_reason) {
if (!response.has_value()) { barrier.Run();
std::move(callback).Run(false, "Error sharing " + path); if (!success) {
return; LOG(ERROR) << "Error SharePath=" << path
<< ", FailureReason=" << failure_reason;
} }
std::move(callback).Run(response.value().success(),
response.value().failure_reason());
} }
std::vector<std::string> CrostiniSharePath::GetSharedPaths(Profile* profile) { } // namespace
namespace crostini {
void SharePath(Profile* profile,
std::string vm_name,
const base::FilePath& path,
base::OnceCallback<void(bool, std::string)> callback) {
DCHECK(profile);
DCHECK(callback);
// TODO(joelhockey): Save new path into prefs once management UI is ready.
CallSeneschalSharePath(profile, vm_name, path, std::move(callback));
}
std::vector<std::string> GetSharedPaths(Profile* profile) {
DCHECK(profile);
std::vector<std::string> result; std::vector<std::string> result;
const base::ListValue* shared_paths = const base::ListValue* shared_paths =
profile->GetPrefs()->GetList(prefs::kCrostiniSharedPaths); profile->GetPrefs()->GetList(prefs::kCrostiniSharedPaths);
...@@ -74,4 +117,16 @@ std::vector<std::string> CrostiniSharePath::GetSharedPaths(Profile* profile) { ...@@ -74,4 +117,16 @@ std::vector<std::string> CrostiniSharePath::GetSharedPaths(Profile* profile) {
return result; return result;
} }
void ShareAllPaths(Profile* profile, base::OnceCallback<void()> callback) {
DCHECK(profile);
std::vector<std::string> paths = GetSharedPaths(profile);
base::RepeatingClosure barrier =
base::BarrierClosure(paths.size(), std::move(callback));
for (const auto& path : paths) {
CallSeneschalSharePath(
profile, kCrostiniDefaultVmName, base::FilePath(path),
base::BindOnce(&SharePathLogErrorCallback, std::move(path), barrier));
}
}
} // namespace crostini } // namespace crostini
...@@ -7,44 +7,27 @@ ...@@ -7,44 +7,27 @@
#include <vector> #include <vector>
#include "base/macros.h" #include "base/callback.h"
#include "base/memory/singleton.h" #include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "chromeos/dbus/seneschal/seneschal_service.pb.h" #include "chromeos/dbus/seneschal/seneschal_service.pb.h"
class Profile; class Profile;
namespace crostini { namespace crostini {
class CrostiniSharePath { // Share specified absolute path with vm.
public: // Callback receives success bool and failure reason string.
// Returns the singleton instance of CrostiniSharePath. void SharePath(Profile* profile,
static CrostiniSharePath* GetInstance(); std::string vm_name,
const base::FilePath& path,
base::OnceCallback<void(bool, std::string)> callback);
// Share specified path with vm. // Get list of all shared paths for the default crostini container.
void SharePath(Profile* profile, std::vector<std::string> GetSharedPaths(Profile* profile);
std::string vm_name,
std::string path,
base::OnceCallback<void(bool, std::string)> callback);
void OnSharePathResponse(
std::string path,
base::OnceCallback<void(bool, std::string)> callback,
base::Optional<vm_tools::seneschal::SharePathResponse> response) const;
// Get list of all shared paths for the default crostini container. // Share all paths configured in prefs for the default crostini container.
std::vector<std::string> GetSharedPaths(Profile* profile); // Called at container startup. Callback is invoked once complete.
void ShareAllPaths(Profile* profile, base::OnceCallback<void()> callback);
private:
friend struct base::DefaultSingletonTraits<CrostiniSharePath>;
CrostiniSharePath();
~CrostiniSharePath();
base::WeakPtrFactory<CrostiniSharePath> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CrostiniSharePath);
};
} // namespace crostini } // namespace crostini
......
...@@ -4,27 +4,38 @@ ...@@ -4,27 +4,38 @@
#include "chrome/browser/chromeos/crostini/crostini_share_path.h" #include "chrome/browser/chromeos/crostini/crostini_share_path.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/sys_info.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "chrome/browser/chromeos/crostini/crostini_manager.h" #include "chrome/browser/chromeos/crostini/crostini_manager.h"
#include "chrome/browser/chromeos/crostini/crostini_pref_names.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/chromeos/file_manager/path_util.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_cicerone_client.h" #include "chromeos/dbus/fake_cicerone_client.h"
#include "chromeos/dbus/fake_concierge_client.h" #include "chromeos/dbus/fake_concierge_client.h"
#include "chromeos/dbus/fake_seneschal_client.h" #include "chromeos/dbus/fake_seneschal_client.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace crostini { namespace crostini {
const char kLsbRelease[] =
"CHROMEOS_RELEASE_NAME=Chrome OS\n"
"CHROMEOS_RELEASE_VERSION=1.2.3.4\n";
class CrostiniSharePathTest : public testing::Test { class CrostiniSharePathTest : public testing::Test {
public: public:
void SharePathSuccessStartTerminaVmCallback(ConciergeClientResult result) { void SharePathSuccessStartTerminaVmCallback(ConciergeClientResult result) {
EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called()); EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
EXPECT_EQ(result, ConciergeClientResult::SUCCESS); EXPECT_EQ(result, ConciergeClientResult::SUCCESS);
CrostiniSharePath::GetInstance()->SharePath( SharePath(
profile(), "vm-running-success", "path", profile(), "success", share_path_,
base::BindOnce(&CrostiniSharePathTest::SharePathSuccessCallback, base::BindOnce(&CrostiniSharePathTest::SharePathSuccessCallback,
base::Unretained(this), run_loop()->QuitClosure())); base::Unretained(this), run_loop()->QuitClosure()));
} }
...@@ -38,22 +49,26 @@ class CrostiniSharePathTest : public testing::Test { ...@@ -38,22 +49,26 @@ class CrostiniSharePathTest : public testing::Test {
std::move(closure).Run(); std::move(closure).Run();
} }
void SharePathErrorStartTerminaVmCallback(ConciergeClientResult result) { void SharePathErrorSeneschalStartTerminaVmCallback(
ConciergeClientResult result) {
EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called()); EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
EXPECT_EQ(result, ConciergeClientResult::SUCCESS); EXPECT_EQ(result, ConciergeClientResult::SUCCESS);
CrostiniSharePath::GetInstance()->SharePath( SharePath(profile(), "error-seneschal", share_path_,
profile(), "vm-running-error", "path", base::BindOnce(&CrostiniSharePathTest::SharePathErrorCallback,
base::BindOnce(&CrostiniSharePathTest::SharePathErrorCallback, base::Unretained(this), true, "test failure",
base::Unretained(this), run_loop()->QuitClosure())); run_loop()->QuitClosure()));
} }
void SharePathErrorCallback(base::OnceClosure closure, void SharePathErrorCallback(bool expected_seneschal_client_called,
std::string expected_failure_reason,
base::OnceClosure closure,
bool success, bool success,
std::string failure_reason) { std::string failure_reason) {
EXPECT_TRUE(fake_seneschal_client_->share_path_called()); EXPECT_EQ(fake_seneschal_client_->share_path_called(),
expected_seneschal_client_called);
EXPECT_EQ(success, false); EXPECT_EQ(success, false);
EXPECT_EQ(failure_reason, "test failure"); EXPECT_EQ(failure_reason, expected_failure_reason);
std::move(closure).Run(); std::move(closure).Run();
} }
...@@ -83,16 +98,38 @@ class CrostiniSharePathTest : public testing::Test { ...@@ -83,16 +98,38 @@ class CrostiniSharePathTest : public testing::Test {
void SetUp() override { void SetUp() override {
run_loop_ = std::make_unique<base::RunLoop>(); run_loop_ = std::make_unique<base::RunLoop>();
profile_ = std::make_unique<TestingProfile>(); profile_ = std::make_unique<TestingProfile>();
// Fake that this is a real ChromeOS system in order to use TestingProfile
// /tmp path for Downloads rather than the current Linux user $HOME.
// SetChromeOSVersionInfoForTest() must not be called until D-Bus is
// initialized with fake clients, and then it must be cleared in TearDown()
// before D-Bus is re-initialized for the next test.
base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
// Setup Downloads and path to share.
downloads_ = file_manager::util::GetDownloadsFolderForProfile(profile());
share_path_ = downloads_.AppendASCII("path");
ASSERT_TRUE(base::CreateDirectory(share_path_));
// Create 'vm-running' VM instance which is running.
vm_tools::concierge::VmInfo vm_info;
CrostiniManager::GetForProfile(profile())->AddRunningVmForTesting(
"vm-running", vm_info);
} }
void TearDown() override { void TearDown() override {
run_loop_.reset(); run_loop_.reset();
profile_.reset(); profile_.reset();
// Clear SetChromeOSVersionInfoForTest() so D-Bus will use fake clients
// again in the next test.
base::SysInfo::SetChromeOSVersionInfoForTest("", base::Time());
} }
protected: protected:
base::RunLoop* run_loop() { return run_loop_.get(); } base::RunLoop* run_loop() { return run_loop_.get(); }
Profile* profile() { return profile_.get(); } Profile* profile() { return profile_.get(); }
base::FilePath downloads_;
base::FilePath share_path_;
// Owned by chromeos::DBusThreadManager // Owned by chromeos::DBusThreadManager
chromeos::FakeSeneschalClient* fake_seneschal_client_; chromeos::FakeSeneschalClient* fake_seneschal_client_;
...@@ -101,7 +138,6 @@ class CrostiniSharePathTest : public testing::Test { ...@@ -101,7 +138,6 @@ class CrostiniSharePathTest : public testing::Test {
std::unique_ptr<base::RunLoop> std::unique_ptr<base::RunLoop>
run_loop_; // run_loop_ must be created on the UI thread. run_loop_; // run_loop_ must be created on the UI thread.
std::unique_ptr<TestingProfile> profile_; std::unique_ptr<TestingProfile> profile_;
private: private:
base::test::ScopedTaskEnvironment scoped_task_environment_; base::test::ScopedTaskEnvironment scoped_task_environment_;
content::TestBrowserThreadBundle test_browser_thread_bundle_; content::TestBrowserThreadBundle test_browser_thread_bundle_;
...@@ -115,14 +151,14 @@ TEST_F(CrostiniSharePathTest, Success) { ...@@ -115,14 +151,14 @@ TEST_F(CrostiniSharePathTest, Success) {
fake_concierge_client_->set_start_vm_response(start_vm_response); fake_concierge_client_->set_start_vm_response(start_vm_response);
CrostiniManager::GetForProfile(profile())->StartTerminaVm( CrostiniManager::GetForProfile(profile())->StartTerminaVm(
"vm-running-success", base::FilePath("path"), "success", share_path_,
base::BindOnce( base::BindOnce(
&CrostiniSharePathTest::SharePathSuccessStartTerminaVmCallback, &CrostiniSharePathTest::SharePathSuccessStartTerminaVmCallback,
base::Unretained(this))); base::Unretained(this)));
run_loop()->Run(); run_loop()->Run();
} }
TEST_F(CrostiniSharePathTest, SharePathError) { TEST_F(CrostiniSharePathTest, SharePathErrorSeneschal) {
vm_tools::concierge::StartVmResponse start_vm_response; vm_tools::concierge::StartVmResponse start_vm_response;
start_vm_response.set_success(true); start_vm_response.set_success(true);
start_vm_response.mutable_vm_info()->set_seneschal_server_handle(123); start_vm_response.mutable_vm_info()->set_seneschal_server_handle(123);
...@@ -134,18 +170,61 @@ TEST_F(CrostiniSharePathTest, SharePathError) { ...@@ -134,18 +170,61 @@ TEST_F(CrostiniSharePathTest, SharePathError) {
fake_seneschal_client_->set_share_path_response(share_path_response); fake_seneschal_client_->set_share_path_response(share_path_response);
CrostiniManager::GetForProfile(profile())->StartTerminaVm( CrostiniManager::GetForProfile(profile())->StartTerminaVm(
"vm-running-error", base::FilePath("path"), "error-seneschal", share_path_,
base::BindOnce( base::BindOnce(
&CrostiniSharePathTest::SharePathErrorStartTerminaVmCallback, &CrostiniSharePathTest::SharePathErrorSeneschalStartTerminaVmCallback,
base::Unretained(this))); base::Unretained(this)));
run_loop()->Run(); run_loop()->Run();
} }
TEST_F(CrostiniSharePathTest, SharePathErrorPathNotAbsolute) {
const base::FilePath path("not/absolute/dir");
SharePath(profile(), "vm-running", path,
base::BindOnce(&CrostiniSharePathTest::SharePathErrorCallback,
base::Unretained(this), false,
"Path must be absolute", run_loop()->QuitClosure()));
run_loop()->Run();
}
TEST_F(CrostiniSharePathTest, SharePathErrorNotUnderDownloads) {
const base::FilePath path("/not/under/downloads");
SharePath(profile(), "vm-running", path,
base::BindOnce(&CrostiniSharePathTest::SharePathErrorCallback,
base::Unretained(this), false,
"Path must be under Downloads",
run_loop()->QuitClosure()));
run_loop()->Run();
}
TEST_F(CrostiniSharePathTest, SharePathErrorVmNotRunning) { TEST_F(CrostiniSharePathTest, SharePathErrorVmNotRunning) {
CrostiniSharePath::GetInstance()->SharePath( SharePath(profile(), "error-vm-not-running", share_path_,
profile(), "vm-not-running", "path", base::BindOnce(&CrostiniSharePathTest::SharePathErrorCallback,
base::BindOnce(&CrostiniSharePathTest::SharePathErrorVmNotRunningCallback, base::Unretained(this), false, "VM not running",
base::Unretained(this), run_loop()->QuitClosure())); run_loop()->QuitClosure()));
run_loop()->Run();
}
TEST_F(CrostiniSharePathTest, SharePathErrorNotValidDirectory) {
const base::FilePath path = share_path_.AppendASCII("not-exists");
SharePath(profile(), "vm-running", path,
base::BindOnce(&CrostiniSharePathTest::SharePathErrorCallback,
base::Unretained(this), false,
"Path is not a valid directory",
run_loop()->QuitClosure()));
run_loop()->Run();
}
TEST_F(CrostiniSharePathTest, ShareAllPaths) {
base::FilePath share_path2_ = downloads_.AppendASCII("path");
ASSERT_TRUE(base::CreateDirectory(share_path2_));
vm_tools::concierge::VmInfo vm_info;
CrostiniManager::GetForProfile(profile())->AddRunningVmForTesting(
kCrostiniDefaultVmName, vm_info);
base::ListValue shared_paths = base::ListValue();
shared_paths.GetList().push_back(base::Value(share_path_.value()));
shared_paths.GetList().push_back(base::Value(share_path2_.value()));
profile()->GetPrefs()->Set(prefs::kCrostiniSharedPaths, shared_paths);
ShareAllPaths(profile(), run_loop()->QuitClosure());
run_loop()->Run(); run_loop()->Run();
} }
......
...@@ -692,20 +692,8 @@ FileManagerPrivateInternalSharePathWithCrostiniFunction::Run() { ...@@ -692,20 +692,8 @@ FileManagerPrivateInternalSharePathWithCrostiniFunction::Run() {
storage::FileSystemURL cracked = storage::FileSystemURL cracked =
file_system_context->CrackURL(GURL(params->url)); file_system_context->CrackURL(GURL(params->url));
// TODO(joelhockey): Seneschal currently only supports sharing crostini::SharePath(
// directories under Downloads. profile, kCrostiniDefaultVmName, cracked.path(),
std::string downloads_mount_name =
file_manager::util::GetDownloadsMountPointName(profile);
if (cracked.filesystem_id() != downloads_mount_name) {
return RespondNow(Error(
"Share with Linux only allowed for directories within Downloads."));
}
// Path must be relative under Downloads/
std::string share_path =
cracked.virtual_path().value().substr(downloads_mount_name.size() + 1);
crostini::CrostiniSharePath::GetInstance()->SharePath(
profile, kCrostiniDefaultVmName, share_path,
base::BindOnce(&FileManagerPrivateInternalSharePathWithCrostiniFunction:: base::BindOnce(&FileManagerPrivateInternalSharePathWithCrostiniFunction::
SharePathCallback, SharePathCallback,
this)); this));
...@@ -723,14 +711,13 @@ ExtensionFunction::ResponseAction ...@@ -723,14 +711,13 @@ ExtensionFunction::ResponseAction
FileManagerPrivateInternalGetCrostiniSharedPathsFunction::Run() { FileManagerPrivateInternalGetCrostiniSharedPathsFunction::Run() {
Profile* profile = Profile::FromBrowserContext(browser_context()); Profile* profile = Profile::FromBrowserContext(browser_context());
file_manager::util::FileDefinitionList file_definition_list; file_manager::util::FileDefinitionList file_definition_list;
auto shared_paths = auto shared_paths = crostini::GetSharedPaths(profile);
crostini::CrostiniSharePath::GetInstance()->GetSharedPaths(profile);
for (const std::string& path : shared_paths) { for (const std::string& path : shared_paths) {
file_manager::util::FileDefinition file_definition; file_manager::util::FileDefinition file_definition;
// All shared paths should be directories. Even if this is not true, it // All shared paths should be directories. Even if this is not true, it
// is fine for foreground/js/crostini.js class to think so. // is fine for foreground/js/crostini.js class to think so.
// We verify that the paths are in fact valid directories before calling // We verify that the paths are in fact valid directories before calling
// seneschal/9p. // seneschal/9p in CrostiniSharePath::CallSeneschalSharePath().
file_definition.is_directory = true; file_definition.is_directory = true;
if (file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath( if (file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
profile, extension_id(), base::FilePath(path), profile, extension_id(), base::FilePath(path),
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "net/base/escape.h" #include "net/base/escape.h"
#include "net/base/filename_util.h" #include "net/base/filename_util.h"
#include "storage/browser/fileapi/external_mount_points.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -87,6 +88,15 @@ const base::FilePath::CharType kAndroidFilesPath[] = ...@@ -87,6 +88,15 @@ const base::FilePath::CharType kAndroidFilesPath[] =
FILE_PATH_LITERAL("/run/arc/sdcard/write/emulated/0"); FILE_PATH_LITERAL("/run/arc/sdcard/write/emulated/0");
base::FilePath GetDownloadsFolderForProfile(Profile* profile) { base::FilePath GetDownloadsFolderForProfile(Profile* profile) {
// Check if FilesApp has a registered path already. This happens for tests.
const std::string mount_point_name =
util::GetDownloadsMountPointName(profile);
storage::ExternalMountPoints* const mount_points =
storage::ExternalMountPoints::GetSystemInstance();
base::FilePath path;
if (mount_points->GetRegisteredPath(mount_point_name, &path))
return path;
// On non-ChromeOS system (test+development), the primary profile uses // On non-ChromeOS system (test+development), the primary profile uses
// $HOME/Downloads for ease for accessing local files for debugging. // $HOME/Downloads for ease for accessing local files for debugging.
if (!base::SysInfo::IsRunningOnChromeOS() && if (!base::SysInfo::IsRunningOnChromeOS() &&
...@@ -99,6 +109,8 @@ base::FilePath GetDownloadsFolderForProfile(Profile* profile) { ...@@ -99,6 +109,8 @@ base::FilePath GetDownloadsFolderForProfile(Profile* profile) {
if (user == primary_user) if (user == primary_user)
return DownloadPrefs::GetDefaultDownloadDirectory(); return DownloadPrefs::GetDefaultDownloadDirectory();
} }
// Return <cryptohome>/Downloads.
return profile->GetPath().AppendASCII(kDownloadsFolderName); return profile->GetPath().AppendASCII(kDownloadsFolderName);
} }
......
...@@ -47,9 +47,7 @@ chrome.test.runTests([ ...@@ -47,9 +47,7 @@ chrome.test.runTests([
function testSharePathWithCrostiniNotDownloads() { function testSharePathWithCrostiniNotDownloads() {
getEntry('testing', 'test_dir').then((entry) => { getEntry('testing', 'test_dir').then((entry) => {
chrome.fileManagerPrivate.sharePathWithCrostini( chrome.fileManagerPrivate.sharePathWithCrostini(
entry, entry, chrome.test.callbackFail('Path must be under Downloads'));
chrome.test.callbackFail(
'Share with Linux only allowed for directories within Downloads.'));
}); });
}, },
function testGetCrostiniSharedPaths() { function testGetCrostiniSharedPaths() {
......
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