Index: chrome/browser/extensions/api/image_writer_private/operation.cc |
diff --git a/chrome/browser/extensions/api/image_writer_private/operation.cc b/chrome/browser/extensions/api/image_writer_private/operation.cc |
index e58ca43ead964cb863311c2d56342397a19a26bb..a37c81c4e6755c4b553f9f820b04bd53e9d103da 100644 |
--- a/chrome/browser/extensions/api/image_writer_private/operation.cc |
+++ b/chrome/browser/extensions/api/image_writer_private/operation.cc |
@@ -15,36 +15,34 @@ |
using content::BrowserThread; |
+namespace { |
+ |
const int kMD5BufferSize = 1024; |
-#if defined(OS_CHROMEOS) |
-// Chrome OS only has a 1 GB temporary partition. This is too small to hold our |
-// unzipped image. Fortunately we mount part of the temporary partition under |
-// /var/tmp. |
-const char kChromeOSTempRoot[] = "/var/tmp"; |
-#endif |
+ |
+void RemoveTempDirectory(const base::FilePath path) { |
+ base::DeleteFile(path, true); |
+} |
+ |
+} // namespace |
Operation::Operation(base::WeakPtr<OperationManager> manager, |
const ExtensionId& extension_id, |
- const std::string& device_path) |
+ const std::string& storage_unit_id) |
: manager_(manager), |
extension_id_(extension_id), |
-#if defined(OS_WIN) |
- device_path_(base::FilePath::FromUTF8Unsafe(device_path)), |
-#else |
- device_path_(device_path), |
-#endif |
-#if defined(OS_LINUX) && !defined(CHROMEOS) |
- image_file_(base::kInvalidPlatformFileValue), |
- device_file_(base::kInvalidPlatformFileValue), |
-#endif |
+ storage_unit_id_(storage_unit_id), |
+ verify_write_(true), |
stage_(image_writer_api::STAGE_UNKNOWN), |
progress_(0) { |
} |
-Operation::~Operation() {} |
+Operation::~Operation() { |
+} |
void Operation::Cancel() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ |
+ DVLOG(1) << "Cancelling image writing operation for ext: " << extension_id_; |
stage_ = image_writer_api::STAGE_NONE; |
@@ -61,82 +59,6 @@ |
image_writer_api::Stage Operation::GetStage() { |
return stage_; |
-} |
- |
-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(BrowserThread::CurrentlyOn(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; |
- } |
- |
- // Create a new target to unzip to. The original file is opened by the |
- // zip_reader_. |
- 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::OnUnzipSuccess, 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) { |
@@ -171,10 +93,6 @@ |
return; |
} |
- if (progress <= progress_) { |
- return; |
- } |
- |
if (IsCancelled()) { |
return; |
} |
@@ -219,51 +137,124 @@ |
progress_)); |
} |
+void Operation::Finish() { |
+ if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { |
+ BrowserThread::PostTask(BrowserThread::FILE, |
+ FROM_HERE, |
+ base::Bind(&Operation::Finish, this)); |
+ return; |
+ } |
+ DVLOG(1) << "Write operation complete."; |
+ |
+ CleanUp(); |
+ |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(&OperationManager::OnComplete, |
+ manager_, |
+ extension_id_)); |
+} |
+ |
bool Operation::IsCancelled() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
return stage_ == image_writer_api::STAGE_NONE; |
} |
-void Operation::AddCleanUpFunction(const base::Closure& callback) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+void Operation::AddCleanUpFunction(base::Closure callback) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ |
cleanup_functions_.push_back(callback); |
} |
+void Operation::CleanUp() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ for (std::vector<base::Closure>::iterator it = cleanup_functions_.begin(); |
+ it != cleanup_functions_.end(); |
+ ++it) { |
+ it->Run(); |
+ } |
+ cleanup_functions_.clear(); |
+} |
+ |
+void Operation::UnzipStart(scoped_ptr<base::FilePath> zip_path) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ if (IsCancelled()) { |
+ return; |
+ } |
+ |
+ DVLOG(1) << "Starting unzip stage for " << zip_path->value(); |
+ |
+ SetStage(image_writer_api::STAGE_UNZIP); |
+ |
+ base::FilePath tmp_dir; |
+ if (!base::CreateTemporaryDirInDir(zip_path->DirName(), |
+ FILE_PATH_LITERAL("image_writer"), |
+ &tmp_dir)) { |
+ Error(error::kTempDirError); |
+ return; |
+ } |
+ |
+ AddCleanUpFunction(base::Bind(&RemoveTempDirectory, tmp_dir)); |
+ |
+ if (!base::CreateTemporaryFileInDir(tmp_dir, &image_path_)) { |
+ DLOG(ERROR) << "Failed create temporary unzip target in " |
+ << tmp_dir.value(); |
+ Error(error::kTempDirError); |
+ return; |
+ } |
+ |
+ if (!(zip_reader_.Open(*zip_path) && |
+ zip_reader_.AdvanceToNextEntry() && |
+ zip_reader_.OpenCurrentEntryInZip())) { |
+ DLOG(ERROR) << "Failed to open zip file."; |
+ Error(error::kUnzipGenericError); |
+ return; |
+ } |
+ |
+ if (zip_reader_.HasMore()) { |
+ DLOG(ERROR) << "Image zip has more than one file."; |
+ Error(error::kUnzipInvalidArchive); |
+ return; |
+ } |
+ |
+ zip_reader_.ExtractCurrentEntryToFilePathAsync( |
+ image_path_, |
+ base::Bind(&Operation::OnUnzipSuccess, this), |
+ base::Bind(&Operation::OnUnzipFailure, this), |
+ base::Bind(&Operation::OnUnzipProgress, |
+ this, |
+ zip_reader_.current_entry_info()->original_size())); |
+} |
+ |
void Operation::GetMD5SumOfFile( |
- const base::FilePath& file_path, |
+ scoped_ptr<base::FilePath> file_path, |
int64 file_size, |
int progress_offset, |
int progress_scale, |
- const base::Callback<void(const std::string&)>& callback) { |
+ const base::Callback<void(scoped_ptr<std::string>)>& callback) { |
if (IsCancelled()) { |
return; |
} |
base::MD5Init(&md5_context_); |
- |
- base::PlatformFile file = base::CreatePlatformFile( |
- file_path, |
- base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, |
- NULL, |
- NULL); |
- if (file == base::kInvalidPlatformFileValue) { |
+ scoped_ptr<image_writer_utils::ImageReader> reader( |
+ new image_writer_utils::ImageReader()); |
+ |
+ if (!reader->Open(*file_path)) { |
Error(error::kImageOpenError); |
return; |
} |
- |
if (file_size <= 0) { |
- if (!base::GetFileSize(file_path, &file_size)) { |
- Error(error::kImageOpenError); |
- return; |
- } |
+ file_size = reader->GetSize(); |
} |
BrowserThread::PostTask(BrowserThread::FILE, |
FROM_HERE, |
base::Bind(&Operation::MD5Chunk, |
this, |
- file, |
+ base::Passed(&reader), |
0, |
file_size, |
progress_offset, |
@@ -272,64 +263,68 @@ |
} |
void Operation::MD5Chunk( |
- const base::PlatformFile& file, |
+ scoped_ptr<image_writer_utils::ImageReader> reader, |
int64 bytes_processed, |
int64 bytes_total, |
int progress_offset, |
int progress_scale, |
- const base::Callback<void(const std::string&)>& callback) { |
- if (IsCancelled()) { |
- base::ClosePlatformFile(file); |
- 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) { |
- // Nothing to read, we are done. |
- base::MD5Digest digest; |
- base::MD5Final(&digest, &md5_context_); |
- callback.Run(base::MD5DigestToBase16(digest)); |
+ const base::Callback<void(scoped_ptr<std::string>)>& callback) { |
+ if (IsCancelled()) { |
+ reader->Close(); |
+ return; |
+ } |
+ |
+ char buffer[kMD5BufferSize]; |
+ int len; |
+ |
+ if (bytes_total - bytes_processed <= kMD5BufferSize) { |
+ len = reader->Read(buffer, bytes_total - bytes_processed); |
} else { |
- int len = |
- base::ReadPlatformFile(file, bytes_processed, buffer.get(), read_size); |
- |
- if (len == read_size) { |
- // Process data. |
- 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, |
- file, |
- bytes_processed + len, |
- bytes_total, |
- progress_offset, |
- progress_scale, |
- callback)); |
- // Skip closing the file. |
- return; |
+ len = reader->Read(buffer, kMD5BufferSize); |
+ } |
+ |
+ if (len > 0) { |
+ base::MD5Update(&md5_context_, base::StringPiece(buffer, len)); |
+ int percent_prev = (bytes_processed * progress_scale + progress_offset) / |
+ (bytes_total); |
+ int percent_curr = ((bytes_processed + len) * progress_scale + |
+ progress_offset) / |
+ (bytes_total); |
+ if (percent_curr > percent_prev) { |
+ SetProgress(progress_); |
+ } |
+ |
+ BrowserThread::PostTask(BrowserThread::FILE, |
+ FROM_HERE, |
+ base::Bind(&Operation::MD5Chunk, |
+ this, |
+ base::Passed(&reader), |
+ bytes_processed + len, |
+ bytes_total, |
+ progress_offset, |
+ progress_scale, |
+ callback)); |
+ } else if (len == 0) { |
+ if (bytes_processed + len < bytes_total) { |
+ reader->Close(); |
+ Error(error::kHashReadError); |
} else { |
- // We didn't read the bytes we expected. |
- Error(error::kHashReadError); |
+ base::MD5Digest digest; |
+ base::MD5Final(&digest, &md5_context_); |
+ scoped_ptr<std::string> hash( |
+ new std::string(base::MD5DigestToBase16(digest))); |
+ callback.Run(hash.Pass()); |
} |
- } |
- base::ClosePlatformFile(file); |
-} |
- |
-void Operation::OnUnzipSuccess(const base::Closure& continuation) { |
+ } else { // len < 0 |
+ reader->Close(); |
+ Error(error::kHashReadError); |
+ } |
+} |
+ |
+void Operation::OnUnzipSuccess() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
SetProgress(kProgressComplete); |
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation); |
+ WriteStart(); |
} |
void Operation::OnUnzipFailure() { |
@@ -344,15 +339,5 @@ |
SetProgress(progress_percent); |
} |
-void Operation::CleanUp() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- for (std::vector<base::Closure>::iterator it = cleanup_functions_.begin(); |
- it != cleanup_functions_.end(); |
- ++it) { |
- it->Run(); |
- } |
- cleanup_functions_.clear(); |
-} |
- |
} // namespace image_writer |
} // namespace extensions |