Commit db27cd40 authored by Julian Watson's avatar Julian Watson Committed by Commit Bot

crostini: share file not whole directory for export

BUG=chromium:987127

Change-Id: I5941380c70786e7c8d9f3b6c2d4a992944775a53
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1715170Reviewed-by: default avatarJoel Hockey <joelhockey@chromium.org>
Commit-Queue: Julian Watson <juwa@google.com>
Cr-Commit-Position: refs/heads/master@{#681088}
parent 20579950
...@@ -7,8 +7,10 @@ ...@@ -7,8 +7,10 @@
#include <utility> #include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file_util.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "base/time/time.h" #include "base/time/time.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_util.h" #include "chrome/browser/chromeos/crostini/crostini_util.h"
...@@ -175,12 +177,26 @@ void CrostiniExportImport::Start( ...@@ -175,12 +177,26 @@ void CrostiniExportImport::Start(
switch (type) { switch (type) {
case ExportImportType::EXPORT: case ExportImportType::EXPORT:
guest_os::GuestOsSharePath::GetForProfile(profile_)->SharePath( base::PostTaskWithTraitsAndReply(
kCrostiniDefaultVmName, path.DirName(), false, FROM_HERE, {base::MayBlock()},
// Ensure file exists so that it can be shared.
base::BindOnce(
[](const base::FilePath& path) {
base::File file(path, base::File::FLAG_CREATE_ALWAYS |
base::File::FLAG_WRITE);
DCHECK(file.IsValid()) << path << " is invalid";
},
path),
base::BindOnce(
&guest_os::GuestOsSharePath::SharePath,
base::Unretained(
guest_os::GuestOsSharePath::GetForProfile(profile_)),
kCrostiniDefaultVmName, path, false,
base::BindOnce(&CrostiniExportImport::ExportAfterSharing, base::BindOnce(&CrostiniExportImport::ExportAfterSharing,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(),
std::move(container_id), path.BaseName(), std::move(container_id), std::move(callback))
std::move(callback)));
));
break; break;
case ExportImportType::IMPORT: case ExportImportType::IMPORT:
guest_os::GuestOsSharePath::GetForProfile(profile_)->SharePath( guest_os::GuestOsSharePath::GetForProfile(profile_)->SharePath(
...@@ -194,7 +210,6 @@ void CrostiniExportImport::Start( ...@@ -194,7 +210,6 @@ void CrostiniExportImport::Start(
void CrostiniExportImport::ExportAfterSharing( void CrostiniExportImport::ExportAfterSharing(
const ContainerId& container_id, const ContainerId& container_id,
const base::FilePath& filename,
CrostiniManager::CrostiniResultCallback callback, CrostiniManager::CrostiniResultCallback callback,
const base::FilePath& container_path, const base::FilePath& container_path,
bool result, bool result,
...@@ -209,8 +224,7 @@ void CrostiniExportImport::ExportAfterSharing( ...@@ -209,8 +224,7 @@ void CrostiniExportImport::ExportAfterSharing(
return; return;
} }
CrostiniManager::GetForProfile(profile_)->ExportLxdContainer( CrostiniManager::GetForProfile(profile_)->ExportLxdContainer(
kCrostiniDefaultVmName, kCrostiniDefaultContainerName, kCrostiniDefaultVmName, kCrostiniDefaultContainerName, container_path,
container_path.Append(filename),
base::BindOnce(&CrostiniExportImport::OnExportComplete, base::BindOnce(&CrostiniExportImport::OnExportComplete,
weak_ptr_factory_.GetWeakPtr(), base::Time::Now(), weak_ptr_factory_.GetWeakPtr(), base::Time::Now(),
container_id, std::move(callback))); container_id, std::move(callback)));
...@@ -238,6 +252,10 @@ void CrostiniExportImport::OnExportComplete( ...@@ -238,6 +252,10 @@ void CrostiniExportImport::OnExportComplete(
} }
} else { } else {
LOG(ERROR) << "Error exporting " << int(result); LOG(ERROR) << "Error exporting " << int(result);
base::PostTaskWithTraits(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::BindOnce(base::IgnoreResult(&base::DeleteFile),
it->second->path(), false));
switch (result) { switch (result) {
case CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED: case CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED:
enum_hist_result = ExportContainerResult::kFailedVmStopped; enum_hist_result = ExportContainerResult::kFailedVmStopped;
......
...@@ -131,7 +131,6 @@ class CrostiniExportImport : public KeyedService, ...@@ -131,7 +131,6 @@ class CrostiniExportImport : public KeyedService,
uint64_t minimum_required_space) override; uint64_t minimum_required_space) override;
void ExportAfterSharing(const ContainerId& container_id, void ExportAfterSharing(const ContainerId& container_id,
const base::FilePath& filename,
CrostiniManager::CrostiniResultCallback callback, CrostiniManager::CrostiniResultCallback callback,
const base::FilePath& container_path, const base::FilePath& container_path,
bool result, bool result,
......
...@@ -55,6 +55,7 @@ class CrostiniExportImportNotification ...@@ -55,6 +55,7 @@ class CrostiniExportImportNotification
Status status() const { return status_; } Status status() const { return status_; }
ExportImportType type() const { return type_; } ExportImportType type() const { return type_; }
const base::FilePath& path() const { return path_; }
// Getters for testing. // Getters for testing.
message_center::Notification* get_notification() { message_center::Notification* get_notification() {
return notification_.get(); return notification_.get();
......
...@@ -174,6 +174,9 @@ TEST_F(CrostiniExportImportTest, TestDeprecatedExportSuccess) { ...@@ -174,6 +174,9 @@ TEST_F(CrostiniExportImportTest, TestDeprecatedExportSuccess) {
vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_DONE); vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_DONE);
EXPECT_EQ(notification->status(), EXPECT_EQ(notification->status(),
CrostiniExportImportNotification::Status::DONE); CrostiniExportImportNotification::Status::DONE);
// CrostiniExportImport should've created the exported file.
thread_bundle_.RunUntilIdle();
EXPECT_TRUE(base::PathExists(tarball_));
} }
TEST_F(CrostiniExportImportTest, TestExportSuccess) { TEST_F(CrostiniExportImportTest, TestExportSuccess) {
...@@ -229,6 +232,9 @@ TEST_F(CrostiniExportImportTest, TestExportSuccess) { ...@@ -229,6 +232,9 @@ TEST_F(CrostiniExportImportTest, TestExportSuccess) {
vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_DONE); vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_DONE);
EXPECT_EQ(notification->status(), EXPECT_EQ(notification->status(),
CrostiniExportImportNotification::Status::DONE); CrostiniExportImportNotification::Status::DONE);
// CrostiniExportImport should've created the exported file.
thread_bundle_.RunUntilIdle();
EXPECT_TRUE(base::PathExists(tarball_));
} }
TEST_F(CrostiniExportImportTest, TestExportFail) { TEST_F(CrostiniExportImportTest, TestExportFail) {
...@@ -243,6 +249,9 @@ TEST_F(CrostiniExportImportTest, TestExportFail) { ...@@ -243,6 +249,9 @@ TEST_F(CrostiniExportImportTest, TestExportFail) {
vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_FAILED); vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_FAILED);
EXPECT_EQ(notification->status(), EXPECT_EQ(notification->status(),
CrostiniExportImportNotification::Status::FAILED); CrostiniExportImportNotification::Status::FAILED);
// CrostiniExportImport should cleanup the file if an export fails.
thread_bundle_.RunUntilIdle();
EXPECT_FALSE(base::PathExists(tarball_));
} }
TEST_F(CrostiniExportImportTest, TestImportSuccess) { TEST_F(CrostiniExportImportTest, TestImportSuccess) {
......
...@@ -632,18 +632,20 @@ void GuestOsSharePath::CheckIfPathDeleted(const base::FilePath& path) { ...@@ -632,18 +632,20 @@ void GuestOsSharePath::CheckIfPathDeleted(const base::FilePath& path) {
return; return;
} }
// VolumeManager will be nullptr if running inside a test.
auto* vmgr = file_manager::VolumeManager::Get(profile_);
if (!vmgr) {
return;
}
// If we can't find the path, check if the volume was unmounted. // If we can't find the path, check if the volume was unmounted.
// FileWatchers may fire before VolumeManager::OnVolumeUnmounted. // FileWatchers may fire before VolumeManager::OnVolumeUnmounted.
bool volume_still_mounted = false; const auto volume_list = vmgr->GetVolumeList();
const std::vector<base::WeakPtr<file_manager::Volume>>& volume_list = const bool volume_still_mounted = std::any_of(
file_manager::VolumeManager::Get(profile_)->GetVolumeList(); volume_list.begin(), volume_list.end(), [&path](const auto& volume) {
for (const auto& volume : volume_list) { return (path == volume->mount_path() ||
if ((path == volume->mount_path() || volume->mount_path().IsParent(path)) && volume->mount_path().IsParent(path)) &&
base::PathExists(volume->mount_path())) { base::PathExists(volume->mount_path());
volume_still_mounted = true; });
break;
}
}
if (!volume_still_mounted) { if (!volume_still_mounted) {
return; return;
} }
......
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