1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/file_manager/zip_file_creator.h"
6
7#include "base/bind.h"
8#include "base/callback_helpers.h"
9#include "base/message_loop/message_loop.h"
10#include "base/threading/sequenced_worker_pool.h"
11#include "chrome/common/chrome_utility_messages.h"
12#include "content/public/browser/browser_thread.h"
13#include "content/public/browser/utility_process_host.h"
14
15using content::BrowserThread;
16using content::UtilityProcessHost;
17
18namespace {
19
20// Creates the destination zip file only if it does not already exist.
21base::File OpenFileHandleOnBlockingThreadPool(const base::FilePath& zip_path) {
22  return base::File(zip_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
23}
24
25}  // namespace
26
27namespace file_manager {
28
29ZipFileCreator::ZipFileCreator(
30    const ResultCallback& callback,
31    const base::FilePath& src_dir,
32    const std::vector<base::FilePath>& src_relative_paths,
33    const base::FilePath& dest_file)
34    : callback_(callback),
35      src_dir_(src_dir),
36      src_relative_paths_(src_relative_paths),
37      dest_file_(dest_file) {
38  DCHECK(!callback_.is_null());
39}
40
41void ZipFileCreator::Start() {
42  DCHECK_CURRENTLY_ON(BrowserThread::UI);
43
44  base::PostTaskAndReplyWithResult(
45      BrowserThread::GetBlockingPool(),
46      FROM_HERE,
47      base::Bind(&OpenFileHandleOnBlockingThreadPool, dest_file_),
48      base::Bind(&ZipFileCreator::OnOpenFileHandle, this));
49}
50
51ZipFileCreator::~ZipFileCreator() {
52}
53
54bool ZipFileCreator::OnMessageReceived(const IPC::Message& message) {
55  bool handled = true;
56  IPC_BEGIN_MESSAGE_MAP(ZipFileCreator, message)
57    IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_CreateZipFile_Succeeded,
58                        OnCreateZipFileSucceeded)
59    IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_CreateZipFile_Failed,
60                        OnCreateZipFileFailed)
61    IPC_MESSAGE_UNHANDLED(handled = false)
62  IPC_END_MESSAGE_MAP()
63  return handled;
64}
65
66void ZipFileCreator::OnProcessCrashed(int exit_code) {
67  ReportDone(false);
68}
69
70void ZipFileCreator::OnOpenFileHandle(base::File file) {
71  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
72
73  if (!file.IsValid()) {
74    LOG(ERROR) << "Failed to create dest zip file " << dest_file_.value();
75    ReportDone(false);
76    return;
77  }
78
79  BrowserThread::PostTask(
80      BrowserThread::IO,
81      FROM_HERE,
82      base::Bind(
83          &ZipFileCreator::StartProcessOnIOThread, this, base::Passed(&file)));
84}
85
86void ZipFileCreator::StartProcessOnIOThread(base::File dest_file) {
87  DCHECK_CURRENTLY_ON(BrowserThread::IO);
88
89  base::FileDescriptor dest_fd(dest_file.Pass());
90
91  UtilityProcessHost* host = UtilityProcessHost::Create(
92      this,
93      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI).get());
94  host->SetExposedDir(src_dir_);
95  host->Send(new ChromeUtilityMsg_CreateZipFile(src_dir_, src_relative_paths_,
96                                                dest_fd));
97}
98
99void ZipFileCreator::OnCreateZipFileSucceeded() {
100  ReportDone(true);
101}
102
103void ZipFileCreator::OnCreateZipFileFailed() {
104  ReportDone(false);
105}
106
107void ZipFileCreator::ReportDone(bool success) {
108  DCHECK_CURRENTLY_ON(BrowserThread::UI);
109
110  // Guard against calling observer multiple times.
111  if (!callback_.is_null())
112    base::ResetAndReturn(&callback_).Run(success);
113}
114
115}  // namespace file_manager
116