blob: c1cfa08b6a274788afdb3c5a5308a9e351dccb4e [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/utility/image_writer/image_writer_handler.h"
#include <memory>
#include <optional>
#include <utility>
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "chrome/services/removable_storage_writer/public/mojom/removable_storage_writer.mojom.h"
#include "chrome/utility/image_writer/error_message_strings.h"
namespace {
bool IsTestDevice(const base::FilePath& device) {
return device.AsUTF8Unsafe() ==
chrome::mojom::RemovableStorageWriter::kTestDevice;
}
base::FilePath MakeTestDevicePath(const base::FilePath& image) {
return image.ReplaceExtension(FILE_PATH_LITERAL("out"));
}
} // namespace
namespace image_writer {
ImageWriterHandler::ImageWriterHandler() = default;
ImageWriterHandler::~ImageWriterHandler() = default;
void ImageWriterHandler::Write(
const base::FilePath& image,
const base::FilePath& device,
mojo::PendingRemote<chrome::mojom::RemovableStorageWriterClient> client) {
client_.Bind(std::move(client));
client_.set_disconnect_handler(
base::BindOnce(&ImageWriterHandler::Cancel, base::Unretained(this)));
base::FilePath target_device = device;
const bool test_mode = IsTestDevice(device);
if (test_mode)
target_device = MakeTestDevicePath(image);
if (ShouldResetImageWriter(image, target_device))
image_writer_ = std::make_unique<ImageWriter>(this, image, target_device);
if (image_writer_->IsRunning()) {
SendFailed(error::kOperationAlreadyInProgress);
return;
}
if (test_mode) {
image_writer_->Write();
return;
}
if (!image_writer_->IsValidDevice()) {
SendFailed(error::kInvalidDevice);
return;
}
image_writer_->UnmountVolumes(
base::BindOnce(&ImageWriter::Write, image_writer_->AsWeakPtr()));
}
void ImageWriterHandler::Verify(
const base::FilePath& image,
const base::FilePath& device,
mojo::PendingRemote<chrome::mojom::RemovableStorageWriterClient> client) {
client_.Bind(std::move(client));
client_.set_disconnect_handler(
base::BindOnce(&ImageWriterHandler::Cancel, base::Unretained(this)));
base::FilePath target_device = device;
const bool test_mode = IsTestDevice(device);
if (test_mode)
target_device = MakeTestDevicePath(image);
if (ShouldResetImageWriter(image, target_device))
image_writer_ = std::make_unique<ImageWriter>(this, image, target_device);
if (image_writer_->IsRunning()) {
SendFailed(error::kOperationAlreadyInProgress);
return;
}
if (test_mode) {
image_writer_->Verify();
return;
}
if (!image_writer_->IsValidDevice()) {
SendFailed(error::kInvalidDevice);
return;
}
image_writer_->Verify();
}
void ImageWriterHandler::SendProgress(int64_t progress) {
client_->Progress(progress);
}
void ImageWriterHandler::SendSucceeded() {
client_->Complete(std::nullopt);
client_.reset();
}
void ImageWriterHandler::SendFailed(const std::string& error) {
if (client_) {
// client_ may be null as the ImageWriter implementation may have reported
// an error already.
client_->Complete(error);
client_.reset();
}
}
void ImageWriterHandler::Cancel() {
if (image_writer_)
image_writer_->Cancel();
client_.reset();
}
bool ImageWriterHandler::ShouldResetImageWriter(const base::FilePath& image,
const base::FilePath& device) {
if (!image_writer_)
return true;
if (image != image_writer_->GetImagePath())
return true;
if (device != image_writer_->GetDevicePath())
return true;
// When writing and verifying the same file on the same device, keep
// the file handles open; do not reset them since that can cause the
// operation to fail in unexpected ways: crbug.com/352442#c7
return false;
}
} // namespace image_writer