Commit b5e820d7 authored by haven@chromium.org's avatar haven@chromium.org

Unmounts volumes before writing to a drive.

When writing to a drive with mounted volumes, Chrome OS will recreate the partition table if it is observe to be missing and the volumes are accessed after writing.  This only occurs when erasing just the partition table because enough of the volume information is still present.

We also expand the amount of data erased when destroying partitions to 8k to account for 4k block sizes.  This has the side effect of overwriting the LBA for 512-byte-block drives, which only increases the effect of destroying partitions.

BUG=284834
BUG=335390

Review URL: https://codereview.chromium.org/282853003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271551 0039d316-1c4b-4281-b951-d872f2087c98
parent 1f7926e4
......@@ -10,10 +10,10 @@
namespace extensions {
namespace image_writer {
// Number of bytes for the maximum partition table size. By wiping this many
// bytes we can essentially guarantee the header and associated information will
// be wiped. See http://crbug.com/328246 for more information.
const int kPartitionTableSize = 1 * 1024;
// Number of bytes for the maximum partition table size. GUID partition tables
// reside in the second sector of the disk. Disks can have up to 4k sectors.
// See http://crbug.com/328246 for more information.
const int kPartitionTableSize = 2 * 4096;
DestroyPartitionsOperation::DestroyPartitionsOperation(
base::WeakPtr<OperationManager> manager,
......
......@@ -45,6 +45,7 @@ const char kImageNotFound[] = "IMAGE_NOT_FOUND";
const char kImageOpenError[] = "IMAGE_OPEN_ERROR";
const char kImageReadError[] = "IMAGE_READ_ERROR";
const char kImageSizeError[] = "IMAGE_STAT_ERROR";
const char kUnmountVolumesError[] = "UNMOUNT_VOLUMES_ERROR";
// Verification Errors
const char kHashReadError[] = "HASH_READ_ERROR";
......
......@@ -46,6 +46,7 @@ extern const char kImageNotFound[];
extern const char kImageOpenError[];
extern const char kImageReadError[];
extern const char kImageSizeError[];
extern const char kUnmountVolumesError[];
// Verification Errors
extern const char kHashReadError[];
......
......@@ -164,8 +164,14 @@ class Operation : public base::RefCountedThreadSafe<Operation> {
#endif
#if defined(OS_CHROMEOS)
void StartWriteOnUIThread(const base::Closure& continuation);
// Unmounts all volumes on |device_path_|.
void UnmountVolumes(const base::Closure& continuation);
// Starts the write after unmounting.
void UnmountVolumesCallback(const base::Closure& continuation, bool success);
// Starts the ImageBurner write. Note that target_path is the file path of
// the device where device_path has been a system device path.
void StartWriteOnUIThread(const std::string& target_path,
const base::Closure& continuation);
void OnBurnFinished(const base::Closure& continuation,
const std::string& target_path,
bool success,
......
......@@ -6,11 +6,13 @@
#include "chrome/browser/extensions/api/image_writer_private/operation.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/image_burner_client.h"
#include "chromeos/disks/disk_mount_manager.h"
#include "content/public/browser/browser_thread.h"
namespace extensions {
namespace image_writer {
using chromeos::disks::DiskMountManager;
using chromeos::ImageBurnerClient;
using content::BrowserThread;
......@@ -35,12 +37,13 @@ void Operation::Write(const base::Closure& continuation) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
SetStage(image_writer_api::STAGE_WRITE);
// Note this has to be run on the FILE thread to avoid concurrent access.
AddCleanUpFunction(base::Bind(&ClearImageBurner));
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&Operation::StartWriteOnUIThread, this, continuation));
AddCleanUpFunction(base::Bind(&ClearImageBurner));
base::Bind(&Operation::UnmountVolumes, this, continuation));
}
void Operation::VerifyWrite(const base::Closure& continuation) {
......@@ -50,9 +53,42 @@ void Operation::VerifyWrite(const base::Closure& continuation) {
continuation.Run();
}
void Operation::StartWriteOnUIThread(const base::Closure& continuation) {
void Operation::UnmountVolumes(const base::Closure& continuation) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DiskMountManager::GetInstance()->UnmountDeviceRecursively(
device_path_.value(),
base::Bind(&Operation::UnmountVolumesCallback, this, continuation));
}
void Operation::UnmountVolumesCallback(const base::Closure& continuation,
bool success) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!success) {
LOG(ERROR) << "Volume unmounting failed.";
Error(error::kUnmountVolumesError);
return;
}
const DiskMountManager::DiskMap& disks =
DiskMountManager::GetInstance()->disks();
DiskMountManager::DiskMap::const_iterator iter =
disks.find(device_path_.value());
if (iter == disks.end()) {
LOG(ERROR) << "Disk not found in disk list after unmounting volumes.";
Error(error::kUnmountVolumesError);
return;
}
StartWriteOnUIThread(iter->second->file_path(), continuation);
}
void Operation::StartWriteOnUIThread(const std::string& target_path,
const base::Closure& continuation) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// TODO(haven): Image Burner cannot handle multiple burns. crbug.com/373575
ImageBurnerClient* burner =
chromeos::DBusThreadManager::Get()->GetImageBurnerClient();
......@@ -61,7 +97,7 @@ void Operation::StartWriteOnUIThread(const base::Closure& continuation) {
base::Bind(&Operation::OnBurnProgress, this));
burner->BurnImage(image_path_.value(),
device_path_.value(),
target_path,
base::Bind(&Operation::OnBurnError, this));
}
......
......@@ -64,9 +64,14 @@ void OperationManager::StartWriteFromUrl(
const std::string& hash,
const std::string& device_path,
const Operation::StartWriteCallback& callback) {
#if defined(OS_CHROMEOS)
// Chrome OS can only support a single operation at a time.
if (operations_.size() > 0) {
#else
OperationMap::iterator existing_operation = operations_.find(extension_id);
if (existing_operation != operations_.end()) {
#endif
return callback.Run(false, error::kOperationAlreadyInProgress);
}
......@@ -89,9 +94,14 @@ void OperationManager::StartWriteFromFile(
const base::FilePath& path,
const std::string& device_path,
const Operation::StartWriteCallback& callback) {
#if defined(OS_CHROMEOS)
// Chrome OS can only support a single operation at a time.
if (operations_.size() > 0) {
#else
OperationMap::iterator existing_operation = operations_.find(extension_id);
if (existing_operation != operations_.end()) {
#endif
return callback.Run(false, error::kOperationAlreadyInProgress);
}
......
......@@ -31,7 +31,7 @@ bool RemovableStorageProvider::PopulateDeviceList(
disk.device_type() == chromeos::DEVICE_TYPE_SD)) {
linked_ptr<api::image_writer_private::RemovableStorageDevice> device(
new api::image_writer_private::RemovableStorageDevice());
device->storage_unit_id = disk.file_path();
device->storage_unit_id = disk.device_path();
device->capacity = disk.total_size_in_bytes();
device->vendor = disk.vendor_name();
device->model = disk.product_name();
......
......@@ -55,6 +55,17 @@ MockOperationManager::MockOperationManager(content::BrowserContext* context)
: OperationManager(context) {}
MockOperationManager::~MockOperationManager() {}
#if defined(OS_CHROMEOS)
FakeDiskMountManager::FakeDiskMountManager() {}
FakeDiskMountManager::~FakeDiskMountManager() {}
void FakeDiskMountManager::UnmountDeviceRecursively(
const std::string& device_path,
const UnmountDeviceRecursivelyCallbackType& callback) {
base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true));
}
#endif
FakeImageWriterClient::FakeImageWriterClient() {}
FakeImageWriterClient::~FakeImageWriterClient() {}
......@@ -131,12 +142,33 @@ void ImageWriterUnitTestBase::SetUp() {
fake_dbus_thread_manager->SetImageBurnerClient(image_burner_fake.Pass());
chromeos::DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager);
}
FakeDiskMountManager* disk_manager = new FakeDiskMountManager();
chromeos::disks::DiskMountManager::InitializeForTesting(disk_manager);
// Adds a disk entry for test_device_path_ with the same device and file path.
disk_manager->CreateDiskEntryForMountDevice(
chromeos::disks::DiskMountManager::MountPointInfo(
test_device_path_.value(),
"/dummy/mount",
chromeos::MOUNT_TYPE_DEVICE,
chromeos::disks::MOUNT_CONDITION_NONE),
"device_id",
"device_label",
"Vendor",
"Product",
chromeos::DEVICE_TYPE_USB,
kTestFileSize,
true,
true,
false);
disk_manager->SetupDefaultReplies();
#endif
}
void ImageWriterUnitTestBase::TearDown() {
#if defined(OS_CHROMEOS)
chromeos::DBusThreadManager::Shutdown();
chromeos::disks::DiskMountManager::Shutdown();
#endif
}
......
......@@ -16,6 +16,11 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_CHROMEOS)
#include "chromeos/disks/disk_mount_manager.h"
#include "chromeos/disks/mock_disk_mount_manager.h"
#endif
namespace extensions {
namespace image_writer {
......@@ -49,6 +54,37 @@ class MockOperationManager : public OperationManager {
const std::string& error_message));
};
#if defined(OS_CHROMEOS)
// A fake for the DiskMountManager that will successfully call the unmount
// callback.
class FakeDiskMountManager : public chromeos::disks::MockDiskMountManager {
public:
FakeDiskMountManager();
virtual ~FakeDiskMountManager();
virtual void UnmountDeviceRecursively(
const std::string& device_path,
const UnmountDeviceRecursivelyCallbackType& callback) OVERRIDE;
/*
MOCK_METHOD1(AddObserver, void(chromeos::disks::DiskMountManager::Observer*));
MOCK_METHOD1(RemoveObserver,
void(chromeos::disks::DiskMountManager::Observer*));
MOCK_CONST_METHOD0(disks, const DiskMap&());
MOCK_CONST_METHOD1(FindDiskBySourcePath, const Disk*(const std::string&));
MOCK_CONST_METHOD0(mount_points, const MountPointMap&());
MOCK_METHOD0(RequestMountInfoRefresh, void());
MOCK_METHOD4(MountPath, void(const std::string&, const std::string&, const
std::string&, chromeos::MountType));
MOCK_METHOD3(UnmountPath, void(const std::string&, chromeos::UnmountOptions,
const UnmountPathCallback&));
MOCK_METHOD1(FormatMountedDevice, void(const std::string&));
*/
private:
DiskMap disks_;
};
#endif
class FakeImageWriterClient : public ImageWriterUtilityClient {
public:
FakeImageWriterClient();
......
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