Commit 6dd41eba authored by Omid Tourzan's avatar Omid Tourzan Committed by Commit Bot

[partition-as-single] Add single partition format for removable device.

Add SinglePartitionFormat method to cros-disk client. It supposed to
remove all existing partition on the disk, create a new one and format
it.

It tracks pending partitioning disks to prevent auto-mounting when
partitioning finished, otherwise there will be conflict between
auto-mount (initiated by kernel reread partition table) and format flow.

The key to get device path of newly created partition is storage device
path that is identical with parent device.

Bug: 491043
Change-Id: I026e72dc499a55bb99f2e5f7bf5707f08c4fb393
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2340347Reviewed-by: default avatarAustin Tankiang <austinct@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Commit-Queue: Omid Tourzan <oto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812508}
parent baa21ca9
......@@ -119,6 +119,31 @@ void DeviceEventRouter::OnFormatCompleted(const std::string& device_path,
device_path, device_label);
}
void DeviceEventRouter::OnPartitionStarted(const std::string& device_path,
const std::string& device_label,
bool success) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (success) {
OnDeviceEvent(file_manager_private::DEVICE_EVENT_TYPE_PARTITION_START,
device_path, device_label);
} else {
OnDeviceEvent(file_manager_private::DEVICE_EVENT_TYPE_PARTITION_FAIL,
device_path, device_label);
}
}
void DeviceEventRouter::OnPartitionCompleted(const std::string& device_path,
const std::string& device_label,
bool success) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
OnDeviceEvent(success
? file_manager_private::DEVICE_EVENT_TYPE_PARTITION_SUCCESS
: file_manager_private::DEVICE_EVENT_TYPE_PARTITION_FAIL,
device_path, device_label);
}
void DeviceEventRouter::OnRenameStarted(const std::string& device_path,
const std::string& device_label,
bool success) {
......
......@@ -56,6 +56,12 @@ class DeviceEventRouter : public VolumeManagerObserver,
void OnFormatCompleted(const std::string& device_path,
const std::string& device_label,
bool success) override;
void OnPartitionStarted(const std::string& device_path,
const std::string& device_label,
bool success) override;
void OnPartitionCompleted(const std::string& device_path,
const std::string& device_label,
bool success) override;
void OnRenameStarted(const std::string& device_path,
const std::string& device_label,
bool success) override;
......
......@@ -842,6 +842,20 @@ void EventRouter::OnFormatCompleted(const std::string& device_path,
// Do nothing.
}
void EventRouter::OnPartitionStarted(const std::string& device_path,
const std::string& device_label,
bool success) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Do nothing.
}
void EventRouter::OnPartitionCompleted(const std::string& device_path,
const std::string& device_label,
bool success) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Do nothing.
}
void EventRouter::OnRenameStarted(const std::string& device_path,
const std::string& device_label,
bool success) {
......
......@@ -136,6 +136,12 @@ class EventRouter
void OnFormatCompleted(const std::string& device_path,
const std::string& device_label,
bool success) override;
void OnPartitionStarted(const std::string& device_path,
const std::string& device_label,
bool success) override;
void OnPartitionCompleted(const std::string& device_path,
const std::string& device_label,
bool success) override;
void OnRenameStarted(const std::string& device_path,
const std::string& device_label,
bool success) override;
......
......@@ -148,6 +148,11 @@ void FakeDiskMountManager::FormatMountedDevice(
chromeos::disks::FormatFileSystemType filesystem,
const std::string& label) {}
void FakeDiskMountManager::SinglePartitionFormatDevice(
const std::string& device_path,
chromeos::disks::FormatFileSystemType filesystem,
const std::string& label) {}
void FakeDiskMountManager::RenameMountedDevice(const std::string& mount_path,
const std::string& volume_name) {
}
......
......@@ -92,6 +92,10 @@ class FakeDiskMountManager : public chromeos::disks::DiskMountManager {
void FormatMountedDevice(const std::string& mount_path,
chromeos::disks::FormatFileSystemType filesystem,
const std::string& label) override;
void SinglePartitionFormatDevice(
const std::string& device_path,
chromeos::disks::FormatFileSystemType filesystem,
const std::string& label) override;
void RenameMountedDevice(const std::string& mount_path,
const std::string& volume_name) override;
void UnmountDeviceRecursively(
......
......@@ -974,6 +974,45 @@ void VolumeManager::OnFormatEvent(
NOTREACHED();
}
void VolumeManager::OnPartitionEvent(
chromeos::disks::DiskMountManager::PartitionEvent event,
chromeos::PartitionError error_code,
const std::string& device_path,
const std::string& device_label) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DVLOG(1) << "OnPartitionEvent: " << event << ", " << error_code << ", "
<< device_path;
switch (event) {
case chromeos::disks::DiskMountManager::PARTITION_STARTED:
for (auto& observer : observers_) {
observer.OnPartitionStarted(
device_path, device_label,
error_code == chromeos::PARTITION_ERROR_NONE);
}
return;
case chromeos::disks::DiskMountManager::PARTITION_COMPLETED:
// If partitioning failed, try to mount the device so the user can retry.
// MountPath auto-detects filesystem format if second argument is
// empty. The third argument (mount label) is not used in a disk mount
// operation.
if (error_code != chromeos::PARTITION_ERROR_NONE) {
disk_mount_manager_->MountPath(device_path, std::string(),
std::string(), {},
chromeos::MOUNT_TYPE_DEVICE,
GetExternalStorageAccessMode(profile_));
}
for (auto& observer : observers_) {
observer.OnPartitionCompleted(
device_path, device_label,
error_code == chromeos::PARTITION_ERROR_NONE);
}
return;
}
NOTREACHED();
}
void VolumeManager::OnRenameEvent(
chromeos::disks::DiskMountManager::RenameEvent event,
chromeos::RenameError error_code,
......
......@@ -391,6 +391,10 @@ class VolumeManager : public KeyedService,
chromeos::FormatError error_code,
const std::string& device_path,
const std::string& device_label) override;
void OnPartitionEvent(chromeos::disks::DiskMountManager::PartitionEvent event,
chromeos::PartitionError error_code,
const std::string& device_path,
const std::string& device_label) override;
void OnRenameEvent(chromeos::disks::DiskMountManager::RenameEvent event,
chromeos::RenameError error_code,
const std::string& device_path,
......
......@@ -54,6 +54,16 @@ class VolumeManagerObserver {
const std::string& device_label,
bool success) {}
// Fired when partitioning a device is started.
virtual void OnPartitionStarted(const std::string& device_path,
const std::string& device_label,
bool success) {}
// Fired when partitioning a device is completed (or terminated on error).
virtual void OnPartitionCompleted(const std::string& device_path,
const std::string& device_label,
bool success) {}
// Fired when renaming a device is started (or failed to start).
virtual void OnRenameStarted(const std::string& device_path,
const std::string& device_label,
......
......@@ -61,16 +61,19 @@ class LoggingObserver : public VolumeManagerObserver {
VOLUME_UNMOUNTED,
FORMAT_STARTED,
FORMAT_COMPLETED,
PARTITION_STARTED,
PARTITION_COMPLETED,
RENAME_STARTED,
RENAME_COMPLETED
} type;
// Available on DEVICE_ADDED, DEVICE_REMOVED, VOLUME_MOUNTED,
// VOLUME_UNMOUNTED, FORMAT_STARTED and FORMAT_COMPLETED.
// VOLUME_UNMOUNTED, FORMAT_STARTED, FORMAT_COMPLETED. PARTITION_STARTED,
// PARTITION_COMPLETED.
std::string device_path;
// Available on FORMAT_STARTED, FORMAT_COMPLETED, RENAME_STARTED and
// RENAME_COMPLETED.
// RENAME_COMPLETED, PARTITION_STARTED, PARTITION_COMPLETED.
std::string device_label;
// Available on DISK_ADDED.
......@@ -79,7 +82,8 @@ class LoggingObserver : public VolumeManagerObserver {
// Available on VOLUME_MOUNTED and VOLUME_UNMOUNTED.
chromeos::MountError mount_error;
// Available on FORMAT_STARTED and FORMAT_COMPLETED.
// Available on FORMAT_STARTED and FORMAT_COMPLETED, PARTITION_STARTED,
// PARTITION_COMPLETED.
bool success;
};
......@@ -158,6 +162,28 @@ class LoggingObserver : public VolumeManagerObserver {
events_.push_back(event);
}
void OnPartitionStarted(const std::string& device_path,
const std::string& device_label,
bool success) override {
Event event;
event.type = Event::PARTITION_STARTED;
event.device_path = device_path;
event.device_label = device_label;
event.success = success;
events_.push_back(event);
}
void OnPartitionCompleted(const std::string& device_path,
const std::string& device_label,
bool success) override {
Event event;
event.type = Event::PARTITION_COMPLETED;
event.device_path = device_path;
event.device_label = device_label;
event.success = success;
events_.push_back(event);
}
void OnRenameStarted(const std::string& device_path,
const std::string& device_label,
bool success) override {
......@@ -772,6 +798,87 @@ TEST_F(VolumeManagerTest, OnFormatEvent_CompletedFailed) {
volume_manager()->RemoveObserver(&observer);
}
TEST_F(VolumeManagerTest, OnPartitionEvent_Started) {
LoggingObserver observer;
volume_manager()->AddObserver(&observer);
volume_manager()->OnPartitionEvent(DiskMountManager::PARTITION_STARTED,
chromeos::PARTITION_ERROR_NONE, "device1",
"label1");
ASSERT_EQ(1U, observer.events().size());
const LoggingObserver::Event& event = observer.events()[0];
EXPECT_EQ(LoggingObserver::Event::PARTITION_STARTED, event.type);
EXPECT_EQ("device1", event.device_path);
EXPECT_EQ("label1", event.device_label);
EXPECT_TRUE(event.success);
volume_manager()->RemoveObserver(&observer);
}
TEST_F(VolumeManagerTest, OnPartitionEvent_StartFailed) {
LoggingObserver observer;
volume_manager()->AddObserver(&observer);
volume_manager()->OnPartitionEvent(DiskMountManager::PARTITION_STARTED,
chromeos::PARTITION_ERROR_UNKNOWN,
"device1", "label1");
ASSERT_EQ(1U, observer.events().size());
const LoggingObserver::Event& event = observer.events()[0];
EXPECT_EQ(LoggingObserver::Event::PARTITION_STARTED, event.type);
EXPECT_EQ("device1", event.device_path);
EXPECT_EQ("label1", event.device_label);
EXPECT_FALSE(event.success);
volume_manager()->RemoveObserver(&observer);
}
TEST_F(VolumeManagerTest, OnPartitionEvent_Completed) {
LoggingObserver observer;
volume_manager()->AddObserver(&observer);
volume_manager()->OnPartitionEvent(DiskMountManager::PARTITION_COMPLETED,
chromeos::PARTITION_ERROR_NONE, "device1",
"label1");
ASSERT_EQ(1U, observer.events().size());
const LoggingObserver::Event& event = observer.events()[0];
EXPECT_EQ(LoggingObserver::Event::PARTITION_COMPLETED, event.type);
EXPECT_EQ("device1", event.device_path);
EXPECT_EQ("label1", event.device_label);
EXPECT_TRUE(event.success);
volume_manager()->RemoveObserver(&observer);
}
TEST_F(VolumeManagerTest, OnPartitionEvent_CompletedFailed) {
LoggingObserver observer;
volume_manager()->AddObserver(&observer);
volume_manager()->OnPartitionEvent(DiskMountManager::PARTITION_COMPLETED,
chromeos::PARTITION_ERROR_UNKNOWN,
"device1", "label1");
ASSERT_EQ(1U, observer.events().size());
const LoggingObserver::Event& event = observer.events()[0];
EXPECT_EQ(LoggingObserver::Event::PARTITION_COMPLETED, event.type);
EXPECT_EQ("device1", event.device_path);
EXPECT_EQ("label1", event.device_label);
EXPECT_FALSE(event.success);
// When "partitioning" fails, VolumeManager requests to mount it for retry.
ASSERT_EQ(1U, disk_mount_manager_->mount_requests().size());
const FakeDiskMountManager::MountRequest& mount_request =
disk_mount_manager_->mount_requests()[0];
EXPECT_EQ("device1", mount_request.source_path);
EXPECT_EQ("", mount_request.source_format);
EXPECT_EQ("", mount_request.mount_label);
EXPECT_EQ(chromeos::MOUNT_TYPE_DEVICE, mount_request.type);
volume_manager()->RemoveObserver(&observer);
}
TEST_F(VolumeManagerTest, OnExternalStorageDisabledChanged) {
// Here create four mount points.
disk_mount_manager_->MountPath("mount1", "", "", {},
......
......@@ -131,7 +131,13 @@ enum DeviceEventType {
// Rename succeeded.
rename_success,
// Rename failed.
rename_fail
rename_fail,
// Partition started.
partition_start,
// Partition succeeded.
partition_success,
// Partition failed.
partition_fail
};
// Drive sync error type.
......
......@@ -240,6 +240,20 @@ class CrosDisksClientImpl : public CrosDisksClient {
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
// CrosDisksClient override.
void SinglePartitionFormat(const std::string& device_path,
PartitionCallback callback) override {
dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
cros_disks::kSinglePartitionFormat);
dbus::MessageWriter writer(&method_call);
writer.AppendString(device_path);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&CrosDisksClientImpl::OnPartitionCompleted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void Rename(const std::string& device_path,
const std::string& volume_name,
VoidDBusMethodCallback callback) override {
......@@ -497,6 +511,23 @@ class CrosDisksClientImpl : public CrosDisksClient {
}
}
void OnPartitionCompleted(PartitionCallback callback,
dbus::Response* response) {
if (!response) {
std::move(callback).Run(PARTITION_ERROR_UNKNOWN);
return;
}
uint32_t status = PARTITION_ERROR_UNKNOWN;
dbus::MessageReader reader(response);
if (!reader.PopUint32(&status)) {
LOG(ERROR) << "Error reading SinglePartitionFormat response: "
<< response->ToString();
std::move(callback).Run(PARTITION_ERROR_UNKNOWN);
return;
}
std::move(callback).Run(static_cast<PartitionError>(status));
}
// Handles RenameCompleted signal and notifies observers.
void OnRenameCompleted(dbus::Signal* signal) {
dbus::MessageReader reader(signal);
......
......@@ -110,6 +110,18 @@ enum FormatError {
FORMAT_ERROR_COUNT,
};
// Partition error reported by cros-disks.
enum PartitionError {
PARTITION_ERROR_NONE = 0,
PARTITION_ERROR_UNKNOWN = 1,
PARTITION_ERROR_INTERNAL = 2,
PARTITION_ERROR_INVALID_DEVICE_PATH = 3,
PARTITION_ERROR_DEVICE_BEING_PARTITIONED = 4,
PARTITION_ERROR_PROGRAM_NOT_FOUND = 5,
PARTITION_ERROR_PROGRAM_FAILED = 6,
PARTITION_ERROR_DEVICE_NOT_ALLOWED = 7,
};
// Event type each corresponding to a signal sent from cros-disks.
enum MountEventType {
CROS_DISKS_DISK_ADDED,
......@@ -294,6 +306,10 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) CrosDisksClient : public DBusClient {
// The argument is the unmount error code.
typedef base::OnceCallback<void(MountError error_code)> UnmountCallback;
// A callback to handle the result of SinglePartitionFormat.
// The argument is the partition error code.
using PartitionCallback = base::OnceCallback<void(PartitionError error_code)>;
class Observer : public base::CheckedObserver {
public:
// Called when a mount event signal is received.
......@@ -359,6 +375,11 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) CrosDisksClient : public DBusClient {
const std::string& label,
VoidDBusMethodCallback callback) = 0;
// Calls SinglePartitionFormat async method. |callback| is called when
// response received.
virtual void SinglePartitionFormat(const std::string& device_path,
PartitionCallback callback) = 0;
// Calls Rename method. On completion, |callback| is called, with |true| on
// success, or with |false| otherwise.
virtual void Rename(const std::string& device_path,
......
......@@ -185,6 +185,16 @@ void FakeCrosDisksClient::Format(const std::string& device_path,
FROM_HERE, base::BindOnce(std::move(callback), format_success_));
}
void FakeCrosDisksClient::SinglePartitionFormat(const std::string& device_path,
PartitionCallback callback) {
DCHECK(!callback.is_null());
partition_call_count_++;
last_partition_device_path_ = device_path;
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), partition_error_));
}
void FakeCrosDisksClient::Rename(const std::string& device_path,
const std::string& volume_name,
VoidDBusMethodCallback callback) {
......
......@@ -55,6 +55,8 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCrosDisksClient
const std::string& filesystem,
const std::string& label,
VoidDBusMethodCallback callback) override;
void SinglePartitionFormat(const std::string& device_path,
PartitionCallback callback) override;
void Rename(const std::string& device_path,
const std::string& volume_name,
VoidDBusMethodCallback callback) override;
......@@ -123,6 +125,18 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCrosDisksClient
format_success_ = false;
}
// Returns how many times Format() was called.
int partition_call_count() const { return partition_call_count_; }
// Returns the |device_path| parameter from the last invocation of Format().
const std::string& last_partition_device_path() const {
return last_partition_device_path_;
}
// Sets the SinglePartitionFormat() result code for the callback.
// Non error by default.
void SetPartitionResult(PartitionError error) { partition_error_ = error; }
// Returns how many times Rename() was called.
int rename_call_count() const { return rename_call_count_; }
......@@ -172,6 +186,9 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCrosDisksClient
std::string last_format_filesystem_;
std::string last_format_label_;
bool format_success_ = true;
int partition_call_count_ = 0;
std::string last_partition_device_path_;
PartitionError partition_error_ = PARTITION_ERROR_NONE;
int rename_call_count_ = 0;
std::string last_rename_device_path_;
std::string last_rename_volume_name_;
......
......@@ -188,6 +188,25 @@ class DiskMountManagerImpl : public DiskMountManager,
filesystem, label));
}
// DiskMountManager override.
void SinglePartitionFormatDevice(const std::string& device_path,
FormatFileSystemType filesystem,
const std::string& label) override {
DiskMap::const_iterator disk_iter = disks_.find(device_path);
if (disk_iter == disks_.end()) {
LOG(ERROR) << "Device with path \"" << device_path << "\" not found.";
OnPartitionCompleted(device_path, filesystem, label,
PARTITION_ERROR_INVALID_DEVICE_PATH);
return;
}
UnmountDeviceRecursively(
device_path,
base::BindOnce(
&DiskMountManagerImpl::OnUnmountDeviceForSinglePartitionFormat,
weak_ptr_factory_.GetWeakPtr(), device_path, filesystem, label));
}
void RenameMountedDevice(const std::string& mount_path,
const std::string& volume_name) override {
MountPointMap::const_iterator mount_point = mount_points_.find(mount_path);
......@@ -342,6 +361,10 @@ class DiskMountManagerImpl : public DiskMountManager,
// |disks_|. The key is a device_path and the value is a FormatChange.
std::map<std::string, FormatChange> pending_format_changes_;
// Stores device path are being partitioning.
// It allows preventing auto-mount of the disks in this set.
std::set<std::string> pending_partitioning_disks_;
// Stores new volume name for a device on which renaming is invoked on, so
// that OnRenameCompleted can set it back to |disks_|. The key is a
// device_path and the value is new volume_name.
......@@ -553,6 +576,20 @@ class DiskMountManagerImpl : public DiskMountManager,
}
}
void OnUnmountDeviceForSinglePartitionFormat(const std::string& device_path,
FormatFileSystemType filesystem,
const std::string& label,
MountError error_code) {
if (error_code != MOUNT_ERROR_NONE ||
disks_.find(device_path) == disks_.end()) {
OnPartitionCompleted(device_path, filesystem, label,
PARTITION_ERROR_UNKNOWN);
return;
}
SinglePartitionFormatUnmountedDevice(device_path, filesystem, label);
}
// Starts device formatting.
void FormatUnmountedDevice(const std::string& device_path,
FormatFileSystemType filesystem,
......@@ -607,10 +644,110 @@ class DiskMountManagerImpl : public DiskMountManager,
pending_format_changes_.erase(device_path);
EnsureMountInfoRefreshed(base::DoNothing(), true /* force */);
NotifyFormatStatusUpdate(FORMAT_COMPLETED, error_code, device_path,
device_label);
}
void SinglePartitionFormatUnmountedDevice(const std::string& device_path,
FormatFileSystemType filesystem,
const std::string& label) {
DiskMap::const_iterator disk = disks_.find(device_path);
DCHECK(disk != disks_.end() && disk->second->mount_path().empty());
pending_partitioning_disks_.insert(disk->second->device_path());
NotifyPartitionStatusUpdate(PARTITION_STARTED, PARTITION_ERROR_NONE,
device_path, label);
cros_disks_client_->SinglePartitionFormat(
disk->second->file_path(),
base::BindOnce(&DiskMountManagerImpl::OnPartitionCompleted,
weak_ptr_factory_.GetWeakPtr(), device_path, filesystem,
label));
}
void OnPartitionCompleted(const std::string& device_path,
FormatFileSystemType filesystem,
const std::string& label,
PartitionError error_code) {
auto iter = disks_.find(device_path);
// disk might have been removed by now?
if (iter != disks_.end()) {
Disk* disk = iter->second.get();
DCHECK(disk);
if (error_code == PARTITION_ERROR_NONE) {
EnsureMountInfoRefreshed(
base::BindOnce(&DiskMountManagerImpl::OnRefreshAfterPartition,
weak_ptr_factory_.GetWeakPtr(), device_path,
filesystem, label),
true /* force */);
}
} else {
// Remove disk from pending partitioning list if disk removed.
pending_partitioning_disks_.erase(iter->second->device_path());
}
NotifyPartitionStatusUpdate(PARTITION_COMPLETED, error_code, device_path,
label);
}
void OnRefreshAfterPartition(const std::string& device_path,
FormatFileSystemType filesystem,
const std::string& label,
bool success) {
DiskMap::const_iterator device_disk = disks_.find(device_path);
if (device_disk == disks_.end()) {
LOG(ERROR) << "Device not found, maybe ejected";
pending_partitioning_disks_.erase(device_path);
NotifyPartitionStatusUpdate(PARTITION_COMPLETED,
PARTITION_ERROR_INVALID_DEVICE_PATH,
device_path, label);
return;
}
std::string new_partition_device_path;
// Find new partition using common storage path with parent device.
for (DiskMountManager::DiskMap::const_iterator it = disks_.begin();
it != disks_.end(); ++it) {
if (it->second->storage_device_path() ==
device_disk->second->storage_device_path() &&
!it->second->is_parent()) {
new_partition_device_path = it->second->device_path();
break;
}
}
if (new_partition_device_path.empty()) {
LOG(ERROR) << "New partition couldn't be found";
pending_partitioning_disks_.erase(device_path);
NotifyPartitionStatusUpdate(PARTITION_COMPLETED,
PARTITION_ERROR_INVALID_DEVICE_PATH,
device_path, label);
return;
}
const std::string filesystem_str = FormatFileSystemTypeToString(filesystem);
pending_format_changes_[new_partition_device_path] = {filesystem_str,
label};
// It's expected the disks (parent device and new partition) are not
// mounted, but try unmounting before starting format if it got
// mounted through another flow.
UnmountDeviceRecursively(
device_path,
base::BindOnce(&DiskMountManagerImpl::OnUnmountPathForFormat,
weak_ptr_factory_.GetWeakPtr(),
new_partition_device_path, filesystem, label));
// It's ok to remove it from pending partitioning as format flow started.
pending_partitioning_disks_.erase(device_path);
}
void OnUnmountPathForRename(const std::string& device_path,
const std::string& volume_name,
MountError error_code) {
......@@ -816,6 +953,10 @@ class DiskMountManagerImpl : public DiskMountManager,
// Notifies all observers about disk status update.
void NotifyDiskStatusUpdate(DiskEvent event, const Disk& disk) {
for (auto& observer : observers_) {
// Skip mounting of new partitioned disks while waiting for the format.
if (IsPendingPartitioningDisk(disk.device_path())) {
continue;
}
disk.is_auto_mountable() ? observer.OnAutoMountableDiskEvent(event, disk)
: observer.OnBootDeviceDiskEvent(event, disk);
}
......@@ -844,6 +985,14 @@ class DiskMountManagerImpl : public DiskMountManager,
observer.OnFormatEvent(event, error_code, device_path, device_label);
}
void NotifyPartitionStatusUpdate(PartitionEvent event,
PartitionError error_code,
const std::string& device_path,
const std::string& device_label) {
for (auto& observer : observers_)
observer.OnPartitionEvent(event, error_code, device_path, device_label);
}
void NotifyRenameStatusUpdate(RenameEvent event,
RenameError error_code,
const std::string& device_path,
......@@ -852,6 +1001,22 @@ class DiskMountManagerImpl : public DiskMountManager,
observer.OnRenameEvent(event, error_code, device_path, device_label);
}
bool IsPendingPartitioningDisk(const std::string& device_path) {
if (pending_partitioning_disks_.find(device_path) !=
pending_partitioning_disks_.end()) {
return true;
}
// If device path doesn't match check whether if it's a child path.
for (auto it = pending_partitioning_disks_.begin();
it != pending_partitioning_disks_.end(); ++it) {
if (base::StartsWith(device_path, *it, base::CompareCase::SENSITIVE)) {
return true;
}
}
return false;
}
// Mount event change observers.
base::ObserverList<DiskMountManager::Observer> observers_;
......
......@@ -63,7 +63,12 @@ class COMPONENT_EXPORT(CHROMEOS_DISKS) DiskMountManager {
enum FormatEvent {
FORMAT_STARTED,
FORMAT_COMPLETED
FORMAT_COMPLETED,
};
enum PartitionEvent {
PARTITION_STARTED,
PARTITION_COMPLETED,
};
enum RenameEvent { RENAME_STARTED, RENAME_COMPLETED };
......@@ -126,6 +131,10 @@ class COMPONENT_EXPORT(CHROMEOS_DISKS) DiskMountManager {
FormatError error_code,
const std::string& device_path,
const std::string& device_label) {}
virtual void OnPartitionEvent(PartitionEvent event,
PartitionError error_code,
const std::string& device_path,
const std::string& device_label) {}
// Called on rename process events.
virtual void OnRenameEvent(RenameEvent event,
RenameError error_code,
......@@ -197,6 +206,18 @@ class COMPONENT_EXPORT(CHROMEOS_DISKS) DiskMountManager {
FormatFileSystemType filesystem,
const std::string& label) = 0;
// Deletes partitions of the device, create a partition taking whole device
// and format it as single volume. It converts devices with multiple child
// volumes to a single volume disk. It unmounts the mounted child volumes
// before erasing.
// Example: device_path: /sys/devices/pci0000:00/0000:00:14.0/usb1/1-3/
// 1-3:1.0/host0/target0:0:0/0:0:0:0
// filesystem: FormatFileSystemType::kNtfs
// label: MYUSB
virtual void SinglePartitionFormatDevice(const std::string& device_path,
FormatFileSystemType filesystem,
const std::string& label) = 0;
// Renames Device given its mount path.
// Example: mount_path: /media/VOLUME_LABEL
// volume_name: MYUSB
......
......@@ -141,6 +141,7 @@ void MockDiskMountManager::SetupDefaultReplies() {
EXPECT_CALL(*this, UnmountPath(_, _)).Times(AnyNumber());
EXPECT_CALL(*this, RemountAllRemovableDrives(_)).Times(AnyNumber());
EXPECT_CALL(*this, FormatMountedDevice(_, _, _)).Times(AnyNumber());
EXPECT_CALL(*this, SinglePartitionFormatDevice(_, _, _)).Times(AnyNumber());
EXPECT_CALL(*this, UnmountDeviceRecursively(_, _))
.Times(AnyNumber());
}
......
......@@ -50,6 +50,10 @@ class MockDiskMountManager : public DiskMountManager {
void(const std::string&,
FormatFileSystemType,
const std::string&));
MOCK_METHOD3(SinglePartitionFormatDevice,
void(const std::string&,
FormatFileSystemType,
const std::string&));
MOCK_METHOD2(RenameMountedDevice,
void(const std::string&, const std::string&));
MOCK_METHOD2(UnmountDeviceRecursively,
......
......@@ -161,6 +161,9 @@ chrome.fileManagerPrivate.DeviceEventType = {
RENAME_START: 'rename_start',
RENAME_SUCCESS: 'rename_success',
RENAME_FAIL: 'rename_fail',
PARTITION_START: 'partition_start',
PARTITION_SUCCESS: 'partition_success',
PARTITION_FAIL: 'partition_fail',
};
/** @enum {string} */
......
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