This source file includes following definitions.
- progress_
- Cancel
- Abort
- GetProgress
- GetStage
- SetUtilityClientForTesting
- Start
- Unzip
- Finish
- Error
- SetProgress
- SetStage
- IsCancelled
- AddCleanUpFunction
- CompleteAndContinue
- StartUtilityClient
- StopUtilityClient
- WriteImageProgress
- GetMD5SumOfFile
- MD5Chunk
- OnUnzipFailure
- OnUnzipProgress
- CleanUp
#include "chrome/browser/extensions/api/image_writer_private/operation.h"
#include "base/file_util.h"
#include "base/files/file_enumerator.h"
#include "base/threading/worker_pool.h"
#include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
#include "chrome/browser/extensions/api/image_writer_private/operation_manager.h"
#include "content/public/browser/browser_thread.h"
namespace extensions {
namespace image_writer {
using content::BrowserThread;
const int kMD5BufferSize = 1024;
#if defined(OS_CHROMEOS)
const char kChromeOSTempRoot[] = "/var/tmp";
#endif
Operation::Operation(base::WeakPtr<OperationManager> manager,
const ExtensionId& extension_id,
const std::string& device_path)
: manager_(manager),
extension_id_(extension_id),
#if defined(OS_WIN)
device_path_(base::FilePath::FromUTF8Unsafe(device_path)),
#else
device_path_(device_path),
#endif
stage_(image_writer_api::STAGE_UNKNOWN),
progress_(0) {
}
Operation::~Operation() {}
void Operation::Cancel() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
stage_ = image_writer_api::STAGE_NONE;
CleanUp();
}
void Operation::Abort() {
Error(error::kAborted);
}
int Operation::GetProgress() {
return progress_;
}
image_writer_api::Stage Operation::GetStage() {
return stage_;
}
#if !defined(OS_CHROMEOS)
void Operation::SetUtilityClientForTesting(
scoped_refptr<ImageWriterUtilityClient> client) {
image_writer_client_ = client;
AddCleanUpFunction(
base::Bind(&ImageWriterUtilityClient::Shutdown, image_writer_client_));
}
#endif
void Operation::Start() {
#if defined(OS_CHROMEOS)
if (!temp_dir_.CreateUniqueTempDirUnderPath(
base::FilePath(kChromeOSTempRoot))) {
#else
if (!temp_dir_.CreateUniqueTempDir()) {
#endif
Error(error::kTempDirError);
return;
}
AddCleanUpFunction(
base::Bind(base::IgnoreResult(&base::ScopedTempDir::Delete),
base::Unretained(&temp_dir_)));
StartImpl();
}
void Operation::Unzip(const base::Closure& continuation) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (IsCancelled()) {
return;
}
if (image_path_.Extension() != FILE_PATH_LITERAL(".zip")) {
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
return;
}
SetStage(image_writer_api::STAGE_UNZIP);
if (!(zip_reader_.Open(image_path_) && zip_reader_.AdvanceToNextEntry() &&
zip_reader_.OpenCurrentEntryInZip())) {
Error(error::kUnzipGenericError);
return;
}
if (zip_reader_.HasMore()) {
Error(error::kUnzipInvalidArchive);
return;
}
zip::ZipReader::EntryInfo* entry_info = zip_reader_.current_entry_info();
if (entry_info) {
image_path_ = temp_dir_.path().Append(entry_info->file_path().BaseName());
} else {
Error(error::kTempDirError);
return;
}
zip_reader_.ExtractCurrentEntryToFilePathAsync(
image_path_,
base::Bind(&Operation::CompleteAndContinue, this, continuation),
base::Bind(&Operation::OnUnzipFailure, this),
base::Bind(&Operation::OnUnzipProgress,
this,
zip_reader_.current_entry_info()->original_size()));
}
void Operation::Finish() {
if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE, base::Bind(&Operation::Finish, this));
return;
}
CleanUp();
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&OperationManager::OnComplete, manager_, extension_id_));
}
void Operation::Error(const std::string& error_message) {
if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
BrowserThread::PostTask(BrowserThread::FILE,
FROM_HERE,
base::Bind(&Operation::Error, this, error_message));
return;
}
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&OperationManager::OnError,
manager_,
extension_id_,
stage_,
progress_,
error_message));
CleanUp();
}
void Operation::SetProgress(int progress) {
if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
base::Bind(&Operation::SetProgress,
this,
progress));
return;
}
if (progress <= progress_) {
return;
}
if (IsCancelled()) {
return;
}
progress_ = progress;
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
base::Bind(&OperationManager::OnProgress,
manager_,
extension_id_,
stage_,
progress_));
}
void Operation::SetStage(image_writer_api::Stage stage) {
if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
base::Bind(&Operation::SetStage,
this,
stage));
return;
}
if (IsCancelled()) {
return;
}
stage_ = stage;
progress_ = 0;
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&OperationManager::OnProgress,
manager_,
extension_id_,
stage_,
progress_));
}
bool Operation::IsCancelled() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
return stage_ == image_writer_api::STAGE_NONE;
}
void Operation::AddCleanUpFunction(const base::Closure& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
cleanup_functions_.push_back(callback);
}
void Operation::CompleteAndContinue(const base::Closure& continuation) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
SetProgress(kProgressComplete);
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
}
#if !defined(OS_CHROMEOS)
void Operation::StartUtilityClient() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (!image_writer_client_) {
image_writer_client_ = new ImageWriterUtilityClient();
AddCleanUpFunction(base::Bind(&Operation::StopUtilityClient, this));
}
}
void Operation::StopUtilityClient() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&ImageWriterUtilityClient::Shutdown, image_writer_client_));
}
void Operation::WriteImageProgress(int64 total_bytes, int64 curr_bytes) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (IsCancelled()) {
return;
}
int progress = kProgressComplete * curr_bytes / total_bytes;
if (progress > GetProgress()) {
SetProgress(progress);
}
}
#endif
void Operation::GetMD5SumOfFile(
const base::FilePath& file_path,
int64 file_size,
int progress_offset,
int progress_scale,
const base::Callback<void(const std::string&)>& callback) {
if (IsCancelled()) {
return;
}
base::MD5Init(&md5_context_);
base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!file.IsValid()) {
Error(error::kImageOpenError);
return;
}
if (file_size <= 0) {
file_size = file.GetLength();
if (file_size < 0) {
Error(error::kImageOpenError);
return;
}
}
BrowserThread::PostTask(BrowserThread::FILE,
FROM_HERE,
base::Bind(&Operation::MD5Chunk,
this,
Passed(file.Pass()),
0,
file_size,
progress_offset,
progress_scale,
callback));
}
void Operation::MD5Chunk(
base::File file,
int64 bytes_processed,
int64 bytes_total,
int progress_offset,
int progress_scale,
const base::Callback<void(const std::string&)>& callback) {
if (IsCancelled())
return;
CHECK_LE(bytes_processed, bytes_total);
scoped_ptr<char[]> buffer(new char[kMD5BufferSize]);
int read_size = std::min(bytes_total - bytes_processed,
static_cast<int64>(kMD5BufferSize));
if (read_size == 0) {
base::MD5Digest digest;
base::MD5Final(&digest, &md5_context_);
callback.Run(base::MD5DigestToBase16(digest));
} else {
int len = file.Read(bytes_processed, buffer.get(), read_size);
if (len == read_size) {
base::MD5Update(&md5_context_, base::StringPiece(buffer.get(), len));
int percent_curr =
((bytes_processed + len) * progress_scale) / bytes_total +
progress_offset;
SetProgress(percent_curr);
BrowserThread::PostTask(BrowserThread::FILE,
FROM_HERE,
base::Bind(&Operation::MD5Chunk,
this,
Passed(file.Pass()),
bytes_processed + len,
bytes_total,
progress_offset,
progress_scale,
callback));
return;
} else {
Error(error::kHashReadError);
}
}
}
void Operation::OnUnzipFailure() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
Error(error::kUnzipGenericError);
}
void Operation::OnUnzipProgress(int64 total_bytes, int64 progress_bytes) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
int progress_percent = kProgressComplete * progress_bytes / total_bytes;
SetProgress(progress_percent);
}
void Operation::CleanUp() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
for (std::vector<base::Closure>::iterator it = cleanup_functions_.begin();
it != cleanup_functions_.end();
++it) {
it->Run();
}
cleanup_functions_.clear();
}
}
}