Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1137)

Side by Side Diff: chrome/browser/chromeos/drive/file_system/create_file_operation.cc

Issue 137423010: drive: Support offline file creation (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h" 5 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "chrome/browser/chromeos/drive/drive.pb.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" 11 #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" 12 #include "chrome/browser/chromeos/drive/resource_metadata.h"
17 #include "content/public/browser/browser_thread.h" 13 #include "content/public/browser/browser_thread.h"
18 #include "net/base/mime_util.h" 14 #include "net/base/mime_util.h"
19 15
20 using content::BrowserThread; 16 using content::BrowserThread;
21 17
22 namespace drive { 18 namespace drive {
23 namespace file_system { 19 namespace file_system {
24 20
25 namespace { 21 namespace {
26 22
27 const char kMimeTypeOctetStream[] = "application/octet-stream"; 23 const char kMimeTypeOctetStream[] = "application/octet-stream";
28 24
29 // Part of CreateFileOperation::CreateFile(), runs on |blocking_task_runner_| 25 // Updates local state.
30 // of the operation, before server-side file creation. 26 FileError UpdateLocalState(internal::ResourceMetadata* metadata,
31 FileError CheckPreConditionForCreateFile(internal::ResourceMetadata* metadata, 27 const base::FilePath& file_path,
32 const base::FilePath& file_path, 28 const std::string& mime_type_in,
33 bool is_exclusive, 29 ResourceEntry* entry) {
34 std::string* parent_resource_id,
35 std::string* mime_type) {
36 DCHECK(metadata); 30 DCHECK(metadata);
37 DCHECK(parent_resource_id);
38 DCHECK(mime_type);
39 31
40 ResourceEntry entry; 32 FileError error = metadata->GetResourceEntryByPath(file_path, entry);
41 FileError error = metadata->GetResourceEntryByPath(file_path, &entry); 33 if (error == FILE_ERROR_OK)
42 if (error == FILE_ERROR_OK) { 34 return FILE_ERROR_EXISTS;
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;
48 }
49 35
50 // If the file is not found, an actual request to create a new file will be 36 if (error != FILE_ERROR_NOT_FOUND)
51 // sent to the server. 37 return error;
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;
59 38
60 // In the request, parent_resource_id and mime_type are needed. 39 // If parent path is not a directory, it is an error.
61 // Here, populate them. 40 ResourceEntry parent;
62 *parent_resource_id = parent.resource_id(); 41 if (metadata->GetResourceEntryByPath(
42 file_path.DirName(), &parent) != FILE_ERROR_OK ||
43 !parent.file_info().is_directory())
44 return FILE_ERROR_NOT_A_DIRECTORY;
63 45
64 // If mime_type is not set or "application/octet-stream", guess from the 46 // 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. 47 // |file_path|. If it is still unsure, use octet-stream by default.
66 if ((mime_type->empty() || *mime_type == kMimeTypeOctetStream) && 48 std::string mime_type = mime_type_in;
67 !net::GetMimeTypeFromFile(file_path, mime_type)) { 49 if ((mime_type.empty() || mime_type == kMimeTypeOctetStream) &&
68 *mime_type = kMimeTypeOctetStream; 50 !net::GetMimeTypeFromFile(file_path, &mime_type))
69 } 51 mime_type = kMimeTypeOctetStream;
70 }
71 52
53 // Add the entry to the local resource metadata.
54 const base::Time now = base::Time::Now();
55 entry->mutable_file_info()->set_last_modified(now.ToInternalValue());
56 entry->mutable_file_info()->set_last_accessed(now.ToInternalValue());
57 entry->set_title(file_path.BaseName().AsUTF8Unsafe());
58 entry->set_parent_local_id(parent.local_id());
59 entry->set_metadata_edit_state(ResourceEntry::DIRTY);
60 entry->mutable_file_specific_info()->set_content_mime_type(mime_type);
61
62 std::string local_id;
63 error = metadata->AddEntry(*entry, &local_id);
64 entry->set_local_id(local_id);
72 return error; 65 return error;
73 } 66 }
74 67
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);
86
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;
93
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);
100
101 std::string local_id;
102 error = metadata->AddEntry(entry, &local_id);
103
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);
108
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);
113
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);
124 }
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;
129 }
130
131 return error;
132 }
133
134 } // namespace 68 } // namespace
135 69
136 CreateFileOperation::CreateFileOperation( 70 CreateFileOperation::CreateFileOperation(
137 base::SequencedTaskRunner* blocking_task_runner, 71 base::SequencedTaskRunner* blocking_task_runner,
138 OperationObserver* observer, 72 OperationObserver* observer,
139 JobScheduler* scheduler, 73 internal::ResourceMetadata* metadata)
140 internal::ResourceMetadata* metadata,
141 internal::FileCache* cache)
142 : blocking_task_runner_(blocking_task_runner), 74 : blocking_task_runner_(blocking_task_runner),
143 observer_(observer), 75 observer_(observer),
144 scheduler_(scheduler),
145 metadata_(metadata), 76 metadata_(metadata),
146 cache_(cache),
147 weak_ptr_factory_(this) { 77 weak_ptr_factory_(this) {
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
149 } 79 }
150 80
151 CreateFileOperation::~CreateFileOperation() { 81 CreateFileOperation::~CreateFileOperation() {
152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
153 } 83 }
154 84
155 void CreateFileOperation::CreateFile(const base::FilePath& file_path, 85 void CreateFileOperation::CreateFile(const base::FilePath& file_path,
156 bool is_exclusive, 86 bool is_exclusive,
157 const std::string& mime_type, 87 const std::string& mime_type,
158 const FileOperationCallback& callback) { 88 const FileOperationCallback& callback) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160 DCHECK(!callback.is_null()); 90 DCHECK(!callback.is_null());
161 91
162 std::string* parent_resource_id = new std::string; 92 ResourceEntry* entry = new ResourceEntry;
163 std::string* determined_mime_type = new std::string(mime_type);
164 base::PostTaskAndReplyWithResult( 93 base::PostTaskAndReplyWithResult(
165 blocking_task_runner_.get(), 94 blocking_task_runner_.get(),
166 FROM_HERE, 95 FROM_HERE,
167 base::Bind(&CheckPreConditionForCreateFile, 96 base::Bind(&UpdateLocalState,
168 metadata_, 97 metadata_,
169 file_path, 98 file_path,
170 is_exclusive, 99 mime_type,
171 parent_resource_id, 100 entry),
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)));
179 }
180
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);
191
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;
197 }
198
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));
208 }
209
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());
216
217 FileError error = GDataToFileError(gdata_error);
218 if (error != FILE_ERROR_OK) {
219 callback.Run(error);
220 return;
221 }
222 DCHECK(resource_entry);
223
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, 101 base::Bind(&CreateFileOperation::CreateFileAfterUpdateLocalState,
234 weak_ptr_factory_.GetWeakPtr(), 102 weak_ptr_factory_.GetWeakPtr(),
235 callback, 103 callback,
236 base::Owned(file_path))); 104 file_path,
105 is_exclusive,
106 base::Owned(entry)));
237 } 107 }
238 108
239 void CreateFileOperation::CreateFileAfterUpdateLocalState( 109 void CreateFileOperation::CreateFileAfterUpdateLocalState(
240 const FileOperationCallback& callback, 110 const FileOperationCallback& callback,
241 base::FilePath* file_path, 111 const base::FilePath& file_path,
112 bool is_exclusive,
113 ResourceEntry* entry,
242 FileError error) { 114 FileError error) {
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
244 DCHECK(!callback.is_null()); 116 DCHECK(!callback.is_null());
245 DCHECK(file_path);
246 117
247 // Notify observer if the file creation process is successfully done. 118 if (error == FILE_ERROR_EXISTS) {
248 if (error == FILE_ERROR_OK) 119 // Error if an exclusive mode is requested, or the entry is not a file.
249 observer_->OnDirectoryChangedByOperation(file_path->DirName()); 120 error = (is_exclusive ||
250 121 entry->file_info().is_directory() ||
122 entry->file_specific_info().is_hosted_document()) ?
123 FILE_ERROR_EXISTS : FILE_ERROR_OK;
124 } else if (error == FILE_ERROR_OK) {
125 // Notify observer if the file was newly created.
126 observer_->OnDirectoryChangedByOperation(file_path.DirName());
127 observer_->OnEntryUpdatedByOperation(entry->local_id());
128 }
251 callback.Run(error); 129 callback.Run(error);
252 } 130 }
253 131
254 } // namespace file_system 132 } // namespace file_system
255 } // namespace drive 133 } // namespace drive
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698