Chromium Code Reviews| 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 a37c81c4e6755c4b553f9f820b04bd53e9d103da..429c4d33d8e366547c4b389aeb6a4db24328ba0a 100644 |
| --- a/chrome/browser/extensions/api/image_writer_private/operation.cc |
| +++ b/chrome/browser/extensions/api/image_writer_private/operation.cc |
| @@ -15,23 +15,28 @@ namespace image_writer { |
| using content::BrowserThread; |
| -namespace { |
| - |
| const int kMD5BufferSize = 1024; |
| - |
| -void RemoveTempDirectory(const base::FilePath path) { |
| - base::DeleteFile(path, true); |
| -} |
| - |
| -} // namespace |
| +#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 |
| Operation::Operation(base::WeakPtr<OperationManager> manager, |
| const ExtensionId& extension_id, |
| - const std::string& storage_unit_id) |
| + const std::string& device_path) |
| : manager_(manager), |
| extension_id_(extension_id), |
| - storage_unit_id_(storage_unit_id), |
| - verify_write_(true), |
| +#if defined(OS_WIN) |
| + device_path_(base::FilePath::FromUTF8Unsafe(device_path)), |
| +#else |
| + device_path_(device_path), |
| +#endif |
| +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| + source_(base::kInvalidPlatformFileValue), |
| + target_(base::kInvalidPlatformFileValue), |
| +#endif |
| stage_(image_writer_api::STAGE_UNKNOWN), |
| progress_(0) { |
| } |
| @@ -42,8 +47,6 @@ 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; |
| CleanUp(); |
| @@ -61,6 +64,76 @@ 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); |
| + Cancel(); |
| + } |
|
tbarzic
2014/02/13 06:58:52
a suggestion:
Instead of calling Operation::Start
Drew Haven
2014/02/13 20:48:10
That makes more sense. It will help guarantee tha
|
| +} |
| + |
| +void Operation::Unzip(const base::Closure& continuation) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + if (IsCancelled()) { |
| + return; |
| + } |
| + |
| + if (image_path_.Extension() != FILE_PATH_LITERAL(".zip")) { |
| + continuation.Run(); |
| + 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; |
| + if ((entry_info = zip_reader_.current_entry_info())) { |
|
tbarzic
2014/02/13 06:58:52
I think this would look better:
ZipReader::EntryIn
Drew Haven
2014/02/13 20:48:10
Done.
|
| + 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) { |
| if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { |
| BrowserThread::PostTask(BrowserThread::FILE, |
| @@ -93,6 +166,10 @@ void Operation::SetProgress(int progress) { |
| return; |
| } |
| + if (progress <= progress_) { |
| + return; |
| + } |
| + |
| if (IsCancelled()) { |
| return; |
| } |
| @@ -137,124 +214,51 @@ void Operation::SetStage(image_writer_api::Stage stage) { |
| 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(base::Closure callback) { |
| +void Operation::AddCleanUpFunction(const 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( |
| - scoped_ptr<base::FilePath> file_path, |
| + const base::FilePath file_path, |
|
tbarzic
2014/02/13 06:58:52
missing &
Drew Haven
2014/02/13 20:48:10
Done.
|
| int64 file_size, |
| int progress_offset, |
| int progress_scale, |
| - const base::Callback<void(scoped_ptr<std::string>)>& callback) { |
| + const base::Callback<void(const std::string&)>& callback) { |
| if (IsCancelled()) { |
| return; |
| } |
| base::MD5Init(&md5_context_); |
| - scoped_ptr<image_writer_utils::ImageReader> reader( |
| - new image_writer_utils::ImageReader()); |
| - if (!reader->Open(*file_path)) { |
| + base::PlatformFile file = base::CreatePlatformFile( |
| + file_path, |
| + base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, |
| + NULL, |
| + NULL); |
| + if (file == base::kInvalidPlatformFileValue) { |
| Error(error::kImageOpenError); |
| return; |
| } |
| + |
| if (file_size <= 0) { |
| - file_size = reader->GetSize(); |
| + if (!base::GetFileSize(file_path, &file_size)) { |
| + Error(error::kImageOpenError); |
| + return; |
| + } |
| } |
| BrowserThread::PostTask(BrowserThread::FILE, |
| FROM_HERE, |
| base::Bind(&Operation::MD5Chunk, |
| this, |
| - base::Passed(&reader), |
| + file, |
| 0, |
| file_size, |
| progress_offset, |
| @@ -263,68 +267,66 @@ void Operation::GetMD5SumOfFile( |
| } |
| void Operation::MD5Chunk( |
| - scoped_ptr<image_writer_utils::ImageReader> reader, |
| + base::PlatformFile file, |
| int64 bytes_processed, |
| int64 bytes_total, |
| int progress_offset, |
| int progress_scale, |
| - const base::Callback<void(scoped_ptr<std::string>)>& callback) { |
| + const base::Callback<void(const std::string&)>& callback) { |
| if (IsCancelled()) { |
| - reader->Close(); |
| + base::ClosePlatformFile(file); |
| return; |
| } |
| - char buffer[kMD5BufferSize]; |
| int len; |
| + scoped_ptr<char[]> buffer(new char[kMD5BufferSize]); |
| if (bytes_total - bytes_processed <= kMD5BufferSize) { |
| - len = reader->Read(buffer, bytes_total - bytes_processed); |
| + len = base::ReadPlatformFile( |
|
tbarzic
2014/02/13 06:58:52
what do you think about:
int read_size = std::min
Drew Haven
2014/02/13 20:48:10
I like it. I've had people complain about the use
|
| + file, bytes_processed, buffer.get(), bytes_total - bytes_processed); |
| } else { |
| - len = reader->Read(buffer, kMD5BufferSize); |
| + len = base::ReadPlatformFile( |
| + file, bytes_processed, buffer.get(), 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_); |
| - } |
| + 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, |
| - base::Passed(&reader), |
| + file, |
| bytes_processed + len, |
| bytes_total, |
| progress_offset, |
| progress_scale, |
| callback)); |
| + // Skip closing the file. |
| + return; |
| } else if (len == 0) { |
| if (bytes_processed + len < bytes_total) { |
|
tbarzic
2014/02/13 06:58:52
you should not attempt reading if (bytes_process =
Drew Haven
2014/02/13 20:48:10
I think I cleaned up the logic a bit. Thanks for
|
| - reader->Close(); |
| Error(error::kHashReadError); |
| } else { |
| base::MD5Digest digest; |
| base::MD5Final(&digest, &md5_context_); |
| - scoped_ptr<std::string> hash( |
| - new std::string(base::MD5DigestToBase16(digest))); |
| - callback.Run(hash.Pass()); |
| + std::string hash = base::MD5DigestToBase16(digest); |
|
tbarzic
2014/02/13 06:58:52
you don't need tmp var
Drew Haven
2014/02/13 20:48:10
Done.
|
| + callback.Run(hash); |
| } |
| } else { // len < 0 |
| - reader->Close(); |
| Error(error::kHashReadError); |
| } |
| + base::ClosePlatformFile(file); |
| } |
| -void Operation::OnUnzipSuccess() { |
| +void Operation::OnUnzipSuccess(const base::Closure& continuation) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| SetProgress(kProgressComplete); |
| - WriteStart(); |
| + continuation.Run(); |
| } |
| void Operation::OnUnzipFailure() { |
| @@ -339,5 +341,15 @@ void Operation::OnUnzipProgress(int64 total_bytes, int64 progress_bytes) { |
| 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 |