Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chromeos / drive / file_system / create_file_operation.cc
blob36da187d463591abed73cd0c6654ce955ce88cfc
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.
5 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h"
7 #include <string>
9 #include "base/file_util.h"
10 #include "chrome/browser/chromeos/drive/drive.pb.h"
11 #include "chrome/browser/chromeos/drive/file_cache.h"
12 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
13 #include "chrome/browser/chromeos/drive/file_system_util.h"
14 #include "chrome/browser/chromeos/drive/job_scheduler.h"
15 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
16 #include "chrome/browser/chromeos/drive/resource_metadata.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "net/base/mime_util.h"
20 using content::BrowserThread;
22 namespace drive {
23 namespace file_system {
25 namespace {
27 const char kMimeTypeOctetStream[] = "application/octet-stream";
29 // Part of CreateFileOperation::CreateFile(), runs on |blocking_task_runner_|
30 // of the operation, before server-side file creation.
31 FileError CheckPreConditionForCreateFile(internal::ResourceMetadata* metadata,
32 const base::FilePath& file_path,
33 bool is_exclusive,
34 std::string* parent_resource_id,
35 std::string* mime_type) {
36 DCHECK(metadata);
37 DCHECK(parent_resource_id);
38 DCHECK(mime_type);
40 ResourceEntry entry;
41 FileError error = metadata->GetResourceEntryByPath(file_path, &entry);
42 if (error == FILE_ERROR_OK) {
43 // Error if an exclusive mode is requested, or the entry is not a file.
44 return (is_exclusive ||
45 entry.file_info().is_directory() ||
46 entry.file_specific_info().is_hosted_document()) ?
47 FILE_ERROR_EXISTS : FILE_ERROR_OK;
50 // If the file is not found, an actual request to create a new file will be
51 // sent to the server.
52 if (error == FILE_ERROR_NOT_FOUND) {
53 // If parent path is not a directory, it is an error.
54 ResourceEntry parent;
55 if (metadata->GetResourceEntryByPath(
56 file_path.DirName(), &parent) != FILE_ERROR_OK ||
57 !parent.file_info().is_directory())
58 return FILE_ERROR_NOT_A_DIRECTORY;
60 // In the request, parent_resource_id and mime_type are needed.
61 // Here, populate them.
62 *parent_resource_id = parent.resource_id();
64 // If mime_type is not set or "application/octet-stream", guess from the
65 // |file_path|. If it is still unsure, use octet-stream by default.
66 if ((mime_type->empty() || *mime_type == kMimeTypeOctetStream) &&
67 !net::GetMimeTypeFromFile(file_path, mime_type)) {
68 *mime_type = kMimeTypeOctetStream;
72 return error;
75 // Part of CreateFileOperation::CreateFile(), runs on |blocking_task_runner_|
76 // of the operation, after server side file creation.
77 FileError UpdateLocalStateForCreateFile(
78 internal::ResourceMetadata* metadata,
79 internal::FileCache* cache,
80 scoped_ptr<google_apis::ResourceEntry> resource_entry,
81 base::FilePath* file_path) {
82 DCHECK(metadata);
83 DCHECK(cache);
84 DCHECK(resource_entry);
85 DCHECK(file_path);
87 // Add the entry to the local resource metadata.
88 ResourceEntry entry;
89 std::string parent_resource_id;
90 if (!ConvertToResourceEntry(*resource_entry, &entry, &parent_resource_id) ||
91 parent_resource_id.empty())
92 return FILE_ERROR_NOT_A_FILE;
94 std::string parent_local_id;
95 FileError error = metadata->GetIdByResourceId(parent_resource_id,
96 &parent_local_id);
97 if (error != FILE_ERROR_OK)
98 return error;
99 entry.set_parent_local_id(parent_local_id);
101 std::string local_id;
102 error = metadata->AddEntry(entry, &local_id);
104 // Depending on timing, the metadata may have inserted via change list
105 // already. So, FILE_ERROR_EXISTS is not an error.
106 if (error == FILE_ERROR_EXISTS)
107 error = metadata->GetIdByResourceId(entry.resource_id(), &local_id);
109 if (error == FILE_ERROR_OK) {
110 // At this point, upload to the server is fully succeeded.
111 // Populate the |file_path| which will be used to notify the observer.
112 *file_path = metadata->GetFilePath(local_id);
114 // Also store an empty file to the cache.
115 // Here, failure is not a fatal error, so ignore the returned code.
116 FileError cache_store_error = FILE_ERROR_FAILED;
117 base::FilePath empty_file;
118 if (base::CreateTemporaryFile(&empty_file)) {
119 cache_store_error = cache->Store(
120 local_id,
121 entry.file_specific_info().md5(),
122 empty_file,
123 internal::FileCache::FILE_OPERATION_MOVE);
125 DLOG_IF(WARNING, cache_store_error != FILE_ERROR_OK)
126 << "Failed to store a cache file: "
127 << FileErrorToString(cache_store_error)
128 << ", local_id: " << local_id;
131 return error;
134 } // namespace
136 CreateFileOperation::CreateFileOperation(
137 base::SequencedTaskRunner* blocking_task_runner,
138 OperationObserver* observer,
139 JobScheduler* scheduler,
140 internal::ResourceMetadata* metadata,
141 internal::FileCache* cache)
142 : blocking_task_runner_(blocking_task_runner),
143 observer_(observer),
144 scheduler_(scheduler),
145 metadata_(metadata),
146 cache_(cache),
147 weak_ptr_factory_(this) {
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
151 CreateFileOperation::~CreateFileOperation() {
152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
155 void CreateFileOperation::CreateFile(const base::FilePath& file_path,
156 bool is_exclusive,
157 const std::string& mime_type,
158 const FileOperationCallback& callback) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160 DCHECK(!callback.is_null());
162 std::string* parent_resource_id = new std::string;
163 std::string* determined_mime_type = new std::string(mime_type);
164 base::PostTaskAndReplyWithResult(
165 blocking_task_runner_.get(),
166 FROM_HERE,
167 base::Bind(&CheckPreConditionForCreateFile,
168 metadata_,
169 file_path,
170 is_exclusive,
171 parent_resource_id,
172 determined_mime_type),
173 base::Bind(&CreateFileOperation::CreateFileAfterCheckPreCondition,
174 weak_ptr_factory_.GetWeakPtr(),
175 file_path,
176 callback,
177 base::Owned(parent_resource_id),
178 base::Owned(determined_mime_type)));
181 void CreateFileOperation::CreateFileAfterCheckPreCondition(
182 const base::FilePath& file_path,
183 const FileOperationCallback& callback,
184 std::string* parent_resource_id,
185 std::string* mime_type,
186 FileError error) {
187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
188 DCHECK(!callback.is_null());
189 DCHECK(parent_resource_id);
190 DCHECK(mime_type);
192 // If the file is found, or an error other than "not found" is found,
193 // runs callback and quit the operation.
194 if (error != FILE_ERROR_NOT_FOUND) {
195 callback.Run(error);
196 return;
199 scheduler_->CreateFile(
200 *parent_resource_id,
201 file_path,
202 file_path.BaseName().value(),
203 *mime_type,
204 ClientContext(USER_INITIATED),
205 base::Bind(&CreateFileOperation::CreateFileAfterUpload,
206 weak_ptr_factory_.GetWeakPtr(),
207 callback));
210 void CreateFileOperation::CreateFileAfterUpload(
211 const FileOperationCallback& callback,
212 google_apis::GDataErrorCode gdata_error,
213 scoped_ptr<google_apis::ResourceEntry> resource_entry) {
214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
215 DCHECK(!callback.is_null());
217 FileError error = GDataToFileError(gdata_error);
218 if (error != FILE_ERROR_OK) {
219 callback.Run(error);
220 return;
222 DCHECK(resource_entry);
224 base::FilePath* file_path = new base::FilePath;
225 base::PostTaskAndReplyWithResult(
226 blocking_task_runner_.get(),
227 FROM_HERE,
228 base::Bind(&UpdateLocalStateForCreateFile,
229 metadata_,
230 cache_,
231 base::Passed(&resource_entry),
232 file_path),
233 base::Bind(&CreateFileOperation::CreateFileAfterUpdateLocalState,
234 weak_ptr_factory_.GetWeakPtr(),
235 callback,
236 base::Owned(file_path)));
239 void CreateFileOperation::CreateFileAfterUpdateLocalState(
240 const FileOperationCallback& callback,
241 base::FilePath* file_path,
242 FileError error) {
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
244 DCHECK(!callback.is_null());
245 DCHECK(file_path);
247 // Notify observer if the file creation process is successfully done.
248 if (error == FILE_ERROR_OK)
249 observer_->OnDirectoryChangedByOperation(file_path->DirName());
251 callback.Run(error);
254 } // namespace file_system
255 } // namespace drive