- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / file_system / open_file_operation.cc
1 // Copyright 2013 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/drive/file_system/open_file_operation.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/task_runner_util.h"
13 #include "chrome/browser/chromeos/drive/drive.pb.h"
14 #include "chrome/browser/chromeos/drive/file_cache.h"
15 #include "chrome/browser/chromeos/drive/file_errors.h"
16 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h"
17 #include "chrome/browser/chromeos/drive/file_system/download_operation.h"
18 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
19 #include "chrome/browser/chromeos/drive/file_system_interface.h"
20 #include "content/public/browser/browser_thread.h"
21
22 using content::BrowserThread;
23
24 namespace drive {
25 namespace file_system {
26
27 OpenFileOperation::OpenFileOperation(
28     base::SequencedTaskRunner* blocking_task_runner,
29     OperationObserver* observer,
30     JobScheduler* scheduler,
31     internal::ResourceMetadata* metadata,
32     internal::FileCache* cache,
33     const base::FilePath& temporary_file_directory)
34     : blocking_task_runner_(blocking_task_runner),
35       observer_(observer),
36       cache_(cache),
37       create_file_operation_(new CreateFileOperation(
38           blocking_task_runner, observer, scheduler, metadata, cache)),
39       download_operation_(new DownloadOperation(
40           blocking_task_runner, observer, scheduler,
41           metadata, cache, temporary_file_directory)),
42       weak_ptr_factory_(this) {
43 }
44
45 OpenFileOperation::~OpenFileOperation() {
46 }
47
48 void OpenFileOperation::OpenFile(const base::FilePath& file_path,
49                                  OpenMode open_mode,
50                                  const std::string& mime_type,
51                                  const OpenFileCallback& callback) {
52   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
53   DCHECK(!callback.is_null());
54
55   switch (open_mode) {
56     case OPEN_FILE:
57       // It is not necessary to create a new file even if not exists.
58       // So call OpenFileAfterCreateFile directly with FILE_ERROR_OK
59       // to skip file creation.
60       OpenFileAfterCreateFile(file_path, callback, FILE_ERROR_OK);
61       break;
62     case CREATE_FILE:
63       create_file_operation_->CreateFile(
64           file_path,
65           true,  // exclusive: fail if already exists
66           mime_type,
67           base::Bind(&OpenFileOperation::OpenFileAfterCreateFile,
68                      weak_ptr_factory_.GetWeakPtr(), file_path, callback));
69       break;
70     case OPEN_OR_CREATE_FILE:
71       create_file_operation_->CreateFile(
72           file_path,
73           false,  // not-exclusive
74           mime_type,
75           base::Bind(&OpenFileOperation::OpenFileAfterCreateFile,
76                      weak_ptr_factory_.GetWeakPtr(), file_path, callback));
77       break;
78   }
79 }
80
81 void OpenFileOperation::OpenFileAfterCreateFile(
82     const base::FilePath& file_path,
83     const OpenFileCallback& callback,
84     FileError error) {
85   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
86   DCHECK(!callback.is_null());
87
88   if (error != FILE_ERROR_OK) {
89     callback.Run(error, base::FilePath(), base::Closure());
90     return;
91   }
92
93   download_operation_->EnsureFileDownloadedByPath(
94       file_path,
95       ClientContext(USER_INITIATED),
96       GetFileContentInitializedCallback(),
97       google_apis::GetContentCallback(),
98       base::Bind(
99           &OpenFileOperation::OpenFileAfterFileDownloaded,
100           weak_ptr_factory_.GetWeakPtr(), callback));
101 }
102
103 void OpenFileOperation::OpenFileAfterFileDownloaded(
104     const OpenFileCallback& callback,
105     FileError error,
106     const base::FilePath& local_file_path,
107     scoped_ptr<ResourceEntry> entry) {
108   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
109   DCHECK(!callback.is_null());
110
111   if (error == FILE_ERROR_OK) {
112     DCHECK(entry);
113     DCHECK(entry->has_file_specific_info());
114     if (entry->file_specific_info().is_hosted_document())
115       // No support for opening a hosted document.
116       error = FILE_ERROR_INVALID_OPERATION;
117   }
118
119   if (error != FILE_ERROR_OK) {
120     callback.Run(error, base::FilePath(), base::Closure());
121     return;
122   }
123
124   base::PostTaskAndReplyWithResult(
125       blocking_task_runner_.get(),
126       FROM_HERE,
127       base::Bind(&internal::FileCache::MarkDirty,
128                  base::Unretained(cache_),
129                  entry->local_id()),
130       base::Bind(&OpenFileOperation::OpenFileAfterMarkDirty,
131                  weak_ptr_factory_.GetWeakPtr(),
132                  local_file_path,
133                  entry->local_id(),
134                  callback));
135 }
136
137 void OpenFileOperation::OpenFileAfterMarkDirty(
138     const base::FilePath& local_file_path,
139     const std::string& local_id,
140     const OpenFileCallback& callback,
141     FileError error) {
142   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
143   DCHECK(!callback.is_null());
144
145   if (error != FILE_ERROR_OK) {
146     callback.Run(error, base::FilePath(), base::Closure());
147     return;
148   }
149
150   ++open_files_[local_id];
151   callback.Run(error, local_file_path,
152                base::Bind(&OpenFileOperation::CloseFile,
153                           weak_ptr_factory_.GetWeakPtr(), local_id));
154 }
155
156 void OpenFileOperation::CloseFile(const std::string& local_id) {
157   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
158   DCHECK_GT(open_files_[local_id], 0);
159
160   if (--open_files_[local_id] == 0) {
161     // All clients closes this file, so notify to upload the file.
162     open_files_.erase(local_id);
163     observer_->OnCacheFileUploadNeededByOperation(local_id);
164
165     // Clients may have enlarged the file. By FreeDiskpSpaceIfNeededFor(0),
166     // we try to ensure (0 + the-minimum-safe-margin = 512MB as of now) space.
167     blocking_task_runner_->PostTask(
168         FROM_HERE,
169         base::Bind(base::IgnoreResult(
170             base::Bind(&internal::FileCache::FreeDiskSpaceIfNeededFor,
171                        base::Unretained(cache_),
172                        0))));
173   }
174 }
175
176 }  // namespace file_system
177 }  // namespace drive